pax_global_header00006660000000000000000000000064130546043040014511gustar00rootroot0000000000000052 comment=48b5680c0bc103e036cbcb08da7c612dd35ce677 concurrent-ruby-1.0.5/000077500000000000000000000000001305460430400146555ustar00rootroot00000000000000concurrent-ruby-1.0.5/.coveralls.yml000066400000000000000000000000561305460430400174510ustar00rootroot00000000000000repo_token: SUelFoD84eVxiCok3zpTOUH2ymQ1BceRW concurrent-ruby-1.0.5/.github/000077500000000000000000000000001305460430400162155ustar00rootroot00000000000000concurrent-ruby-1.0.5/.github/CONTRIBUTING.md000066400000000000000000000144641305460430400204570ustar00rootroot00000000000000# Contributing to Concurrent Ruby You want to contribute? Thank you! Concurrent Ruby is work of [many contributors](https://github.com/ruby-concurrency/concurrent-ruby/graphs/contributors). You're encouraged to submit [pull requests](https://github.com/ruby-concurrency/concurrent-ruby/pulls), [propose features and discuss issues](https://github.com/ruby-concurrency/concurrent-ruby/issues). When in doubt, ask a question in the [Concurrent Ruby gitter.im chatroom](https://gitter.im/ruby-concurrency/concurrent-ruby) or on the [mailing list](https://groups.google.com/forum/#!forum/concurrent-ruby). #### Find Something to Work on If you want to contribute but aren't sure what to work on, we keep our list of current todos on our [issues page](https://github.com/ruby-concurrency/concurrent-ruby/issues). Before starting, feel free to chat with us on [gitter](https://gitter.im/ruby-concurrency/concurrent-ruby). #### Fork the Project Fork the [project on Github](https://github.com/ruby-concurrency/concurrent-ruby) and check out your copy. ``` git clone https://github.com/contributor/concurrent-ruby.git cd concurrent-ruby git remote add upstream https://github.com/ruby-concurrency/concurrent-ruby.git ``` #### Create a Topic Branch Make sure your fork is up-to-date and create a topic branch for your feature or bug fix. ``` git checkout master git pull upstream master git checkout -b my-feature-branch ``` #### Bundle Install, Build and Test Ensure that you can build the project and run tests. Please note that Concurrent Ruby includes native Java and (optional) C extensions. When building you will need the appropriate build tools for your platform. If you don't have the build tools installed that's OK. The tests can still be run. A few tests may fail, but these are just the tests that verify that the extensions exist. You can usually ignore these locally if you are working on the pure Ruby parts of the library (which is most of the lib). ``` bundle install bundle exec rake ``` #### Write Tests Try to write a test that reproduces the problem you're trying to fix or describes a feature that you want to build. Add to [specs](https://github.com/ruby-concurrency/concurrent-ruby/tree/master/spec). We definitely appreciate pull requests that highlight or reproduce a problem, even without a fix. #### Write Code Implement your feature or bug fix. Make sure that `bundle exec rake` completes without errors. #### Follow the Guidelines There are a few very strong guidelines which we follow when adding features. Submissions which fail to follow these guidelines will likely be rejected or will require modification before acceptance. * **No downstream dependencies:** Concurrent Ruby is a foundational library used by major projects like [Rails](http://rubyonrails.org/). Our downstream dependencies become everyone's dependencies. Because we cannot guarantee that downstream projects meet our development standards, it's best for everyone if we simply aviod dependencies. * **Do not monkey patch Ruby:** Changing Ruby for our convenience affects every gem in every project that uses Concurrent Ruby. Monkey patching Ruby may change the behavior of other libraries in unexpected ways and destabilize projects which depend on us. * **Do not polute the global namespace:** Putting all our code within the `Concurrent` module guarantees that there will be no namespace collisions with other gems or the projects which depend on us. * **No global varaibles:** Global state should be kept to an absolute minimum. When it's necessary, add it to the global gem configuration. * **Minimize per-object configuration:** Ruby makes programmers happy. One of Ruby's charms is its simplicity. Concurrent Ruby aims to mirror this simplicity. Advanced configuration options are encouraged when they provide value, but every abstraction should have reasonable defaults that meet the needs of most users. * **Provide explicit behavior and guarantees:** Our APIs should be concrete and clearly define what they do (and don't do). Users of Concurrent Ruby should never be surprised by unexpected behavior or be given guarantees we cannot keep. * **Eat our own dog food:** Concurrent Ruby provides a rich set of low-level (internal and public) classes which provide strong guarantees and are optimized for performance across platforms. All our high-level abstractions should make use of these tools. #### Write Documentation Document any external behavior in the [README](README.md). #### Commit Changes Make sure git knows your name and email address: ``` git config --global user.name "Your Name" git config --global user.email "contributor@example.com" ``` Writing good commit logs is important. A commit log should describe what changed and why. ``` git add ... git commit ``` #### Push ``` git push origin my-feature-branch ``` #### Make a Pull Request Go to https://github.com/contributor/concurrent-ruby and select your feature branch. Click the 'Pull Request' button and fill out the form. Pull requests are usually reviewed within a few days. #### Rebase If you've been working on a change for a while, rebase with upstream/master. ``` git fetch upstream git rebase upstream/master git push origin my-feature-branch -f ``` #### Update CHANGELOG Again Update the [CHANGELOG](CHANGELOG.md) with a description of what you have changed. Amend your previous commit and force push the changes. ``` git commit --amend git push origin my-feature-branch -f ``` #### Check on Your Pull Request Go back to your pull request after a few minutes and see whether it passed muster with Travis-CI and AppVeyor. Everything should look green, otherwise fix issues and amend your commit as described above. Please note that testing concurrency is hard. Very hard. We have a few tests that occasionally fail due (mostly) to incorrect synchronization within the test itself. If everything passes locally but you see an error on CI, it's possibly you've become victim to one of the tests. Don't worry, the Concurrent Ruby team reviews the tests output of all failed CI runs and will let you know if the failing test is unrelated to your commit. #### Thank You Please do know that we really appreciate and value your time and work. We love you, really. And also, a special thank you to the [Volt](https://github.com/voltrb/volt) team for writing an awesome guide for contributors. We have borrowed liberally from theirs. concurrent-ruby-1.0.5/.github/ISSUE_TEMPLATE.md000066400000000000000000000004331305460430400207220ustar00rootroot00000000000000 ****** - Operating system: linux / mac / win - `concurrent-ruby` version: x.y.z - `concurrent-ruby-ext` installed: yes / no - `concurrent-ruby-edge` used: yes / no concurrent-ruby-1.0.5/.gitignore000066400000000000000000000003471305460430400166510ustar00rootroot00000000000000# Project Gemfile.lock .bundle tmp/* coverage pkg # Yard documentation .yardoc yardoc # IDEs' files *.iml *.tmproj .idea tmtags # Local Ruby settings .rspec-local .rvmrc .ruby-version .ruby-gemset # junk .DS_Store .githubtoken concurrent-ruby-1.0.5/.rspec000066400000000000000000000001001305460430400157610ustar00rootroot00000000000000--require spec_helper --color --warnings --format documentation concurrent-ruby-1.0.5/.travis.yml000066400000000000000000000011201305460430400167600ustar00rootroot00000000000000language: ruby rvm: # start with the latest - 2.4.0 - jruby-9.1.5.0 # older versions - 2.3.3 - 2.2.6 - 2.1.9 - 2.0.0 - 1.9.3 - jruby-9.0.5.0 - jruby-1.7.26 - ruby-head - jruby-head - rbx jdk: - oraclejdk8 sudo: false branches: only: - master matrix: include: - rvm: 2.3.1 jdk: oraclejdk8 env: COVERAGE=1 allow_failures: - rvm: ruby-head - rvm: jruby-head - rvm: 1.9.3 - rvm: rbx env: global: - JAVA_OPTS=-Xmx1024m before_install: - "echo JAVA_OPTS: $JAVA_OPTS" script: RUBYOPT=-w bundle exec rake ci concurrent-ruby-1.0.5/.yardopts000066400000000000000000000004521305460430400165240ustar00rootroot00000000000000--no-private --embed-mixins --output-dir ./yardoc --markup markdown --title=Concurrent Ruby --template default --template-path ./yard-template --default-return undocumented ./lib/**/*.rb ./ext/concurrent_ruby_ext/**/*.c - doc/thread_pools.md doc/promises.out.md README.md LICENSE.txt CHANGELOG.md concurrent-ruby-1.0.5/BUILDING.md000066400000000000000000000065331305460430400164030ustar00rootroot00000000000000# Building All published versions of this gem (core, extension, and several platform-specific packages) are compiled, packaged, tested, and published using an open, automated process. This process can also be used to create pre-compiled binaries of the extension gem for virtually any platform. *Documentation is forthcoming...* ``` *MRI only* bundle exec rake build:native # Build concurrent-ruby-ext--.gem into the pkg dir bundle exec rake compile:extension # Compile extension *JRuby only* bundle exec rake build # Build JRuby-specific core gem (alias for `build:core`) bundle exec rake build:core # Build concurrent-ruby--java.gem into the pkg directory *All except JRuby* bundle exec rake build:core # Build concurrent-ruby-.gem into the pkg directory bundle exec rake build:ext # Build concurrent-ruby-ext-.gem into the pkg directory *When Docker IS installed* bundle exec rake build:windows # Build the windows binary gems per rake-compiler-dock bundle exec rake build # Build core, extension, and edge gems, including Windows binaries *When Docker is NOT installed* bundle exec rake build # Build core, extension, and edge gems (excluding Windows binaries) *All* bundle exec rake clean # Remove any temporary products bundle exec rake clobber # Remove any generated file bundle exec rake compile # Compile all the extensions ``` ## Publishing the Gem To create the build you'll need to have both MRI and JRuby installed and configured with the appropriate build tools and libraries. To create the Windows build you'll need to install docker. If you are on OS X you'll also need boot2docker. Once you have all that setup, everything if fairly automated: * Update`version.rb` * Update the CHANGELOG * Switch to MRI - Make sure docker is running (otherwise the windows build task will not be available) - Run `bundle exec rake clean` to get rid of old artifacts - Run `bundle exec rake build` to build core, ext, ext-windows, and edge into the *pkg* directory * Switch to JRuby - Delete *Gemfile.lock* and run `bundle install` (this isn't always necessary, but our multi-gem setup sometimes confuses bundler) - Run `bundle exec rake clean` to get rid of old artifacts - Run `bundle exec rake build` to build core-java into the *pkg* directory * If everything looks good, update git - Commit the changes - Tag the master branch with the version number - Push to GitHub * Update the Yard documentation - Run `bundle exec rake yard` to update the documentation - Run `bundle exec rake yard:push` to push the docs to GitHub Pages * For each gem file in *pkg* run `gem push pkg/concurrent-ruby-<...>.gem` to push to Rubygems * Update the release in GitHub - Select the `releases` link on the main repo page - Press the `Edit` button to edit the release - Name the release based on the version number - Add a description - Attach all the `*.gem` file - Save the updated release The compiled and build gem packages can be tested using the scripts in the `build-tests` folder. The `runner.rb` script is the main test runner. It will run all tests which are available on the given platform. It will install the various gem packages (core, ext, and edge) as necessary, run the tests, then clean up after itself. concurrent-ruby-1.0.5/CHANGELOG.md000066400000000000000000000467301305460430400165000ustar00rootroot00000000000000## Release v1.0.5, edge v0.3.1 (26 Feb 2017) concurrent-ruby: * Documentation for Event and Semaphore * Use Unsafe#fullFence and #loadFence directly since the shortcuts were removed in JRuby * Do not depend on org.jruby.util.unsafe.UnsafeHolder concurrent-ruby-edge: * (#620) Actors on Pool raise an error * (#624) Delayed promises did not interact correctly with flatting * Fix arguments yielded by callback methods * Overridable default executor in promises factory methods * Asking actor to terminate will always resolve to `true` ## Release v1.0.4, edge v0.3.0 (27 Dec 2016) concurrent-ruby: * Nothing concurrent-ruby-edge: * New promises' API renamed, lots of improvements, edge bumped to 0.3.0 * **Incompatible** with previous 0.2.3 version * see https://github.com/ruby-concurrency/concurrent-ruby/pull/522 ## Release v1.0.3 (17 Dec 2016) * Trigger execution of flattened delayed futures * Avoid forking for processor_count if possible * Semaphore Mutex and JRuby parity * Adds Map#each as alias to Map#each_pair * Fix uninitialized instance variables * Make Fixnum, Bignum merger ready * Allows Promise#then to receive an executor * TimerSet now survives a fork * Reject promise on any exception * Allow ThreadLocalVar to be initialized with a block * Support Alpha with `Concurrent::processor_count` * Fixes format-security error when compiling ruby_193_compatible.h * Concurrent::Atom#swap fixed: reraise the exceptions from block ## Release v1.0.2 (2 May 2016) * Fix bug with `Concurrent::Map` MRI backend `#inspect` method * Fix bug with `Concurrent::Map` MRI backend using `Hash#value?` * Improved documentation and examples * Minor updates to Edge ## Release v1.0.1 (27 February 2016) * Fix "uninitialized constant Concurrent::ReentrantReadWriteLock" error. * Better handling of `autoload` vs. `require`. * Improved API for Edge `Future` zipping. * Fix reference leak in Edge `Future` constructor . * Fix bug which prevented thread pools from surviving a `fork`. * Fix bug in which `TimerTask` did not correctly specify all its dependencies. * Improved support for JRuby+Truffle * Improved error messages. * Improved documentation. * Updated README and CONTRIBUTING. ## Release v1.0.0 (13 November 2015) * Rename `attr_volatile_with_cas` to `attr_atomic` * Add `clear_each` to `LockFreeStack` * Update `AtomicReference` documentation * Further updates and improvements to the synchronization layer. * Performance and memory usage performance with `Actor` logging. * Fixed `ThreadPoolExecutor` task count methods. * Improved `Async` performance for both short and long-lived objects. * Fixed bug in `LockFreeLinkedSet`. * Fixed bug in which `Agent#await` triggered a validation failure. * Further `Channel` updates. * Adopted a project Code of Conduct * Cleared interpreter warnings * Fixed bug in `ThreadPoolExecutor` task count methods * Fixed bug in 'LockFreeLinkedSet' * Improved Java extension loading * Handle Exception children in Edge::Future * Continued improvements to channel * Removed interpreter warnings. * Shared constants now in `lib/concurrent/constants.rb` * Refactored many tests. * Improved synchronization layer/memory model documentation. * Bug fix in Edge `Future#flat` * Brand new `Channel` implementation in Edge gem. * Simplification of `RubySingleThreadExecutor` * `Async` improvements - Each object uses its own `SingleThreadExecutor` instead of the global thread pool. - No longers supports executor injection - Much better documentation * `Atom` updates - No longer `Dereferenceable` - Now `Observable` - Added a `#reset` method * Brand new `Agent` API and implementation. Now functionally equivalent to Clojure. * Continued improvements to the synchronization layer * Merged in the `thread_safe` gem - `Concurrent::Array` - `Concurrent::Hash` - `Concurrent::Map` (formerly ThreadSafe::Cache) - `Concurrent::Tuple` * Minor improvements to Concurrent::Map * Complete rewrite of `Exchanger` * Removed all deprecated code (classes, methods, constants, etc.) * Updated Agent, MutexAtomic, and BufferedChannel to inherit from Synchronization::Object. * Many improved tests * Some internal reorganization ## Release v0.9.1 (09 August 2015) * Fixed a Rubiniux bug in synchronization object * Fixed all interpreter warnings (except circular references) * Fixed require statements when requiring `Atom` alone * Significantly improved `ThreadLocalVar` on non-JRuby platforms * Fixed error handling in Edge `Concurrent.zip` * `AtomicFixnum` methods `#increment` and `#decrement` now support optional delta * New `AtomicFixnum#update` method * Minor optimizations in `ReadWriteLock` * New `ReentrantReadWriteLock` class * `ThreadLocalVar#bind` method is now public * Refactored many tests ## Release v0.9.0 (10 July 2015) * Updated `AtomicReference` - `AtomicReference#try_update` now simply returns instead of raising exception - `AtomicReference#try_update!` was added to raise exceptions if an update fails. Note: this is the same behavior as the old `try_update` * Pure Java implementations of - `AtomicBoolean` - `AtomicFixnum` - `Semaphore` * Fixed bug when pruning Ruby thread pools * Fixed bug in time calculations within `ScheduledTask` * Default `count` in `CountDownLatch` to 1 * Use monotonic clock for all timers via `Concurrent.monotonic_time` - Use `Process.clock_gettime(Process::CLOCK_MONOTONIC)` when available - Fallback to `java.lang.System.nanoTime()` on unsupported JRuby versions - Pure Ruby implementation for everything else - Effects `Concurrent.timer`, `Concurrent.timeout`, `TimerSet`, `TimerTask`, and `ScheduledTask` * Deprecated all clock-time based timer scheduling - Only support scheduling by delay - Effects `Concurrent.timer`, `TimerSet`, and `ScheduledTask` * Added new `ReadWriteLock` class * Consistent `at_exit` behavior for Java and Ruby thread pools. * Added `at_exit` handler to Ruby thread pools (already in Java thread pools) - Ruby handler stores the object id and retrieves from `ObjectSpace` - JRuby disables `ObjectSpace` by default so that handler stores the object reference * Added a `:stop_on_exit` option to thread pools to enable/disable `at_exit` handler * Updated thread pool docs to better explain shutting down thread pools * Simpler `:executor` option syntax for all abstractions which support this option * Added `Executor#auto_terminate?` predicate method (for thread pools) * Added `at_exit` handler to `TimerSet` * Simplified auto-termination of the global executors - Can now disable auto-termination of global executors - Added shutdown/kill/wait_for_termination variants for global executors * Can now disable auto-termination for *all* executors (the nuclear option) * Simplified auto-termination of the global executors * Deprecated terms "task pool" and "operation pool" - New terms are "io executor" and "fast executor" - New functions added with new names - Deprecation warnings added to functions referencing old names * Moved all thread pool related functions from `Concurrent::Configuration` to `Concurrent` - Old functions still exist with deprecation warnings - New functions have updated names as appropriate * All high-level abstractions default to the "io executor" * Fixed bug in `Actor` causing it to prematurely warm global thread pools on gem load - This also fixed a `RejectedExecutionError` bug when running with minitest/autorun via JRuby * Moved global logger up to the `Concurrent` namespace and refactored the code * Optimized the performance of `Delay` - Fixed a bug in which no executor option on construction caused block execution on a global thread pool * Numerous improvements and bug fixes to `TimerSet` * Fixed deadlock of `Future` when the handler raises Exception * Added shared specs for more classes * New concurrency abstractions including: - `Atom` - `Maybe` - `ImmutableStruct` - `MutableStruct` - `SettableStruct` * Created an Edge gem for unstable abstractions including - `Actor` - `Agent` - `Channel` - `Exchanger` - `LazyRegister` - **new Future Framework** - unified implementation of Futures and Promises which combines Features of previous `Future`, `Promise`, `IVar`, `Event`, `Probe`, `dataflow`, `Delay`, `TimerTask` into single framework. It uses extensively new synchronization layer to make all the paths **lock-free** with exception of blocking threads on `#wait`. It offers better performance and does not block threads when not required. * Actor framework changes: - fixed reset loop in Pool - Pool can use any actor as a worker, abstract worker class is no longer needed. - Actor events not have format `[:event_name, *payload]` instead of just the Symbol. - Actor now uses new Future/Promise Framework instead of `IVar` for better interoperability - Behaviour definition array was simplified to `[BehaviourClass1, [BehaviourClass2, *initialization_args]]` - Linking behavior responds to :linked message by returning array of linked actors - Supervised behavior is removed in favour of just Linking - RestartingContext is supervised by default now, `supervise: true` is not required any more - Events can be private and public, so far only difference is that Linking will pass to linked actors only public messages. Adding private :restarting and :resetting events which are send before the actor restarts or resets allowing to add callbacks to cleanup current child actors. - Print also object_id in Reference to_s - Add AbstractContext#default_executor to be able to override executor class wide - Add basic IO example - Documentation somewhat improved - All messages should have same priority. It's now possible to send `actor << job1 << job2 << :terminate!` and be sure that both jobs are processed first. * Refactored `Channel` to use newer synchronization objects * Added `#reset` and `#cancel` methods to `TimerSet` * Added `#cancel` method to `Future` and `ScheduledTask` * Refactored `TimerSet` to use `ScheduledTask` * Updated `Async` with a factory that initializes the object * Deprecated `Concurrent.timer` and `Concurrent.timeout` * Reduced max threads on pure-Ruby thread pools (abends around 14751 threads) * Moved many private/internal classes/modules into "namespace" modules * Removed brute-force killing of threads in tests * Fixed a thread pool bug when the operating system cannot allocate more threads ## Release v0.8.0 (25 January 2015) * C extension for MRI have been extracted into the `concurrent-ruby-ext` companion gem. Please see the README for more detail. * Better variable isolation in `Promise` and `Future` via an `:args` option * Continued to update intermittently failing tests ## Release v0.7.2 (24 January 2015) * New `Semaphore` class based on [java.util.concurrent.Semaphore](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html) * New `Promise.all?` and `Promise.any?` class methods * Renamed `:overflow_policy` on thread pools to `:fallback_policy` * Thread pools still accept the `:overflow_policy` option but display a warning * Thread pools now implement `fallback_policy` behavior when not running (rather than universally rejecting tasks) * Fixed minor `set_deref_options` constructor bug in `Promise` class * Fixed minor `require` bug in `ThreadLocalVar` class * Fixed race condition bug in `TimerSet` class * Fixed race condition bug in `TimerSet` class * Fixed signal bug in `TimerSet#post` method * Numerous non-functional updates to clear warning when running in debug mode * Fixed more intermittently failing tests * Tests now run on new Travis build environment * Multiple documentation updates ## Release v0.7.1 (4 December 2014) Please see the [roadmap](https://github.com/ruby-concurrency/concurrent-ruby/issues/142) for more information on the next planned release. * Added `flat_map` method to `Promise` * Added `zip` method to `Promise` * Fixed bug with logging in `Actor` * Improvements to `Promise` tests * Removed actor-experimental warning * Added an `IndirectImmediateExecutor` class * Allow disabling auto termination of global executors * Fix thread leaking in `ThreadLocalVar` (uses `Ref` gem on non-JRuby systems) * Fix thread leaking when pruning pure-Ruby thread pools * Prevent `Actor` from using an `ImmediateExecutor` (causes deadlock) * Added missing synchronizations to `TimerSet` * Fixed bug with return value of `Concurrent::Actor::Utils::Pool#ask` * Fixed timing bug in `TimerTask` * Fixed bug when creating a `JavaThreadPoolExecutor` with minimum pool size of zero * Removed confusing warning when not using native extenstions * Improved documentation ## Release v0.7.0 (13 August 2014) * Merge the [atomic](https://github.com/ruby-concurrency/atomic) gem - Pure Ruby `MutexAtomic` atomic reference class - Platform native atomic reference classes `CAtomic`, `JavaAtomic`, and `RbxAtomic` - Automated [build process](https://github.com/ruby-concurrency/rake-compiler-dev-box) - Fat binary releases for [multiple platforms](https://rubygems.org/gems/concurrent-ruby/versions) including Windows (32/64), Linux (32/64), OS X (64-bit), Solaris (64-bit), and JRuby * C native `CAtomicBoolean` * C native `CAtomicFixnum` * Refactored intermittently failing tests * Added `dataflow!` and `dataflow_with!` methods to match `Future#value!` method * Better handling of timeout in `Agent` * Actor Improvements - Fine-grained implementation using chain of behaviors. Each behavior is responsible for single aspect like: `Termination`, `Pausing`, `Linking`, `Supervising`, etc. Users can create custom Actors easily based on their needs. - Supervision was added. `RestartingContext` will pause on error waiting on its supervisor to decide what to do next ( options are `:terminate!`, `:resume!`, `:reset!`, `:restart!`). Supervising behavior also supports strategies `:one_for_one` and `:one_for_all`. - Linking was added to be able to monitor actor's events like: `:terminated`, `:paused`, `:restarted`, etc. - Dead letter routing added. Rejected envelopes are collected in a configurable actor (default: `Concurrent::Actor.root.ask!(:dead_letter_routing)`) - Old `Actor` class removed and replaced by new implementation previously called `Actress`. `Actress` was kept as an alias for `Actor` to keep compatibility. - `Utils::Broadcast` actor which allows Publish–subscribe pattern. * More executors for managing serialized operations - `SerializedExecution` mixin module - `SerializedExecutionDelegator` for serializing *any* executor * Updated `Async` with serialized execution * Updated `ImmediateExecutor` and `PerThreadExecutor` with full executor service lifecycle * Added a `Delay` to root `Actress` initialization * Minor bug fixes to thread pools * Refactored many intermittently failing specs * Removed Java interop warning `executor.rb:148 warning: ambiguous Java methods found, using submit(java.lang.Runnable)` * Fixed minor bug in `RubyCachedThreadPool` overflow policy * Updated tests to use [RSpec 3.0](http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3) * Removed deprecated `Actor` class * Better support for Rubinius ## Release v0.6.1 (14 June 2014) * Many improvements to `Concurrent::Actress` * Bug fixes to `Concurrent::RubyThreadPoolExecutor` * Fixed several brittle tests * Moved documentation to http://ruby-concurrency.github.io/concurrent-ruby/frames.html ## Release v0.6.0 (25 May 2014) * Added `Concurrent::Observable` to encapsulate our thread safe observer sets * Improvements to new `Channel` * Major improvements to `CachedThreadPool` and `FixedThreadPool` * Added `SingleThreadExecutor` * Added `Current::timer` function * Added `TimerSet` executor * Added `AtomicBoolean` * `ScheduledTask` refactoring * Pure Ruby and JRuby-optimized `PriorityQueue` classes * Updated `Agent` behavior to more closely match Clojure * Observer sets support block callbacks to the `add_observer` method * New algorithm for thread creation in `RubyThreadPoolExecutor` * Minor API updates to `Event` * Rewritten `TimerTask` now an `Executor` instead of a `Runnable` * Fixed many brittle specs * Renamed `FixedThreadPool` and `CachedThreadPool` to `RubyFixedThreadPool` and `RubyCachedThreadPool` * Created JRuby optimized `JavaFixedThreadPool` and `JavaCachedThreadPool` * Consolidated fixed thread pool tests into `spec/concurrent/fixed_thread_pool_shared.rb` and `spec/concurrent/cached_thread_pool_shared.rb` * `FixedThreadPool` now subclasses `RubyFixedThreadPool` or `JavaFixedThreadPool` as appropriate * `CachedThreadPool` now subclasses `RubyCachedThreadPool` or `JavaCachedThreadPool` as appropriate * New `Delay` class * `Concurrent::processor_count` helper function * New `Async` module * Renamed `NullThreadPool` to `PerThreadExecutor` * Deprecated `Channel` (we are planning a new implementation based on [Go](http://golangtutorials.blogspot.com/2011/06/channels-in-go.html)) * Added gem-level [configuration](http://robots.thoughtbot.com/mygem-configure-block) * Deprecated `$GLOBAL_THREAD_POOL` in lieu of gem-level configuration * Removed support for Ruby [1.9.2](https://www.ruby-lang.org/en/news/2013/12/17/maintenance-of-1-8-7-and-1-9-2/) * New `RubyThreadPoolExecutor` and `JavaThreadPoolExecutor` classes * All thread pools now extend the appropriate thread pool executor classes * All thread pools now support `:overflow_policy` (based on Java's [reject policies](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html)) * Deprecated `UsesGlobalThreadPool` in lieu of explicit `:executor` option (dependency injection) on `Future`, `Promise`, and `Agent` * Added `Concurrent::dataflow_with(executor, *inputs)` method to support executor dependency injection for dataflow * Software transactional memory with `TVar` and `Concurrent::atomically` * First implementation of [new, high-performance](https://github.com/ruby-concurrency/concurrent-ruby/pull/49) `Channel` * `Actor` is deprecated in favor of new experimental actor implementation [#73](https://github.com/ruby-concurrency/concurrent-ruby/pull/73). To avoid namespace collision it is living in `Actress` namespace until `Actor` is removed in next release. ## Release v0.5.0 This is the most significant release of this gem since its inception. This release includes many improvements and optimizations. It also includes several bug fixes. The major areas of focus for this release were: * Stability improvements on Ruby versions with thread-level parallelism ([JRuby](http://jruby.org/) and [Rubinius](http://rubini.us/)) * Creation of new low-level concurrency abstractions * Internal refactoring to use the new low-level abstractions Most of these updates had no effect on the gem API. There are a few notable exceptions which were unavoidable. Please read the [release notes](API-Updates-in-v0.5.0) for more information. Specific changes include: * New class `IVar` * New class `MVar` * New class `ThreadLocalVar` * New class `AtomicFixnum` * New class method `dataflow` * New class `Condition` * New class `CountDownLatch` * New class `DependencyCounter` * New class `SafeTaskExecutor` * New class `CopyOnNotifyObserverSet` * New class `CopyOnWriteObserverSet` * `Future` updated with `execute` API * `ScheduledTask` updated with `execute` API * New `Promise` API * `Future` now extends `IVar` * `Postable#post?` now returns an `IVar` * Thread safety fixes to `Dereferenceable` * Thread safety fixes to `Obligation` * Thread safety fixes to `Supervisor` * Thread safety fixes to `Event` * Various other thread safety (race condition) fixes * Refactored brittle tests * Implemented pending tests * Added JRuby and Rubinius as Travis CI build targets * Added [CodeClimate](https://codeclimate.com/) code review * Improved YARD documentation concurrent-ruby-1.0.5/CODE_OF_CONDUCT.md000066400000000000000000000036751305460430400174670ustar00rootroot00000000000000# Contributor Code of Conduct As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery * Personal attacks * Trolling or insulting/derogatory comments * Public or private harassment * Publishing other's private information, such as physical or electronic addresses, without explicit permission * Other unethical or unprofessional conduct. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/) concurrent-ruby-1.0.5/Gemfile000066400000000000000000000016501305460430400161520ustar00rootroot00000000000000source 'https://rubygems.org' gem 'concurrent-ruby', path: '.' gem 'concurrent-ruby-edge', path: '.' gem 'concurrent-ruby-ext', path: '.', platform: :mri group :development do gem 'rake', '~> 11.0' gem 'rake-compiler', '~> 0.9.5' gem 'rake-compiler-dock', '~> 0.4.3' gem 'gem-compiler', '~> 0.3.0' gem 'benchmark-ips', '~> 2.7' # documentation gem 'countloc', '~> 0.4.0', :platforms => :mri, :require => false gem 'yard', '~> 0.8.0', :require => false gem 'redcarpet', '~> 3.3', platforms: :mri # understands github markdown gem 'md-ruby-eval' gem 'pry' # needed by md-ruby-eval end group :testing do gem 'rspec', '~> 3.3.0' gem 'timecop', '~> 0.7.4' end # made opt-in since it will not install on jruby 1.7 if ENV['COVERAGE'] group :coverage do gem 'simplecov', '~> 0.10.0', :require => false gem 'coveralls', '~> 0.8.2', :require => false end end group :benchmarks do gem 'bench9000' end concurrent-ruby-1.0.5/LICENSE.txt000066400000000000000000000022261305460430400165020ustar00rootroot00000000000000Copyright (c) Jerry D'Antonio -- released under the MIT license. http://www.opensource.org/licenses/mit-license.php Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. concurrent-ruby-1.0.5/README.md000066400000000000000000000372621305460430400161460ustar00rootroot00000000000000# Concurrent Ruby [![Gem Version](https://badge.fury.io/rb/concurrent-ruby.svg)](http://badge.fury.io/rb/concurrent-ruby) [![Build Status](https://travis-ci.org/ruby-concurrency/concurrent-ruby.svg?branch=master)](https://travis-ci.org/ruby-concurrency/concurrent-ruby) [![Build status](https://ci.appveyor.com/api/projects/status/iq8aboyuu3etad4w?svg=true)](https://ci.appveyor.com/project/rubyconcurrency/concurrent-ruby) [![Code Climate](https://codeclimate.com/github/ruby-concurrency/concurrent-ruby.svg)](https://codeclimate.com/github/ruby-concurrency/concurrent-ruby) [![Inline docs](http://inch-ci.org/github/ruby-concurrency/concurrent-ruby.svg)](http://inch-ci.org/github/ruby-concurrency/concurrent-ruby) [![Dependency Status](https://gemnasium.com/ruby-concurrency/concurrent-ruby.svg)](https://gemnasium.com/ruby-concurrency/concurrent-ruby) [![License](https://img.shields.io/badge/license-MIT-green.svg)](http://opensource.org/licenses/MIT) [![Gitter chat](https://img.shields.io/badge/IRC%20(gitter)-devs%20%26%20users-brightgreen.svg)](https://gitter.im/ruby-concurrency/concurrent-ruby) Modern concurrency tools for Ruby. Inspired by [Erlang](http://www.erlang.org/doc/reference_manual/processes.html), [Clojure](http://clojure.org/concurrent_programming), [Scala](http://akka.io/), [Haskell](http://www.haskell.org/haskellwiki/Applications_and_libraries/Concurrency_and_parallelism#Concurrent_Haskell), [F#](http://blogs.msdn.com/b/dsyme/archive/2010/02/15/async-and-parallel-design-patterns-in-f-part-3-agents.aspx), [C#](http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx), [Java](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html), and classic concurrency patterns. The design goals of this gem are: * Be an 'unopinionated' toolbox that provides useful utilities without debating which is better or why * Remain free of external gem dependencies * Stay true to the spirit of the languages providing inspiration * But implement in a way that makes sense for Ruby * Keep the semantics as idiomatic Ruby as possible * Support features that make sense in Ruby * Exclude features that don't make sense in Ruby * Be small, lean, and loosely coupled ### Supported Ruby versions MRI 1.9.3, 2.0 and above, JRuby 1.7x in 1.9 mode, JRuby 9000, and Rubinius 2.x are supported. This gem should be fully compatible with any interpreter that is compliant with Ruby 1.9.3 or newer. Java 8 is preferred for JRuby but every Java version on which JRuby 9000 runs is supported. ## Thread Safety *Concurrent Ruby makes the strongest thread safety guarantees of any Ruby concurrency library. We are the only library with a published [memory model](https://github.com/ruby-concurrency/concurrent-ruby/blob/master/doc/synchronization.md) which provides consistent behavior and guarantees on all three of the main Ruby interpreters (MRI/CRuby, JRuby, and Rubinius).* Every abstraction in this library is thread safe. Similarly, all are deadlock free and many are fully lock free. Specific thread safety guarantees are documented with each abstraction. It is critical to remember, however, that Ruby is a language of mutable references. *No* concurrency library for Ruby can ever prevent the user from making thread safety mistakes (such as sharing a mutable object between threads and modifying it on both threads) or from creating deadlocks through incorrect use of locks. All the library can do is provide safe abstractions which encourage safe practices. Concurrent Ruby provides more safe concurrency abstractions than any other Ruby library, many of which support the mantra of ["Do not communicate by sharing memory; instead, share memory by communicating"](https://blog.golang.org/share-memory-by-communicating). Concurrent Ruby is also the only Ruby library which provides a full suite of thread safe and immutable variable types and data structures. ## Features & Documentation The primary site for documentation is the automatically generated [API documentation](http://ruby-concurrency.github.io/concurrent-ruby/frames.html) We also have a [mailing list](http://groups.google.com/group/concurrent-ruby) and [IRC (gitter)](https://gitter.im/ruby-concurrency/concurrent-ruby). #### General-purpose Concurrency Abstractions * [Async](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Async.html): A mixin module that provides simple asynchronous behavior to a class. Loosely based on Erlang's [gen_server](http://www.erlang.org/doc/man/gen_server.html). * [Future](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Future.html): An asynchronous operation that produces a value. * [Dataflow](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent.html#dataflow-class_method): Built on Futures, Dataflow allows you to create a task that will be scheduled when all of its data dependencies are available. * [Promise](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Promise.html): Similar to Futures, with more features. * [ScheduledTask](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ScheduledTask.html): Like a Future scheduled for a specific future time. * [TimerTask](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/TimerTask.html): A Thread that periodically wakes up to perform work at regular intervals. #### Thread-safe Value Objects, Structures, and Collections Collection classes that were originally part of the (deprecated) `thread_safe` gem: * [Array](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Array.html) A thread-safe subclass of Ruby's standard [Array](http://ruby-doc.org/core-2.2.0/Array.html). * [Hash](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Hash.html) A thread-safe subclass of Ruby's standard [Hash](http://ruby-doc.org/core-2.2.0/Hash.html). * [Map](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Map.html) A hash-like object that should have much better performance characteristics, especially under high concurrency, than `Concurrent::Hash`. * [Tuple](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Tuple.html) A fixed size array with volatile (synchronized, thread safe) getters/setters. Value objects inspired by other languages: * [Maybe](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Maybe.html) A thread-safe, immutable object representing an optional value, based on [Haskell Data.Maybe](https://hackage.haskell.org/package/base-4.2.0.1/docs/Data-Maybe.html). * [Delay](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Delay.html) Lazy evaluation of a block yielding an immutable result. Based on Clojure's [delay](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Delay.html). Structure classes derived from Ruby's [Struct](http://ruby-doc.org/core-2.2.0/Struct.html): * [ImmutableStruct](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ImmutableStruct.html) Immutable struct where values are set at construction and cannot be changed later. * [MutableStruct](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/MutableStruct.html) Synchronized, mutable struct where values can be safely changed at any time. * [SettableStruct](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/SettableStruct.html) Synchronized, write-once struct where values can be set at most once, either at construction or any time thereafter. Thread-safe variables: * [Agent](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Agent.html): A way to manage shared, mutable, *asynchronous*, independent state. Based on Clojure's [Agent](http://clojure.org/agents). * [Atom](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Atom.html): A way to manage shared, mutable, *synchronous*, independent state. Based on Clojure's [Atom](http://clojure.org/atoms). * [AtomicBoolean](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/AtomicBoolean.html) A boolean value that can be updated atomically. * [AtomicFixnum](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/AtomicFixnum.html) A numeric value that can be updated atomically. * [AtomicReference](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/MutexAtomic.html) An object reference that may be updated atomically. * [Exchanger](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Exchanger.html) A synchronization point at which threads can pair and swap elements within pairs. Based on Java's [Exchanger](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Exchanger.html). * [MVar](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/MVar.html) A synchronized single element container. Based on Haskell's [MVar](https://hackage.haskell.org/package/base-4.8.1.0/docs/Control-Concurrent-MVar.html) and Scala's [MVar](http://docs.typelevel.org/api/scalaz/nightly/index.html#scalaz.concurrent.MVar$). * [ThreadLocalVar](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ThreadLocalVar.html) A variable where the value is different for each thread. * [TVar](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/TVar.html) A transactional variable implementing software transactional memory (STM). Based on Clojure's [Ref](http://clojure.org/refs). #### Java-inspired ThreadPools and Other Executors * See the [thread pool](http://ruby-concurrency.github.io/concurrent-ruby/file.thread_pools.html) overview, which also contains a list of other Executors available. #### Thread Synchronization Classes and Algorithms * [CountDownLatch](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/CountDownLatch.html) A synchronization object that allows one thread to wait on multiple other threads. * [CyclicBarrier](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/CyclicBarrier.html) A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point. * [Event](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Event.html) Old school kernel-style event. * [IVar](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/IVar.html) Similar to a "future" but can be manually assigned once, after which it becomes immutable. * [ReadWriteLock](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ReadWriteLock.html) A lock that supports multiple readers but only one writer. * [ReentrantReadWriteLock](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ReentrantReadWriteLock.html) A read/write lock with reentrant and upgrade features. * [Semaphore](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Semaphore.html) A counting-based locking mechanism that uses permits. ### Edge Features These are available in the `concurrent-ruby-edge` companion gem. These features are under active development and may change frequently. They are expected not to keep backward compatibility (there may also lack tests and documentation). Semantic versions will be obeyed though. Features developed in `concurrent-ruby-edge` are expected to move to `concurrent-ruby` when final. * [Promises Framework](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Promises.html): Unified implementation of futures and promises which combines features of previous `Future`, `Promise`, `IVar`, `Event`, `dataflow`, `Delay`, and `TimerTask` into a single framework. It extensively uses the new synchronization layer to make all the features **non-blocking** and **lock-free**, with the exception of obviously blocking operations like `#wait`, `#value`. It also offers better performance. * [Actor](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Actor.html): Implements the Actor Model, where concurrent actors exchange messages. * [Channel](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Edge/Channel.html): Communicating Sequential Processes ([CSP](https://en.wikipedia.org/wiki/Communicating_sequential_processes)). Functionally equivalent to Go [channels](https://tour.golang.org/concurrency/2) with additional inspiration from Clojure [core.async](https://clojure.github.io/core.async/). * [LazyRegister](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/LazyRegister.html) * [AtomicMarkableReference](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Edge/AtomicMarkableReference.html) * [LockFreeLinkedSet](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Edge/LockFreeLinkedSet.html) * [LockFreeStack](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/LockFreeStack.html) #### Statuses: *Why are these not in core?* - **Promises Framework** - They are being finalized to be able to be moved to core. They'll deprecate old implementation. - **Actor** - Partial documentation and tests; depends on new future/promise framework; stability is good. - **Channel** - Brand new implementation; partial documentation and tests; stability is good. - **LazyRegister** - Missing documentation and tests. - **AtomicMarkableReference, LockFreeLinkedSet, LockFreeStack** - Need real world battle testing. ## Usage Everything within this gem can be loaded simply by requiring it: ```ruby require 'concurrent' ``` To use the tools in the Edge gem it must be required separately: ```ruby require 'concurrent-edge' ``` If the library does not behave as expected, `Concurrent.use_stdlib_logger(Logger::DEBUG)` could help to reveal the problem. ## Installation ```shell gem install concurrent-ruby ``` or add the following line to Gemfile: ```ruby gem 'concurrent-ruby', require: 'concurrent' ``` and run `bundle install` from your shell. ### Edge Gem Installation The Edge gem must be installed separately from the core gem: ```shell gem install concurrent-ruby-edge ``` or add the following line to Gemfile: ```ruby gem 'concurrent-ruby-edge', require: 'concurrent-edge' ``` and run `bundle install` from your shell. ### C Extensions for MRI Potential performance improvements may be achieved under MRI by installing optional C extensions. To minimize installation errors the C extensions are available in the `concurrent-ruby-ext` extension gem. `concurrent-ruby` and `concurrent-ruby-ext` are always released together with same version. Simply install the extension gem too: ```ruby gem install concurrent-ruby-ext ``` or add the following line to Gemfile: ```ruby gem 'concurrent-ruby-ext' ``` and run `bundle install` from your shell. In code it is only necessary to ```ruby require 'concurrent' ``` The `concurrent-ruby` gem will automatically detect the presence of the `concurrent-ruby-ext` gem and load the appropriate C extensions. #### Note For gem developers No gems should depend on `concurrent-ruby-ext`. Doing so will force C extensions on your users. The best practice is to depend on `concurrent-ruby` and let users to decide if they want C extensions. ## Maintainers * [Petr Chalupa](https://github.com/pitr-ch) (lead maintainer) * [Jerry D'Antonio](https://github.com/jdantonio) (creator) * [Michele Della Torre](https://github.com/mighe) * [Chris Seaton](https://github.com/chrisseaton) * [PaweÅ‚ Obrok](https://github.com/obrok) * [Lucas Allan](https://github.com/lucasallan) ### Special Thanks * [Brian Durand](https://github.com/bdurand) for the `ref` gem * [Charles Oliver Nutter](https://github.com/headius) for the `atomic` and `thread_safe` gems * [thedarkone](https://github.com/thedarkone) for the `thread_safe` gem ## License and Copyright *Concurrent Ruby* is free software released under the [MIT License](http://www.opensource.org/licenses/MIT). The *Concurrent Ruby* [logo](https://github.com/ruby-concurrency/concurrent-ruby/wiki/Logo) was designed by [David Jones](https://twitter.com/zombyboy). It is Copyright © 2014 [Jerry D'Antonio](https://twitter.com/jerrydantonio). All Rights Reserved. concurrent-ruby-1.0.5/Rakefile000066400000000000000000000126051305460430400163260ustar00rootroot00000000000000#!/usr/bin/env rake $:.push File.join(File.dirname(__FILE__), 'lib') require 'concurrent/version' require 'concurrent/utility/native_extension_loader' ## load the gemspec files CORE_GEMSPEC = Gem::Specification.load('concurrent-ruby.gemspec') EXT_GEMSPEC = Gem::Specification.load('concurrent-ruby-ext.gemspec') EDGE_GEMSPEC = Gem::Specification.load('concurrent-ruby-edge.gemspec') ## constants used for compile/build tasks GEM_NAME = 'concurrent-ruby' EXT_NAME = 'extension' EDGE_NAME = 'edge' JAVA_EXT_NAME = 'concurrent_ruby_ext' if Concurrent.on_jruby? CORE_GEM = "#{GEM_NAME}-#{Concurrent::VERSION}-java.gem" else CORE_GEM = "#{GEM_NAME}-#{Concurrent::VERSION}.gem" EXT_GEM = "#{GEM_NAME}-ext-#{Concurrent::VERSION}.gem" NATIVE_GEM = "#{GEM_NAME}-ext-#{Concurrent::VERSION}-#{Gem::Platform.new(RUBY_PLATFORM)}.gem" EDGE_GEM = "#{GEM_NAME}-edge-#{Concurrent::EDGE_VERSION}.gem" end ## safely load all the rake tasks in the `tasks` directory def safe_load(file) begin load file rescue LoadError => ex puts "Error loading rake tasks from '#{file}' but will continue..." puts ex.message end end Dir.glob('tasks/**/*.rake').each do |rakefile| safe_load rakefile end def has_docker? if Concurrent.on_linux? system("docker version > /dev/null 2>&1") elsif Concurrent.on_osx? system("docker version > /dev/null 2>&1 || boot2docker version > /dev/null 2>&1") else false end end if Concurrent.on_jruby? ## create the compile task for the JRuby-specific gem require 'rake/javaextensiontask' Rake::JavaExtensionTask.new(JAVA_EXT_NAME, CORE_GEMSPEC) do |ext| ext.ext_dir = 'ext' end elsif Concurrent.allow_c_extensions? ## create the compile tasks for the extension gem require 'rake/extensiontask' Rake::ExtensionTask.new(EXT_NAME, EXT_GEMSPEC) do |ext| ext.ext_dir = 'ext/concurrent' ext.lib_dir = 'lib/concurrent' ext.source_pattern = '*.{c,h}' ext.cross_compile = true ext.cross_platform = ['x86-mingw32', 'x64-mingw32'] end ENV['RUBY_CC_VERSION'].to_s.split(':').each do |ruby_version| platforms = { 'x86-mingw32' => 'i686-w64-mingw32', 'x64-mingw32' => 'x86_64-w64-mingw32' } platforms.each do |platform, prefix| task "copy:#{EXT_NAME}:#{platform}:#{ruby_version}" do |t| ["lib", "tmp/#{platform}/stage/lib/concurrent"].each do |dir| so_file = "#{dir}/#{ruby_version[/^\d+\.\d+/]}/#{EXT_NAME}.so" if File.exists?(so_file) sh "#{prefix}-strip -S #{so_file}" end end end end end else ## create an empty compile task task :compile end task :clean do rm_rf 'pkg/classes' rm_rf 'tmp' rm_rf Dir.glob('lib/concurrent/1.?') rm_rf Dir.glob('lib/concurrent/2.?') rm_f Dir.glob('./**/*.so') rm_f Dir.glob('./**/*.bundle') rm_f Dir.glob('./lib/*.jar') mkdir_p 'pkg' end ## create build tasks tailored to current platform namespace :build do task :mkdir_pkg do mkdir_p 'pkg' end build_deps = [:clean, 'build:mkdir_pkg'] build_deps << :compile if Concurrent.on_jruby? desc "Build #{CORE_GEM} into the pkg directory" task :core => build_deps do sh "gem build #{CORE_GEMSPEC.name}.gemspec" sh 'mv *.gem pkg/' end unless Concurrent.on_jruby? desc "Build #{EDGE_GEM} into the pkg directory" task :edge => 'build:mkdir_pkg' do sh "gem build #{EDGE_GEMSPEC.name}.gemspec" sh 'mv *.gem pkg/' end desc "Build #{EXT_GEM} into the pkg directory" task :ext => build_deps do sh "gem build #{EXT_GEMSPEC.name}.gemspec" sh 'mv *.gem pkg/' end end if Concurrent.allow_c_extensions? desc "Build #{NATIVE_GEM} into the pkg directory" task :native => 'build:mkdir_pkg' do sh "gem compile pkg/#{EXT_GEM}" sh 'mv *.gem pkg/' end end if has_docker? desc "Build the windows binary #{Concurrent::VERSION} gems per rake-compiler-dock" task :windows do require 'rake_compiler_dock' RakeCompilerDock.sh <<-EOT bundle --without="development testing" && rake cross native gem RUBY_CC_VERSION=1.9.3:2.0.0:2.1.6:2.2.2 rm -rf .bundle EOT end end end if Concurrent.on_jruby? desc 'Build JRuby-specific core gem (alias for `build:core`)' task :build => ['build:core'] elsif has_docker? desc 'Build core, extension, and edge gems, including Windows binaries' task :build => ['build:core', 'build:ext', 'build:edge', 'build:windows'] else desc 'Build core, extension, and edge gems (excluding Windows binaries)' task :build => ['build:core', 'build:ext', 'build:edge'] end ## the RSpec task that compiles extensions when available begin require 'rspec' require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) options = %w[ --color --backtrace --seed 1 --format documentation --tag ~unfinished --tag ~notravis --tag ~buggy ] RSpec::Core::RakeTask.new(:travis) do |t| t.rspec_opts = ['--color', *options].join(' ') end RSpec::Core::RakeTask.new(:appveyor) do |t| t.rspec_opts = [*options].join(' ') end if Concurrent.on_windows? task :ci => [:clean, :compile, :appveyor] else task :ci => [:clean, :compile, :travis] end task :default => [:clean, :compile, :spec] rescue LoadError puts 'Error loading Rspec rake tasks, probably building the gem...' end concurrent-ruby-1.0.5/appveyor.yml000066400000000000000000000007461305460430400172540ustar00rootroot00000000000000install: - SET PATH=C:\Ruby%ruby_version%\bin;%PATH% - SET PATH=C:\MinGW\bin;%PATH% - SET RAKEOPT=-rdevkit - ruby --version - gem --version - bundle install build: off test_script: - bundle exec rake ci environment: matrix: - ruby_version: "193" - ruby_version: "200" - ruby_version: "200-x64" - ruby_version: "21" - ruby_version: "21-x64" - ruby_version: "22" - ruby_version: "22-x64" matrix: allow_failures: - ruby_version: "193" concurrent-ruby-1.0.5/benchmarks/000077500000000000000000000000001305460430400167725ustar00rootroot00000000000000concurrent-ruby-1.0.5/benchmarks/default.config.rb000066400000000000000000000007321305460430400222110ustar00rootroot00000000000000rbenv '2.2.3' rbenv 'jruby-9.0.4.0-indy', 'jruby-9.0.4.0', '-Xcompile.invokedynamic=true' rbenv 'rbx-2.5.8' rbenv 'jruby-dev-truffle-graal', 'jruby-master+graal-dev', '-J-Xmx2G -X+T' binary 'baseline', 'false' rubies = ['baseline', '2.2.3', 'jruby-9.0.4.0-indy', 'rbx-2.5.8'] rubies = ['2.2.3', 'jruby-9.0.4.0-indy', 'rbx-2.5.8'] implementation_group 'rubies', *rubies implementation_group 'rubies+truffle', *rubies, 'jruby-dev-truffle-graal' concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015.config.rb000066400000000000000000000014051305460430400244150ustar00rootroot00000000000000future_benchmarks = [ 'mutex-complete', 'mutex-value', 'mutex-fulfill', 'special-complete', 'special-value', 'special-fulfill', 'cr-complete', 'cr-value', 'cr-fulfill', 'cr-cas-complete', 'cr-cas-value', 'cr-cas-fulfill', ] future_new_benchmarks = [ 'cr-cas-new', 'cr-new', 'special-new' ] all_bechmarks = future_benchmarks + future_new_benchmarks all_bechmarks.each do |name| benchmark "future-#{name}", "#{default_benchmarks_dir}/futures-rubyconf2015/benchmarks/#{name}.rb", "-I #{default_benchmarks_dir}/futures-rubyconf2015/lib" end benchmark_group 'future', *(future_benchmarks.map { |v| "future-#{v}" }) benchmark_group 'future-new', *(all_bechmarks.map { |v| "future-#{v}" }) concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/000077500000000000000000000000001305460430400226245ustar00rootroot00000000000000concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/benchmarks/000077500000000000000000000000001305460430400247415ustar00rootroot00000000000000concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/benchmarks/cr-cas-complete.rb000066400000000000000000000001241305460430400302410ustar00rootroot00000000000000require 'cr_cas_future' FutureImplementation = CRCasFuture require 'bench_complete' concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/benchmarks/cr-cas-fulfill.rb000066400000000000000000000001231305460430400300650ustar00rootroot00000000000000require 'cr_cas_future' FutureImplementation = CRCasFuture require 'bench_fulfill' concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/benchmarks/cr-cas-new.rb000066400000000000000000000001171305460430400272240ustar00rootroot00000000000000require 'cr_cas_future' FutureImplementation = CRCasFuture require 'bench_new' concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/benchmarks/cr-cas-value.rb000066400000000000000000000001211305460430400275420ustar00rootroot00000000000000require 'cr_cas_future' FutureImplementation = CRCasFuture require 'bench_value' concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/benchmarks/cr-complete.rb000066400000000000000000000001151305460430400274750ustar00rootroot00000000000000require 'cr_future' FutureImplementation = CRFuture require 'bench_complete' concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/benchmarks/cr-fulfill.rb000066400000000000000000000001141305460430400273210ustar00rootroot00000000000000require 'cr_future' FutureImplementation = CRFuture require 'bench_fulfill' concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/benchmarks/cr-new.rb000066400000000000000000000001101305460430400264510ustar00rootroot00000000000000require 'cr_future' FutureImplementation = CRFuture require 'bench_new' concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/benchmarks/cr-value.rb000066400000000000000000000001121305460430400267760ustar00rootroot00000000000000require 'cr_future' FutureImplementation = CRFuture require 'bench_value' concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/benchmarks/mutex-complete.rb000066400000000000000000000001231305460430400302320ustar00rootroot00000000000000require 'mutex_future' FutureImplementation = MutexFuture require 'bench_complete' concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/benchmarks/mutex-fulfill.rb000066400000000000000000000001221305460430400300560ustar00rootroot00000000000000require 'mutex_future' FutureImplementation = MutexFuture require 'bench_fulfill' concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/benchmarks/mutex-new.rb000066400000000000000000000001161305460430400272150ustar00rootroot00000000000000require 'mutex_future' FutureImplementation = MutexFuture require 'bench_new' concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/benchmarks/mutex-value.rb000066400000000000000000000001201305460430400275330ustar00rootroot00000000000000require 'mutex_future' FutureImplementation = MutexFuture require 'bench_value' concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/benchmarks/special-complete.rb000066400000000000000000000011571305460430400305200ustar00rootroot00000000000000require 'concurrent_needed' require 'concurrent/utility/engine' FutureImplementation = case when Concurrent.on_cruby? require 'gvl_future' GVLFuture when Concurrent.on_rbx? || Concurrent.on_truffle? require 'rbx_future' RBXFuture when Concurrent.on_jruby? require 'jruby_future' JRubyFuture else raise end require 'bench_complete' concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/benchmarks/special-fulfill.rb000066400000000000000000000011561305460430400303440ustar00rootroot00000000000000require 'concurrent_needed' require 'concurrent/utility/engine' FutureImplementation = case when Concurrent.on_cruby? require 'gvl_future' GVLFuture when Concurrent.on_rbx? || Concurrent.on_truffle? require 'rbx_future' RBXFuture when Concurrent.on_jruby? require 'jruby_future' JRubyFuture else raise end require 'bench_fulfill' concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/benchmarks/special-new.rb000066400000000000000000000011521305460430400274740ustar00rootroot00000000000000require 'concurrent_needed' require 'concurrent/utility/engine' FutureImplementation = case when Concurrent.on_cruby? require 'gvl_future' GVLFuture when Concurrent.on_rbx? || Concurrent.on_truffle? require 'rbx_future' RBXFuture when Concurrent.on_jruby? require 'jruby_future' JRubyFuture else raise end require 'bench_new' concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/benchmarks/special-value.rb000066400000000000000000000011541305460430400300210ustar00rootroot00000000000000require 'concurrent_needed' require 'concurrent/utility/engine' FutureImplementation = case when Concurrent.on_cruby? require 'gvl_future' GVLFuture when Concurrent.on_rbx? || Concurrent.on_truffle? require 'rbx_future' RBXFuture when Concurrent.on_jruby? require 'jruby_future' JRubyFuture else raise end require 'bench_value' concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/lib/000077500000000000000000000000001305460430400233725ustar00rootroot00000000000000concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/lib/bench_complete.rb000066400000000000000000000004431305460430400266670ustar00rootroot00000000000000ITERATIONS = 2_500_000 def harness_input FutureImplementation.new end def harness_sample(input) ITERATIONS.times do input.complete? end input.fulfill true ITERATIONS.times do input.complete? end end def harness_verify(output) true end require 'bench9000/harness' concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/lib/bench_fulfill.rb000066400000000000000000000004631305460430400265160ustar00rootroot00000000000000ITERATIONS = 2_500_000 def harness_input end def harness_sample(input) last_future = nil ITERATIONS.times do |i| last_future = FutureImplementation.new last_future.fulfill i end last_future end def harness_verify(output) output.value == ITERATIONS - 1 end require 'bench9000/harness' concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/lib/bench_new.rb000066400000000000000000000004101305460430400256420ustar00rootroot00000000000000 ITERATIONS = 2_500_000 def harness_input end def harness_sample(input) last = nil ITERATIONS.times do |i| last = FutureImplementation.new end last end def harness_verify(output) output.is_a? FutureImplementation end require 'bench9000/harness' concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/lib/bench_value.rb000066400000000000000000000004301305460430400261670ustar00rootroot00000000000000ITERATIONS = 5_000_000 def harness_input f = FutureImplementation.new f.fulfill 1 f end def harness_sample(input) sum = 0 ITERATIONS.times do sum += input.value end sum end def harness_verify(output) output == ITERATIONS end require 'bench9000/harness' concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/lib/concurrent_needed.rb000066400000000000000000000002751305460430400274110ustar00rootroot00000000000000concurrent_ruby_load_path = File.expand_path(File.join(File.dirname(__FILE__), '../../../lib')) $LOAD_PATH << concurrent_ruby_load_path unless $LOAD_PATH.include? concurrent_ruby_load_path concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/lib/cr_cas_future.rb000066400000000000000000000026461305460430400265530ustar00rootroot00000000000000require 'concurrent_needed' require 'concurrent/synchronization' require 'concurrent/atomics' class CRCasFuture < Concurrent::Synchronization::Object class Node < Concurrent::Synchronization::Object attr_volatile(:awake) safe_initialization! def initialize(thread) super() @Thread = thread self.awake = false end def thread @Thread end end safe_initialization! PENDING = Object.new attr_atomic(:atomic_value) attr_atomic(:head) def initialize super self.head = nil self.atomic_value = PENDING end def complete?(value = atomic_value) value != PENDING end def value value = atomic_value return value if complete? value begin while true head = self.head node = Node.new Thread.current break if compare_and_set_head head, node end until complete?(value = atomic_value) # may go to sleep even if completed, but it has a record by then sleep end value ensure node.awake = true wakeup head end end def fulfill(value) if compare_and_set_atomic_value(PENDING, value) wakeup head else raise 'already fulfilled' end self end private def wakeup(node) return unless node while true break if node.awake # has to be confirmed node.thread.wakeup Thread.pass end end end concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/lib/cr_future.rb000066400000000000000000000017331305460430400257210ustar00rootroot00000000000000require 'concurrent_needed' require 'concurrent/synchronization' require 'concurrent/atomics' class CRFuture < Concurrent::Synchronization::Object PENDING = Object.new safe_initialization! # also defines reader and writer methods private *attr_volatile(:volatile_value) def initialize super @Lock = Mutex.new @Condition = ConditionVariable.new self.volatile_value = PENDING end def complete?(value = volatile_value) value != PENDING end def value # read only once value = volatile_value return value if complete? value # critical section @Lock.synchronize do until complete?(value = volatile_value) # blocks thread until it is broadcasted @Condition.wait @Lock end end value end def fulfill(value) @Lock.synchronize do raise 'already fulfilled' if complete? self.volatile_value = value @Condition.broadcast end self end end concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/lib/example_reordering_ivar.rb000066400000000000000000000003661305460430400306200ustar00rootroot00000000000000class ACLass attr_reader :value def initialize(value) @value = value # 1 end end instance = nil Thread.new do raise if instance.value.nil? # may raise end instance = ACLass.new(42) # 2 puts instance.value # 3: prints always 42 concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/lib/example_usage_of_future.rb000066400000000000000000000012601305460430400306130ustar00rootroot00000000000000require_relative 'mutex_future' require 'thread' # prints seconds and the value def timed_puts(value) puts format('%2d: %s', Time.now.sec, value) end ## Simple background processing ## WORKER_QUEUE = Queue.new workers = Array.new(2) do Thread.new do while true sleep 1.5 # simulate slow computation # blocking job, future = WORKER_QUEUE.pop result = job.call future.fulfill result timed_puts result end end end def async(&block) future = MutexFuture.new WORKER_QUEUE << [block, future] future end jobs = Array.new(5) { |i| async { i*2 } } timed_puts jobs.map(&:class).inspect # blocks timed_puts jobs.map(&:value).inspect concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/lib/gvl_future.rb000066400000000000000000000011721305460430400261020ustar00rootroot00000000000000class GVLFuture PENDING = Object.new def initialize @lock = Mutex.new @condition = ConditionVariable.new @value = PENDING end def complete?(value = @value) value != PENDING end def value value = @value return value if complete? value @lock.synchronize do # recheck complete? @condition.wait @lock unless complete? @value end @value end def fulfill(value) # why not check complete? before synchronizing? @lock.synchronize do raise 'already fulfilled' if complete? @value = value @condition.broadcast self end end end concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/lib/jruby_future.rb000066400000000000000000000015451305460430400264510ustar00rootroot00000000000000require 'java' class JRubyFuture java_import java.util.concurrent.atomic.AtomicReference java_import org.jruby.util.unsafe.UnsafeHolder PENDING = Object.new def initialize @Value = AtomicReference.new PENDING UnsafeHolder.fullFence end def complete?(value = @Value.get) value != PENDING end def value # read only once value = @Value.get return value if complete? value JRuby.reference(self).synchronized do # recheck is in the loop condition until complete?(value = @Value.get) # may wakeup spuriously, therefore kept in a loop JRuby.reference(self).wait end end value end def fulfill(value) JRuby.reference(self).synchronized do raise 'already fulfilled' if complete? @Value.set value JRuby.reference(self).notify_all end self end end concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/lib/mutex_future.rb000066400000000000000000000012521305460430400264530ustar00rootroot00000000000000require 'thread' class MutexFuture PENDING = Object.new def initialize # non-re-entrant lock @lock = Mutex.new # allows to block treads until the condition is met @condition = ConditionVariable.new @value = PENDING end def complete?(value = @lock.synchronize { @value }) value != PENDING end def value # critical section, visibility @lock.synchronize do return @value if complete? @value @condition.wait @lock @value end end def fulfill(value) @lock.synchronize do raise 'already fulfilled' if complete? @value @value = value @condition.broadcast end self end end concurrent-ruby-1.0.5/benchmarks/futures-rubyconf2015/lib/rbx_future.rb000066400000000000000000000015621305460430400261100ustar00rootroot00000000000000require 'thread' class RBXFuture PENDING = Object.new def initialize @Lock = Mutex.new @Condition = ConditionVariable.new # reference to a value with volatile semantics @Value = Rubinius::AtomicReference.new PENDING # protect against reordering Rubinius.memory_barrier end def complete?(value = @Value.get) value != PENDING end def value # read only once value = @Value.get # check without synchronization return value if complete? value # critical section @Lock.synchronize do until complete?(value = @Value.get) # blocks thread until it is broadcasted @Condition.wait @Lock end end value end def fulfill(value) @Lock.synchronize do raise 'already fulfilled' if complete? @Value.set value @Condition.broadcast end self end end concurrent-ruby-1.0.5/benchmarks/readme.md000066400000000000000000000004471305460430400205560ustar00rootroot00000000000000# How to run a benchmark These benchmarks are using bench9000 gem, see its [readme](https://github.com/jruby/bench9000). To run the `futures-rubyconf2015` benchmark collection use: bundle exec bench9000 report future rubies+truffle --data data.txt --config futures-rubyconf2015 concurrent-ruby-1.0.5/build-tests/000077500000000000000000000000001305460430400171145ustar00rootroot00000000000000concurrent-ruby-1.0.5/build-tests/atomic_boolean_builds_spec.rb000066400000000000000000000040721305460430400247730ustar00rootroot00000000000000require 'benchmark' require_relative 'example_group_extensions' require_relative 'platform_helpers' require 'concurrent/atomics' def atomic_boolean_test(clazz, opts = {}) threads = opts.fetch(:threads, 5) tests = opts.fetch(:tests, 100) atomic = Concurrent.const_get(clazz.to_s).new latch = Concurrent::CountDownLatch.new(threads) stats = Benchmark.measure do threads.times do |i| Thread.new do tests.times{ atomic.value = true } latch.count_down end end latch.wait end stats end describe Concurrent::AtomicBoolean do let!(:threads) { 10 } let!(:tests) { 1000 } unless jruby? describe Concurrent::MutexAtomicBoolean do specify 'is defined' do expect(defined?(Concurrent::MutexAtomicBoolean)).to be_truthy end specify 'runs the benchmarks' do stats = atomic_boolean_test('MutexAtomicBoolean', threads: threads, tests: tests) expect(stats).to be_benchmark_results end end end if jruby? describe Concurrent::JavaAtomicBoolean do specify 'Concurrent::JavaAtomicBoolean is defined' do expect(defined?(Concurrent::JavaAtomicBoolean)).to be_truthy end specify 'runs the benchmarks' do stats = atomic_boolean_test('JavaAtomicBoolean', threads: threads, tests: tests) expect(stats).to be_benchmark_results end end else specify 'Concurrent::JavaAtomicBoolean is not defined' do expect(defined?(Concurrent::JavaAtomicBoolean)).to be_falsey end end if 'EXT' == ENV['TEST_PLATFORM'].strip describe Concurrent::CAtomicBoolean do specify 'Concurrent::CAtomicBoolean is defined' do expect(defined?(Concurrent::CAtomicBoolean)).to be_truthy end specify 'runs the benchmarks' do stats = atomic_boolean_test('CAtomicBoolean', threads: threads, tests: tests) expect(stats).to be_benchmark_results end end else specify 'Concurrent::CAtomicBoolean is not defined' do expect(defined?(Concurrent::CAtomicBoolean)).to be_falsey end end end concurrent-ruby-1.0.5/build-tests/atomic_fixnum_builds_spec.rb000066400000000000000000000040341305460430400246600ustar00rootroot00000000000000require 'benchmark' require_relative 'example_group_extensions' require_relative 'platform_helpers' require 'concurrent/atomics' def atomic_fixnum_test(clazz, opts = {}) threads = opts.fetch(:threads, 5) tests = opts.fetch(:tests, 100) atomic = Concurrent.const_get(clazz.to_s).new latch = Concurrent::CountDownLatch.new(threads) stats = Benchmark.measure do threads.times do |i| Thread.new do tests.times{ atomic.up } latch.count_down end end latch.wait end stats end describe Concurrent::AtomicFixnum do let!(:threads) { 10 } let!(:tests) { 1000 } unless jruby? describe Concurrent::MutexAtomicFixnum do specify 'is defined' do expect(defined?(Concurrent::MutexAtomicFixnum)).to be_truthy end specify 'runs the benchmarks' do stats = atomic_fixnum_test('MutexAtomicFixnum', threads: threads, tests: tests) expect(stats).to be_benchmark_results end end end if jruby? describe Concurrent::JavaAtomicFixnum do specify 'Concurrent::JavaAtomicFixnum is defined' do expect(defined?(Concurrent::JavaAtomicFixnum)).to be_truthy end specify 'runs the benchmarks' do stats = atomic_fixnum_test('JavaAtomicFixnum', threads: threads, tests: tests) expect(stats).to be_benchmark_results end end else specify 'Concurrent::JavaAtomicFixnum is not defined' do expect(defined?(Concurrent::JavaAtomicFixnum)).to be_falsey end end if 'EXT' == ENV['TEST_PLATFORM'].strip describe Concurrent::CAtomicFixnum do specify 'Concurrent::CAtomicFixnum is defined' do expect(defined?(Concurrent::CAtomicFixnum)).to be_truthy end specify 'runs the benchmarks' do stats = atomic_fixnum_test('CAtomicFixnum', threads: threads, tests: tests) expect(stats).to be_benchmark_results end end else specify 'Concurrent::CAtomicFixnum is not defined' do expect(defined?(Concurrent::CAtomicFixnum)).to be_falsey end end end concurrent-ruby-1.0.5/build-tests/atomic_reference_builds_spec.rb000066400000000000000000000042131305460430400253070ustar00rootroot00000000000000require 'benchmark' require_relative 'example_group_extensions' require_relative 'platform_helpers' require 'concurrent/atomics' def atomic_reference_test(clazz, opts = {}) threads = opts.fetch(:threads, 5) tests = opts.fetch(:tests, 100) atomic = Concurrent.const_get(clazz.to_s).new latch = Concurrent::CountDownLatch.new(threads) stats = Benchmark.measure do threads.times do |i| Thread.new do tests.times{ atomic.value = true } latch.count_down end end latch.wait end stats end describe Concurrent::AtomicReference do let!(:threads) { 10 } let!(:tests) { 1000 } unless jruby? describe Concurrent::MutexAtomicReference do specify 'is defined' do expect(defined?(Concurrent::MutexAtomicReference)).to be_truthy end specify 'runs the benchmarks' do stats = atomic_reference_test('MutexAtomicReference', threads: threads, tests: tests) expect(stats).to be_benchmark_results end end end if jruby? && 'JRUBY' == ENV['TEST_PLATFORM'].strip describe Concurrent::JavaAtomicReference do specify 'Concurrent::JavaAtomicReference is defined' do expect(defined?(Concurrent::JavaAtomicReference)).to be_truthy end specify 'runs the benchmarks' do stats = atomic_reference_test('JavaAtomicReference', threads: threads, tests: tests) expect(stats).to be_benchmark_results end end else specify 'Concurrent::JavaAtomicReference is not defined' do expect(defined?(Concurrent::JavaAtomicReference)).to be_falsey end end if 'EXT' == ENV['TEST_PLATFORM'].strip describe Concurrent::CAtomicReference do specify 'Concurrent::CAtomicReference is defined' do expect(defined?(Concurrent::CAtomicReference)).to be_truthy end specify 'runs the benchmarks' do stats = atomic_reference_test('CAtomicReference', threads: threads, tests: tests) expect(stats).to be_benchmark_results end end else specify 'Concurrent::CAtomicReference is not defined' do expect(defined?(Concurrent::CAtomicReference)).to be_falsey end end end concurrent-ruby-1.0.5/build-tests/example_group_extensions.rb000066400000000000000000000002031305460430400245620ustar00rootroot00000000000000require 'benchmark' RSpec::Matchers.define :be_benchmark_results do match do |actual| actual.is_a? Benchmark::Tms end end concurrent-ruby-1.0.5/build-tests/platform_helpers.rb000066400000000000000000000004451305460430400230120ustar00rootroot00000000000000require 'rbconfig' def windows? host_os = RbConfig::CONFIG['host_os'] host_os =~ /mswin32/i || host_os =~ /mingw32/i end def mri?(engine = RUBY_ENGINE) engine == 'ruby' end def jruby?(engine = RUBY_ENGINE) engine == 'jruby' end def rbx?(engine = RUBY_ENGINE) engine == 'rbx' end concurrent-ruby-1.0.5/build-tests/runner.rb000077500000000000000000000061151305460430400207600ustar00rootroot00000000000000#!/usr/bin/env ruby if File.exist?('Gemfile') puts <<-WARNING !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! A Gemfile has been detected. This will likely cause some tests !! !! to erroneously fail (RSpec + Bundler shenanigans!). You may need !! !! to run tests from a different directory. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WARNING end $:.push File.join(File.dirname(__FILE__), '..', 'lib') require 'concurrent/version' require_relative 'platform_helpers' EXT_PLATFORMS = { 'i686-linux' => 'x86-linux', 'x86_64-linux' => 'x86_64-linux', 'i386-mingw32' => 'x86-mingw32', 'x64-mingw32' => 'x64-mingw32', 'i386-solaris2.11' => 'x86-solaris-2.11', 'x86_64-darwin14.0' => 'x86_64-darwin-14', } TEST_PATH = File.dirname(__FILE__) PKG_PATH = File.join(File.dirname(__FILE__), '..', 'pkg') TEST_FILES = Dir["#{TEST_PATH}/*_spec.rb"] RSPEC = "rspec --default-path #{TEST_PATH} -fd #{windows? ? '' : '--color'} --seed 0" INSTALL_RSPEC_COMMAND = 'gem install rspec' UNINSTALL_GEMS_COMMAND = <<-CMD gem uninstall -q -a -I concurrent-ruby-ext && \ gem uninstall -q -a -I concurrent-ruby && \ gem uninstall -q -a -I ref CMD PLATFORM_BREAK = "######################################################################\n" SUITE_BREAK = "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" def platform_specific_extensions?(platform = RUBY_PLATFORM) EXT_PLATFORMS.keys.include?(platform) && File.exists?("#{PKG_PATH}/#{extension_gem_name(platform)}") end def extension_gem_name(platform = RUBY_PLATFORM) platform = EXT_PLATFORMS.fetch(platform, '') platform = '-' + platform unless platform.empty? "concurrent-ruby-ext-#{Concurrent::VERSION}#{platform}.gem" end def install_gems_command(ext, platform = '') cmd = "gem install #{PKG_PATH}/concurrent-ruby-#{Concurrent::VERSION}.gem" if ext cmd << " && gem install #{PKG_PATH}/#{extension_gem_name(platform)}" end cmd end def install_java_gem_command "gem install #{PKG_PATH}/concurrent-ruby-#{Concurrent::VERSION}-java.gem" end def run_test_suite(files, ext, platform = '') test_platform = if ext 'EXT' elsif jruby? 'JRUBY' else 'RUBY' end cmd = if jruby? install_java_gem_command else install_gems_command(ext, platform) end ok = system(cmd) files.each do |file| if windows? cmd = "set TEST_PLATFORM=#{test_platform} && #{RSPEC} #{file}" else cmd = "TEST_PLATFORM='#{test_platform}' #{RSPEC} #{file}" end ok = system(cmd) end ok = system(UNINSTALL_GEMS_COMMAND) end ok = system(INSTALL_RSPEC_COMMAND) ok = system(UNINSTALL_GEMS_COMMAND) puts PLATFORM_BREAK puts RUBY_PLATFORM puts SUITE_BREAK run_test_suite(TEST_FILES, false) if mri? if ! windows? puts SUITE_BREAK run_test_suite(TEST_FILES, true) end if platform_specific_extensions?(RUBY_PLATFORM) puts SUITE_BREAK run_test_suite(TEST_FILES, true, RUBY_PLATFORM) end end concurrent-ruby-1.0.5/concurrent-ruby-edge.gemspec000066400000000000000000000025451305460430400222730ustar00rootroot00000000000000$:.push File.join(File.dirname(__FILE__), 'lib') $:.push File.join(File.dirname(__FILE__), 'support') require 'concurrent/version' require 'file_map' Gem::Specification.new do |s| git_files = `git ls-files`.split("\n") s.name = 'concurrent-ruby-edge' s.version = Concurrent::EDGE_VERSION s.platform = Gem::Platform::RUBY s.authors = ["Jerry D'Antonio", 'Petr Chalupa', 'The Ruby Concurrency Team'] s.email = 'concurrent-ruby@googlegroups.com' s.homepage = 'http://www.concurrent-ruby.com' s.summary = 'Edge features and additions to the concurrent-ruby gem.' s.license = 'MIT' s.date = Time.now.strftime('%Y-%m-%d') s.files = FileMap::MAP.fetch(:edge) s.extra_rdoc_files = Dir['README*', 'LICENSE*'] s.require_paths = ['lib'] s.description = <<-TXT These features are under active development and may change frequently. They are expected not to keep backward compatibility (there may also lack tests and documentation). Semantic versions will be obeyed though. Features developed in `concurrent-ruby-edge` are expected to move to `concurrent-ruby` when final. Please see http://concurrent-ruby.com for more information. TXT s.required_ruby_version = '>= 1.9.3' s.add_runtime_dependency 'concurrent-ruby', "= #{Concurrent::VERSION}" end concurrent-ruby-1.0.5/concurrent-ruby-ext.gemspec000066400000000000000000000023401305460430400221600ustar00rootroot00000000000000$:.push File.join(File.dirname(__FILE__), 'lib') require 'concurrent/version' Gem::Specification.new do |s| s.name = 'concurrent-ruby-ext' s.version = Concurrent::VERSION s.platform = Gem::Platform::RUBY s.authors = ["Jerry D'Antonio", 'The Ruby Concurrency Team'] s.email = 'concurrent-ruby@googlegroups.com' s.homepage = 'http://www.concurrent-ruby.com' s.summary = 'C extensions to optimize concurrent-ruby under MRI.' s.license = 'MIT' s.date = Time.now.strftime('%Y-%m-%d') s.description = <<-EOF C extensions to optimize the concurrent-ruby gem when running under MRI. Please see http://concurrent-ruby.com for more information. EOF s.files = Dir['ext/**/*.{h,c,cpp}'] s.files += [ 'lib/concurrent/atomic_reference/concurrent_update_error.rb', 'lib/concurrent/atomic_reference/direct_update.rb', 'lib/concurrent/atomic_reference/numeric_cas_wrapper.rb', ] s.extra_rdoc_files = Dir['README*', 'LICENSE*', 'CHANGELOG*'] s.require_paths = ['lib', 'ext'] s.extensions = 'ext/concurrent/extconf.rb' s.required_ruby_version = '>= 1.9.3' s.add_runtime_dependency 'concurrent-ruby', "= #{Concurrent::VERSION}" end concurrent-ruby-1.0.5/concurrent-ruby.gemspec000066400000000000000000000024301305460430400213620ustar00rootroot00000000000000$:.push File.join(File.dirname(__FILE__), 'lib') $:.push File.join(File.dirname(__FILE__), 'support') require 'concurrent/version' require 'file_map' Gem::Specification.new do |s| git_files = `git ls-files`.split("\n") s.name = 'concurrent-ruby' s.version = Concurrent::VERSION s.platform = Gem::Platform::RUBY s.authors = ["Jerry D'Antonio", 'Petr Chalupa', 'The Ruby Concurrency Team'] s.email = 'concurrent-ruby@googlegroups.com' s.homepage = 'http://www.concurrent-ruby.com' s.summary = 'Modern concurrency tools for Ruby. Inspired by Erlang, Clojure, Scala, Haskell, F#, C#, Java, and classic concurrency patterns.' s.license = 'MIT' s.date = Time.now.strftime('%Y-%m-%d') s.files = FileMap::MAP.fetch(:core) s.extra_rdoc_files = Dir['README*', 'LICENSE*', 'CHANGELOG*'] s.require_paths = ['lib'] s.description = <<-EOF Modern concurrency tools including agents, futures, promises, thread pools, actors, supervisors, and more. Inspired by Erlang, Clojure, Go, JavaScript, actors, and classic concurrency patterns. EOF if defined?(JRUBY_VERSION) s.files += Dir['lib/**/*.jar'] s.platform = 'java' end s.required_ruby_version = '>= 1.9.3' end concurrent-ruby-1.0.5/doc/000077500000000000000000000000001305460430400154225ustar00rootroot00000000000000concurrent-ruby-1.0.5/doc/actor/000077500000000000000000000000001305460430400165325ustar00rootroot00000000000000concurrent-ruby-1.0.5/doc/actor/celluloid_benchmark.rb000066400000000000000000000047351305460430400230560ustar00rootroot00000000000000require 'benchmark' require 'concurrent/actor' require 'celluloid' require 'celluloid/autostart' # require 'stackprof' # require 'profiler' logger = Logger.new($stderr) logger.level = Logger::INFO Concurrent.configuration.logger = lambda do |level, progname, message = nil, &block| logger.add level, message, progname, &block end scale = 1 ADD_TO = (100 * scale).to_i counts_size = (500 * scale).to_i adders_size = (500 * scale).to_i class Counter include Celluloid def initialize(adders, i) @adders = adders @i = i end def counting(count, ivar) if count < ADD_TO @adders[(@i+1) % @adders.size].counting count+1, ivar else ivar.set count end end end if defined? Celluloid threads = [] # Profiler__.start_profile # StackProf.run(mode: :cpu, # interval: 10, # out: File.join(File.dirname(__FILE__), 'stackprof-cpu-myapp.dump')) do Benchmark.bmbm(10) do |b| [2, adders_size, adders_size*2, adders_size*3].each do |adders_size| b.report(format('%5d %4d %s', ADD_TO*counts_size, adders_size, 'concurrent')) do counts = Array.new(counts_size) { [0, Concurrent::IVar.new] } adders = Array.new(adders_size) do |i| Concurrent::Actor::Utils::AdHoc.spawn("adder#{i}") do lambda do |(count, ivar)| if count < ADD_TO adders[(i+1) % adders_size].tell [count+1, ivar] else ivar.set count end end end end counts.each_with_index do |count, i| adders[i % adders_size].tell count end counts.each do |count, ivar| raise unless ivar.value >= ADD_TO end threads << Thread.list.size adders.each { |a| a << :terminate! } end if defined? Celluloid b.report(format('%5d %4d %s', ADD_TO*counts_size, adders_size, 'celluloid')) do counts = [] counts_size.times { counts << [0, Concurrent::IVar.new] } adders = [] adders_size.times do |i| adders << Counter.new(adders, i) end counts.each_with_index do |count, i| adders[i % adders_size].counting *count end counts.each do |count, ivar| raise unless ivar.value >= ADD_TO end threads << Thread.list.size adders.each(&:terminate) end end end end # end # Profiler__.stop_profile p threads # Profiler__.print_profile $stdout concurrent-ruby-1.0.5/doc/actor/define.in.rb000066400000000000000000000015461305460430400207240ustar00rootroot00000000000000Message = Struct.new :action, :value # class AnActor < Concurrent::Actor::RestartingContext def initialize(init) @counter = init end # override #on_message to define actor's behaviour on message received def on_message(message) case message.action when :add @counter = @counter + message.value when :subtract @counter = @counter - message.value when :value @counter else pass end end # set counter to zero when there is an error def on_event(event) if event == :reset @counter = 0 # ignore initial value end end end # an_actor = AnActor.spawn name: 'an_actor', args: 10 # an_actor << Message.new(:add, 1) << Message.new(:subtract, 2) # an_actor.ask!(Message.new(:value, nil)) an_actor << :boo << Message.new(:add, 1) # an_actor.ask!(Message.new(:value, nil)) an_actor << :terminate! concurrent-ruby-1.0.5/doc/actor/define.out.rb000066400000000000000000000017211305460430400211200ustar00rootroot00000000000000Message = Struct.new :action, :value class AnActor < Concurrent::Actor::RestartingContext def initialize(init) @counter = init end # override #on_message to define actor's behaviour on message received def on_message(message) case message.action when :add @counter = @counter + message.value when :subtract @counter = @counter - message.value when :value @counter else pass end end # set counter to zero when there is an error def on_event(event) if event == :reset @counter = 0 # ignore initial value end end end an_actor = AnActor.spawn name: 'an_actor', args: 10 an_actor << Message.new(:add, 1) << Message.new(:subtract, 2) an_actor.ask!(Message.new(:value, nil)) # => 9 an_actor << :boo << Message.new(:add, 1) an_actor.ask!(Message.new(:value, nil)) # => 1 an_actor << :terminate! # => # concurrent-ruby-1.0.5/doc/actor/examples.in.rb000066400000000000000000000000031305460430400212730ustar00rootroot00000000000000 concurrent-ruby-1.0.5/doc/actor/examples.out.rb000066400000000000000000000000031305460430400214740ustar00rootroot00000000000000 concurrent-ruby-1.0.5/doc/actor/format.rb000066400000000000000000000036401305460430400203520ustar00rootroot00000000000000require 'rubygems' require 'bundler/setup' require 'pry' require 'pp' root = File.dirname(File.expand_path(Process.argv0)) input_paths = if ARGV.empty? Dir.glob("#{root}/*.in.rb") else ARGV end.map { |p| File.expand_path p } input_paths.each_with_index do |input_path, i| pid = fork do require File.join(root, 'init.rb') begin output_path = input_path.gsub /\.in\.rb$/, '.out.rb' input = File.readlines(input_path) chunks = [] line = '' while !input.empty? line += input.shift if Pry::Code.complete_expression? line chunks << line line = '' end end raise unless line.empty? chunks.map! { |chunk| [chunk, [chunk.split($/).size, 1].max] } environment = Module.new.send :binding evaluate = ->(code, line) do eval(code, environment, input_path, line) end indent = 50 line_count = 1 output = '' chunks.each do |chunk, lines| result = evaluate.(chunk, line_count) unless chunk.strip.empty? || chunk =~ /\A *#/ pre_lines = chunk.lines.to_a last_line = pre_lines.pop output << pre_lines.join if last_line =~ /\#$/ output << last_line.gsub(/\#$/, '') else if last_line.size < indent && result.inspect.size < indent output << "%-#{indent}s %s" % [last_line.chomp, "# => #{result.inspect}\n"] else output << last_line << " # => #{result.inspect}\n" end end else output << chunk end line_count += lines end puts "#{input_path}\n -> #{output_path}" #puts output File.write(output_path, output) rescue => ex puts "#{ex} (#{ex.class})\n#{ex.backtrace * "\n"}" end end Process.wait pid end concurrent-ruby-1.0.5/doc/actor/init.rb000066400000000000000000000000571305460430400200240ustar00rootroot00000000000000require 'concurrent' require 'concurrent-edge' concurrent-ruby-1.0.5/doc/actor/io.in.rb000066400000000000000000000023131305460430400200720ustar00rootroot00000000000000require 'concurrent' # logger = Logger.new(STDOUT) # Concurrent.configuration.logger = logger.method(:add) # First option is to use operation pool class ActorDoingIO < Concurrent::Actor::RestartingContext def on_message(message) # do IO operation end def default_executor Concurrent.global_io_executor end end # actor_doing_io = ActorDoingIO.spawn :actor_doing_io actor_doing_io.executor == Concurrent.global_io_executor # It can be also built into a pool so there is not too many IO operations class IOWorker < Concurrent::Actor::Context def on_message(io_job) # do IO work sleep 0.1 puts "#{path} second:#{(Time.now.to_f*100).floor} message:#{io_job}" end def default_executor Concurrent.global_io_executor end end # pool = Concurrent::Actor::Utils::Pool.spawn('pool', 2) do |index| IOWorker.spawn(name: "worker-#{index}") end pool << 1 << 2 << 3 << 4 << 5 << 6 # prints two lines each second # /pool/worker-0 second:1414677666 message:1 # /pool/worker-1 second:1414677666 message:2 # /pool/worker-0 second:1414677667 message:3 # /pool/worker-1 second:1414677667 message:4 # /pool/worker-0 second:1414677668 message:5 # /pool/worker-1 second:1414677668 message:6 sleep 1 concurrent-ruby-1.0.5/doc/actor/io.out.rb000066400000000000000000000031071305460430400202750ustar00rootroot00000000000000require 'concurrent' # => false # logger = Logger.new(STDOUT) # Concurrent.configuration.logger = logger.method(:add) # First option is to use operation pool class ActorDoingIO < Concurrent::Actor::RestartingContext def on_message(message) # do IO operation end def default_executor Concurrent.global_io_executor end end actor_doing_io = ActorDoingIO.spawn :actor_doing_io # => # actor_doing_io.executor == Concurrent.global_io_executor # => true # It can be also built into a pool so there is not too many IO operations class IOWorker < Concurrent::Actor::Context def on_message(io_job) # do IO work sleep 0.1 puts "#{path} second:#{(Time.now.to_f*100).floor} message:#{io_job}" end def default_executor Concurrent.global_io_executor end end pool = Concurrent::Actor::Utils::Pool.spawn('pool', 2) do |index| IOWorker.spawn(name: "worker-#{index}") end # => # pool << 1 << 2 << 3 << 4 << 5 << 6 # => # # prints two lines each second # /pool/worker-0 second:1414677666 message:1 # /pool/worker-1 second:1414677666 message:2 # /pool/worker-0 second:1414677667 message:3 # /pool/worker-1 second:1414677667 message:4 # /pool/worker-0 second:1414677668 message:5 # /pool/worker-1 second:1414677668 message:6 sleep 1 # => 1 concurrent-ruby-1.0.5/doc/actor/main.md000066400000000000000000000210401305460430400177750ustar00rootroot00000000000000# Actor model - Light-weighted running on thread-pool. - Inspired by Akka and Erlang. - Modular. This Actor model implementation makes actors very cheap to create and discard. Thousands of actors can be created, allowing you to break the program into smaller maintainable pieces, without violating the single responsibility principle. ## What is an actor model? Actor-based concurrency is all the rage in some circles. Originally described in 1973, the actor model is a paradigm for creating asynchronous, concurrent objects that is becoming increasingly popular. Much has changed since actors were first written about four decades ago, which has led to a serious fragmentation within the actor community. There is *no* universally accepted, strict definition of "actor" and actor implementations differ widely between languages and libraries. [Wiki](http://en.wikipedia.org/wiki/Actor_model) definition is pretty good: _The actor model in computer science is a mathematical model of concurrent computation that treats **actors** as the universal primitives of concurrent digital computation: in response to a message that it receives, an actor can make local decisions, create more actors, send more messages, and determine how to respond to the next message received._ ## Why? Concurrency is hard to get right, actors are one of many ways how to simplify the problem. ## Quick example An example: ```ruby class Counter < Concurrent::Actor::Context # Include context of an actor which gives this class access to reference # and other information about the actor # use initialize as you wish def initialize(initial_value) @count = initial_value end # override on_message to define actor's behaviour def on_message(message) if Integer === message @count += message end end end # # Create new actor naming the instance 'first'. # Return value is a reference to the actor, the actual actor is never returned. counter = Counter.spawn(:first, 5) # Tell a message and forget returning self. counter.tell(1) counter << 1 # (First counter now contains 7.) # Send a messages asking for a result. counter.ask(0).class counter.ask(0).value ``` {include:file:doc/actor/quick.out.rb} ## Spawning actors - {Concurrent::Actor.spawn} and {Concurrent::Actor.spawn!} - {Concurrent::Actor::AbstractContext.spawn} and {Concurrent::Actor::AbstractContext.spawn!} ## Sending messages - {Concurrent::Actor::Reference#tell} {include:Concurrent::Actor::Reference#tell} - {Concurrent::Actor::Reference#ask} {include:Concurrent::Actor::Reference#ask} - {Concurrent::Actor::Reference#ask!} {include:Concurrent::Actor::Reference#ask!} Messages are processed in same order as they are sent by a sender. It may interleaved with messages from other senders though. ### Immutability Messages sent between actors should be **immutable**. Gems like - [Algebrick](https://github.com/pitr-ch/algebrick) - Typed struct on steroids based on algebraic types and pattern matching - [Hamster](https://github.com/hamstergem/hamster) - Efficient, Immutable, Thread-Safe Collection classes for Ruby are very helpful. {include:file:doc/actor/messaging.out.rb} ## Actor definition {include:Concurrent::Actor::AbstractContext} ## Reference {include:Actor::Reference} ## Garbage collection Spawned actor cannot be garbage-collected until it's terminated. There is a reference held in the parent actor. ## Parent-child relationship, name, and path - {Core#name} {include:Actor::Core#name} - {Core#path} {include:Actor::Core#path} - {Core#parent} {include:Actor::Core#parent} ## Behaviour {include:Actor::Behaviour} ## IO cooperation Actors are running on shared thread poll which allows user to create many actors cheaply. Downside is that these actors cannot be directly used to do IO or other blocking operations. Blocking operations could starve the `default_task_pool`. However there are two options: - Create an regular actor which will schedule blocking operations in `global_operation_pool` (which is intended for blocking operations) sending results back to self in messages. - Create an actor using `global_operation_pool` instead of `global_task_pool`, e.g. `AnIOActor.spawn name: :blocking, executor: Concurrent.configuration.global_operation_pool`. ### Example {include:file:doc/actor/io.out.rb} ## Dead letter routing see {AbstractContext#dead_letter_routing} description: > {include:Actor::AbstractContext#dead_letter_routing} ## FAQ ### What happens if I try to supervise using a normal Context? Alleged supervisor will receive errors from its supervised actors. They'll have to be handled manually. ### How to change supervision strategy? Use option `behaviour_definition: Behaviour.restarting_behaviour_definition(:resume!)` or `behaviour_definition: Behaviour.restarting_behaviour_definition(:reset!, :one_for_all)` ### How to change behaviors? Any existing behavior can be subclassed ### How to implement custom restarting? By subclassing {Behaviour::Pausing} and overriding {Behaviour::Pausing#restart!}. Implementing {AbstractContext#on_event} could be also considered. _We'll be happy to answer any other questions, just [open an Issue](https://github.com/ruby-concurrency/concurrent-ruby/issues/new) or find us on https://gitter.im/ruby-concurrency/concurrent-ruby._ ## Speed Simple benchmark Actor vs Celluloid, the numbers are looking good but you know how it is with benchmarks. Source code is in `examples/actor/celluloid_benchmark.rb`. It sends numbers between x actors and adding 1 until certain limit is reached. Benchmark legend: - mes. - number of messages send between the actors - act. - number of actors exchanging the messages - impl. - which gem is used ### JRUBY Rehearsal --------------------------------------------------------- 50000 2 concurrent 26.140000 0.610000 26.750000 ( 7.761000) 50000 2 celluloid 41.440000 5.270000 46.710000 ( 17.535000) 50000 500 concurrent 11.340000 0.180000 11.520000 ( 3.498000) 50000 500 celluloid 19.310000 10.680000 29.990000 ( 14.619000) 50000 1000 concurrent 10.640000 0.180000 10.820000 ( 3.563000) 50000 1000 celluloid 17.840000 19.850000 37.690000 ( 18.892000) 50000 1500 concurrent 14.120000 0.290000 14.410000 ( 4.618000) 50000 1500 celluloid 19.060000 28.920000 47.980000 ( 25.185000) ---------------------------------------------- total: 225.870000sec mes. act. impl. user system total real 50000 2 concurrent 7.320000 0.530000 7.850000 ( 3.637000) 50000 2 celluloid 13.780000 4.730000 18.510000 ( 10.756000) 50000 500 concurrent 9.270000 0.140000 9.410000 ( 3.020000) 50000 500 celluloid 16.540000 10.920000 27.460000 ( 14.308000) 50000 1000 concurrent 9.970000 0.160000 10.130000 ( 3.445000) 50000 1000 celluloid 15.930000 20.840000 36.770000 ( 18.272000) 50000 1500 concurrent 11.580000 0.240000 11.820000 ( 3.723000) 50000 1500 celluloid 19.440000 29.060000 48.500000 ( 25.227000) (1) ### MRI 2.1.0 Rehearsal --------------------------------------------------------- 50000 2 concurrent 4.180000 0.080000 4.260000 ( 4.269435) 50000 2 celluloid 7.740000 3.100000 10.840000 ( 10.043875) 50000 500 concurrent 5.900000 1.310000 7.210000 ( 6.565067) 50000 500 celluloid 12.820000 5.810000 18.630000 ( 17.320765) 50000 1000 concurrent 6.080000 1.640000 7.720000 ( 6.931294) 50000 1000 celluloid 17.130000 8.320000 25.450000 ( 23.786146) 50000 1500 concurrent 6.940000 2.030000 8.970000 ( 7.927330) 50000 1500 celluloid 20.980000 12.040000 33.020000 ( 30.849578) ---------------------------------------------- total: 116.100000sec mes. act. impl. user system total real 50000 2 concurrent 3.730000 0.100000 3.830000 ( 3.822688) 50000 2 celluloid 7.900000 2.910000 10.810000 ( 9.924014) 50000 500 concurrent 5.420000 1.230000 6.650000 ( 6.025579) 50000 500 celluloid 12.720000 5.540000 18.260000 ( 16.889517) 50000 1000 concurrent 5.420000 0.910000 6.330000 ( 5.896689) 50000 1000 celluloid 16.090000 8.040000 24.130000 ( 22.347102) 50000 1500 concurrent 5.580000 0.760000 6.340000 ( 6.038535) 50000 1500 celluloid 20.000000 11.680000 31.680000 ( 29.590774) (1) *Note (1):* Celluloid is using thread per actor so this bench is creating about 1500 native threads. Actor is using constant number of threads. concurrent-ruby-1.0.5/doc/actor/messaging.in.rb000066400000000000000000000015521305460430400214440ustar00rootroot00000000000000require 'algebrick' # Actor message protocol definition with Algebrick Protocol = Algebrick.type do variants Add = type { fields! a: Numeric, b: Numeric }, Subtract = type { fields! a: Numeric, b: Numeric } end class Calculator < Concurrent::Actor::RestartingContext include Algebrick::Matching def on_message(message) # pattern matching on the message with deconstruction # ~ marks values which are passed to the block match message, (on Add.(~any, ~any) do |a, b| a + b end), # or using multi-assignment (on ~Subtract do |(a, b)| a - b end) end end # calculator = Calculator.spawn('calculator') addition = calculator.ask Add[1, 2] substraction = calculator.ask Subtract[1, 0.5] results = (addition & substraction) results.value! calculator.ask! :terminate! concurrent-ruby-1.0.5/doc/actor/messaging.out.rb000066400000000000000000000025031305460430400216420ustar00rootroot00000000000000require 'algebrick' # => true # Actor message protocol definition with Algebrick Protocol = Algebrick.type do variants Add = type { fields! a: Numeric, b: Numeric }, Subtract = type { fields! a: Numeric, b: Numeric } end # => Protocol(Add | Subtract) class Calculator < Concurrent::Actor::RestartingContext include Algebrick::Matching def on_message(message) # pattern matching on the message with deconstruction # ~ marks values which are passed to the block match message, (on Add.(~any, ~any) do |a, b| a + b end), # or using multi-assignment (on ~Subtract do |(a, b)| a - b end) end end calculator = Calculator.spawn('calculator') # => # addition = calculator.ask Add[1, 2] # => <#Concurrent::Promises::Future:0x7fbedc05f7b0 pending> substraction = calculator.ask Subtract[1, 0.5] # => <#Concurrent::Promises::Future:0x7fbedd891388 pending> results = (addition & substraction) # => <#Concurrent::Promises::Future:0x7fbedc04eeb0 pending> results.value! # => [3, 0.5] calculator.ask! :terminate! # => true concurrent-ruby-1.0.5/doc/actor/quick.in.rb000066400000000000000000000012251305460430400206000ustar00rootroot00000000000000class Adder < Concurrent::Actor::RestartingContext def initialize(init) @count = init end def on_message(message) case message when :add @count += 1 else # pass to ErrorsOnUnknownMessage behaviour, which will just fail pass end end end # # `link: true` makes the actor linked to root actor and supervised # which is default behavior adder = Adder.spawn(name: :adder, link: true, args: [1]) adder.parent # tell and forget adder.tell(:add).tell(:add) # ask to get result adder.ask!(:add) # fail the actor adder.ask!(:bad) rescue $! # actor is restarted with initial values adder.ask!(:add) adder.ask!(:terminate!) concurrent-ruby-1.0.5/doc/actor/quick.out.rb000066400000000000000000000021011305460430400207730ustar00rootroot00000000000000class Adder < Concurrent::Actor::RestartingContext def initialize(init) @count = init end def on_message(message) case message when :add @count += 1 else # pass to ErrorsOnUnknownMessage behaviour, which will just fail pass end end end # `link: true` makes the actor linked to root actor and supervised # which is default behavior adder = Adder.spawn(name: :adder, link: true, args: [1]) # => # adder.parent # => # # tell and forget adder.tell(:add).tell(:add) # => # # ask to get result adder.ask!(:add) # => 4 # fail the actor adder.ask!(:bad) rescue $! # => #> # actor is restarted with initial values adder.ask!(:add) # => 2 adder.ask!(:terminate!) # => true concurrent-ruby-1.0.5/doc/actor/supervision_tree.in.rb000066400000000000000000000030021305460430400230640ustar00rootroot00000000000000 class Master < Concurrent::Actor::RestartingContext def initialize # create listener a supervised child of master @listener = Listener.spawn(name: 'listener1', supervise: true) end def on_message(msg) command, *args = msg case command when :listener @listener when :reset, :terminated, :resumed, :paused log(DEBUG) { " got #{msg} from #{envelope.sender}"} else pass end end # TODO this should be a part of a behaviour, it ensures that children are restarted/paused etc. when theirs parents are def on_event(event) event_name, _ = event case event_name when :resetting, :restarting @listener << :terminate! when Exception, :paused @listener << :pause! when :resumed @listener << :resume! end end end # class Listener < Concurrent::Actor::RestartingContext def initialize @number = (rand() * 100).to_i end def on_message(msg) case msg when :number @number else pass end end end # master = Master.spawn(name: 'master', supervise: true) listener = master.ask!(:listener) listener.ask!(:number) # crash the listener which is supervised by master, it's restarted automatically reporting a different number listener.tell(:crash) listener.ask!(:number) master << :crash sleep 0.1 # ask for listener again, old one is terminated with master and replaced with new one listener.ask!(:terminated?) listener = master.ask!(:listener) listener.ask!(:number) master.ask!(:terminate!) sleep 0.1 concurrent-ruby-1.0.5/doc/actor/supervision_tree.out.rb000066400000000000000000000042421305460430400232740ustar00rootroot00000000000000 class Master < Concurrent::Actor::RestartingContext def initialize # create listener a supervised child of master @listener = Listener.spawn(name: 'listener1', supervise: true) end def on_message(msg) command, *args = msg case command when :listener @listener when :reset, :terminated, :resumed, :paused log(DEBUG) { " got #{msg} from #{envelope.sender}"} else pass end end # TODO this should be a part of a behaviour, it ensures that children are restarted/paused etc. when theirs parents are def on_event(event) event_name, _ = event case event_name when :resetting, :restarting @listener << :terminate! when Exception, :paused @listener << :pause! when :resumed @listener << :resume! end end end class Listener < Concurrent::Actor::RestartingContext def initialize @number = (rand() * 100).to_i end def on_message(msg) case msg when :number @number else pass end end end master = Master.spawn(name: 'master', supervise: true) # => # listener = master.ask!(:listener) # => # listener.ask!(:number) # => 39 # crash the listener which is supervised by master, it's restarted automatically reporting a different number listener.tell(:crash) # => # listener.ask!(:number) # => 73 master << :crash # => # sleep 0.1 # => 0 # ask for listener again, old one is terminated with master and replaced with new one listener.ask!(:terminated?) # => true listener = master.ask!(:listener) # => # listener.ask!(:number) # => 72 master.ask!(:terminate!) # => true sleep 0.1 # => 0 concurrent-ruby-1.0.5/doc/channel.md000066400000000000000000000333541305460430400173640ustar00rootroot00000000000000# Channels and Goroutines Channels, popularized by the [Go programming language](https://golang.org/doc/effective_go.html#channels), are a modern variation of [communicating sequential processes (CSP)](https://en.wikipedia.org/wiki/Communicating_sequential_processes). CSP was first proposed by C. A. R. Hoare in 1978. The Go philosophy on concurrency is: > Do not communicate by sharing memory; instead, share memory by communicating. As [Rob Pike](https://en.wikipedia.org/wiki/Rob_Pike) eloquently explains in his [Concurrency Is Not Parallelism](https://vimeo.com/49718712) conference talk, concurrency is the "composition of independently executing things." Combining these two ideas, channels are a queue-like mechanism that can be used to communicate between independently executing things. The channel implementation in this library was highly influenced by Go, but also incorporates ideas from Clojure's [core.async](https://clojure.github.io/core.async/) library. Runtime differences aside, this channel library is functionally equivalent to Go and even includes a few features Go does not. ### Example Programs Every code example in the channel chapters of both [A Tour of Go](https://tour.golang.org/welcome/1) and [Go By Example](https://gobyexample.com/) has been reproduced in Ruby. The code can be found in the [examples](https://github.com/ruby-concurrency/concurrent-ruby/tree/master/examples) directory of the source repository. Many of those examples appear in the documentation below, but many do not. They are a valuable resource for learning how to use channels. ### Additional Resources * "A Tour of Go" [channels exercises](https://tour.golang.org/concurrency/2) * "Go By Example" [channels exercises](https://gobyexample.com/channels) * "Effective Go" [concurrency chapters](https://golang.org/doc/effective_go.html#concurrency) * "Concurrency Is Not Parallelims" [conference presentation](https://vimeo.com/49718712) by Rob Pike, principal designer of Go * "Clojure core.async Channels" [blog post](http://clojure.com/blog/2013/06/28/clojure-core-async-channels.html) by Rich Hickey, inventor of Clojure * Clojure core.async [API reference](https://clojure.github.io/core.async/) ## Goroutines The Go programming languages uses "goroutines" as the core concurrency mechanism. A goroutine is little more than an independently executing function, multiplexed with all other goroutines onto a thread pool managed by the runtime. Ruby has a very different runtime so true goroutines are not possible. Instread, a {.go} method is provided for running a block asynchronously, multiplexed onto a special thread pool reserved just for `Channel` operations. This is similar to what Clojure does with the `go` function from the [core.async](https://clojure.github.io/core.async/#clojure.core.async/go) library. ```ruby puts "Main thread: #{Thread.current}" Concurrent::Channel.go do puts "Goroutine thread: #{Thread.current}" end # Main thread: # # Goroutine thread: # ``` Although it is possible to use `Channel.go` independent of channels or to use channels with other asynchronous processing tools (such as `Future` and `Actor`), mixing the tools is not advised. Most high-level asynchronous processing tools already have a queue-like mechanism built in. Adding channels to the mix may indicate a design flaw. Conversely, `Channel.go` provides no mechanism for coordination and communication. That's what channels are for. Additionally, strictly using `Channel.go` along with channels provides an opportunity for future optimizations, such as Clojure's inversion of control (IOC) threads. ## Channel Basics Channels are "pipes" through which values can be sent. They are thread safe and naturally concurrent. When shared between goroutines they provide a communication mechanism for coordinating asynchronous actions. The core channel operations are {#put} and {#take} (aliased as {#send} and {#receive}, respectively). The former function inserts a value into a channel where the latter removes a value. By default these are blocking operations. A call to `put` will block until the channel is ready to receive the value. Similarly, a call to `take` will block until a value is available to be removed. The following, simple example creates a channel, launches a goroutine from which a value is placed into the channel, then reads that value from the channel. When run this example will display "ping" in the console. ```ruby messages = Concurrent::Channel.new Concurrent::Channel.go do messages.put 'ping' end msg = messages.take puts msg ``` By default, channels are *unbuffered*, meaning that they have a capacity of zero and only accept puts and takes when both a putting and a taking thread are available. If a `put` is started when there is no taker thread the call will block. As soon as another thread calls `take` the exchange will occur and both calls will return on their respective threads. Similarly, is a `take` is started when there is no putting thread the call will block until another thread calls `put`. The following, slightly more complex example, concurrently sums two different halves of a list then combines the results. It uses an unbuffered channel to pass the results from the two goroutines back to the main thread. The main thread blocks on the two `take` calls until the worker goroutines are done. This example also uses the convenience aliases {#<<} and {#~}. Since channels in Go are part of the language, channel operations are performed using special channel operators rather than functions. These operators help clearly indicate that channel operations are being performed. The operator overloads `<<` for `put` and `~` for `take` help reinforce this idea in Ruby. ```ruby def sum(a, c) sum = a.reduce(0, &:+) c << sum # `<<` is an alias for `put` or `send` end a = [7, 2, 8, -9, 4, 0] l = a.length / 2 c = Concurrent::Channel.new Concurrent::Channel.go { sum(a[-l, l], c) } Concurrent::Channel.go { sum(a[0, l], c) } x, y = ~c, ~c # `~` is an alias for `take` or `receive` puts [x, y, x+y].join(' ') ``` ## Channel Buffering One common channel variation is a *buffered* channel. A buffered channel has a finite number of slots in the buffer which can be filled. Putting threads can put values into the channel even if there is no taking threads, up to the point where the buffer is filled. Once a buffer becomes full the normal blocking behavior resumes. A buffered channel is created by giving a `:capacity` option on channel creation: The following example creates a buffered channel with two slots. It then makes two `put` calls, adding values to the channel. These calls do not block because the buffer has room. Were a third `put` call to be made before an `take` calls, the third `put` would block. ```ruby ch = Concurrent::Channel.new(capacity: 2) ch << 1 ch << 2 puts ~ch puts ~ch ``` ## Channel Synchronization The main purpose of channels is to synchronize operations across goroutines. One common pattern for this is to created a `capacity: 1` buffered channel which is used to signal that work is complete. The following example calls a `worker` function on a goroutine and passes it a "done" channel. The main thread then calls `take` on the "done" channel and blocks until signaled. ```ruby def worker(done_channel) print "working...\n" sleep(1) print "done\n" done_channel << true end done = Concurrent::Channel.new(capacity: 1) Concurrent::Channel.go{ worker(done) } ~done # block until signaled ``` ## Multichannel Select Often it is necessary for a single thread to operate on more than one channel. The {.select} method facilitates multivariate channel operations. The `select` method takes a block and passes through a special "selector" object as the first block parameter. The selector can then be used to specify various channel operations. The `select` call will block until one of the operations occurs. If a block is provided for the triggered clause (required for some clauses, optional for others) the block will then be called. Finally, the `select` call will immediately exit, guaranteeing that only one of the select clauses will trigger. The following example spawns two goroutines, each of which goes to sleep before putting a value onto a channel. The main thread loops twice over a `select` and, in each loop, takes a value off of whichever channel returns one first. ```ruby c1 = Concurrent::Channel.new c2 = Concurrent::Channel.new Concurrent::Channel.go do sleep(1) c1 << 'one' end Concurrent::Channel.go do sleep(2) c1 << 'two' end 2.times do Concurrent::Channel.select do |s| s.take(c1) { |msg| print "received #{msg}\n" } s.take(c2) { |msg| print "received #{msg}\n" } end end ``` The output from the above example is: ``` received one received two ``` The next example calculates the first 10 fibonacci numbers, passing them to the main thread via a channel. The fibonacci function puts each calculated value onto a channel while simultaneously listening to a different channel for the signal to stop. This example uses the `case` method on the selector object. This is just a convenience method for `put` and `take`, allowing the Ruby code to look more like Go. ```ruby def fibonacci(c, quit) x, y = 0, 1 loop do Concurrent::Channel.select do |s| s.case(c, :<<, x) { x, y = y, x+y; x } # alias for `s.put` s.case(quit, :~) do # alias for `s.take` puts 'quit' return end end end end c = Concurrent::Channel.new quit = Concurrent::Channel.new Concurrent::Channel.go do 10.times { puts ~c } quit << 0 end fibonacci(c, quit) ``` ## Closing and Iterating Over Channels Newly created channels are in an "open" state. Open channels can receive values via `put` operations. When a program is done with a channel it can be closed by calling the `#close` method. Once a channel is closed it will no longer allow values to be `put`. If the channel is buffered and values are in the buffer when the channel is closed, the remaining values can still be removed via `take` operations. The `Channel` class implements an {#each} method which can be used to retrieve successive values from the channel. The `each` method is a blocking method. When the channel is open and there are no values in the buffer, `each` will block until a new item is `put`. The `each` method will not exit until the channel is closed. The following example launches a goroutine which calculates several fibonacci values and puts them into a channel. The main thread uses the `each` method to retrieve all the values successively and display them in the console. Once the fibonacci goroutine is done it closes the channel which subsequently causes the `each` iteration to end, unblocking the main thread. ```ruby def fibonacci(n, c) x, y = 0, 1 (1..n).each do c << x x, y = y, x+y end c.close end chan = Concurrent::Channel.new(capacity: 10) Concurrent::Channel.go { fibonacci(chan.capacity, c) } chan.each { |i| puts i } ``` `Channel` also includes Ruby's [Enumerable](http://ruby-doc.org/core-2.2.3/Enumerable.html) mixin, allowing for a wide range of list comprehensions. Since the `Enumerable` methods iterate over the entire set of objects they can only complete once the channel is closed. Calling a method from `Enumerable` on an open channel will cause the method to block until the channel is closed. ## Timers and Tickers A {.timer} is a specialized channel which triggers at a predefined time, specified as a number of seconds in the future. It is similar in concept to a {Concurrent::ScheduledTask} but operates as a channel and can fully participate in all channel operations. The following code example creates two timers with different delay values. The first timer is allowed to expire (trigger) by having the main thread perform a `take` on it. When the timer expires it puts a {Concurrent::Channel::Tick} object into its buffer and closes. The second timer is listened to on a goroutine but the it never expires: the main thread stops (closes) the timer before it expires. Note that the goroutine in this example blocks forever and never exits. Since the timer is closed it never puts the `Tick` into its buffer. ```ruby timer1 = Concurrent::Channel.timer(2) ~timer1 puts 'Timer 1 expired' timer2 = Concurrent::Channel.timer(1) Concurrent::Channel.go do ~timer2 print "Timer 2 expired\n" end stop2 = timer2.stop # alias for `close` print "Timer 2 stopped\n" if stop2 ``` A {.ticker} is a specialized channel which triggers over and over again at a predefined interval, specified as a number of seconds between ticks. It is similar in concept to a {Concurrent::TimerTask} but operates as a channel and can fully participate in all channel operations. The following example creates a ticker which triggers every half-second. A goroutine iterates over the ticker using the `each` method, printing the tick at every interval. When the main thread stops (closes) the ticker the `each` call ends and the goroutine exits. ```ruby ticker = Concurrent::Channel.ticker(0.5) Concurrent::Channel.go do ticker.each do |tick| print "Tick at #{tick}\n" end end sleep(1.6) ticker.stop # alias for `close` print "Ticker stopped\n" ``` ## Default Selection As with a Ruby `case` statement, a `Channel.select` statement will accept a `default` clause which will trigger if none of the other clauses trigger. Not surprisingly, the `default` clause must be the last clause in a `select` block. ```ruby tick = Concurrent::Channel.tick(0.1) # alias for `ticker` boom = Concurrent::Channel.after(0.5) # alias for `timer` loop do Concurrent::Channel.select do |s| s.take(tick) { print "tick.\n" } s.take(boom) do print "BOOM!\n" exit end s.default do print " .\n" sleep(0.05) end end end ``` The output of this code example is: ``` . . tick. . . tick. . . tick. . . tick. . . tick. BOOM! ``` concurrent-ruby-1.0.5/doc/dataflow.md000066400000000000000000000116021305460430400175450ustar00rootroot00000000000000Dataflow allows you to create a task that will be scheduled when all of its data dependencies are available. Data dependencies are `Future` values. The dataflow task itself is also a `Future` value, so you can build up a graph of these tasks, each of which is run when all the data and other tasks it depends on are available or completed. Our syntax is somewhat related to that of Akka's `flow` and Habanero Java's `DataDrivenFuture`. However unlike Akka we don't schedule a task at all until it is ready to run, and unlike Habanero Java we pass the data values into the task instead of dereferencing them again in the task. The theory of dataflow goes back to the 70s. In the terminology of the literature, our implementation is coarse-grained, in that each task can be many instructions, and dynamic in that you can create more tasks within other tasks. ### Example A dataflow task is created with the `dataflow` method, passing in a block. ```ruby task = Concurrent::dataflow { 14 } ``` This produces a simple `Future` value. The task will run immediately, as it has no dependencies. We can also specify `Future` values that must be available before a task will run. When we do this we get the value of those futures passed to our block. ```ruby a = Concurrent::dataflow { 1 } b = Concurrent::dataflow { 2 } c = Concurrent::dataflow(a, b) { |av, bv| av + bv } ``` Using the `dataflow` method you can build up a directed acyclic graph (DAG) of tasks that depend on each other, and have the tasks run as soon as their dependencies are ready and there is CPU capacity to schedule them. This can help you create a program that uses more of the CPU resources available to you. ### Derivation This section describes how we could derive dataflow from other primitives in this library. Consider a naive fibonacci calculator. ```ruby def fib(n) if n < 2 n else fib(n - 1) + fib(n - 2) end end puts fib(14) #=> 377 ``` We could modify this to use futures. ```ruby def fib(n) if n < 2 Concurrent::Future.new { n } else n1 = fib(n - 1).execute n2 = fib(n - 2).execute Concurrent::Future.new { n1.value + n2.value } end end f = fib(14) #=> # # 377 ``` One of the drawbacks of this approach is that all the futures start, and then most of them immediately block on their dependencies. We know that there's no point executing those futures until their dependencies are ready, so let's not execute each future until all their dependencies are ready. To do this we'll create an object that counts the number of times it observes a future finishing before it does something - and for us that something will be to execute the next future. ```ruby class CountingObserver def initialize(count, &block) @count = count @block = block end def update(time, value, reason) @count -= 1 if @count <= 0 @block.call() end end end def fib(n) if n < 2 Concurrent::Future.new { n }.execute else n1 = fib(n - 1) n2 = fib(n - 2) result = Concurrent::Future.new { n1.value + n2.value } barrier = CountingObserver.new(2) { result.execute } n1.add_observer barrier n2.add_observer barrier n1.execute n2.execute result end end ``` We can wrap this up in a dataflow utility. ```ruby f = fib(14) #=> # 377 def dataflow(*inputs, &block) result = Concurrent::Future.new(&block) if inputs.empty? result.execute else barrier = CountingObserver.new(inputs.size) { result.execute } inputs.each do |input| input.add_observer barrier end end result end def fib(n) if n < 2 dataflow { n } else n1 = fib(n - 1) n2 = fib(n - 2) dataflow(n1, n2) { n1.value + n2.value } end end f = fib(14) #=> # 377 ``` Since we know that the futures the dataflow computation depends on are already going to be available when the future is executed, we might as well pass the values into the block so we don't have to reference the futures inside the block. This allows us to write the dataflow block as straight non-concurrent code without reference to futures. ```ruby def dataflow(*inputs, &block) result = Concurrent::Future.new do values = inputs.map { |input| input.value } block.call(*values) end if inputs.empty? result.execute else barrier = CountingObserver.new(inputs.size) { result.execute } inputs.each do |input| input.add_observer barrier end end result end def fib(n) if n < 2 Concurrent::dataflow { n } else n1 = fib(n - 1) n2 = fib(n - 2) Concurrent::dataflow(n1, n2) { |v1, v2| v1 + v2 } end end f = fib(14) #=> # 377 ``` concurrent-ruby-1.0.5/doc/dataflow_top_stock_calc.md000066400000000000000000000051511305460430400226160ustar00rootroot00000000000000This program determines which stock had the highest price in a given year. It as an example from chapter 1 "Introduction", section 1.2 "What's Scala?" of the book [Programming Scala: Tackle Multi-Core Complexity on the Java Virtual Machine](http://pragprog.com/book/vsscala/programming-scala). ## What It Does This program takes a list of one or more stock symbols and a year. It then concurrently obtains the relevant stock data from Yahoo's iChart service for each symbol. Once all the data has been retrieved the program determines which stock had the highest year-end closing price. * A sample of the data can be downloaded [here](http://ichart.finance.yahoo.com/table.csv?s=AAPL&a=11&b=01&c=2008&d=11&e=31&f=2008&g=m). #### The Ruby Code ```ruby require 'concurrent' require 'open-uri' def get_year_end_closing(symbol, year) uri = "http://ichart.finance.yahoo.com/table.csv?s=#{symbol}&a=11&b=01&c=#{year}&d=11&e=31&f=#{year}&g=m" data = open(uri) {|f| f.collect{|line| line.strip } } price = data[1].split(',')[4] price.to_f [symbol, price.to_f] end def get_top_stock(symbols, year, timeout = 5) stock_prices = symbols.collect{|symbol| Concurrent::dataflow{ get_year_end_closing(symbol, year) }} Concurrent::dataflow(*stock_prices) { |*prices| prices.reduce(['', 0.0]){|highest, price| price.last > highest.last ? price : highest} }.value(timeout) end symbols = ['AAPL', 'GOOG', 'IBM', 'ORCL', 'MSFT'] year = 2008 top_stock, highest_price = get_top_stock(symbols, year) puts "Top stock of #{year} is #{top_stock} closing at price $#{highest_price}" ``` #### The Scala Code ```scala //START:PART1 import scala.actors._ import Actor._ val symbols = List( "AAPL", "GOOG", "IBM", "JAVA", "MSFT") val receiver = self val year = 2008 symbols.foreach { symbol => actor { receiver ! getYearEndClosing(symbol, year) } } val (topStock, highestPrice) = getTopStock(symbols.length) printf("Top stock of %d is %s closing at price %f\n", year, topStock, highestPrice) //END:PART1 //START:PART2 def getYearEndClosing(symbol : String, year : Int) = { val url = "http://ichart.finance.yahoo.com/table.csv?s=" + symbol + "&a=11&b=01&c=" + year + "&d=11&e=31&f=" + year + "&g=m" val data = io.Source.fromURL(url).mkString val price = data.split("\n")(1).split(",")(4).toDouble (symbol, price) } //END:PART2 //START:PART3 def getTopStock(count : Int) : (String, Double) = { (1 to count).foldLeft("", 0.0) { (previousHigh, index) => receiveWithin(10000) { case (symbol : String, price : Double) => if (price > previousHigh._2) (symbol, price) else previousHigh } } } //START:PART3 ``` concurrent-ruby-1.0.5/doc/future.md000066400000000000000000000126521305460430400172640ustar00rootroot00000000000000`Future` is inspired by [Clojure's](http://clojure.org/) [future](http://clojuredocs.org/clojure_core/clojure.core/future) function. A future represents a promise to complete an action at some time in the future. The action is atomic and permanent. The idea behind a future is to send an operation for asynchronous completion, do other stuff, then return and retrieve the result of the async operation at a later time. `Future`s run on the global thread pool. ```cucumber Feature: As a highly responsive Ruby application I want long-running tasks on a separate thread So I can perform other tasks without waiting ``` `Future`s have several possible states: *:unscheduled*, *:pending*, *:processing*, *:rejected*, or *:fulfilled*. These are also aggregated as `#incomplete?` and `#complete?`. When a `Future` is created it is set to *:unscheduled*. Once the `#execute` method is called the state becomes *:pending*. Once a job is pulled from the thread pool's queue and is given to a thread for processing (often immediately upon `#post`) the state becomes *:processing*. The future will remain in this state until processing is complete. A future that is in the *:unscheduled*, *:pending*, or *:processing* is considered `#incomplete?`. A `#complete?` `Future` is either *:rejected*, indicating that an exception was thrown during processing, or *:fulfilled*, indicating success. If a `Future` is *:fulfilled* its `#value` will be updated to reflect the result of the operation. If *:rejected* the `reason` will be updated with a reference to the thrown exception. The predicate methods `#unscheduled?`, `#pending?`, `#rejected?`, and `#fulfilled?` can be called at any time to obtain the state of the `Future`, as can the `#state` method, which returns a symbol. Retrieving the value of a `Future` is done through the `#value` (alias: `#deref`) method. Obtaining the value of a `Future` is a potentially blocking operation. When a `Future` is *:rejected* a call to `#value` will return `nil` immediately. When a `Future` is *:fulfilled* a call to `#value` will immediately return the current value. When a `Future` is *:pending* a call to `#value` will block until the `Future` is either *:rejected* or *:fulfilled*. A *timeout* value can be passed to `#value` to limit how long the call will block. If `nil` the call will block indefinitely. If `0` the call will not block. Any other integer or float value will indicate the maximum number of seconds to block. The constructor can also be given zero or more processing options. Currently the only supported options are those recognized by the [Dereferenceable](Dereferenceable) module. The `Future` class also includes the behavior of the Ruby standard library [Observable](http://ruby-doc.org/stdlib-2.0/libdoc/observer/rdoc/Observable.html) module, but does so in a thread-safe way. On fulfillment or rejection all observers will be notified according to the normal `Observable` behavior. The observer callback function will be called with three parameters: the `Time` of fulfillment/rejection, the final `value`, and the final `reason`. Observers added after fulfillment/rejection will still be notified as normal. The notification will occur on the same thread that processed the job. ### Examples A fulfilled example: ```ruby require 'concurrent' require 'thread' # for Queue require 'open-uri' # for open(uri) class Ticker def get_year_end_closing(symbol, year) uri = "http://ichart.finance.yahoo.com/table.csv?s=#{symbol}&a=11&b=01&c=#{year}&d=11&e=31&f=#{year}&g=m" data = open(uri) {|f| f.collect{|line| line.strip } } data[1].split(',')[4].to_f end end # Future price = Concurrent::Future.execute{ Ticker.new.get_year_end_closing('TWTR', 2013) } price.state #=> :pending price.pending? #=> true price.value(0) #=> nil (does not block) sleep(1) # do other stuff price.value #=> 63.65 (after blocking if necessary) price.state #=> :fulfilled price.fulfilled? #=> true price.value #=> 63.65 ``` A rejected example: ```ruby count = Concurrent::Future.execute{ sleep(10); raise StandardError.new("Boom!") } count.state #=> :pending count.pending? #=> true count.value #=> nil (after blocking) count.rejected? #=> true count.reason #=> # ``` An example with observation: ```ruby class Ticker Stock = Struct.new(:symbol, :name, :exchange) def update(time, value, reason) ticker = value.collect do |symbol| Stock.new(symbol['symbol'], symbol['name'], symbol['exch']) end output = ticker.join("\n") print "#{output}\n" end end yahoo = Finance.new('YAHOO') future = Concurrent::Future.new { yahoo.update.suggested_symbols } future.add_observer(Ticker.new) future.execute # do important stuff... #>> # #>> # #>> # #>> # #>> # #>> # #>> # #>> # #>> # #>> # ``` concurrent-ruby-1.0.5/doc/images/000077500000000000000000000000001305460430400166675ustar00rootroot00000000000000concurrent-ruby-1.0.5/doc/images/tvar/000077500000000000000000000000001305460430400176435ustar00rootroot00000000000000concurrent-ruby-1.0.5/doc/images/tvar/implementation-absolute (1).png000066400000000000000000003335571305460430400254740ustar00rootroot00000000000000‰PNG  IHDRÜ„»8óÄ/iCCPICC Profile(c``2ptqre``ÈÍ+) rwRˆˆŒR`¿ÀÀÁÀÍ Ì`Ì`˜\\ààÃyùy© |»ÆÀ¹¬ 2 UŽ +¹ ¨¨ê¥¤'300ÙÙå%@qÆ9@¶HR6˜½Ä. rвùÒ!ì+ v„ýÄ.z¨æ H}:˜ÍÄb'AØ2 vIjÈ^çü‚Ê¢ÌôŒ#Ç”ü¤T…àÊâ’ÔÜbϼäü¢‚ü¢Ä’Ô Zˆû@º! A!¦ahii¡ ¥"ŠˆqŸÁáË(v!†°(¹´¨ Êcd2f` ÄG˜1G‚Á)Ë„˜I/Ãþ©15C}†}sïPoì%¬´ pHYs.#.#x¥?v@IDATxì½XT×ÿÿv"šBŠV“ÅíjŠI1¿0¦º>š´$M»²i~Ym´ð›Í£ØÝjñ[Ýo±«Å4«ø¤)¦øMÀm‚Í:öçBÓ­˜ ©c6²¢l*›@ “ž½¿sgæž{îü™a@À÷õÁ9÷Üóçs^çÿçž{ÎM\àE$@$@$@$@$@$@$@$@$@$@$0"6"ßôL$@$@$@$@$@$@$@$@$@$@$à%@…;  Äîq€È H€H€H€H€H€H€H€H€H€H€H€ w–          ˆ*Üã‘A î,$@$@$@$@$@$@$@$@$@$@$T¸Ç"ƒ           *ÜYH€H€H€H€H€H€H€H€H€H€H ¨pDA$@$@$@$@$@$@$@$@$@$@T¸³ @Pሠ‚H€H€H€H€H€H€H€H€H€H€¨pg           8 Â= PáÎ2@$@$@$@$@$@$@$@$@$@$@q @…{ 2           Âe€H€H€H€H€H€H€H€H€H€H€â@€ ÷8@d$@$@$@$@$@$@$@$@$@$@$@…;Ë Äîq€È H€H€H€H€H€H€H€H€H€H€H€ w–          ˆ*Üã‘A î,$@$@$@$@$@$@$@$@$@$@$T¸Ç"ƒ           *ÜYH€H€H€H€H€H€H€H€H€H€H ¨pDA$@$@$@$@$@$@$@$@$@$@T¸³ @Pሠ‚H€H€H€H€H€H€H€H€H€H€¨pg           8 Â= PáÎ2@$@$@$@$@$@$@$@$@$@$@q @…{ 2          H  ˆ˜€§ Ç~ñ:pÝu¸rå:|îoV"=9ŒoáöÈÏðÁeàŽ¾Š¥iIa^=kO{3êO¿+˜»r–#m‚´ˆí§jpúD6\¼+"ÏnÄ=9Y˜•àAsM=Þþè >ñ™»°rQZá\=§ƒ=-ø÷Ú7¼å/)®\9|û=Xž1+oŠ[NÕüïtŸ¹÷ËX4˲"ì¨=í§ð‹Óïˆð#­/=¨;ìÂyÏe̼ã¬^ŸrÖu¶¿ùÏ÷–ÿ+}|â&Üþ×K‘¶¢ ¢¥¦¥•µøxºHî_®Áv®‚/¤¡žúñ°§5¿8D›ºUº‚ºE{“ž‰¬;3‘z•ÛZO›(˯‹²ü‰ÏâË+31½S[Ã1¼þÞO/Áª¥sÇ>Np ;šëðÚÛ¢¡Ž¸ëO̾w¬)^|ä?zl‡¹ã¬¨›ÿ\7û;šñÊko=®c8|âFÜ|K:nIO‹_{=æ)CSµ>/c4«T“ëΘé©úÌ]áæƒ8[÷ïðw1üñöÈÊH Â'è#EŸÏ!£¦% À˜¢‰kŒâb4$@œ@ÛáG0]…LEnU+JW§Ë{Õài>ˆ”Å[¼VEMÝØ¶(ô`Cõ3ÖææƒË±xK½ˆÖŽÆÞ:, §›‹H°Atµµâƒ 1eÒÃ*ú" lG\ž¯ØC¸ ÷¨¸©›oyËS–AO¹­¨g¶- ç|\Ù«e*jÁì%è­Ëó+M£ôí9%y5в¼tü•å(S“ópõeÐÓÖK½"ÌDÌ™ŸŽdC™ªp³5¡nÛ¢˜âµzå¡(ÿn«m¸;{~ ž-Ì ~1¨Èf­ƒ¨Ù±Ù{•ìÅè®ÛŒT õ,œÍ>¶v,ººiGeÓ‹X»(Ö`#g*˲Mäí=oã| ¶ /qÊd°¹h(EºQ7¤= Áb+ƒ€Ú6Ä£O–lÄ6aÛ‡ÄgŒÖºƒ(ÿñ©éúj…¡¯?~3å¢0/ zרvlþÏñ¶!ü~Œ÷?NÇÿ.Þ† Ë[òA´7ŸÀé?$â37þ WæáÞ¬Œ°/fÛŽ`ñü5p;ļàhtó‚c[§ÀqÀ—.{±×n1® ìÿó«1°¥7V"]Ø7e6¶û-ó«/aÿÊá¦DÏÖHyG$0Æ8ôcàŒŽ&..ü¬¨Â"~Ù3ÇñýÕa”‰S¥[˸HÚ^}CâÔ9~!R„ªp„—LJæ/%ö±ËÚ?0hñ}4¸(mâÍìL¼„Ãö#àI˜–vqÑkdÂÕMÙGŒpUM+æáÃÚ‹Ø6R¥»Òo…D,Ô¸v¶>(íQ|Æh8ô*ôÕ<‘^ö%ø–P¸ë=ãû-5¨(γOü@862¬¿ û¾:Û]ÚòÑø«'±tV ªËƒ—þP¶ ç…›ˆzÎ_?PØå¬¾Î P¸®Õêom´öÿ~ö'Åᢈ¯vk¤Øv<8¯@Ãæ³Œƒ «A °ê_ ' À ÐßöKlTrÕ?‡†öDZj.›]om(eGw"Œ ¿îÄÃÚã„„^<ûwbÐé«:PÝú,–¦ HÉœ”,†µI·â»U•øšØRfÆ‚›&@é󉘜¹ÝZÓ”„Þׄù+|kDì…µøYþç0ØHŒÎ©êYVß|ÿwQžò5È Ü¤¼x0'Ì7ùë›"1éÞ¼dú}ù€AÏ%4ÙÇc}± +æ=†¦Þ°È˜%‡©}ã=“³'_XoN¦†zfø™è¿qhÇE'pdÛ–:8ÐçAç…&<½!üýÈ–‚Å#Þ/&:´@ùûñË2cÍšùlËOðøÒU£¢à7c™¦8”ÁI@ášIÂhôaà ×î_3´ÇwBûsSÚA¼÷ÆoðÏw¯A…ßrûŠç±AÛ‰«óÊÖ”l<™®þ-É·ØÄ;‘ÀÉ¢BÉ&ž»ÕçÆKo~ÿš¡l·Awêr»oTÆ™R•í6œ3/…¿ß}ËfOÃEmæ*yšËáýP[|õúÄòáW“+^½Æ´ÌÏ‹o¢õ×>ârÕâbÿzdʯ àüojý&ãçNµïEzºÕaÏ…×}áèÎì9³ëŒˆü½úù,E¡H Ô’E‰NH€€Ó‡ƒ?q¹±*Ô'u××@S“¤|>9UÑFZ8Äç&9u–©”A&a¶P°×ì9³jÛÄo*²V¯E–b31Œ H<½Jžuƒ?å†O"U©`(VåFJ 5= ëÅ_àe.KFâ´À§£{ŸôÉHJN–‹¼±%gˆ6©Ýö/âïlküš üãžÛÚÛ'…©ÉÓeÑq¬X&;p‡x6ºÉ»ÐãÑŽ%]/”Êâ_’Ùî'%%!9u%öWW£nN¶ï…ú:¼åÙl~1v©ݘz^à ­ÓŸÀ]¸Ê|é£>£Ù$2h†FÓ8'0ýGø0ôûãœÑµ"^ÈþÜŸøÔ¬ÕxáR5ÜFÿ&¼ífÅm¬göW•÷Õ£%amé¬ý¡X!?X/}Q„°ó4ã‘”Åþ'ÔVlô³ºÅKyŸ{qyè­Z¬¢ÿìalð¯lÏ/oÄ“ë—z_hÿŸš}˜Ÿ­¿ôÞ‹çë¶bçrcÞÐ…ý£o«Óòâµ±-™•‰•òBš.>‹LËþ6=x­Zèo Ì Õ ±6=Ã’‚ §ëä½}åÒˆ_]ý|–bÓ@$?‹À \ëÄ~t»Œ•pŸ«ò%t,®-GÐ> Ÿ”DÚêJ‘—³S¦Lñý-ÌÁ¾Ã b×ÕÐW×ÙìÎË1Ýëþ„ŸƒÇšÑÚ »šQºõ‘?˱£ô:Ây k°‡÷íÆ¾Ý»qøTGàSï}{ÃaìÏ÷•Ö YÄá8Ça÷Ž–+o.TÿûD¥umVÿƒ]¨;´OpÈÁò… ±Pü-ÏÉÃÁÃuèŠT>kˆáïÂ?ôÃ,KQZzGÌÜëj>æM÷î}‡Ñ1Øæ#ñÈrŸœº¬ì(ÅÙ_¸í§Ža‡ÈÝ^¦ãÈ©°yÓÕR‡}[ó³|¹ßÏräí8ˆº–®¡èÙI BWKîÈóæƒQ&.ÏÁŽƒ‡q¶#\© Ø —Óî}û¼y¾û`•A”ynäÁ¾C ¢d‰°éõÆ`æ+/¥CÔ«„=¨)ÕåÚ‡Ý!t[(·»Åóe]ø=èO“(ç:‘‘‡¥¥¥8X*ê¼(¯úýAö?ï×'ú%^Àíqí>„¶€òœœ’OGƒ·N/”m€^JÑ<¢Âï[Ùî‹ßújæj¼x¢HZÖoÍ2kƒë€~VéŽÇÍz\û<õäð)¼5Ä3KR£Êï.ù£·%‡:0ØÓŒ}zÒùä,ô÷“^¢íÝ*Ò׿o|¥[Ÿ¡_f¬—£Ó.ÄÛ¿†ñámWY®Æ1ËÙcÍ!ú¼¨ûDŸ\ã© ²Ä­oó´àˆh Kò¶_zø;ñ×]/1¾¢? ÈBó6Æz·t™’è!ªñŠÁ8Ò¾+âþ#Š6aø0ƒÛ}k’£CF›f5.oÍ¡Ýu} r¶Ds핦³‰ñB¤õzD²›‘ÆÙ¾?÷F”öylu˜QÊ¥-1¶QfHb;ªç)¾>Æ7n*­ ã y}HˆñáL‹OÊ1Z²]O±P¶‹üðㆲ(n|ËÓt{qõ€&¿~Ú~ûM>»aþ7ÇþÈ÷+Ûu/é+C±¿Û­CŽî¿:jöû¾έÂW3c}S3 w®31¿m¾hïûíy/z_¸asæÂá—£âhcÀøÅwµÿmð™sÏ­2œž³s1}L ÏŸâÐYψÆâ±ÌÅb™ËÄÐ@$臦ò" ¡tž(ÒD{éý³6 §ÝZ¡Íw¯Û—¸{ƒ¼÷ºK¤ÃoÈ_[v.À{S‰sh¿Îíâ€5Ê‹µÅCû]« ˆÈ-ãqhM† ½MšÏûÒZ¤§5ðêÕŠíþ´Û‹µîÞFM ½BÆ-c”ž.МaÜù¸8´êÖ>é>zC¯Vî0äPÒ* EfqP’tÑTl™k¾9´ÂÂðù#¶t‘áù Ú ÉÙÏúk/¬ÖF”r¥¬9ŠÍô"o‹ÃËo¤µ°ú¢t¯õ5ɼ+nê6í…)0¬’ÆNù<–<7óÀ®å:maóÃ&8T¯ièÔŠd=µiÕ¦hÂI·YŽõr™ï²†×Y«‰y‚/~ÿ3U¶FQ_‹ÂÉg×ôç*7ƒkè_‡vÂ"›™‚`“ZΡæG°û‹Z‘ñ+ ö9 ª‚‡de-Ÿ°íÕö†}&Ú¤Qç·"lv“·.¯½$öp…Д%tš}é¼oëmn¼áÇP^•¾$°¯Šºýœã.£pL–Èú®aû]˜Àúª^(m°a*í…:öÑ£Še iò,Íz<Þ«»QŽ)Ôº§š‹O(cÃ_¸ßêu̲‡“aHûðuS¶Å"o‡ïÏÕq‹Ã7ÎÐ㱊ežbñc+ÒB ]º•öÁQ9ÄøVí/&Ë-|A¸èÊ—}¡½ð„Åa_k•|VnXœYn̼(Ô.Yž˜ã9q°©ïÉ@«–ïm?lš+piñ;üMw£ÒïæVYòW/ÖžÓª Œq²R^õ(úÜJ`}fÖMhv‡áß×§èuÄ|îkÛîy“Û\,–ùøðé‚®-T¸_[ùÍÔ’@ ú´J§9I­<çSªƒd[A ’UŒŒœDØsµ’Ê*­¤0W¬¼Ïœæ€tà¢9èŸäiÅ•Zí‰Z­ª¤À¢L‘ƒ(‘¢^w¹%<›³H«nlÒk+µ\‹¢L(@ í˜ðg¦AQP1!öÁS&º²F(IŠóóµ‚|§)ŸÝ©äkņrÄ2°ÒY:´¢ò*ÍUY,•û>FNSñuN)r‰ð ½bÈ`¤Ñäaæ·³ H+)2É2/½W¡ (*Òò„UMõ¹8ÄÇ’7Žü"­ÊåÒŠ Vû’áå!Ó",Õ²¨Äô3ÐZi· D«>qB«®*Ñr-Ê.§æ6’¡ð2'„bðjQÜÛ´J·R¸bÌóPy`wh%å%‚³™/z>D2iPÃ+¬U¦$Bñ`¼Xòåi¦Nï;kM%a¡_n†å+_î*QÎ 4§Ýœ8ó ´üübÍÛL(ÜÌrc× K*µÊâK>Ø ª³*̽ZÎ#™ ëJ)³¬åWù–Šl¾2Ó§U ™òE=–²úëq~‘K{9ì³jŸr2–üVdðÆ©¶U¿Â=–p93¯Ì23d9Ф “#ºõðup@ë¾Ø¨*uÌV¤N¸û´ª\SV½,®ªÖNÔVõŽ·)I Co»d× E›ÐÏäWË—J’òbCWîYêDn¥|éaF8´©ïœÒ¾ýšEÆ@¥Š^·Vb©ßzßW®¹\åZ¾ÂLlô*û°Þ&ëKm›£@+mke±µ½¶Ë¿¢î(}¹Þ¿UVkMMZe‘••éGȧȺ}Uê¤òC2öæ‰/oG³ ŠRVáJ–‘ômjy7Ú /ÿÊJÑ·)mˆžv¡‘ïl±Œc=Iº¼¥1޲ •ßÃöBm›0l˜aø| i¶]C¥ÙWÛû4—ÒÖéå¦ÒU«ÕVWi…–—ìV%œÑRÿÆV¯CÕ‰áeŽ=2›Èêf¨Å;jøÝ–6/_k5*V˜|5ý*ñ+mT¨zŒaç)—”G¡•·¦’š1~2e±šÔ|˜c4kúäxÉdö¯JÞù¨yQ$ÚÑ"1sØíš]ü9¹Zq剠—ߪŸüÊ&Ùζ* ° ¦ç*}}œ¾XeÄ—eá€5-µRÁnÓjÅ” ³Úë) rúÎ)óV1Þïæåå+æ¸Úècô_}b–™Çâ"äXæb±ÌÇe"h ¨p—(h I@¬t•+¸•ÕÖŽ8×TNúQBú Aì¯'Cº“î&e°!žWú—á™ hNë’\ïj'9`ÓW—{ãêµ(*Å',ñhb݃º¢Ï®(y̸uŒwmÀ\­`Q ‹L…Ÿ-¿Ò:h X™èכĈþS&qQ¸;4W«9ì/5äŠg‘_¶‚*E5 Õš«ã¥RZ °eÙÊ’FEá+Òt±VY%ñ²ÁPpG”^Ó‘ZÖB+„L·ç”«Eu…Me®1ÈU&»J™ð­Êv%OuÅUeÀ×±æ¹Y&õ ¼M+Wè¢h%Ê„¼ ÚÊÓL¥iRõêD#x…¦uâhNÿ{S6¥¾ˆ¨L¦â%…1ÖEP¸ém€¾rÖ”WÀÞsUf™²®Pò: ñŸZÎ#T¸—˜õO–E6i§Ç6D=êYLù­Èà«[N­úœu½\LáŠd˜ye9*ý!rðRë wr(&É6›Íüùïµ7~ÅJoKJU%Ÿøêɲ*[DÒ«(²-ù¥0ô†Ÿk ·»QQJ+eLò1”/—je€hßò«,`#ÃýžPÚÁÂZ#…š+ßhWD¿V~.(k}t|ñ!tfûšïÒ_ ½¢ˆw›_Sé÷µº”¶WðõÒª ×ãP+«è)O(«2žZ-ìe*”:iðÏ$cožGÑ–ÅX#W¸¼o ,ï¹åÖÆ–¶M¤¿ÊXQ©”W•e|êùÈÓ¥gi|d‰<¿Ã÷æ˜ Ñ´ " áÃ4¿V3ùÇc E;«”ˆ1µÚ'zù+/òåXJ抵^Ç\?ÃÈ1´µÒFŒOU9r+µK[µÖVëß9wðKÁÜJ¥U˜šùªJ¤Ä¯´Qõ8¦yJ¹[HŒ!Îi¹F?‡à¹‘Õ±h«Åë䣦P¿Ъ•>°(Ä' aËxAòmœe¬ð¢ÚîМ–@þ…$ò s<JÊÈíÔ/-Ô±³òE¥1_¾T-ǹêªþVÿ =ó>µNèÏÅÕ–y£ù<±xŒs13žHç㑤K¸–pwÑ’ñ"O å—æ~´Î­ÙòP—„¹÷@|þî¿ÊpôtàÑÆ3ñ+öË3³1lS­‡XyjÜâ¥ãozÍÊ.wÓ»?Ͻ†Yw¢ ¼…(̹úùŒý-?Ç&c<[žÝœåÝ)Ðô˜†Í/4Alçâ½ê·¿Œ¶a¶‰4ýFa4wÄeÅ,ö¿ÿÉvCÀ\¼øäZÌòoYè =a®¯ ׋õbWÇ«åV=…U鿇©·,–ûö‹ {ú¯VJÀ]k¾&…þð}^s›ØË¾Þoë,yKÓ¤Ý0wù6ˆÉ½ß®'ÏŒ~Êg¦/ñ§#)Ý"~Òê¢;ý.Š'rPÅUÊô~œ:¸wË<µ£êÜI¬Í0Y!Nyž[ù"Ö/5{Ò…˜…¯o{\JÓøÖ»ÒÎ4? â3Zïå>ò;¹ûù“æaMþ§¨?sÉﲿÚëßLÓ‘ƒÛRýÖa~.<øØ—õ†…ò›gÅ‘jPÉ_6÷cu7áè¶ÊVÂÚxóˇv > Wu7ážÅ!¿ÅnŸp]*ÇÊ %¿ã®.vTå(\õ€¢¹êëáv»Í¿@¿ÞB‹~€q%ÍÄœ¾º—»õa¤øœ`lÐ^‚ǬœÉ@¯¿VØücp»SÌõ ‘ï”MáÎÇ꺌I\*ò~zrQï‚lkmùhì,Ä\áëÔ ½ý»£d7–*ƒÐþþ~èÑ_©øBŽX ñ\§7ˆÁöÓâ˜Vße_wo,’¶ëüIª?òkøNIéÇë¿1J }×<¿¯àñõ'^ؼÒ:o væµ ×îÅ:‹v>F,Z“À5O€ ÷k¾ E@HWd lXw¦âxV}ÍœPîªøõ°HÅeqÞŠ%¸ï¡Íñ¨´bªÏ7JŸeëxr;\Ó€¶Žq„d–®ß†=;÷`§€èãØ9uAîöUe‹ (ù¬0ÆF¸€÷Ã*¥¸ú[›åàŽEHÞôôXþúñ)ÜfÄX_‡·Ì$¶cük‡sE 2Zy‰à¸ó&æHõo¼+äŠéj£ìˆå²™èHwG¤Ü&SŽºSF=³„R錦‰¯»J‘™0OO:Ú[Ð|ª5‡âñ CʰaÁl,Ûb¨æ€ÂFV«Êv=åqÉs} #H%ô4„…x¡ó7ùþѾ»g½ïÅ<8]çKƒ=¿b+ïUWNÔ1quœÁqŸœ_Y•â1ÔK =({áƒH·ê÷„­ššÐ/8übŒè§¯çÃùÎs\ò;w'¾dæ0.áŠWyq)GÃAPž‹- ¶@BI‰òW,^”æÊFXœ¯»wÏ[ŠqЩïJCÞ gô¯.Qº>ƒýtuu ål3êjpð[[äa¶JT£½øQdD[Æ*Öaö컽“q_`E8¹gUTeÞ¢ë·U²­·l°(ZRï\e¾0poÇ/ÛÔIþ®È6ßûïJ3‚4Ó¾„Ösnœ/1^Þx›è÷ä[.8rîC¸wG«xáqNü½Œ;¦©qäb;Œç¶»¾ Íïuīތ}”‰2Ä£o³êxÈrܱ +Ûtèߘ¦)>õ<>éŠ,±ç·µÿy› S¶†ir7LñCF‘æi7Àå€mÚrì(=Œ†³mèñˆöpÖRìܳ{öìÄÊÀ7†Ðò7õ: Ùe¼WÙPÿk´È63>²D3OIHËÂㆸþ9ü¶ÝèÇ€×<'z|õik˜ôc´~üûÖÉäÿà+–…¾=8ùœ\-ú¸¢êsÐê^s½ØÿBz[kÅ2ãªÇŠïü»o¬ª[%e`ÛÑ´6Õ¢²²ÒûW}âzÏìÇRý¥rW˜êaçâû}sØö†ÃxDL>mÚ4ïß”…9(­i1"ˆè÷–/˜íûñ>¿í¯þRú͹Ï8uîYçû¸àw^û%¼*§G¹¸ëeÁŽ ÁgؾñÞ›ÈnÍv/ö¹X´óñÈ$£+¸öMM®=L1 @8ý-DZ].Ìr#û¾åBAþÏùÌ™p‹UŒò*{§¿¿Y©ÒfXCÂ7{îzÚ}+Òsv ÐV†]þxë+öBÿó]6äl„ók#Ë¿ôâkÕ2žE™s¤ÙjHÄŒ›u¥£/Ps bu5w¿oëÚ„9Ó6™÷aLc)_hRpýP½C¯©ì åß§V'‚À:¡¨/—§­?Ú÷¶—ùø#¬þ•WQ°t¥å…R¼ò<>å ‹X xWÕãw-=XžzÕþ¤Û\‹ÏϨG™¾"ùÀ tî_ ü®Ñ_SÄNÚŸŸ7:¦×”Ù×›7clz÷­&crJ|¨Ê…!ùíXôYï Äx‡«‡ÿ«R›oÎ~yBiêÚóƒìs,Àvo×!ú”ïE_éjÚ=h8ü#W‘£\{.6>îÄÃ_άm’µíA½ŽXv%êÑ0T5!ïs7 oÀ|Ÿ˜˜ˆßGóÉŸbÝ–¾hëwáñòûQ·yÑhˆa 3Ô7uû2ÿîÊv»Ói~qaàõ»²ñÌ©‹ëñ–ç³>w/ŒÅX5¯_€§Õí_ÑkÃ’Û…RnÉ2¿üÇáîò ¥ÑXß^€%sG:Ø÷M¥±ÐéMN5´™ÀÏi€Aþã’ßê6Tþân´c`"-2Öd±íÅj³žÿ}úÃÁvì[ž‚»×…P¶ÛÄê]ÿv32œQ3Ô#Ûù\ôÛzu½†ë3o媯7·ÔFËU¿ý§æÖfB¹$kÖG¶Ë¼{•ýÊÜÙ(uÔ8z-¢Xn¦Ï@ô=et}¢%ÂÉp“æí…Ò“Ïœþ…ãxªçãI–±jÆ~ )¶Ó[¹Ý­'P$NB¼ÜõeزænÌž–£lèÊ?ªõ:Lœa¬{ÚÄ—‚Í8Õ|=CñÁN¼evÃJͰ6÷³·`nz:222ä_º~¿h)ÖnÞÖ*¡äö_õ§[ÌvÓ° û;’6Ê—ÊyŠˆ'}Ńr\Uñü+Þ>ãl'cûœÌ +õÁd£ýöyS¹]°MÝŠÒÊ 5m.ÒÓE¾(Û W éÙ(6²xšÙb8 úíoy }±‰­ßZ%r££Êv[.\M­¸x®þp][–á˜òµBP€ª…úå´û5¼ÕîÆoŒ1€3Û¢DO¾í ržz þwhkcX¹Ù‹‚[˜Ñˆ‘Aé4݇2`.å| ?€ÇþåAÔmËòºyžŠ»Œ‰AÅ8|Õ¶‚Ïûö~žeÃj‘UbëLìZc®¸[÷¥Û-iþfôònø¸C¹èÁ¡íÙò%òÅAgÁE0”ǨìF+¿G+ܨ7 Ž/Š—¹F¸b{ªAñï?^5¦ª6Tžûwqq@F‰³Ì)ªá9¿öü Ï×7U "Û·±CÙšÇàì¬ 8¼4\|¨’g;¿·«ç†v+zK¸6ùR¿å§ x|©P¦%ÍÃ"½Úéʪú£x½k3–[ÁÁtü 3æøöŒµ5âd¶Ùï=÷ÊëBq¯²n½~µk†8¨N· °Þ“f®jü¾'Ϫó{US^8ïk€ú]úÄà@'¶M8{d›zŸ?9¯ºäK‘ÜüîÆS=¿º²¨ýG¼Ú5ÌÐålÞhŽ!CD9ØÑ€½OW‹/{>‰ì'¾‰¬´d¤‰½0Vék7£°íó¾±ñùÿö®â¯åB_jÛ1’z:ô¨lÍ׋n¼7àU¼9!¶¾™м¸+¾„£<#±à+Æ6*òyŠe¾¸¡PL?ôQ ?é%L;âŸhØŠðÅa÷ß7ÂÑ'ç­ëôQ³¯Ï_vüå9[ŠÛ&/|×Eì×W£^ýçñ[ï ýÁî<ážSå¾@Žü/ÿ!­Oûæpdã6Y Ep 3å‹îóïë±È®yËV‡ÐÏy-Û+:[ñ · ÷/ ”?K³Å¿b1»ú®Cº·;KGEI­&.Ö¹XbÔóqŒJZ"Ë º"ñL€[ÊŒçÜ¡l$pÕˆýhËý%"±Ç\Ø+aÖ‡2ŠAçOjt«õªØTˆ†«ÄjãÒ^m€x`æˆß>¼þüvìÝ»ÛÅR™`K2²²Wš ÓfÎõŽqtËúí{ƒãö͇Ÿ–_{Q¨ÃÍ õÏ÷ŒÏû]Õ¯l- ö,|Â|I x³•RúäÅ}/·/kÕ†Ù[va×.ñwºÛp=Á“°ä~S ´áŸ_q¨nþï?dc×^‘nñ÷î€þÒe/ñ èCþBí·¦›@”ƒâsÓòm.-lÄ€5¤8ÆLr.òÝ%RØzñÅÅ!ÿ)^ã1ÏoQðóK}ÿ}~Sî]-¿ÕõÛ9qŸ²¥Lè† üiÈçñ˜2]X(á÷wàÐÖ{ažkƒ+ÿoGåEÖhå÷h…«PÚ¨´cC;´>MN™nµPî<íuøû‡ÖI›ýv¡jðà¿ÏýÆLÜtc 6fuO?e¶»1Ê%#U )æMÚÊ”Ë÷Mõ¸û›‡C´Y¦{ÃÔßòІTÂeì{÷u1ÞÙ+ƹÛñ²;xoÿd±ò}¥QU­ß”†nõ:Dh#±š*= á{q’ϲÿâš/¾{C|é(ýFaPÚîxŒÛ#Ÿ§˜2κ+Ç·UˆHòM뼊Tý©sûª)›>ƒM“oŒ6ˆ¦ê#2¡….Žhüu@,à ìÎô@N•í4åßù!ß¶ÑuàÙÜ-Þ›òï]Žõç-Yâsàz§ÕHúß1N'Ã-iŸ2ö7iþ2ïa®úbïåý]¿Xt¦?›ûù/úÜøÿ÷úÉ·#„S‹»ØnÔv/Ö¹XôóñØd¥/˜ü¨pŸüyÌ’@ôÄ~´Er b.V- \n§™€¬MŠkÓq´«…Y¨ºp÷½y8Ö܆žñ™{û)ìøÒ|98ÕWÐßë=¤.·/3f{±*¯-=†‚ºíÍG°áncKnýt2Òîû`~D<3òPÓbŒ¤Äé쇶b±E¡.V¾óÎénÕ•8âÓ¿Û}ºÚÏâÐŽÕ¾ý¼·RQ²Ímíðxçs‘Wiîe¾nÁßâЩ6è_úzÐ|lf,ó õpŠ·f[?E4Ÿ€¿sÿ6Ï;õŠ.^6üíÖÃhóæç <ÍØ—3›Œ+b¥©#pUkœÓœ0ØgÊ꽡Öïú'jhƒ§¿ýž.œ:v_+H}Ou'8ý¦QŽB ’œ¹ÕFÙ6«~±õÒÖ/,SV#né~ç#èe„QFZ£ŒnDÎõñÍ2ÿ¸Cç4¾±ã+™a^ zc¾:õ† ´M¾éVY×dgã`]‹|±×ïiǑݰÝßFÚ–é/$‡ºFP¯‡ 6êgÉX¬ï™á½ÜX3ÿïqì¬÷{Ð~ê0þvÁ©pwä,&MCD®¼üƒ«— ½~Ú¨Èç)Š|I °NÊ>Mfdž/‹·Ã'ßíNû·'Ô™|>#ü<2yÁ}r|Šú-˜ýÈ>œjëó¤Aô÷èu"ËäË` RŒ †Ò··{ÚW‡r]p*óŠä›?çQ]/ú̪kÆÙ†#xdéb¿2߆ÿ÷®!Þ˜æaÂ<|ÑœÞyŸÚ ïõ}9à6aîqŒ®õÊ·/2V×ÑÝ©í^ls±èçãÑIH×$p Ðx‘ @w¹SÍ ÷ÏVXð4ÄmŸ[Cmé§ÄÝ«õºKä½Vè_§ÖØ­„ÙY«‰á«Å¯Íf³ÜëáØ O˜žz›41決~Ãɯt›~„É]b¤Ó¡5õšNÚ­a†­ßÛÄŸ½D“Þúš4¡2²ø³—ñuj%Në³P,ì‚õ€)F”¦^M¬ÎôÇoMOP@ЬŽâ&ù8¯áG汚n¿o5¿Õ0»#)v­öÒR®”55n™0ièÓªr F‘ý:+ÏišÂ«¸I-¬"`QöÔ|w”†îšÐÊç¹U­êS¯9œlî‡ôç+×¢üõ / ·ÐùE™•Òôj%²œ›ò†ªO†³øDp½ '›R΃dê™C~‡“A¦U7Ä®ð.¯Œ Ã–#E&ƒŸÙ޾ƒÕð Cÿ:µê‹z!ñ]}­Ueh¸¼ÍÕΠŒI>!Ú²&KyèŸ _Kß'Ú±NãAø_µ…£\ö!­UÃ2ÈWëeß9MLà‡ñS µ*M«»<7Ƚø´=À._]¸åŠ¥O”Œº?RËŒ¥®ÅXE먴 Ö8‡”E©×–>ÝO ”œªÝÐåZU«YÎ÷‰£PÏcH—/É£ ‹Xe¦æw¸þ#æ6AÄ.̰üã<†ô°i®Ob¼T#kOô¸b©×CÖ f¸ü2Òô+Æîê"t½pZÆÚz¦ЂÆWA‘tk%v³½*n4Ü`¦¦;)KÀ¸]M£t²M ßô6Œq•šRãƒR0”Åä£ùS¨–‡ÀñfÅýPˆüyã,i á[±8§‰¯ŠEX6­:ļâbuaØxræˆJ¨a­UÖ>µè„Y&=Õªcp!Ÿ+„|º³NXû1#¼pÏö{ÂcLs±Xæã†ü%¸Â]ô°¼H€Tœ­•ËÛ±uÿ<ÕI Ù»ÊC.ÛÃɦKâ8óÓ‚’ÈEèª_G!ÜÝ/À²ý©X¹wò\5rÅ{½[~¯çóœ_R ×Nß~Ù^›äE(ímE±Õ“²èÄŽ’b_Àµ™jìHœjl}`]}–µóg¨*0V\ª^l(®mBu‘x¦¯hIQž%-®J¹yŒïÁe±Ç{ÍBÞ ½¨-X áªÿT6á•Ëã´ÚÁš%¿ÑÜO39%Ñ|,³lÿjºMߦI†#Ö®.ÍCo«5?M‡Â$Ê@cç+b÷¡Ö«X| }£Äì0 «x%j9Qå×¢»¯rá¨xæþÇ^‘ ƒµDÙ+v™ëV\›JqÖûQFŒy.å7bT 4J·Bß/Î6¿D±¯X…#í’‹ŒÅ «|d|VÙ2¿²+¨~‹óŦœ…ÏfH'^ËD̼QiÂ8´Ù((ª„ûR¯8¨8+D½Š@6™Þ‘=‹%¿Íƒ,“ÃnK¸B^)_\¥[áoÈv,i¥"-ƒ 6 ËkÑ9ðV*û}&¥¯Æ¥%rå§Å£=Õ­ÝeÅú<>I3Ä Ñ–-ÚøÌW*ð´«E‰×jì¿Ød® w~C~ æ÷ºàKb/[#×oqÑÿWúê=‚A¹žáÀøu \ïÃÔƒ\“2°gà"ÊÅgé¡.G~ Z{÷ÈÜu7™ëKÑZ]lÆ/ìÔîÕž_Ž‹}û¸ ;¦>Ñ`,?è%¥ßNº÷1—A±˜,îÒà‹@†`(Rˆò`q"Ã1m Ê˃Ú?ïS[®(·½XmÙË9\åzUºFYŽÂ1\ÿ{› Êy´}RŒcH3Ô«€4ëõ©Ú2G–««¤E›WÛê >ËÁ[°‚ÿ‹©^Ë<ˆNöàØý6bìþ³s.ËØÝâV¯ŸgàXl‘˜lŒÃ-ÅÂêHÞ%@œ¹-¯-/Ëmci£bž§H D›³HY-ì 7|1æ¯T'Çͧÿƒw壶û—`¶Â,”qÖÒÍès¿0Ý™ðâë_È qN—`ó3{?µ>•!æsWîD§[Äã0ûM›=U—P0GT‚ kœ»ä‹JêÀ=w„_Éÿ9e ›Øz&„|zDáæ¦Rˆ0u7|»ã\,–ù¸’ ƒÀ]õnÜð—H€F€Ø¦åMüWן ï·x}Z:e˜[ZÇ;ˆö³M8óŸïàÊu×áº+WpÝŸíÒôC+Ã\=bë—×Ï]€p+]Á'>}3>·8©á½„ Iá*¶¹xñ]|,äMœž‚yóçbˆ¨½á ?â{øÄibbœŠ¤€x{:à~£^w=>™–†›ç¥#5pÛâ°RMÔúVn´\ìôæÍõ©ŸDšÈ›ô´¡?˜­Ôêåä¶. ˆO‘¯ÿä,ÜzK†™ƒ=hkï)MÃŒg û€LŒR¨k#ÏÑÕ!ö£<’’‘|2p”Ô&®óÑÊïÑ 7éáÚ±P~âb×߃³gÞ@ןDQº³þêVdÌ5ÛOG;:û1-efÏJ ñ"%.R\Ý@ÄVcmçÎãý½Õ Óo¸ óÓÓ†L«§« çß~ßë!qú bü9˜5T§âåü:.¼§÷CWðÑ•Oà³ ?‡L…u(±ô‰¡Â‰ÄÁ„Sù+q÷‰CááßtüQ o1kn: “gá¢ËzNÃ~ìd¢ÿˆ¹M"L#!~ã9† ¼ÅjPl—Ñôú¼Ó­×C1fãÖÏÜjƒMŒcuÄX¯-BøFëA¤+U ûÑŽ‡WDŽ8J%€‘µQÑÎSôˆÛ±uÊ<¯’bÅs¥Èˆ)ó”DŒŠ1¶ú0*¢ hOG Þãó+båÆŸÄÜ/uÎ-¸-3øÜ¥à`úq¶î׸på:,¼wù5z†çpù¬ÖÏëÙ\,¶ùxpþІ®MT¸_›ùÎT“ Êiš@IDAT DI@U¸‹m0°y‘ùR(Ê èœH`ðœ:ˆÿ9Lb«$ݼh§†¢“ Ä›À¸|ïD2<       ˆ€X ßö¦O{{r·øƒ±ã¡²=v¦ôI$@““î“3_™*       8è?û1϶Éš½è»Èâ‡.&¼! xh*K DB`à²âŠk—4’À¤'0`©ÿ"¹Ž"<+gçE$@$@¸‡{ Þ“ @(ýtt{OGŸ¼‡÷†J7íH€q8mËù?àcq¨'¦Ï‡ÜÎí[²$ ˜ô¨pŸôYÌ’ Œn)3” À¤'@…û¤Ïb&H€H€H€H€H€H€H€H€H€H`,Pá>” À¤'@…û¤Ïb&H€H€H€H€H€H€H€H€H€H`,Pá>” À¤'@…û¤Ïb&H€H€H€H€H€H€H€H€H€H`,Pá>” À¤'@…û¤Ïb&H€H€H€H€H€H€H€H€H€H`,Pá>” À¤'@…û¤Ïb&H€H€H€H€H€H€H€H€H€H`,Pá>” À¤'@…û¤Ïb&H€H€H€H€H€H€H€H€H€H`,Pá>” À¤'@…û¤Ïb&H€H€H€H€H€H€H€H€H€H`,Pá>” À¤'@…û¤Ïb&H€H€H€H€H€H€H€H€H€H`,Pá>” À¤'@…û¤Ïb&H€H€H€H€H€H€H€H€H€H`,Pá>åÁ~x<xú‡rå6ˆþþ~ Fâ6‚àè„H€H€H€H€H€H€H€H€H€H`B Â=\võŸE^â4¤¤¤ eé3è 㮿ë,Jw<‚)S1mÚ4$&&bÊÂì>TƒêÞÃP£5 L>S4qM¾d4Eý8œ7 ëÊüá8JÐ{4ÉÁö4ÂŒÅlÕÛ|¸{÷#3Уê„f          IA€+ÜCdcÛ‘SÙ®?ï áh°ßV•í¶\TV×¢ª¼véül†GÞÓ@$@$@$@$@$@$@$@$@$@$0Y P᳃íÇðàš¶Á·-/퇱¶B´6•bíÊåX½~'êz›kx©X‡Ÿ¥ÊÝÀÁ_         ˜¬¨p·äl;ö®rÀm± uÓ…cERÝŽª— ž ¸K^„®|iñ|õ›ÒL Àä$@…»’¯ »7`—_Û^䪂©2WéÆžÔZy[î±hÛ}nçÞùl~oõ5¿{èªß H€H€H€H€H€H€H€H€H€H€&8*ÜýØÕ°wïª÷ÞÙ N`ÛªÛñ~˜Ìõ\x>—€}ݘÊ]ê\ÜoØ×ŸÄî*cÐà/ LJT¸ëÙÚs ݽݟÁx¹0 èÿ8ìa§‰‰fYHIºÞ¼QM ³q«Ã°ð`À0ò—H€H€H€H€H€H€H€H€H€H`R Â]¨ÕmX—?{+Ïí’û±'‡Éòî®NùäÆOM—æ¡ ŠŽ~(g|F$@$@$@$@$@$@$@$@$@$0A \ó ÷³‡þüÚvg‰k3’|Y)–¤«»À *œœ~/òý´/Êœ£<¡‘H€H€H€H€H€H€H€H€H€HàZ%p­&\O·§å0lÊ|œåx6/ÓÄ1m:ä ÷”©˜f>Á໿Åÿ¡©Íg/™ÊÓÐÆX·”yàpüøñІ±M{ÞüÙŸ]óïRÂСõD# išWä)S¦L4Ñ)/ ÄÀÿüÏÿ°]M4 °/˜ˆ¹F™ãM€}A¼‰2¼‰F€u`¢åå7}<¤ÿQßo² ïj¸|ùrTÑëåÿí·ßÆ_ýÕ_Eåo¬_Ó ÷ó¯¼dò®¨Eá§Îàa£oóñ…¨0žºžÇ–­g€÷?Æÿ÷ð7Óo0žà=ÏÇÒh0‹L2Ô}ßÝ u_SSƒùóç#''g(g–g7Ýt®¿>ÌÞò—¼!ñO ¡¡o½õ6nÜ8þ…¥„$0Jvî܉Ç{lÜ*F)ù –pôèQ/…hÆCÄF“‰Àý×áÙgŸÅîÝ»'S²˜ˆŠÇCQá¢ãIHà÷¿ÿ=~ýë_#??¦ŽIºV èÊscqM$ ž|òIüñ÷sãkZáž8UÍÊ ì= Þ«æz”¨÷Z¤oý> lÈîj~ƒX„ žó¨66†w|·øwªQCÔœ™™‰}ûöEêœîH`RÐß^êo^^Þ¤JCÑxê©§°fÍÜqÇÑx£[˜4te£~±/˜4YÊ„DI@W²TUU±DÉÎ'އ&W~25ÑÐ ´µµ±/ˆ}L"ºÂ}"\Az≠t¼dœþË‘›3fNS7Œ1BïC£ÐÀûÔìvä,>èCÆ HžsœÂ™w|Ù/q®x52ê=ož”±Ú—ßanOcÏ_          IEàšV¸§¯ÚŒÒUáòs‡Þ w}•ºãkØ»g=Lú8r…ÂÝ»ý{öýt+^XŸ¡Ôg ¶Èû‡ì·I3 $@$@$@$@$@$@$@$@$@$@““OÖ ›¯}æ“ÞËPî„}þæ‰ù¼bÃì8܀ޮ.tµ7c_Îl÷-ì%øJ¦<~Uú¡H€H€H€H€H€H€H€H€H€H`r Â=Âü ü 9s#j íÒ÷ÞuwcÎìÙ˜=o1¶{·ÃWùF¤JW4 LVT¸G’³)¡%`ùNª‹ÄÞ2¡.›®s¿Æª¹ªúPŽiG$@$@$@$@$@$@$@$@$@$0Ñ P6“±þ¨†õaŸë’±r[)þ×?Áýûtþ銰»N¬rÏ€-#Ml<ËH€H€H€H€H€H€H€H€H€HàZ!@pr:!9 ‹²Ò⃠         ˜¨¸¥ÌDÍ9ÊM$@$@$@$@$@$@$@$@$@$0®Pá>®²ƒÂ LTT¸OÔœ£Ü$@$@$@$@$@$@$@$@$@$@ãŠÀM\ãJ" c!ðÉO~6lÀþýû-ö¼!k…@WW<>ó™Ï\+If:I ˆÀÙ³g1þ|L›6-è-HàZ péÒ%o2çÌ™s-$—i$ ü1ÚÚÚ™™ôŒ$p­àxèZÉi¦3?þñèììÄ­·ÞÎ íI`Ò˜2eŠwL4ÞuD<4uœÅ?ÿó?GRRÒ8—’â‘Àè˜5kô?^$p- ‚åZÎ}¦]'@E;ËÁµN`úôéT¶_ë…€ég`¸æ è 2õ?^$p­Ðu¥ãýâ–2ã=‡( À„ Àî"›($ ÀD!ÐÓÒ€Ú7Þâ~K¾¼s‡ùp½ýT N¿ó‘pþY|ye&†q>Q0ÄAÎÔvá¼ç2fÞñV/M‹C˜W#škêñöGWð‰ÏÜ…•‹Æ_:»Î⥗_ƒ3±òë«e™5Êæu×]Ü•>•ë>Ì%YÈœ›ÒÍXZzÚN᯿ú4–ÐW*܃ЂH€H€H€H€H€H€H€b'pᕚ-õÞŠšº±mÑŠÈþflY– —îÚVŒn*ÜMðž·ð½u “´-™¸ wÏ›øÇl‡7¶¢Æq©pwÿë¬ó–Y;× w\¹ÙØâ6³d(“½ /îY‹«¹)ìù㾺Ǻ4TVñÙ(à–2£ ˜Á“ \[§š}G²Z=ÙÀ3s*¸2Ò€!~aL‰¤âu¼g"q\Šf–Ù‹„)7G.nýÞu˜½¼]‘{‰»K™Ö¥¸³e€‘ Â=rVtI$@$@$@$@$@$@$@$@ÑH¾ß­ªDyy9òï¹):¿ãƵ':û0Ðׇ>ù׋ÎK­¨.É7¥¬ß„òS=æ=M$p à‹Ók0Ó™d        ±"ЬÕk‘5VÑR<×'%!A|i`*“”–Œ•yûQÛ~+öú¶Qª9uÛ–±Ò(ÉÇ`I`¼0ëÈx‘ˆr À5O  Ç–ã̇À½¿‰;Ýx®¤/iÄ^63±ìþ‡÷Ä×±(-x¿•®³5(yº»Ê¼»ÃûhÚ(Þ½ ¹«ùfDó‘çpümÉåÙXû­õH íu‡ðü«˜ŠË¸áó_CÞòé#’­¿ýîÙ‹íŠl6»뾑‹ÇÖf!”ª69%žŽøîS8"üy··Ù‘«3Ø*ÌRìJ»ÎËøô½á¼ý]üË· Q©ûs–£÷…õ0¶ñìjÆs{öcÓ ³Ä‰p ÏÇ__…@´]ÍÇP~ü DÀøæú;á>öJò"/øsåæexèÑ<|]2ÖƒÕ}Éwøëm¬Îšë«¿ãÊž{ýS§šq‡0]•7ƒ]¨«(Ç‹G_Ãù ¼eb¦ˆ;ç+áá—ÂC†éAÃá¡ìÇ5^~3…ý- W™ÿf%O—®b1,Yøî)!è ÿëó8z¼õnߦð6»÷ç|¯~™Bq¯^±qVC6vÂ3%>Þ—ÿxK6æceº5Þ`_´!h¼Æ53fhßþö·ÇµŒŽH€H€H€H€H€H€HÀ$à.qjBEãý+nê6„2õ5iN¿[ØK´^ÃMo£f÷ÛÛrs5›á&è×®Õ^0|y›”ø 9,¿Îí¢×K¯Vb÷É©?/<Ñi ÇwÓ­+nÊÏ G [ku‘dc‘I¦«@kíó‹¡²‘ÏMyMÿÍ"º"lv+;ÁØÈ‘‹µÅÃÈbתôô*WS±ÝïÇ®å:maýÛ k5™+Š<ö¢&šV¨4©vv­QcàÒ ³Ì„äâЪ%Dtµ"%Mvj<ºÙ¡5ɸzµr‡ñÜa‘A&Âo8Qdp–[yÎò¸±Ø¬áâ-¬¾hñc²‰‚³AÖ=µ.é!w0s–k2ƒt¼&½ü\¼h-+ãQnîá.rŠ Œ+Ê¡î²2ߊnˆ•×……(ÈÏUD­ÇŠ'…A¿Í`û,Þd¬Ö¶¡ ¸µ'jQUR¡´÷]›°á™faNÆß)4l±ëåßÊp¤¥X…ý\½ÿÎV„û3ÄŠàeó4—b~öv´ÍQ€r— •ÅÊàØ‹Çž’n‚ v–T ?Ê#žØ_cÞ+òÁ]·L¸p’âsæ9{óVl‘~lÎ"T76¡±¶¹Ò}=Ö,p AÙ’\ʉz”UøVjÛ()/A¾C÷®ø÷v®(ò¨‡¿NÿÔBˆ°Û­§xÕb¹”ƒLûÏbÜ»aä°P£¨¼ ®Êba2.²ç?†fqïÁ¡ ó°ÝÈGaí,(BIq¡(Q#»û{ÄW»q· Ügv† t°í0–mQ¤-(Aõ‰¨®*A®ù®ìïàl¿ô†˜8›Þ½&£N «9³f¹•è~a=f%xà- Ä‹Àx| @™L\án² ‰H€H€H€H€H€H€&¹ÊV¬ÆŒy…{àêî\±"WI|wc‰¹ºÚV¨]ò?SãvV«>„±ÊW(e}þ잕ޖxœšÛX]2WÆã,÷¯\¶øáE$[·e5½£¸QI¦õµºäŠ~@¬r×WÄc/pÉÕéºçÞsUæêu…êOèÎ…üN­úœÊB¬ì—+·¡9ŠO˜«Ñ½R]ÒŠ•çö¢^[ý?•¯Ð–kåj¸Z‰²ê½ ÚŸ+J:Åæ wh€¡·IÉ[!«Uºh,rÈü°åWZWi‹UìªÜŽ·×Ÿ5<»æRWí\2«Øõßp+Ü}nì6›fSþ„~RÊ£›KšTšv®Ü\Ý®¦Ã— ^­2×øJÀº‚>&Î"PéÏXá~©Ö,óB>[~•ù‰¤JÃD! —1®p×[†C$@$@$@$@$@$@$@×,\œû¡X‘«¤?ué×!¶ûð]î&¼ã_Í<¹¬Ó»}ûŠKo³îDAy‘X%_€Âœ[1Mdú|cIwªOwIçúÞã¿úq™ÿ^¸ûÒ|å™aŒL¶þ6ÕûýØ‹ðÌæ¥FÞߤôUØ&ºGGŸå±¸Édz…«,û»'g|[C0P}ºÅº~×¥r¬Ì0éõ·ü›Œ­íŪýg7g)ê¾Ó°ù…&ˆ­~¼Wýö—Ñ&—Kû-ÅOnå‹X¿Ô "‡¾¾íqé ñ­w¥9RÃ`G ‹7IçBÙ=«Ò}÷ƒ-øÉvCð\¼øäZë*턹BîF¹ÒÝõb½ÈÁA¼úÂ32¼ÂÚ±JÿJÁ¸Ò÷l“ôcX‡ûÕ÷_w+îÚÝ-Pªcfúÿ—¹xøKþtHOÉXt§QöćÒÞjˆ‰óœdôë+Û笀AÌVàÂÉý«åþýÖXxGñ#À'âÇ’!‘ @Ü Ø‹EFgÀ¡¬¼aæÒ¾lÝœ¯.À7Öec©ívÌMKÅÒõÛ`Uu'àóllñú«|¹ ßÌZéS@ë‡LJrÇV|>-HD*ÛÀÀe)—#ç>¡Ò¾îÝÑ ÷£zº1O (¹í…"=(úÐ ,!çîÄ—ä0_Jän_ey‘!ý&ß‚B™_áÕÖ^Àûâ€õ|M}ÀÜ:Åð§J”bXFúÛß‚oÍɛո/qÀ«k[–q‡þÖf¯?àX„”Az< $árZ§p›øõŠ]_‡·<«á®óm}#¾À×–«/üA'-Â?ÚáÚ%c–qš}{¢Ç17à|×;ÛñÚ‘½pù£Ø»án«M{|ehVÖfœÑ6û‚„§§žÞðî»]èl{û6T˜Q„4Åȹbf[‚.ÂÉ=«¨lɘ–ñ&ÔTÅ;†G$@$@$@$@$@$@$@$;eïaIÏÙB[vù õ{¡ÿù.r 6Âùµ‡‘¥¬øN¶Ý/ÖoÁáÈ}àßpnïJd&m¿ü7ÿÞñb}ù£öÊÊHe»øZµ”ý¶[o’fÕ4+™ª>XÑ%§Ì¾^u±Ù±è³I±\ª,‹2çXž™7‰˜q³¾úÚÒx¡a>¿"[u¹¹¥_]àÍŸŸ´–¯·0øø}38×&Ì™f®„7XM‰½‹× }»c.fXË»ëoîõ€ ?ž‡ÌPšÄ{ÐV³OîÏïÞ›£û°:ÝGÞÓÖ€í{ ÛËŒµæ2Úˆ ¡ØGäÑ⨯v|+^¾XœDxóQU>|öÙ]O~gi?ÿ9¦L x3ù“=d CU“!=ð! @d¦&§zQÔ‰Ãé<#‰Rl+²³©÷¾ô,ž*Ú.Wû¼ºQ¶w‹÷Ï!¶*9j¬žNHÇW‹ì8à=ø² Õg¾Ì¥ Êv2|5kn$±‡u3ïžGŶ%.ïÊë¹³•-MÂúx`.x0Ìíeu͹Ïí¼û6‰íb\ÞƒG/(Z}KPIHý‹™›Ñ¼©Ûýwæ67â(ÓÚK…A+ú§}úvïÖ/‘«­{1 Š_$´;ë† Õƒ±Ê?\`é+·¡¶°+ü«ä;>Ô'¡£næ¬ØÝéÄò¥NHGq³¬G¶ó9t×åY¶%Š%øë>÷9Üð¸¹uP,aL*? õq“*µ%†D"ÂDG$@$@$@$@$@$@$@$!e±góv™C¨<»/™ Ç^Ë.*FÂYB*²Önóþyz:pþßáä¯ëñÜ®2.×ö»qä!± y®oòÂUß¼ w Òõ¾)ö%‘ÛÉä:±05D4QÉèøJ“ÉËûl° ßU”íöüb|÷Ñû‘ñ—³‘œœŒ$¾-{:毓å9¢ûÜ’&”nLÄ#‰6_~×o·܇ÒÕ{ÉGÍuóçCÿãEáüY¸´'       ˆžÀ¼Å_žÊžùÔcHå¿¡å•J©·ÛoáêÛ~4Ú‡;v`ß¡SÞ-ГSÓ°(k6ïÜ/öÒî…«À.Eèø@_…ì»’2î[ÑøÌîã/ã¥Ã/K¹ ÷ŒXù=GaòÜ+¯ÑZ~µkfÏž-þîÅis›u‹›xܨùsôWo†Òóª¥þøf|Ê{Âlh§#±õœ=„ùkôÍ||W~Õ9ä- ýv#ñsç{×Ùw˜”ŒÔÔÔ€¿¼Zö$ž|Rü•ýƒÉŸÆr#Ëë_Äë! cªŸ^Ù>ôK‡~|t£¿éIŽ;Ïã¼?]Ð÷£ß¿Y™é˜•êS¶ë:þ ].ãók/Áò‰w7™(çWÙšÇÐ’á‚¿$0rT¸œ!C        I ù/o›‚ø¯úíøÎ¡fãÎòëi9‚‡”C#WÞ›ayýM^~;öîÝ‹í\¸@2²²Wš¶ jr¶ŠUÎúå>€u›„Ø«?ÍÅš;ÕÕ}N¢ý?ù¦[$÷®ƒ¨ Tzö4 DêïÇ_ ñQ@´qºŸ6s®/iâAýö½hè t4~Z®&·…:°5ØOÔ6]upØ6HoÎâFì_¾ $¥/{íû/q(èË-ýÆüí9UŽì-»°k—ø;Ý-ìSqë2C^ï•ÔI·†¡«®üÿgï~ ¢¾ïüß¿h1 &`4¹Øþ0ÅdM6Œ]=¹šœâf0'?hvOWÛ&ânl~o6GHϯ¼‰ý»r¡›5x³)ÚÓÅ»¢ÛT·7co‹Û_‘^Ívåd1s£¥_~)4Ð0iD˜vîgþ|¿3ÿt€ç÷ìd¾>ŸÏ÷óy|Fzö=Ÿy­7X§b¼§ë†¿tðèÄÞRmØßªçÔ½Ÿ6h<û¥âà¿ç]9òÑx;ëë¡_UrÕDdWŠÑ±š.žUP®:óÜàÖ¤Õ_=¬árÖuÞ˜¸÷‰Ò € € € ÈÈSe•áÓþÍ+”ÿÌ^:צÎÎNµkÖáêÍ»{ƒ½Š\Ž*åM4°®{íàj¥Ö–ìÓ…^+´Ø¯Ž3Gµyµ•OÛ¡»üAш-÷áv :pÚÄOEZjRLx[¯ç¬%ô&”½fa‰Ž_è–×ëUç…ã*ypu8À]ãÒÄ2ÆÞÛ䬇TUf¡ÝZìK°V¿š<£[Â+¾ËŠî½Áq]íЮ‡ÖÈ^DoÚøô­¿ÖÑ£‡uøð×ÃjîôÏc¶JÛwÛx÷çu ¹Mþ,<^¯GgŽU+sU©}½æ™BóË„d=T²Ë>×´sÖUSw uO¿.˜‡.ŒHûb¶S¯¢¿®ÖÞ½Õª®ö¿öªÚü’bǮڴlžÖ”†ÓÂ8«*)q’½zyp„M;¿®§ÚäéïW¿§[ÍÇöêáE…ã¯×ëo ýfX'â?aÒç„·t½ì¶Í—Ç;×ÙC`’&ãOæ$w‰æ@@@@é-°rÛ˪:î¶W7½X*ÿ+öæTCÃWN,5ö¬*É&°¿GŽÊ5@~ëþ-ºÛ¼‡Z[­ÕÇÁ¶/©`hžð¬•zÊ|O°%âù™¹á¾˜]{ߤü¯½¢òw«2Ðâ~ÞÒ†oR®ï<µÒ>Ï}ü•G¯—¬‚Š:¿¸BÁ„úbœÆ)RªìP«Öu²{ÿΰþx>PKäLS•Ã_Ò m¹êtVf¥iécßTmÃ~¿hÒæUK^#®å¬hÔS¡Ô4ÉÙkÕRW¬›ƒ£uo7¯µ¾w W‰¹ù¬ÚÖýÛ5Ò'ت\TÕ¨ïl Í_Æ}zÞ|?°!p[Ó×Õ±ûjÕݲb¡^;t^y•¿Uv¬ïÉYkUWë2_¤?Ü•…Ûåê9¨•±³÷ŒµyÊ#%À ÷(@@@@ÉÈÒ¶Ÿ¼'w•$f£Îâ*~ïÇÃƒßæ±—ÖúóôyW˵a•4·0+É_;ß bk·954Ø^VÛ(÷óy1ú“¡‚¢ˆþšU÷,M‹Qnœ}K[ªÝƒíª+³îDµí*«Õ¥¾Ýʱ—‡Žó>Æî¶PËésF°K_®}}—T lwªöd»ö<–ÕGÙÄ0.>²ËÆGJ¸á #ïÝlcJö©±&¼Ò}h­òC-úÉóùfm{x[þø>wW„ODì9Ëku¨*”NÈþÔ ̉c˜þ’®â 5žïÒÁmùùþÓ´þïÛUiqßâšFõ\¾d?;À©õWKØvqtÀ.kªZû)e‚ JËŸxAåö¿‹z½ä¾`]âIHò™mR[¤±I˜?¾Š‹‹ù×&µaC@@@k#`Ò}t\º¨ÿÑÙ¥ß øo™ªŒ…YúÌK´ =2,:™Ýñªã\‹ÎþÇ»HMUêÀ€RoûŒŸu(k”{v{F‹]ÁdêŇ.ißc9“Ù)»-Ow›.þò7’ <§Üp³n¿m‘y˜f¬à¾]eÊvz;ÎéóïÈià£Ýôé;ô'+r•1US3I#ñövªõÍ ê2ªÔÔuKV–îXœ£Q=:ó‹P3”sr²âjO°Ï~ã7Ûº5hæûÆ[è®;—†ûéíU[GyÀé\e޶МOpø ZP}üIIIjooWvöT&ÿ¬šÜ-‰}'àž C·@@@˜q½Ú›Ÿ©Ò@Úm—Zú^Õò©ÅÎ8E„S#0]î|e45óO« € € € €À´èïîЯoÐ?Û ¶›‡¥V•lŸ³G'@ Ѹ'ÚŒÐ@@@@àš xô½/-ÖæÀªvë¦N}ãÉðƒK­³¼#€\]€‡¦^݈ € € € €ÀŒèû zhU ßQ^Fô9Ž@â`…{|N”B@@@f @º6;/çkÐŒnþe'úÓBgà,0$˜9ÜgÎ\2@@@@`ÌÙK•‘=æjT@ˆ!@J™(œB@@@@@`¬ÜÇ*Fy@@@@@bpÂ)@@@@@Æ*@÷±ŠQ@@@˜ážŽfþÇï©¡é„ÞijUkh¼§Kùë´©è/´<+}†+Œqxžÿ—×õ‘©vÓgPÁò¬160µÅ=mÍú—7Þ5û#ýYA®Òâ¸]Góq½þîGJMMYzà£4z“rïËSnvFÌ2×òäxÆx-ûǽf‡÷Ù1ÏŒ@@@ˆCÀ£{ŸÒšÒú˜e[›Üò¿^ܾYŵ'US’Wà6fc3ì¤ç¢[…J£rTN¸€ûÅ•kCi“ä¨QO\wÜÅ…*µ¾m¹Ê|9Ëé•ÝiÁUÊMåå±q*{CÛ³U€”2³uæ7 € € € %ЫÃ%ó†Û‹ŠËUUU¥òbWTéý[Vkå®òFÅ)sìÁß‘–bï'ÊNÊœEÁ®ÌŸ£xWàλ#þÞ7UnÔÂü}ꎿʤ—Ï'½48ë¸Ïú € € € €€Ô¼w³6îK8˨½Ï§ƒûvkÛ¶mÚ½ïUù.¿'wU‘]¨uç½ÜÜk³3S\:ÙuYƒ—/ë²ýêS×{—ÔP[tÓÕñy{°7+¸ÏÊigÐ € € € €@„@ï •—ºíÅu-:±{½²‡¦iOËÒÚmu²Êi—-­tËc±3SnLKS²y¥Ù¯t-ÈÊQAÉ5–‡?Ǜߙ©Œ ¸¸ÇÅD!@@@@`æ 4g¯LvïàæªÓß>¾Ü:Šùž÷ä7ä°®¸ÿQ‡DܽÝg´ï™MJJJ ¿–åkǾcêì·*ï¾pJ{w”(Ù2»Þ²üuÚ±÷°Îu¹‰©Þ{wíÒ®êÃêôöëÌÑj­ Ô]¦çÂå»Ï×®’uv›~-[§½ÇÎhÄîx»uâ@µJÖ­ ôg™i7]‰ö>¡î+ S|gLßíÓ¦ü/c—¿i‡Žé¥ šcެ·L›ž©Ö©¶øyàínÖ^ãX]]­];véx[Øn”›Û—î[¿ÎÞŸgï…wÆ:¯Ýg‚óZ}à”IYä Ø”¬Ë—¬yØ7ÚÜ…omïMtŒvCì p5[B dffúž}öÙ„î#C@@@é,Ðã«qÊgbHWÕÉ®83è»tºÑ×Ðh^ §}]ƒá*í5v[V›ÑïNß‘ó}á ¡½Ó5EW©'_EC{T½–§]ÇérØûþûÕ´ôʶÔ^¥Ý¢Z_{Dÿý•ß;é3‰s¢Ú‹ƒË×pérT_úZkíò®š–¨k£ ¶ûj\£ÝK>g¹Û7Lìò%Ÿù¡}ÏèþÏ—»/Ù·nµœµÑmu kQ]h>û|uv¿\¾ÓÃ:`7í3¿x°ûQ|è|ø‚ٛؼ:}ÅEÑó9NGE£/rêÆ>ƨ®ràþ¹ooþˆ]f…»™)6@@@@`Ö xÞщ&kô.=ôÙÖÁ(ïÉÊY™¯‚|ó*X©¡§pzÎÐâ5¥v=GQ•N·ètã!ÛKâ›´án—NE,Àö¶ÖªÒz»ž«¼V 'OªáH­ŠÃÙJ´³ð9‹X]|Hf°á&w«]ßÚñvÕŠ-V»•×RãÉF©-¯Ð¯ß¢Í/Ÿ±ªHýç´yÑjYµ$—ªêŽÈ}¨ÆìY›[…KžÔ™±-·*G¼{t`ób…³ù8Tu¨A--§u¨ªØ.×Té’«ºÙ>6kûµïËK´Ýž7ÿØêävש,«Òõd”³Õ€ý ÛîSZ·0b¬Å‡Ôsðq{>­ò#½{û{ͯ viµÝ§Š —ÚÅ'6¯þfš´¿>8¯Î¢rÕÖÕª,< ò?CàÇöhìûúwì³cT£ @"~ @ŸÂ¬p[°‡ € € €S Ð×â31Ìà eG…oüëGû|µöŠhù\5'£Vû|ïE­ävV´s¾.¼ =rUv°@ŸïP±µÊ9z¥µ½¢9Ôÿ¢š†¨Õö‘׋†¬Ü7+»íq;k|ÁõðfEv•Ë^­í(;ÕžoÈjtWm«=†ñ¬pïk ¯Š—Š|'#*`Z~ïd䯜¾“¡NöµDž÷׳»av.ûÜåáçeîàŒÚÖ ÷÷Ãã7~޲#Ñ+ßÍQx…{ðóát8|Žˆ—‰=ÚVþýÚ–¨Žø&g^¾ºÓ‘ívùj#V½—7¼g~ìc´«²3 üŸ1V¸Çñ§  € € € €Àõ˜;_+¬UÑw,Tæ8{Òá‡Úb=wÕQ¥ïlÍShá{¨Å,m=Ø"“ª%°5mÿÚBËççÜZq^¬GÎ •°ÞÒµü~{y¼R¬ÓCÞå :¸µ juö`Äã\oèù ºÆ‚ûU^W¥òŠrU¬»KsýW½ôÛ­Aë•o=Õž’³ÍNÛ+Ýݯ4™µæãÝúõÃ=[ìÊ'ÿNyÖOBg³ò¶Ê¤Ä 5©¾±Íìû땆ë5V™zö¡ÙIÓÚ§Ëì'ξoïv¥«ß¿ê{ÑY#u”»õÚžõúŒÜèŠf½yk«Z#^C¯w´^ˆÊ‰?óZ|è=¾2r€ ôWÛž²o}úí!ãó_™Àí†ÙA`œÑ÷ÆÙÕ@@@@¦©€÷½m§&™3îA †ó«o_«È©ÝhúZc–•×"½ïè7—¥å]`Ëg}[ƒÅ¼^yz{åéû@ï¿ß­®¶7T½9œàÅnkÈÎö'rFºyþmö¹ýïÖņrý—…Zé¸WÙYZùø6­´K˜Pö¥3Úo»–kž×£^œ$penò­ºÇì†ÐtBo{¶jåÕ"ÕV›QÉеáþ˜bºçÏ™ZÁñÿºóC³¿0¢žK<Õjà ëa]:ߪÁA)eþâèëõµ0гJ¯í^{•`»?eÍSÊòñø°«C??Z)+›OåæÕúÑÛ&%Îî‚À—-ŸW—¾òçá5Ö@̰ìmž½±3®1FÔg pŸU@@@@i/`¢—vÜ×}Vï™øòÒ8"FÞ~<—ƒÁèäô µÿ¼Á¦Xž»ÈÞÞIQæþÕêÁ¼Ü‘«Õ=m§ôíê´}¿µî:ºæèGEZº(mX‘œu;TáØ¯ÁÛ©©¾2ð t¨¸ü ýå£Ê[ v~ü›pî-Z4wKøx„½È1ŒP$öéþv5ZC5ÁýE#˜'Ï›Xý‚ùV ¢žóÝ>|Øæ~iÊYšû¾ÃÎ׿v~UY#t PÞ¡GŸ*Qn¬"ÏïVÛñj-)Ü(ÙZY¨WŸ¸¬õ9ÁŽMl^ÍÃú;žñŒ1¾vÿ£·Yç~ó³ø Ï‚Rër¾ªäOLÎ,Í®XÿLfÊØ € € € €ÀÕÒMJ®R>¡ö.¯–Ž|õ7دú/ÏÓæPÀ¸¶µO=´Å¤‹qÖb_Œ^îBš2þ—ùáÃÐ^ç‰j-Z ؽè,*Òõõ¡ýЫֱùÊÀ¿ìyhðÙ¤€y¾¥G~ÿ;z¡j»½;X«Uû+K/WÕI½º-Os?}o ]Œ·Zù½/pÛ‘¯rÅ,?·¿èè¹\ò ™Š‹¬×äO13Ñ­I…EßUωeŒØ”Gƒ—ÍÅVòçlScÅq­Ùü©Dç‡þÂišø¼ŽØ¡1^ˆgŒñ5™ú‰4¥§fÆWx”Jšcë ¸Ul—ÿõÿûý£>Ý÷~r‚®#€ € € €Àä ,Ò²U¦ÅÀêVÕþð¼ J®²:ÚsV¯ÚQé"ÝwgºÚ¿w(”øÄß»‘BN½z븿&¬ö¶éÁvgY¾ñ•G´ôS •žž®4ÓT[á Z²ÑNö2¶á'g(ï±m—§·Sßüw½ö³&}wç‹vß½}µŽ~é²þóoÚyÍýAøƒ[?+ohäM“çεW^' òGm?%E·Y×cæE ^ô¼û¦,±@\>²žóƒ¹ç­vìw¯z»{åÿÚ#9-]éÑ,®mѾ'R´)Åœ³¦-zöèCÚ·~hþ|»Á«î ´X½ êy½J¦bŒþ[Þqó²Àë*·çò,øÄ,û¬ºÏü•ýàß}³nÜ @@@FHÖýEv÷–çuê*Om®3y»­®5ºÓÄs¯øœuF¯þô-{?jÇó¶ì¸ìºÕ<©ÔÛuQ­BEurïÙª¼Ü-ÈÛý—:e—°JÆñÞ¯SªµcÇUhŸÓ3²´¿ÇäŒï“»ÜzZ¬¹Ç—•rs8ºûÜ»Jñ«32†¼’õ¯û¿¥o}˼öÿ,Ðn^$m±–›|öÍÝ _Œ`~ñµvÝe‹o6 Ç#ê5½ª7ºíËáΟ*sáB-4¯¿}6|Þ¿ç¬Õß–,7‘ø\U™œöÖ¶Ó:«­PÿFÞúõÑmþTA¡Ížºyµn2Êû8Ç8J‹\B nîqSMÿ‚©™Iè!à>ýg’ € € € 0¹ òžPDÈ]«3KtªÓ¿>zøvîð3ZUj‡ÛU³ÓÈ42w~v ׸¿FÓöʘAû3‡_²õΪ/(Ç¿ÞjgN<œ«ì{¬ µ[/lŽj"pàiÖÛÚ©/äùW §ëžÖMúfÝ©aõšëkís,½ÝÞìD¬¦Ï*(Wô7ëèWõ°IkK× æË‘Ø›G'ö–jÃþÀO$L§îý´™§)›×ؽˆ:;®1FµÀã à>nºéW15CáÛÒé7zŒ € € €“'¥§[ÂAZi¿V/JÑ3ûŽé\G‡:Ì«íÂ)í-É—cã‹áÛ–¹õÔrp0[rÖCª* ýAûã¬%Óýj>ðŒVl©·ë–ݬçíÔËûƒõ¦_×Smòô÷«ßÓ­æc{õð¢B;¥ŠL”×ß²Ú´›a']÷®²úS©µ%ût¡× '÷«ãÌQm^måwè.XÙ*9Tl··ñîÏë@s›úÍw^¯GgŽU+sU©}½æ™Âaiãýݯ˜•õ»vV×ûWØ{=óŒöëPÁÓ»ì¶Ü¥«´iïqu‡ºØßÙ¬g>·*œ¦§l›îR+oËs_n¬ÕóÊëéÔñ½%ZµÝúBÄ%W^¶}ÀN /u*]E/»í¶d¾d¨8Þi]Œx¯WÑ_WkïÞjUWû_{Uí—ã¦eó´¦4œîÇYU©|ó €ä)›×ˆn´;®1ŽÔ磀-¡233}Ï>ûì¤ôqàÃ?ø¥ LJ[4‚ € € €3OàRC•ÿ§ñq½œåG|=C úZ|&\]ßáð™°wÔ¹²C­5/ûŽG_¿ZŠÔo­- µëòµôE4iív5»·ÃôghûΊ“V óÞå«-ºzœ¾ÁˆZ}­µÃÚzŸÈcgMK vk]ñ°zÇÐû—ùZ‡ŒïÒ‘òaõ"Û÷ï—¹d÷жrÖú†4åk©uE´Uä;˜Ø>_­kh?F?.ªjô]¶ï8uóií 9úo;ö1Úegø?Óííí ßSV¸›™š-[²ÿ‹Ú?˜‡v{üCÙ@@@@hœ‚mìjQM(ÅKôUëÈ¥º“—tb÷z…\[L‘åÚ×wÉÔ·V–›K­­öÃIýéFjO¶kÏc¹á:føú¿oWmdˆ«Å5ê¹|I‘MþêÃ@‰”97„Júƒ1¶ùzí|ƒ"›n5ý‰ÜÊjå~>/âÔ•ìScMx¥{ÄÅÀnù¡ýäùü¨Gæ¤ÌZlÔãy¡â¹ïÓ¥†šð*sS+²‹Î²:µ_Þ£Ü!CÌY¿[ï¬3¢±6ÿçȇ ZÝ›7¼üò'^P¹í[¯—Ü…æ ¹çðšÁ3®â 5žïÒÁmù+þÇ?¯²ú:,ÁPŒØeÍ5k cŒÑ"§˜@’ÿ+ µ@å)˜?¾Š‹‹ùÆ&ãFGnÔçÏ$ëÆÿ”4ÍÑ € € €ÌPþÞN]|»Mïõþ.4ÂT-¼s©îÉÉŠªŽ<øÞŽszãü;Pª>ÐMŸ¾C²"Wþ¼í#lþ:o¶uk0%E7Þ²@w™ûe˜²6o¯Ú:zLʼm¡9?JCÃÚ÷ªã\‹ÎþÇ»HMUê€éÕmŸ‘ã³e¥ÜŽ×´¾yA]¿3åSoÔ-YYºcqN¸OÃî3ý½:wö ½ókÿ½ôÑÀMú£e¢Üìa_kDßĤºi;Q¿ùؤ·7©ão¸ùv-1s4ò¨¢«_‹£©›×kÑ{î‘(III2+Ü•(]ŠÙî1YçädÜÝ5¨¼#ÉÊXFÀ=qf™ž € € € € €ÀhÓ%àNJ™Ñfq^KÍHÒ•~Ô0§–!!€ € € € €Àu à~'àZß>Õü i ÷Zß•û!€ € € € €3_€€û̟㨦fš€»IwƆ € € € € 0¹Ü'×3á[ó§”è%¥LÂOD@@@@i'@À}ÚMÙÄ:<ǿ”2C¤6 € € € € C€€{ ”™|ÊŸÃý )efò36@@@@¸Nܯüõº-)e®—<÷E@@@@™.@À}¦ÏðñšJJ™!*"€ € € € €Hžx´0ü)eH)3¦Œ¾"€ € € 0 <:s¼I¿üHJMc¸¸éôg¹J“Uw@7}æ,ÏŠ£)(âéÐñy]f×·# ÍÓÖ¬yã]Ó9Ëm„‚§;šëõw?2s{R>úH©7)÷¾<åf› ÓuÞÆ3ÆëÜen?¸ÏÀImH¤”M‡k € € € p]\ŸÇ*}é+%ú«µË̓WclÞn¨¯Ó+¯þ\ßyGþZþ:ë¾ø%=ú…|-ˆY)F;qê×™cÿ—ö¼¸ÅĦœEå*{æi­ñA°þ˜Ö·U¹k»ÜvHË¡¢²*~úIååÄ·ÚÒÛݬ—k¢þ9stå·Wtße*È ÷ãj{÷­_'…îóbî¾pJÿôõzõG§ÕÔì¨ÃéÒ#뾨G×ÿ¹rMà>r›ðÜE6Ú=ÆèûƨÆ)Æ.à›õ[¯®H>#7ê«æt×0©ÓUÎQëÛtùN÷ «÷‰ÌÌLß³Ï>wùx »{À÷›×OQÊ € € € €S/p¹ÅWdÅfœµ¾ž±Ü±ï´Ïªë¬j±k¶ÔXq§¯¸È1b ÇQÑè´kwß;îÕ¯¨w—¯áÒå¨Z}­µö=\5á~DŠu0Øî«q—r–»}ÃÂK—/ùªœ£×+w_²ï1§ä@IDATØZ[ìŸñj«kÈX‹ê|]>_ݯÑã['#bdŇÎÛ÷ô Ý7Ê/ºß íQuÆ;wccÔm9Hp¬µ½=ú³’ˆ]žõMm;ú¬6ׇ¿¨p•Õ¨¡±Q‡jÊåŸVéªçt¡?â„<úÅÏ›B'r8b¿¤Û®çã:";lïÏÉLÒ@¯}È € € € 8f‰ôð<£t/â«ó"VÛÐT“ö×WUûWŒ×ÖÕªÌn¯uçý¸#œ™\ýç´yÑj…ÃE.UÕ‘ûPÂÕÜ*\ò¤ÎxÂíŒoÏ£›«ÔmÕv¨êPƒZZNëPU±uRM•.¹ª›íc©Wû¾¼DۭД‰b•×ÔÉí®S™ùöÁÚ*]OêTŒ=ÚîSZ·0b¬Å‡ÔsðqÅHô`5õîíïÕ™£»´ÚîˆSE…Kí2Þ¶ÃZU!Y^«†“'Õp¤VÅýÜYøœÎEÄÝÆ=wö#rÍOpŒM²‹@\cúûW‹ÓªP§ïÚo÷¸¢á’ž·~/“Ÿ¯Ç6­×3®Ð‹¿Éûõ“·þ-]ný§G]ï«:Í´[—Ûí$úŽÿÁ©WLJ6@@@@ áÜ/˵®A±R“øûÚgÒ»ÜùL½ö=ž;†®;Twú§z|å‚`Ç¿ ¥›Ò–P þôù.­ÍÎ \kÞû¼lw”ÒO¿õ˜€^ûE—ö®·äõª8¼M¯–Œ¥Ñ]öœ9±´È<˜´Ny¡h÷òå+õàý¬E«K•š¶—ëÔ“'”gâ:ž3µÅÒûë4õ‚m¯]ûe9w|^®@Š—&ýàT‡òÖfGÝ8ì<¡u‹ÖÈjÆQvD¯íY?Bî|·VÍK’Ó,8ý ¢¥ÖPzëTmË+þYÇ—N5X»2«íµ{­•§&O&ïþŸ–|N÷ûo}ìFnÄ&vEóeB¼s®úÒfLcŒ¬Í>ã˜Ý+Ü=ïª%ø§TìV¹l·<3–«ìù2ë(ú½ÿ»®óÞéõlÀ} ×=Ž@@@@„hU“ÛmVkÇ~ùs€_ìóGgãߊ½¶ª-Ð_m{ÊnàôÛï÷½ôÛ­t±^‰¶ $gkëÁÓöJw÷+Mf­ùx·~ýpÏ»rÅÉ¿³ƒíÖɬ¼­j©5Év[“êÛÌž¿^0ï?]ÑXeÛÅLÔzíÓáxÖ‰³¡±/J‹ÒÕï_õl/wl·**Ýd·^á+Á½ŽÖ ¦wám~Î}¡ Åzôa+Øn]O×òûÃù%R¬ÓCÞãž»Èzcd3ì#0Y¾ÂýÝcþ]û*áÈùTÌŸ+yõqL×þ÷~iøé¬…1Ë$êÉTJV¸'êôÐ/@@@f¹€C.—?;B¾–¾>ÝqëHáÙXt.}åÏ—»²ŸºÚéŒì\®åšçõ¨×c'` ”š›|«î1{°|Ó ½íÙª•ãzöæ ì!kÃý¡%êCzzÏŸ3g‚iY~Ýù¡Ù_QÏSbÞ¼;•ÿÅ"=úÅ<û'GvÅØ ®pO€ŽÐ@@@@`¨€ë)}ïÕ’ØÙE†–ó8ÞðüàÇ¿ ·èÞ¢EsÃ+Ðâ÷âm;º–9êoW£µ˜Þ÷¥Kž7?°JÜJÒUÏù€nOÖ²9‘¦œ¥ñ¦º9®íüª ²Fè@ y‡}ªD¹±Š<¿[mÇ«µ¤p{ dke¡^}â²Öç;æi;¥oW¿ íû­ÁÆêïÈçÆíÕd¹ÇñŒ1¾;þ¦Ï§Övâj–ÖCËLÀÝ:à= 0ëîÑŸŽn.T©e¸øÔÓEý¡ì ýI4‹0‰«$g‘ÊwéòÛMz±>øÇÅÿã"×Ý.5výDùñ>Þ9âžSµ›š‘dšÊ†©ò¥]@@@˜˜Àõ X]~÷M;…°«ê¤ný¬¼—£SÊøG–¤}ë‡æYlsôý«—¡rÞ6}#"Øî,«Ñ7¾òˆ–~j¡ÒÓÓ•f&¹­ð-Ùh'ñýc¼:côwá½ëæ5ÆÎP|V ÌƘêy&€îpš zÄæ©oX´BÇ:¬Ç>ôêµï†¾ë4Áöª†óò8¨ÝÏ?¯=O¨ïR£ŠíúMZóÜàìS×y‡”2×y¸= € € €$¤@ÊÍá|èîsï*ŬÎÈòJÖ¿îÿ–¾õ-óÚÿ³ñÇ|Òk¹+ÄànÐ/FxúêÅ×NØVËßl–þGÔkzUotÛ—Ã;?UæÂ…Zh^~ûlø¼ÏY«¿-Yn"ñ¹&¦Un_Û¿áIŠÕV¨Äè+ùûõÑmñ4SØÛuQ­Ö‹êäÞ³Uy¹9Z ¶û/uþÊ.a•œœ÷qŽqrnN+³]€€{Ô' ]<«³'ÎÊg~'ÓÞÚ bó·Â¿€ÝüW®ç~zÒr†65´ëÒ¥ó:ßÞ£mK£[ÉÉ×ß_:>·ÿGºdÅêÃgãÞûýïor1÷Ëç}õzj¦4Ð;z™¸;GA@@@@`†¤åܧ2k,æÁ›?¸0< ÓÛ\§ÂÒÚ¹Ó¼^ï±JG¿Ï±Ö¿GŸŽ>š«ì{¬ µ[/l޾ì?ò4kO©•àÆ©/äùW §ëžÎPÙ&}³îTh?üÖ\_k<²ôv{?°3/|˜UP®:+èoÖѯþêáPì+\&¸—®b/¥7—=:±·TöhæØ©{?mrϤߩ/ûé¼+gX6oçq}}»µ*Þ”‡lh·F:×GjŒóS%0–x§¿ìtÙ®×/tßÇü(;·@û~Ú¨‹ ׺Sÿ}}ù±À“§3²²GÉke¾$Ì)Tù›Rø»ñk}èÿLDÿz'.¯y‚sàSó­i¼Û~ô#}þ󟱸?¥ÌÀÿ{0b%. € € € €3^ [%‡Šõb(ÍÉÆ»?¯ÓßÑ—Wä˜!zÔúãok…+œ“¼æ™Â˜á÷+ÕÚÑõé`2úXf—/ëvçÓÚúô.©2ñv—®Ò&5èïŠ ´ÀÄú;›U^¸*˜òÅßFÙ6ÝJ²ž·å99L¾tˆ»iûjmJó×{Hƒ]úiÝ7T¸Ý Ò»äÊËŽîA_äaºŠ^vkÛhKæK†ŠjwAx¥°t½Šþ:WOü±éWà;ÓÁß¾¯ßš ü»G+UoÅÚMagU¥òý`ííÔËûƒõ¦_׿£¿¸o‘R=:ÛôO*w•Ú©rdFùú[§åËDvnüûããøoGÍñ ÜrË-úøãÇW9kÍê€{Çñ]Z\¸ÓLSîökmvŒˆø‚ô—æï^Sèï”õe›?îß’“G"œ«yߦ ã?þö¿öµ¯éoþæoâ®=rŸ‚MR&nJ "€ € € €À5° :ŽûM¤îÐÛ-}웪mد-õþ+MÚ¼j‰6-dŽzjy(>ôzS½*­ÅÛC¯…ŽwlÒÖµkÕZW,Çæ`óúÒBÕ—JÖ#ÃUËÔZQ`‚þ¡mA¾~p¤\K6TNXõ¬ËÖ{Ù‘´r„.Ze’³Öª®Ö¥[‚Á¯ÊÂírõ Ô»b2ï­û·ËtmÔ­¨ªQßÙ¶2X&ã>=or.o Í8®Žíh5¸eÅB½vè¼>¶Ô:5iï£qÒnBCcøío;¦:©©©c*½ Ïê”2¼ÝroÒ…÷/0uE}+f~(snŸRÌ*ü¯gŽuÄ®×Qÿ ÒË<ãæv»zäÙO~ò“öý¬ûŽöž””Y}ؾ?àîýHúàoØ5N € € € €×^ ¾ˆÆîWŠ®$}žµTÒ”œc•6éJ®¶Ùeý¨ä`ŸkÂOèZ½üP‹~ò|~8n ¤¤D52´Ê°ãy¡â¹ïÓ¥†9"JÓO8ËêÔ~yr‡ #gýn½w²Î,#µ¹Tw²]{"‚ju/ÆÑåO¼ r»õzÉ}!Ðèœ!÷Œu'ÿ9Wq…Ïwéà¶üˆÿiZÿ÷íªõçkޱ×4ªçò%UD\nýÕ‡Á’V_í™Ñ€uÊ.kNXûc£Õ ï×^`´øf¬k×¾‡ã»c’É÷=k£®ÇžÑb׋A9óð†žƒK^oŠ9kÔsb«’MÀ}žcK°ž9×eÎ ýÁKóÞuZeåØ*skpÏÚ¨?ÂÁÊWÿïüùóU\\¬ÊÊÊ«C‰ïÝ4¨u¿LVÚÂуóch’¢ € € € €ÀŒðš´(­o^P×z£nÉÊÒ‹s”#I„Þß«sgßÐ;¿ößk@ ܤ?Zö'ÊÍ6+'GÛ¼µ¿¨ß˜Ìfm¨n¸ùv-ÉÉWj´ÛLäZoÇ9½ÙÖ­AÓÁoY »î\6ôöª­£Ç¤‘˜«ÌÛšóö:þ‰Ü’º3PÀ¿È¸½½]ÙÙÙ =ºYý Î~ø+*Ò‹Á\Xõ›•ééRKÍ“r,J—§·C§þ©Z®ÒàOzü³XöÔ#Á€üÝ Õ7•já¦~þoEZ–½Ð,OÿÏKæA;íåí:TòpBý‘óeN¦ÿÁ©&­¼é2 € € € €ÀpäŒ,-ÏšÏ|x¹I9“–¡Ü•ùÊkcÉéÊÉ].ÿãTuËÈÎÕÐTòv_“3”“s•/ìÂì ø³:¥ŒÒrõMwyx–ÜÛµbqf }KæÂ%QÁv™ð;­Ÿá$çhÇéšp½úíZµd‘æšoéæf.Ž ¶ÕžÖcK§âkÏðídzçO+s¥gÖþ¸a®W}¡ g~¡·Ù«Ô›R50 e|j±îu˜œR#(e,-О>íì¼ ·MªÁAýÎTÌXt§îÉ͉ç±V®ù{j(¥Ì5¿17D@@@@f¨À¡ä:ÚQ‡•®¥ËóÌkÔB1/fd-ÕJóšN›?¥Ì)e¦Ó”ÑW@@@@HpYŸR&Áçgʺ7‡”2SfKà € € € € 0;¸ÏÎy—?¥Ì•žY:x† € € € €L÷)@MRÊôú¦CWé# € € € € 0-¸O‹išüN¦f&i wòÛ¥E@@@@@`¶ ðÐÔY:ósM¥ƒgØ € € €Ìoïý¸ñM)5uL#P潪ü¥ ÆTÂ# x:šõ/¯¿k dêuùÊšFQ7OÇ5½þK™OETß;šëõw?2¯ØŸ¯>Ò@êMʽ/O¹Ù&Øt7O›™ƒ7ÌÜôGú³‚\¥]çþpûÙ)0þéÏÎ šªQûSÊ\!¥ÌTñÒ. € € €×Dàò;?‘kCéøîå¬U߉¥¯ö,­åUwÛ%}0(¥Ì[¤œ¬°ÞEw¹6”6§N÷™€{øRÂ[]tÿW¹†õÝ#wq¡J[ãë¾³ü^Ùý˜®çW8šGz¸Ç7q”štRÊL:éôh”2Ócžè% € € €£ ¤Ìõò¨?¸"器8LÀÓª/-¹[wß}·¾PÿÖ°ËÓõDÊœE¡®ÏSJÄ æÝqp•ݦÊZ˜¿OÝW)7•—íqÌŸ#VO¥4m&Àgo4|-øÐÔ<@†† € € €À,HÏ}B=]_ˆœ'§©ïokÉšígE£þ¹ìOäí^OÓõO2Í&ÉD£­Ðôi‘¡iéŽG¾¡ºyi”©Û£/M³AÆê®K'»¾§ûͪýð§hPžž.µüð%ny1X©i‹êš¿¨m+ùdÅRäÜì à>;æyØ(Sn–þpÅü‘¼ìSòܤa×9 € € €ÓA Y †'ñH_`þÿÐ6ïæ[”‘n Ó(ʼnÕ÷„{O»!Ü¥9ÑQõŒœ<=n^3u»1-M滜ˆ•ãiJ3ys Jö¨±ã¬ÖTúÓéHÇ›ß!à>S?Œ+.RÊÄÅ4ó }â“IòÝzfÞØ € € €³]À¤{ë=wLÕ»viWõauzûuæhµÖ-[¦¤¤e:pÎc·Ó}á”öî(Q~àZ’¹ž¤eùë´cïaë —³*tŸ ¶[}à”YíÕ™cûTb&ºÌÔ÷¿òוhß±3ê·*D¾{»uüÀ.Óà}ü÷ò¿Ö=³Wg:cÖ0« »uêèÞà=Bå“Ì}Ö•ìÐáç4¼‡Ö =jŒ9ò^Ë´é™jjë òêܱÚµãoT:óNÃ?¨ºz—öh œé½pBûöíÓÞ}GÕ1¬‹ÆÕŒS~ä=’”¿i‡Žé´:b¿OÈδ2Ö¹²o<ÎûÖ¯³kγ÷Â;cíÏDǾsxÏÛݬ½æs^]]mæq—Ž·ü‰×bqøØZ 33Ó÷ì³ÏNIÿï;|½çþ0%mÓ( € € €\?¾ÖZŸ ^®š–Q;ÒRã´Ë:]{ß_¿¦¥'P÷tMQÔy«íÈ÷Іö¨û„ÛuúŠ‹¢Û¬ç¨hô FÖì9í+ õ=²\ä~ÍÉè{ùºN^µŽœU¾ö¨™›^¾ä«r"ÛÜ/w_òùúNûœ#ôÉQu:ÐûÈñžî‹Ð`»¯Æ5ú=œån_d•ȶÆdgn;ž¹j­µæ×åk±;Ò竳ûíòE)bxþÝ“UáÏPñ¡óQWÇÓŸñŽß‡³6ÊsØç£¨Î×5ô³ÕkQÀÿï²½}È¿ýì(+ÜÍLÍÖmNf’zýÿ{Ɇ € € €³U ø IG`øMîÖa Þ¶ÃZUj­ë–\åµj8yR GjUl¢ÐÖ¶³ð9‹XÙm?ÀRMÚ_l×YT®ÚºZ•¹¬ZRëÎ5úq‡•¼_Çž]e¯"w¸ÊuÈݨƆ#ª( öÑ_³tu©šíÊý:úÜj»Žé¡jŽ4èdcƒj+ŠÃ7jÚ®Òïž «Wû¾¼DÛ›¬S•×ÔÉí®SYĸ*]OêÔG·j]Y™ÊËŠd÷ÂY¤òò2=±ôÖ@áñF>xÔ£›«Ô¾GÕ¡µ´œÖ¡ªpßš*]rU7[…nk,vf‘ÿ8çʾñw¼ý½æ»´ÚFtª¨p©ÝÊxû3ÞñÛ76;Ö'Jݧ´naÄç£øz>®$ÚŽäbøhM"ætkÊÿàÔ+=Ó­×ô@@@&_ h/ªiÐß=U`$/h°ogV{k÷ÚœÐqž Ö?¦?-ùœ6î÷×÷èc.“ç{øæPÝéŸêñ•¡|óAK7=¤-¡@üéó]Z›%õ¿¥#ûCµUúÙ«Ûì»æ¬×Ã÷m ÿÝj¾Ø«•ËMp£ÿ¢Üvr]jÞ­œPòò ô؆?Õ¼»7½N¶ã9sP[ì@x‘y(èAå…º·ví—åÜñy¹yÉ›ôƒ×“µgÏÅ=§w_¬—´®/mÓî’ÜáC8ã9sX›íï*ü÷¨3÷†ã–/_©ïÿc-2_ø·¦íå:õä å™!EoqÚ™J—NMÆ\Eß=xäÖªyIr:ú ârkkøsã?]ÛòJTÿ'§?ñ?¢kÁ\ó'´nÑYÓì(;¢×ö¬çq‘PìOº+Ü'tú4è¸X©È¦O·é) € € €L‘€£¼A·†ƒíþÛÌϹ/´ª»X>lÛ­¤kùýöšoE?FÔ*#z%lœ^ ¿Úö”]àôÛï÷M<Ü^¸Þú?õ«ˆóþ+}Zååfey…îºyn°NÚ|}.´ú½ø™Gí`{ð¢yVì’\™5C¶~ýpO0Ðí¿PÑXeÛƒÓ´öé2»Î‰³¡þyÃ{Eïí‚Q;þ{l±ÏTœü;;ØnÌÊÛª–Z«wMªo 惷®ûßã¶3e'c®"ï=t¿ÉØýAvë5ôzGë…¨œü“ÑŸ±ŒßîÏ¢tõûW¶GÛËÝÛm v¦R€îS©›àm§’R&Ágˆî!€ € € pm¶?ñà°.0Aá³¾­Áó^¯<½½òô} ÷ßïVWÛª/áV7xÂ¥¯üùÒa×"Bךg]{³n³öõ¢sϪ¼ö¿¨ð•ºwq¶2¬Ôó»WÚ%‚;Y*9xÖ¼‚GÞ~z=}ðþûêîîÒ?¬ŽH7cUÔ€Ùwé‘Ìêú¡[Öút¾Uƒ¦£)ó½Çqä=еáþÐòù!5ïyàsæLpü¯;?ru v¦æÄçjÈííCº§”=Ç>Øù°«C??Z)+QåæÕúÑÛ&eÎî‚À ó‰÷glã·{W¿Q í_øÏVéµÝkYÙn±3•ܧR7ÁÛ¬p'¥L‚ÏÝC@@@àZ i颴˜7ó´Ò·«_ÐöýVrŽ˜ÅF<9ÒÊ÷a’s´£¡Bû w†.5©r‹y…ŽÎb=ñT‘ý³<-ˆêªG§[/Tm·ƒ¿ÃÚŽ<Ñß®Fk(Ît{T[VÁ4å,=eŒU2æ{ä=\˵h„(\ò¼ù_D'g ··]¨ÊDç*|çÈ=‡}ªD¹±Æðünµ¯Ö’Âí ­•…zõ‰ËZÊë3ÑþŒuü‘½ï׿v~UY±.ÏÞÇ>ý®g"ZV·®JRÒ'’¬CÞÀÄ?e0N[Àýãÿ1m»OÇ@@@@`RÌ’oÿ²ó!ÁçÎÕZ´&Lz;gQ‘>¨æ4zm¼ÇÙÏ«çÒƒúÎK&Àÿ¢¶ÖÚ´_¥þ—y0jc×Qåûó¡{;Týð∇ŸFÜÙaâéø@õ¡\ñö³lÝ^àÞ4<‹]n";‘÷蹡ä25äËcº2usåÑàeÓ•ôØÝÉ)ئƊãZ³3øÚÎý…Ó4uý‰Ý‘Ï6©°è»ê9Qb?`ä²£_yÿ¿ût~ÏïG/4‹®œNÖ'‡ü͘EÃ9Tî1YfÇÉ9&¥Lï/þ0;Ë(@@@@`ìÞ6}#"Øî,«Ñ7¾òˆ–~j¡ÒÓÓ•f"Km…7hÉFë©¥c¿E¬9yڶǼ*=ê|ï¢þ½ù55}ÿ»zÑÊ]bƒ¹æ¹kpßZu¼º;"ØîTÍ‘o˜1Kµ03]éiþHà“±åîè´2))áÔ5Î?V(ü®xÕÛÝ+¯9›œ–®Œô1F#ïaçÌr sèy÷MÃÔÒ(qùᇞ¹Nseuc ÅEèÌuîOqm‹ö=‘¢M)ŽàÜ7mѳGÒ¾õCŸC` ¾÷ÏüÕ'ä±!0’ŸŽ‘dfÁyš: &™!"€ € € 0o×E]´êÕɽg«òrs´ #l÷_êü•]Â*9îwoç)íÚ±C;vTëT§ u›@wVÎr­}l«ö¼zV}—ÜrZ­_üŸf•ºWÿß¿žqèÐùkëú<åd-ÛÍ¥Þn½gÕ±ÞÓk¹+tÐôªÞè¶.D¼wþT™ j¡y=øí³âܼ‡»A¿è]ïâk'ì ËßlïugªçÊÿ㇑·~}t›#|Ùžêþ„ocÏY«¿-Yn¾)ÉUUC¹]`ÿ†'u*Ö\Û%ØA`âÜ'n8m[HÍ”Føc?mEÇ@@@@`òÒïÔ—Šƒ!nç]9Ã2Šx;ëëÛ­•Í&ßÈn_~ÿ í¬¬Teåvý µkØ8ÒÍÊ÷;®{Å\÷èžm •›¯Ûoº Ý«&5ÕCͱ:˜®{VX¡û&}³îÔ°{5××ÚçYz»½oïØmÙg†ìÌUö=VgÝzá`óëæÐÓ¬=¥VÚ§¾7Õ×S:Wéº!öÏüƒÐ‰½¥Ú°ßš§îý´ù,Li†SF‰øEAVA¹ê¬/WÌ'aõW«?ª0L®÷ÉõœV­¥f$i Ç7­úLg@@@@àÚ ${;õòþ`¸ºiç×uàT›<ýýê÷t«ùØ^=¼¨0Ì6‰;^kbˇÓo¿+ðQÿ_,,ÔÞìàh¿§CGwmÖöP\×±ê^“;C÷­³¢©&p^q@m½õ›>v·5koÉÃ&¯¸ЖܯµÈêaÞ–çì{5m_­M{«»ß+¯§SÇ÷–hÕv«žK®¼lÝÊýî~­IgÚ:äñ眉¹%«àé]öwéªÐ=‚§ú;›õÌçV…SÝ”mÓývñ1ïLí\ի诫µwoµª«ý¯½ªöÿa×mZ6OkJÃ)…œU•Ê7'Úþ\…§/òzºŠ^vÛs­úª8ÞY€}&U€î“Ê9½#¥Ìôš/z‹ € € €À5ȸOÏˬ^öß¹I›W/ÑæQ:±eÅB½vè¼>¶t”R£\Ê*ÐKN­<|³U¥kî6HuÈáhU«µ€:PÝ©=Ïäöîy¤H ­ozq³–˜×ˆ[ýf-¬ÿ7¿¼OKäëGʵdCe x}i¡êK‡×,;ò‚VÆ „›Â+ÌËYÛª%¹Ã+úÏd­Uk]±›ƒië³ð=z ²ï«Ýèvd—•òžÿg5Ô˜(¿½ ¶;ËÔhr¹ç/HËY¯÷NÖ†W0ÛõÌŽ)Ûp©Gí g/êÃPBòœõ»Mݺp^øˆR’Ku'Ûµ'ò!›i˵óPYT)] 5f!z¼¹ïÓ¥†š¨þEÛeuj¿¼G¹‘ÕFh+úÆ¡#»ìøçj¤ÏÀœÈ>ży𤫸Bç»tp[¾ÂI}ÆßŸðç!ŽØã7}±ö#RÊXÝ^þÄ *·?§õzÉm¦Ë†À$ùÌ6íÒä$ ÌŸ?_ÅÅÅ&wYå$µÝÌáäAmèIVʼ¤è !€ € € €½çôf[·SRtã- t×K•aEW½½jëè1©œ«ÌÛšóZ«¸«··C-oœÕ»=JMM•ù¯>s—Yí¾4+öJðþ^;û¦º7¨””µà?Ý¥¥Ùá¥éžÎu]öjî¼L-\݆ף¶óõ›Mz“æý†›o×’œîczç5)uºLn™”¹ÉJOÏP\à ôï ½ókÿxôÑÀMú£e¢Üˆ>FpOh÷ZÏÕÕ:›hý¹Z¹ž˜IIIjooWvv8ÅS"ö”€{"ÎJDŸ¦:à~tÁ  þ=Y7ep`g@@@@H`ºÜI)“@šëÑ•TZó4 € € € € €ÀĸOÌoÚ×NÍHÒ@/Y…¦ýD2@@@@¸îܯû\ßœÚ{}ûÀÝ@@@@@™ @À}&ÌâÆjžr…”2¤* € € € €  à>Ë? ¤”™å† € € € €“&@À}Ò(§gC‡¦’RfzN½F@@@@„ àžPÓqí;ãO)3@J™kÏ@@@@@`Æ pŸqS:¶‘Rfl^”F@@@@F à>’Ì,9?'“‡¦Î’©f˜ € € € € 0Åܧ8Ñ›¤”éõ%z7é € € € € ðÜ~Ц¶ƒ©™Ià¡©S‹Lë € € € € 0+¸ÏŠiy<4ud® € € € € €c à>­XÖpì“| ­Ì œ^†„ € € € €×P€€û5ÄNÄ[%ÏMÒ'R¥ß&bïè € € € € 0}¸OŸ¹š²ž¦fš€{Ï”5Oà € € € € €À¬ à>+¦yôAò¸÷’Rft%®"€ € € € €£ pÝgV\“™¤+¬pŸsÍ @@@@@`ê¸Oí´i9¸Â}Út—Ž"€ € € € € )@À=!§åÚv*Ô2×»!€ € € € €ÀŒ à>ã¦tìJÍHâ¡©cg£ € € € € %@À=ŠcvÌÉzgçØ5 € € € € 0YÜ'Kr·ãO)s…”2Óxé: € € € €$‚÷D˜…ëÜRÊ\ç àö € € € € 0#¸ÏˆiœØ RI)31@j#€ € € € €F€€;Í1)ez|H € € € € €L@€€ûðfJUJ™+<4u¦L'ã@@@@@ë$@Àý:Á'ÒmýM àžHSB_@@@@@` pŸ†“6Ù]N½EúýïÌk€´2“mK{ € € € € 0{¸Ïž¹q¤ŸHIRòM¬rˆ  € € € € €@Üã@š EH+3f™1"€ € € € €ÀT pŸJÝiÔvj†YáÞCJ™i4et@@@@L€€{‚MÈõêNjFN½^øÜ@@@@f„÷1ÄœLéJÏÄÛ¡@@@@@`¶ pŸ­3?dÜ”2½¤”ÂÂ! € € € € ·÷¸©fvÁÔLRÊÌìft € € € € 0ÕܧZxš´|hê4é,ÝD@@@@P€€{NÊõè)e®‡:÷D@@@@™$@À}&ÍæÆ2‡”2У* € € € € pçSð¯p¿Ò € € € € €Àx¸Wn†Õ#¥Ì ›P†ƒ € € € €×\€€û5'O̦úSʰÂ=1'‡^!€ € € € €À´ à>-¦iê;XáþÛ©¿w@@@@@fª÷™:³cWêÍÒ$ïǾ1Ö¤8 € € € € €€_€€;Ÿƒ€@Ò'’”z‹H+Ãç@@@@§÷!pÞþ~õ‡^Þ!×F?ôêy½c«5z›×öª?­Ì•Þk{Oî† € € € €Ìî™ô¨ùè^mÊ_¦”¹s57ôJIZ¦’]‡u¡{ä z÷9íÛ±III)z)))JZ¶N»WçÈÕòóxpj/)errè € € € €$¼wõêÀ¦yZµ¡TõM­C&¬UûwnÔÝ S´·¹{È5©÷ÌÍ]èЖÊúèk­níÜ\¨E)Ïèœ'úR"œÚ“È=¤o € € € € €@â Ìú€{ÛÑgµ9"^î*«QCc£Õ”Ë1o¥«žÓ…þˆÞ zvÅæð G±54êH]…œöÙåxê°¦KÌ=p'¥Œ={ì € € € € €c˜å÷NÞµßöªh¸¤W÷lUA~¾Ûº[g{ZTfGÝ÷ë'o…£Ñ¾¿GvMG….µìÓcùZÿøó:Ñ×¢b«Õúúçi²Ì}Nf’®ôRÆš:Þ@@@@@±Ìç]µXYdŠÝ*/ȉ¶ËX®²çˢώºu¬Ê·ëÈÊ•“Q,}¹v¸Ãõþ±á­ˆ‹‰»Ë ÷Äz† € € € €‰/0»îºA÷„V°;r>¥È˜¹5u^}lí†ß{/踨wTéO£¢íÁbÙ÷ÿ¹’¦éø/L¦øÄßR3¥éÐÑħ¤‡ € € € € 0 fwÀ==W¯u©½½] OÞ3|ú{Ï襈”3·Þ<7PÆóÎ[j •vn¼_ †×”2²õˆu¾é5½3 ¹§f$i€”2Ö¬ñŽ € € € €ŒI Ö¢î150Ý '§/PvzxgŽë'zÔ×öº¾»óEY Ùå úBNZ `JJ¸ü¼´Ã‘{É u—ËœpûOz4y-A÷I)“ C·@@@@@`ZÌú€{ô,ytts¡J­({Äŧž~HÁp»ÔÓÝe_¹íÖìýÑv"bô£»®×æRæºúss@@@@˜Þ³;¥LŒ¹›çpÈá %v]7§´aÑ ëèœIÏyPe¡"ËsÅhezžò§”¹BJ™é9yô@@@@®»÷¨)H×ãÏê쉳ò ^V{kƒŠM`½5°â½U®ç~ ÈÝûþ¿éÅÐ*ø3çÞ‹ja¤ƒ‰¤”ùýï¯ÁÁÁ¸_>Ÿo¤nŒzž”2£òp@@@@&I`,ñNÙé²pi¦’Ó”[ }?m”Ó*Sÿ}5?M¾áfëŒ~íùØÞºsÅ>‘®È¼ïöé8v¼^¯¾õ­o)555îWCCC-/’jRÊ þVoÀ~x‹œA@@@@† ÜrË-qÇ;ý±Ñé²Íê€{Çñ]JJJ2¯|;]̰‰[ð€þÒÿðÓÐ64»ûÌ/åµ.F¾{.ª!ðÀTsÒõ9Ýi%€,Ç~rr²¾öµ¯i`` îWaaa-/’rS’dþo°oø5Î € € € € €“%ðÛßþ6îx§?6:]¶Ypÿàí–Ð<5éÂû—G˜3º† Óï|@EVéýÿ]烩ݭ3÷Þ·^“owæVéQWÇvðÉO~Ò¬O‰ûåÿa¼›•û@ïxkS@@@@¸ºÀXâþ²Óe›Õ÷ù‹ï°çiûKnÅŠ3w¯Õö¦P1g¾îðGÎÓتº_Õß»`„Þ;õòRûÜ—œ÷Øû‰¾Èãޓ轤 € € € € €@â Ìê€{öÃ_ ¯T¯ß¬ÌuÕ:ÓÑ+ÞôÞî6Û[¢Å…;íY+{êeŽ’õŸŸ®µÏ×o¾[;ŸRgw·º;ΨzÝ¢ˆ }­¾˜;‘õíöm®ÉNjF’Yá>¾‡®^“r@@@@@ AfuÀ]i¹ú¦»<<5îíZ±83º%sá¹J÷‡¯Õiçúû8=÷ 5V8íãÊ«µháB-\¼BÛ­\2rÈ]÷D(HoMè9¤”Ièù¡s € € € € ¸³;ànæ%{ín½wºNÏE2[U:­Ë8OVþón5TÙ¹e¢ë9Šä>ÿ3­ÍNŽ>ŸàGþ”2WH)“à³D÷@@@@@ ¦W4xгV>®W}¡ g~¡·Ù«Ô›RÍr¥ŒO-ֽޥÊQ)]ÛöiðûºZqA]¿ó?-7Õ¬r_*ÇÒ,XmŠÆ1Í’Rf2i@@@@f£ÀtŒ OÑ<¥kéò<ó{óÉéYZž—5öŠ X#ÕŸR†î 83t @@@@]`Ö§”Iô ºÖý›cRÊðÐÔk­Îý@@@@@`&pŸ ³8‰cHÍLÒ•ÞIl¦@@@@@Y"@À}–Lt¼Ãô?4•”2ñjQ@@@@ üÿìÝ}tT÷çùOa•°KXÂ[Ä-ˆŒ#1¡Hàôt,'’Ó^ˆ7ˆÙöCÉXw$:›ƒ ÛFH÷ @:ù8$w·èAuìd(¦˜Ù e±Ç†ãФ¶vÐØÈ–‚*FOe´·%JWu«ê]9²nÝû»÷~¿¯ŸþúòË÷GÁ}À‚#CÀ_pïèÇ@@@@@`œÜÇ ïÃSŒ–2½´”‰÷i&?@@@@˜ îS€Ëô­pïiå ˆ@@@@ˆŽ÷è¸[ö­¾‚»×#Ýø„¶2–$C@@@@K Pp·ä´D/¨ÛRmº-ÕØ8•¶2ћތ € € € €1)@Á=&§mjƒlœ:µïàé € € € € €@¼ Pp·„|’3}+Üi)3 ”<@@@@H€‚{Mv¤©&gØÔËÆ©‘r1@@@@ð PpçáZÊÜB @@@@@`L îc%Þ€ZÊ$Þ¤“1 € € € €LX€‚û„ ãï¾–2=´”‰¿‰%#@@@@˜R îSÊ›§¥LlÎQ#€ € € € €@t(¸G×ß’oOöµ”iï·dl… € € € €XU€‚»Ug&ŠqùZÊôvD1^ € € € €Ä ÷œ´©9°iêT¿…ç#€ € € € €ñ%@Á=¾æsR²ñõp̤Xò@@@@H î‰3×gJK™ˆ©ˆ € € € €„(¸‡)8 ø7M¥‡{ˆƒß € € € € €@DÜ#bJ¬AÉwJŸ\7~zú+q²E@@@@& @Á}xñzëŒ$›’R/«ÜãuŠÉ @@@@¦@€‚û ÆÃ#S2‚{{ÔƒoAÀ w8@@@@@" à©T‚ lšÚŸ`Y“. € € € € `^€‚»y»¸¾“MSãzzI@@@@¦@€‚û ÆÃ#i)³H € € € € 0I“ù2ow·¼}}ê3j·§)5uR?™¡ò¬1쳤þO$ïÇýJºÝ6Æh.#€ € € € €L "Þ­ËçÞÔoúþ߯&t5É}‹§S…¥+´ò/éK_ú²–äe+õ–1œ°¢€ÍfSòRO»Œ‚»#$&@@@@@ÀZã/¸{ÛÔøó}úÛ’íj3·š|?uÁ‘Ūy©Jë].ǘ÷2 Ú¡¶2·ßíHx? € € € € `}qÜ/4Öê›m¾Ðî,T±sžæÎœéÏúúõtÅ}QMîÁëÞ]ªxÌøQ¡ö}^O­ÌÓ¸°¾g\E˜œiSo{¿‘-eâjbI@@@@¦D ¢zwwÛ=ûeªlCa™jþâß«p¹SóçeÉ1B¿vo·GW¯\’ûT“þ}…üËâ›´aU¾6Véd}•–ç°Þ}¬eC+Ü- € € € € €˜1flÝgôõ¬b{iU½N_jW¿±Ú}ãÚ•Zœ›=b±Ý÷ì¤T‡²skåÚ:ÐØ¯«ïœPͦâÀk›ªµbu½:Æ ‚ÑHÉ”z™œhÐóN@@@@ˆA± îI³´ÈH¬xÇA½ÓÞ§;×iiN†éTçähãžÃêºêV}U¡4;…¶2¦5§öÆä ›±iª¯¥ @@@@@±Æn)“”«ýã/ºz=êèö*))U·¶ŒI³Xëv6jÝXr=j´”‰=/F@@@@{…û¨IytæØ~m-/×Ë-žàH¯ÎÚ,{z¦²²²”™™.Û’rk¡7ɨ”¼˜LK Î !!€ € € € €€UÌܽ—µ»(]ËV­Wu]Z¯{ý9¶½ú-+Ù;4_wVågjÿ¹PQ~èe¾YS Åh)ÓKKkNQ!€ € € € €€åLÜÏ<_¡Ê¦|Ø»õJ]eødaÙ.ÕT7H5ή¯8Ä©aëøZÊôðL°þD! € € € €XBÀ\ÁÝÛ¢Ú W02¼Ò¥ò¥FŸvÏYnž.Ü¥k·hãÎÃ:Q,º7ÕE¹[bâ# ÂßR¦=’‘ŒA@@@@0Wpﺮ‚vUÇ¿¯åÙ©þož·O)\†ÿ‹Õšóǯ ]Ô»W»ƒÇü²º@²¯¥LÇø7̵z^ć € € € €L…€¹‚»]2Ö³û?9w†Ž¤·_k Çø¥åóÃÇ©ó—©ÔÿÍ­w?ì ŸôTB@@IDATçÀÚ)lšjí ":@@@@°”€¹‚»‘B¸3ŒQ||:ôëáõí›´4'°êÝw­ûÒi:Í8•wwZp<¿¬.àëáÞû{©¿ŸUîVŸ+âC@@@@è ˜,¸ÛÃ+Ü7ì>¤V¯táÈ6Q-û¢îK %çÑ?ïÙü²@s3 ñ¡ü¶¦@Òí6Ùn“ú®Y3>¢B@@@@¬$`®àžºXe; y4lÐ<»M÷W‡óÚñÄ—”$¯Î©UyQº«s®éÓhÂã9°®me¬;7D† € € € €Ö0Wp7r(xúyU9‡I¦°FŠ|Û¥véõ½T×40¦¾f}x#Õ³YYÀ×V¦§ÝÊ € € € € ` pã—q‡“𧧝ê+ ûTø´¿§ûÜeëûUko)ª;Kw蹿}Zƒúºû}Üä ›z;|=ÜmQy?/E@@@@bEÀ|ÁÝ—aÒ­Ûfü —®COýªS÷Ù•á oûpB±p.9ÓØ8•î±0UĈ € € € €Q˜XÁ}Œà“RÊ Ö>†’µ/ûZÊV¸[;N¢C@@@@¢-0vwïm-*Òî#gümc&-àî65ÖnÖš­GÔ=iåA“-’ék)3ÙOåy € € € € €@ü Œ]pïúP'›šTY¼Lé6£ð~èUµN Bîí¸¬#µ[µ$-KmØ+Wu‹±½*« °iªUg†¸@@@@@ÀjcÜËôÂñ}*ôGnÞKÔ¼4›žÜZ«Æ3ÔáñŽ™SwG«Î½zD»7¯‘=s¾Š7TËí»ËY¦£Íߔѵ„Eh)cщ!,@@@@°œ@=Ü“”[T®Æ®¯éåg+õXeƒ?‰†ê j¨äã,,ÖŠ% ô©{îѬÔYÆÉu_{_ÿówïéìÉ5ù«ëCs¯:xRUk—Ë1ô4ß,&ìo)Óo±¨@@@@°ž@÷`ЩÙztËu•nÑ?=·Mª]álÜM.¹›Â_G=(ÛuP›¿ù¸ò2"õ¨äâ” øW¸·Oé+x8 € € € € c·”¹)ÍÔìÅ*ßyX]í—tÂU¯ª²b9o3䫳P¥›vé¥ãn]íêWí–µÛ‡Yû -e¬=?D‡ € € € €Ö0½Ì<5#G«×ùvÖzåéðÈÓÕ©¾>_rvÍœ™¦ÔÔ49©ÖÉ–HÆ-b´”éa…û¸Ý¸@@@@OÀtÁ}(U’þŸ¡çùëñ#€ € € € €S/0î–2So°’€¯àîõH7¼lœj¥y!@@@@°žwë͉¥"º-ŦÛfJ½– ‹`@@@@@Ë Pp·Ü”X/ ÚÊXoNˆ@@@@¬'@ÁÝzsb¹ˆR2}+Üi)c¹‰! @@@@°”÷›§ÃÛ­în¯¼Ýuxºo¾šß“3lêiOÈÔI@@@@ˆX )â‘q>°íÜ1íÙ½[Õ MF¦N:Ýjr‡…¥ªÿ›h]Aî-ŽìÖ^¹ »fM·ý\ׇ×sõ×5[”—:쀘8IK™˜˜&‚D@@@@( Pp7& åÐfå—ì4Áb»ïLSƒÖ?ÿ©Ê¥_í\­Áuó[Ž©¡ÎW íS¬oÿq}𣠷àµd_K™vZÊXpj @@@@,$ðwï…—‡Û 7é¥ïýošÛûž~¹¯D{]Ùjª.ÖŽ¯hçÊìàôyôÛ×CÅv§œÎágÕíž+ûð—b欯¥LoGÌ„K  € € € € €@T&Tp÷v\Я]¯è¿¾ñ¦.~à#NuÎý ¹j×Ê1ÆÈé¼üÆ¡ç^WV¯öÚuÊž)Xù¸¾^»^+64øÏTW6hóÊ-šãÿÖ®« kêÕ¸qið®øûåÛ4µç£øË‹Œ@@@@@É0]p÷^>¦‡ç¯RhwDA>!oD§kP‡þ¥)”A©N× Û$iù7¶¨Ô(¸ûKîî×õ®ñï s|ÿbÐý‘N»£ ?{÷t•÷øz¸w¾Ý•wóR@@@@@ VLÜ=j¨¦ØnôUñuVq ÑCŒ“é)2ù¡š¬ož·t8To/|@ ‡ë³žºPK ÁÖ2¡ö0ÝWÞUð”îÍΚ¬ˆ,ùœ@K î–œ‚B@@@@˘«w¿­ã¡j³ Uâ}ý ¹J5÷´èa8–è{ûvhIK»Ò,¾×ºç¬‡s•ú‚Ñö]è±rõÌϵ»ö¨^?{EÆõôô…*z¼TþxæÄšÉ0³áß4•îÃÈp @@@@˜p9¸´þy­+ÈxbL¥ª¨|›ŠFŒ¹Mûÿª,¼’]Åk´(Ø€þÒé×ÂwU–”„Mr¹êTQR,Wó­Î ÞtÓ¨Xùêk)ÓÛÎ ÷X™/âD@@@@èÌ0õZc™wh‹Ô–Í3õ«ßÔÝzJ[‹²´¾n ?Nýÿ,¼ák_gPÀh£ãÿ–ªjÇm*-”šKÅùÅjl³VçúAFth)ÑP!€ € € € € +`®àî¸[Ë‚uæçößã ¯»UGv—+mÞ U‡ú»Ö¿¤uá•êzí‚}fŒ†õ»Ž6«¿ñ€vnÛ¦=ÕùÎq•…UšôÐ÷~e±ÍbÃÁEt’)õ´G4”A € € € € €@ Øú™ì[•+¿¤Îk͉+ÚXmæ1ºÇ£3/ÿG­¬RkÚð «t¢a» ²‡î¨ÚÑzYí]]êK𫼣çÊMï…C²ßj5S¦æ®Zå }ÄMw ÿ533S<òˆþò/ÿrøÜÍÏÏWFÆ­1 34¢S7>é×Ïì^}ýz’nKµEtƒ@@@@@‘Nž<©7nŒtù–ó_üâuéÒ%åääÜrÍJ'LÜ=FË•o«À‚ÙWÕèÿøÊç5÷öÛe·›‹mg†~Œ3•ñ‹s4áÆñC<ñoÞËÚýð|UZÑ.kßñê©¢<“ñvèÙ¢LUøŸY¬“‡µÜD+÷;ï¼SÉÉÉÊÎŽü4ž{î9=ðÀwô„ŸßÙ§¯5')í îƒX8D@@@@_øÂÔe,hŽôsöìÙ˜(¸›¬}w¨~Õ@±Ý‡âª®0~ÆàqÖ¨ýìFMÞÚë1ÞÑåí_?´Ø^UBO¯+5N¯7З=)i$Â4¥§GÀ¨ƒn»í6=õÔSª® wÔÇLø¢oãT_[™´{&ü(€ € € € € .ðÆoŒKÀf‹…Àæz¸k¾SfËòƒÏíߨõ¡eúFçõ—º´sŒb»ç\­±ŠßîÿÙ|äòð¹u¿­7\¡Ks5+-t›¿}÷ÞS݇b3a¢F@@@@Æ)0Òòì1ãÐã/¸õ¹¯Ë(;ë–î1ÃÞÝ'û]ŸuÕø°·MåIïýc¸Ú^¬íµ*çòû½{]Úºz£æÜ空m t¸7.lzD÷™”¾é±Qûšœi3 îQ{=/F@@@@,/`º œ‘»XËs-Ÿß¨z¯¾­ÆA#~sàY½ÑÝ=èÌÐÞž,­}zró¿¢MÆ¥½¾ËMÊz²['Pª%9Y’çŠþù¹ =¶=¼¼]Ë6Ù~èû£ùÍ¿ÂÝh)Ã@@@@@`xÓ÷¡óª£íª>xÿ#]»þ{Éž­eKsÕÕÖ&{Æ¥NÒ[†¾sâߺÞKîðc\Ú^1P$ŸrP¨‡7÷Ô\m=Y£½+*W*µÂøîSºï¤Öæ¥w)¦Î¥ÐR&¦æ‹`@@@@@`úLöpêÕ¹#Ïj̬ͮyÊw:µbŃZ±þyÕ­C_ÉRš}‰žyùŒñÍzod½p>Ïh øÌY¾QíÍGµ©pÐå!‡Åª?qIÊ—9«_|-e|›¦òA@@@@^`kϽ:öÌÃZµ½éÖ'ÏN œóo¬êÖöÇ–i{ÙAµ×®µT÷ £hÞß¿ñÖø#<“‘·R{ûµ½µEo]hSo_Ÿ>îíUƼ…Z´8WŽŸ Ã|-e®ÿ."%F@@@@@ :¦ îm¯þdH±½°l‡VÎ|Y•{&-é¾dRõ¹'ŒNçMþNçR]‰¾û§ËUûhŒ7~fž2²ó´Üø‰ço…ûïÏ݈çÉ @@@@˜€É–2ýòÇ=Ë÷¼¢ÆÚmúNùæ@0R—q´¼|ºÞq)Ôu¥î™_¨uBárs´ü=Üi)-~Þ‹ € € € €1 `®àÞ}I¯÷-ÜuRå˳ý©võõ„S-OÍ]­zWUà¼ûu½ï á †|-ez:b(`BE@@@@¦YÀ\Á]} ÕÍŸXµhÌÓç¦ǸÔrÅŠÛ§Ž™BÂðµ”éíèOx@@@@@‘ÌÜûwµmìzÚ̬à NÝ‘Zû>𠎬/à[áÞKKëO"€ € € € €@ÔÌܳµÌˆyûæ=º Ç3|‰%ZÊÄÒl+ € € € €L·€É‚»C븵)mÃze•R[w‡Ž=[®ôûÒ^wè¢ñ»t—N_íÒžµKýmf]á0†RŒ–2=í10¡"€ € € € €Ó(àk³nîãX¬=FU=Ý)ÿ:öºeÕÝü¨Bí;þ‚Ê‹ro¾À÷ð·”鸃‘2 € € € € 0õ&W¸óÝO«l˜8Kw¼¤+]Û‡±‰ÕSlš«3GÜ € € € € 0+¸û"t,UmçÍE÷½°íQe§NG ¼cºü=Üi)3]ܼ@@@@bL ¢–2Ý­ú ³oäÔì÷jëÉzÕ­XS¡¯ï¾_5¥N©oÐ}ötådgŒü®XZ ÐR¦ßÒ1 € € € € -ˆ îç”jYEÓ¸btU®’«ò¦[œ5j?»Q”Üor‰‘¯¾MS{;b$XÂD@@@@¦Y`â-e¦9`^=K™kRÿ V¹Gox3 € € € €XU ¢î ‹ktü³m²Ûíæóðµ–™“Çêvó‚Q¿3i¦M3Œ¿˜^£èžÂÿM!êóA € € € € `-ˆ Å*ʱVàDd_[cãT îÑñç­ € € € € `]éi)sùl6›lE»Õj] "‹@ÀßV¦ƒ–2P1@@@@L ¢î#›tëÜ«¿Ñ¿vô*y„AÉÉÉrï. \mz]ïy¤lǃ9my”L§Z~–@@@@¢!0‚{«j×ÌÓWda;’Û-£|dãeMß ÷£¥ @@@@@¡¦[ÊœÛ_q±Ý÷J_±½êà3Zš:4¾Å–-ebk¾ˆ@@@@¦OÀdÁ½U‡÷4£,Tý‰wtõ£* žqî8ª+W¯ªùÄA‡sÙ¡Ík‡¿q›É´”‰Í‰#j@@@@˜rswÏû:m¬X÷}6¹êµ® WsrWêÛ»åõÙFG÷ì9s”W°V/_9ªBÿÈíúæ³§üGü'vü+Üi)»Hä € € € € 0eæ îFöо§y 2ÃÁÍœ8ljz[ÆÞ¨þORöJ½ðÒ&ÿ±«Â¥ËÁóüŠMZÊÄæ¼5 € € € €L½€¹‚ûq}êsE+M-ºê”õéÁ/çõ~¨?p™£H1Zʰij M¡"€ € € € €À´ ˜+¸÷)¼‚ýèÑóá`“f¦õöÕðé!Æâx>1,Xáà : € € € € 0Eæ ZÜ!ÕU¹BO>sHçZ»åXøÇÁMRÝZõ7‡ÔáºM¿¨ý‡pøF­žO $„z;úc8BG@@@@¦FÀ\ÁÝèà^¼y_8¢†í%*m0Vº§.ÒšÀ¾©R]‰2mK´Ä–¥õuÁVµHw¥…oã ’3lêeÓÔœ9BF@@@@©0Yp—2––ëÒñšp|³S}‡©*Þ>Pˆ—ÜÆÿ>»NlVnÒÀwŽbO€–2±7gDŒ € € € €Ó#`ºàî /§h£ú»®ªù´[/–-õGì+Äw¾s\UÅNÉY¬²ÒB9 Ëär_Õ–‚9Ó“o™2_ÁÝûéFme¦ ™#€ € € € €@L D´Þ¼ã«:zê=#ÁL}ùñ•Ê|Wêå-ZHwäiçá³Ú“$=šÀmÉ6Ýv»¯»ñÿgÈm$×@@@@@Ä\:1ó‹¯|_%MÆõBüšQpwŒ8” j+CÁ=&›@@@@@ bˆZÊØSæ˜.{Äf`¼ ¤dJ=í´”‰×ù%/@@@@0'QÁÝÜ£¹+^’3lþ–2ñšy!€ € € € €f(¸›QKð{’î¾î|@@@@@ÆYpwÈž6p3G‰)àïáNK™Äœ|²F@@@@"Ú4uàn·Ž>¢+ÉÆ ç“‘ݱ@-Vjäw0Ò‚)´”±à¬ € € € €D[`Ü÷ÊÇŠÍÇì¬QûY îæ­q§¯¥Lw›5b! @@@@@À*ãl)c•°‰#𴔉¦>ïF@@@@« Œs…»S;ê+•oº¥LžhoÕ?…ÈãJö·”éüF"€ € € € € 0î‚ûšÒµZ<λÀ1¡RL1ZÊô¶'TÊ$‹ € € € €Œ)0Ζ2õuùLĹ€¯¥LO+Üã|šI@@@@Æ)0΂û8ŸÎð¸Hδ©·#.S#)@@@@@À´wÓt‰{c`ÓÔÄÍŸÌ@@@@@á"*¸÷õ\ ÞÛ©¾ážÂ¹„H¾SºÑ+y»h+“PO² € € € € 0ª@DÛŸ.xx‹öí{B=š­»í£>‹ `›a“}–±qªÑV&)-&E@@@@@ ˆ îy+UžÁÓ’0¡¶23³&eE@@@@Fˆ¨¥Ì¨OàbB ø î´”IÈÉ'i@@@@V€‚û°,œK %Ó¦žö±Fq@@@@H î‰3דši`…û¤>’‡!€ € € € €1-@Á=¦§/zÁ'+Ü{i)½ àÍ € € € € `9 î–›’Ø(´ijlDK” € € € € €ÀÔ PpŸzã¸|-eârZI @@@@& 4{ÝêUGÛU}ðþGºvý÷’=[˖檫­MöŒ9J¤· z!‡Qðmšúû³7¢¯G@@@@¬#0Áî^;ò¬ÖØìÊÌš§|§S+V<¨ë_‘WÝ:ô•,¥Ù—è™—ÏßøÄ“€o…{O{ € € € €L–€ù‚»/‚Œ¥ÚÖØ§æµ©x ò^ZVŒ¯PU5.]ê<«òåÙ“ó”<§íÜ1m}²H6{šÒÒ–éáåéÊLO“­èIíõˆïìn;§Ú­OÊf³÷¥Én·Ë¶džÙL­q^{wÜ']Oú¤›Uî#þp@@@@FÀÖo|&+[¯±Â»«Or8’äñt)ÍáP,l‘Úrh³òKöŽÊPXåÒ¯v®Öà5úgö+sÙúQîÛ$wç-ž@ßúÙ³g«¬¬LÕÕÕ£¼'z—ŽÜß§^LRæçmÑ ‚7#€ € € € €@\ Øl6]ºtI999–Îsb+ÜoJ-)5Õ(¶ûJÒIÆïØ(¶{/¼<´Ø^¸I/?¡G}«ölª.ÖŽc­'¼-úîàb»³L×Kõ;4°Ö¯œß:$ÏÀ]qwÄÆ©q7¥$„ € € € €&&¶ÝsYÿå˜~ýæ}t}¬®ëúìÇô¼±J| ¾Çzɸ¯¿qèù{ÊêÕ^».¼±kÁÊÇõõÚõZ±¡Á?¦º²A›WnÑã[ËÏ÷¨.t§s‡Þ9½M¹~Í"=úg¨<}YàzC‰~±åkZ7‘eî¡÷Xðw:§ZpV @@@@¢!`ºàÞ}ù˜¾:•šÆuázv<ã§|l‡þ¥)”A©N× Û¯NÒòolQ©Qp÷—Üݯë]c¹úG›Žì —ÛõÒ/«‚Åö`ÀŽ¥ÚêÚ¤ºâ@›šÿtô¼Qp_>åÙDã¾îïýçÑx5ïD@@@@,%`²¥ŒGÿ´~œÅvÚ=–J^ž·t8To7þ1`áàí¡HSê¡A­eì¾ó-:æpîÒ—KÛCwøç|ákrÏ4û­:†\Ÿ/³ò¥ÎæþøIˆL@@@@@“æV¸{ÞÖÑP¡Z¥r¹wé«ùYòz½c„‘4dÓÑ1OýeÇ}oß-iiWÚ‚…òÓo~«ç¬»N{ÂÊsñ|xeaÉü-fF2rôˆqè¯Ë7½¦‹žreX©—Î-›;‘þ›þð®tÃÛ¯IlœjN‘»@@@@@ ÌÜÊt¨v\Zÿ×Z½8Ûo‘”dîqуLUQù6@›öÿU™Âõöâ5Zd$nT™OO½}ø»“²t¿oe¼ÿf|…úxüØ6¥Þmü#Ä[Ò¬Eñ˜!9!€ € € € €‘ ˜k)cTVæþÏ]w ª>GöΘÕÝzJ[‹²´¾.Ô;FªÿáŸùÿ¡¡½íj8‡¹wÍ vŸJŒg±qêhSÏ5@@@@Hswǽ* 6(ßûÌ/ÔOXÝ­:²»\ióV¨:Ü6Gª9~Iëòëú¹_Ö¦`þKÏ‹§ìMåâÛ8õÚyú¸›Âã&@@@@ˆ“=`æèÏŸ«QŃF“òJÍ+ú½Ž?ÿmýÉü,f´>îF÷T“¯œrrμüµþ±Ê@ßõÐû «t¢a» ²vTõ¾ÿ†ö¾Ÿ9wEZœ=âo³-enܸ¡7ß|S{÷îñÙ7_X³fæÏŸóé)ûžn¬pÿ éÆ”=Ÿ#€ € € € €@| üô§?U_ŸÙª©u-LW¿ç|KûT¡ ¾ÜšªõP~õØYÖ¨½q£2Æ9½#¼—µûáùª´¢]*Ö¾ã?ÔSEyº)iæ¬p|x®‡o>è Ÿp éû>áÁ‡~¨óçÏG8Zz衇";}½Ûßú)+Ü'Ã’g € € € € ÍÍÍêíí»To®%Gœ`Ë¡ÿ3PløßÀ”qžžÁÚ¿~h±½ªþ„ž^WÑ? ¸Î¼k¬é_zKQ^ž·u4´ÛjñZ8°@~\i͘1C«V­Ruuÿ 1®'OÞàôÏØü›¦ö÷÷Ëf³MÞƒy € € € €Ä¥ÀsÏ=7®¼^xá…qÖ`swo‹ö”Ô Š¹Pe›VhvÚ S·v©ëΜ[ Ó·Œ›ÞçöoÔú†Ð;ËtâR rF¯Ž;þ‰J[ü·Õý?j®yT‹oº¥ãük ÕÛ ‹>çßl5ô–xûz—MötéïJŽÜxËŽ|@@@@@ÈÌÜ»®ëƒÐóKëÕ~`]D«ÁC·Xæ·÷‚þ1\m/Ö‰öZDÒï&5_ÅeFÁÝÿouÚýoÖuyƒÒjÕ UFûàç‰B£çJœ|}ܯ5÷wV¸ÇùT“ € € € €Œ `®à>èa5›ÿ,6‹íFÞ«o«qP.¿9ð¬ÞèîtfèaOO–Ö>½N¹ÆÆ¯ÿË·÷IuüÖçëÞäúöŸæÉ~ý=ÕW,è_¸O/v }P~›µÈ¦N£à®ÿ5“#%@@@@@ swÇÝZæ”\néð¯ÏkãÒå¼ÊzCºÞKF ÁKÛ+BM`Bçnþ]¨‡7ù îFë”ÅOéøŽõÐöÀN«Õ%êÖ.ëN¹êŸŠÙ¸9ûѾÏÊ—ÚO³qêhF\C@@@@ø˜a.½l=ò-_s©©²LûÏt˜{L”ïòö7€y²‡oIRÑ6—Žî2zË ÷q–ÊÕü­Î1÷oÃ=ÒÊçfù[ÊX9BbC@@@@¦VÀt5øÞ/•¨ÐØ6´ÉX#¾~Y¦ŽWÕ¨øÁÏêÞŒ;e7ªÒ}·³3•ñ‹­³qjÆòêïß8a‡Vn©Uß_~_îß¶èêǽƳ’•5?OμlËm;DǼÕßR¦…îcB1@@@@âVÀdÁ½C?{b•Qlø4TW¨áÖž*|GεŸÝw-V’ÙZZ=4×û–vÍøÇ éú•~ÍœÇÆ© 6ý¤‹ € € € €†€É–2IJ™Cîüw6];Ï*÷¡*|C@@@@D0¹ÂÝ¡Ç_pës^7zšÛuK÷˜aõúd¿ëÓq·º}ØTôdº±qêµæ~Ýó§ @Ú € € € € Ð& îRFîb-ÏMh;’¿IÀßǽù¦“|E@@@@D ¢‚{Ç…3ú—Öe7–²gþ ÊÍ.œyCÆ©ñ}’³õ£JÑKÇ÷dF[@`V¾MWŽÜ°@$„€ € € € €L¿@Dµï‹¯ü•ªl‘ºëd§¶,—^Yÿ *Üã 8N7M§BÜ÷Ü}-eø € € € € €‰(0îMSSí>&;›¦&â_Ë9ßž#õy¤žvŠîcPq@@@@âP ¢î‹}^'—_3ÒŸ©û?ÃÚzcÓÔ÷Ù45ÿ&L§d›aÓ,߯©ÿ£_Y6ÓÏáF@@@@@ "*¸§fçiyöÐô9Ʀ©ÆŠf> ðmœzí¼¯à>ø,Ç € € € € €@ü DTpï¸ðªŽžzÏÐÈÔ—_©ìˆîŠ<2¼U ÐÇýÖóœA@@@@â] ¢î_ù¾JJJŒŸÝz¯+ÞIÈo"¡îy÷"€ € € € €±(QÁÝž2/˜[º±]*FHÏ7ZÊ4³iêÈB\A@@@@xˆ¨à¯É“×ä 8r¥î¤¾?PtŸ|]žˆ € € € €V ànåÙ‰ÁØfØmr,”ãÔ Ÿ@@@@@Óã,¸;dO3ý.nL߯©Í ’,i"€ € € € €A¤ñI¸uôð]I–zÇwc`ô ôpÑb¥š¹—{bF€Scfª@@@@&Q`Ü÷ÊÇŠÍ¿ÞY£ö³ÜÍÆÆ¾î—~v#6‚%J@@@@@`’ÆÙRf’ÞÊcâZ€îq=½$‡ € € € €#Œs…»S;ê+•oº¥Lžh?ÂLÄÑiÇýÒÇÿ&}ÒÓ¯ÛRlq”© € € € € €# Œ»à¾¦t­ó®‘_Ï•xHJ³éö?’:ÿUÊpÆc†ä„ € € € €Ü*0Ζ2õuÝúÎ p³€¯ûµóý7Ÿæ; € € € € ·ã,¸Ç­‰M²@º¯àÞLÁ}’Yy € € € €XX€‚»…''–CcãÔXž=bG@@@@3Üûz®ŸÝ©>3oáž„˜•oôpg…{ÂÍ; #€ € € € Èmºàá-Ú·ï õh¶î¶'2¹G*žg“çéÆ'ýšq›-ÒÛ‡ € € € €Ĭ@D÷Œ¼•*ϋ٠< ɳlJ¹KúƒQtOÿLà• € € € € €À4 DÔRfšcâuq"@÷8™HÒ@@@@@ˆ(¸GÄÄ 3³òmºFw3t܃ € € € €1(@Á='-VBžµHÜce²ˆ@@@@&,@Á}„<`$tß ÷óý#]æ< € € € € WÜãj:­•Œ¯¥Lç¿JýýÝ­53Dƒ € € € €S!@Á}*Ty¦_ uŽM·¥H_@@@@ˆ¤ÉIÑ«Ž¶«úàýtíúï%{¶–-ÍUW[›ìs”:Io™œXyÊt ÌúwSï˜o›Î×ò.@@@@@`Ú&¸ÂÝ«sGžÕ›]™Yó”ïtjÅŠµbý+òª[‡¾’¥4û=óòãŸD˜µˆ>î‰8ïäŒ € € € €@" L àîÕ±g–³¸B®›åf}D|ŸÙ¾ÿ¸µý±eJ+?¤ßW> %0+_êl¦‡{BM:É"€ € € €  ¦ îm¯þD«¶7…Ù Ëvh×&gà{ºïWª>÷ĦðuÕ•è»/_øÎQBøW¸7'Dª$‰ € € € € .`²àîÑ/\¦ÛwòŠk·é;å›ç:¥.ãhyùu½ãRapdÝ3¿Pkø.A`V¾î‰0Ñäˆ € € € €2Wpᄂׂ}d wTùòl?eW_O˜4´OjjîjÕ»ªçݯë}Ox 0óS6Ýè3þæ}ÚÊ$Àt“" € € € € -`®à®>…êæO¬Z4&`úÜ´à—Z®°}ê˜`q6€SãlBI@@@@†0Wp7V,‡>WÛÆ. §ÍÌ wꎴÐÚ÷Ðøï鯯©×Ø85Þ§™ü@@@@HxswÇl- îº}ó]†Ñ>çÕo~öbðÛÍͤà¦IƒÀ ÷I–4@@@@@ aÌÜ•£/—·BuWk~ÑVj´Ò==E¾&2Ým-Ú¿õQ­ªn ¯ÒýŽ„µNØÄÙ85a§žÄ@@@@H(“w©à;/hSˆª©Z+æ¥)ݹ!pƵG_-Z¢´¬|­¯î®j\yéÇßPFè~'Œ=ÜfªI@@@@„0]pWR®ö´ŸÖŽàB÷¡Šn55¹rjßÉ+z47uÐ9EàöùRïï}?ý‰’2y"€ € € € €@ ˜/¸û°2–j[cŸšOÔ¦âÊ{iYq²PU5.]ê<«òåÙ ÈKÊ>·Ù”žglœzž‚; € € € € ¿“°ƒi’ò Öjñó£înuõIG’žÿ».¥9š„į~eæëã~í¼4çO(iRE@@@@„0¹ÂÝ£ýO.‘ÍfÓ“µçÂ`I©©F±Ý×6&Éø=Plo;U«"c¬íÉýò„GsHþ‚{3+ÜiÎÉ@@@@D0Yp·Kž@öH èç\Ôä“u¿¥vo¢“¯O€Sù;@@@@@xˆ¸ãKË¡­zâïÏkAz€ä¢+ðÛõ|…Ö žV«S®àX ÞGuرœŒWt£¥L'+ÜãuzÉ @@@@ ˆ î×?aL€ € € € €–ˆ¸à>4ò =²gŸ.¾xF æÏz‰oŒ 0Ëèã~í|ÿW9 € € € €̀ɂ{·.¿}M™ŸÊUwË/´»%„õÌú¢ž./¢­L$\q8ÆWpÿ·_܈ÃÌH @@@@Ǧ©C±úôö‹•ÚÞ4ôì˜ßœ5ú6÷1™âu€¯¥ÌµgXá¯óK^ € € € €$ºÀ svݳķyêø>ÅÌWÚønat ¤FúÃEé“^Šîq4­¤‚ € € € €A“÷T­ÞsZêêêºåÇwþÊ¥f©F…aêbý_O¯¦LØ#ñ’n·iæ<ÉóVâåNÆ € € € € ÿ& î>˜$9¥¦¦Þòã;Ÿ“§¢G7ª±ý¤Êü‹á]zð»GäS2EÀ¿qj3+ÜG!â € € € €ĨÀ îfœ±\[*˃ëþQnO„÷1,.ü}ÜÏSpËÉ%)@@@@\`ê îð¼ÅKÃÌ}á#Q =ߦNV¸'âÔ“3 € € € €q/0 w¯~ó³ã’#˜µHºFÁ=2,F!€ € € € €@L $™¶ãò9½õþuÙÿ ·jÝn—ú>¾ªS¿Ü­Š½MÁ×,Ò]ifßÈ}ñ žg¬p76Mí¿Ñ/Û [<¤D € € € € €€_ÀdÁÝ£«ªpO±p×*åš|ãøÞÄh« ¤dØ”|§ô‡w%Ç}V’¸@@@@@ñ LCK™@P…›ê[ Æ!wħÆÝ”’ € € € €&×›;ôç¿<­Ï^þ½ì¾Þ1£}’o×}z‘r椎6Šk $0ËØ8Õ×ÇýS«(iRE@@@@¸0Yp—æä.UQnÜûàø6NýðTÿ<™G"€ € € € €Ñ˜¶–2ÑK‘7[M Ý¿ÂÝjQ € € € € 01ˆV¸w´œÒ©Ö•<±wIöl=Xg¶ÍDßÎýðõpïla…»E¦ƒ0@@@@@`’"*¸_üoUZUÑ4ñW:kÔ~6OOˆa´¹6Í0þò>~¯_·ßk‹áL@@@@ ¥Ì€GÓ(àk+ÓilœÊ@@@@ˆˆV¸/z²^îÂ.ÙíI»OöôO±º}"„qt¯oãÔkçûuÏÃq”© € € € € €@B DTpOÍÈÑâêÓÝrHiù%ÆF©NwÐRÇð#ŽìÖ^¹ »fÎ~€®ëÃë¹úëš-ÊKaH‚žžÅÆ© :ó¤ € € € €@ü DTp3}¯Gš«ÿq±CJ6¶VííÕŸRNÞBåΡZ=æC£7àÍ—þ>ørϨA|ØrL ucõ¶/Ö·ÿÎx ÷!–¾SßûÏ7†œã  € € € € Ë,¸{Õrìy}kU…F,;o’kûÓZ½4ÛúNÆ?œûu½Ü>b6ƒrðè·¯‡Æ9åtº4èÐíž« uâô¬x:ôõp¿F÷xšRrA@@@@ á&PpïÖ‘­ËU\íѵWÅÆOᎣúÕ¶•\èÝ­ÆÚéÅ×N«®Á5z.C®¶ëêÅÀ‰Âšz5n\:ä*_F¸ý¤Oº¥î«ýJͲ>˜« € € € € €@ ˜.¸·Û1¤Ø^XZ¥ÿý±•?×höÞÛ¡ çßÔÏŸß.W°ß´}•vüñí\iµ•î}úÿŒ8ëÆøwƒ[æ²û#ÞSøÙ»o¹Ì‰Ñl6›fåV¹SpÝŠ« € € € € & îmj¨¬fèTýé_kÝÒ9C2^^°RkË·éò«µšÿàÿµêUÏ©¼o§rL¾uÈ &í‹]Ÿ¯¬Ñ®}mÖS”’rM¯=_©†1 ðÝWÞUh=ü½ÙY“M"=hÖ"ùÛÊÌýR"eM® € € € € ¯æJßÝïéõ`Aºìà‹·Ûcå”ë’ë²æû ôçõQ—”c©}TSU°v£ ÂA{•rtì‚{ßõÂw\=ósí®=ª×Ï^Q§q6=}¡Š/ÕŸ?^ 9æ„ÃÏŽç÷óñœ!¹!€ € € € €@" ˜*{?ø‚í˵tñ¼1½æ~êÎà˜‹ú]»WK¦^;æ{&g€ñ/|.~-<ª²¤$|8h’ËU§Š’b¹šhuž¥þ…á¦X£÷u–±qê7¢oF@­sô@IDAT@@@&Q`†™g%¥ÏÕ‚ñÜh v«½+²‚vè«þîëôBs:¿ KUµc‡6• Ù¥âüb5¶yã0$0k‘ÑÃý|è+¿@@@@@˜0UpWR¸‚®çÿ±Ic•“Ï¿~.ˆT,ç¼xXíÝ¡×þ!ØÁÝíÖ®£Íêo< Û¶iÏFu¾s\eá?‹&=ô½_iž@w|Zê1zç÷uRtO i'U@@@@âVÀ\oÇB-ÊåjÜ{‹õhæKªÙ´ÆèÍ~óã<:u¨Z+6ýŸEš•–zòè%=b¬ÖïKš«¼œŒ!I9r‹ôÓwªî¾`«™ºWôNÍjå¥Ñ—7nèÍ7ßÔÞ½{#ï´fÍÍŸ??âñÑ8#É&ÇýÆÆ©Æ*÷»VØ¢ïE@@@@iøéOª¾¾¾i~ëÔ¿îæ y„otèñ¿u©¤¡Ø?Þµý1¹¶KÅeU*Zz¿î2±ÿîÂYܾWÁ½Uýãvÿ¶rM¾1ÂÀ¦mXFvކ–Ù‡¾:)w•jŒî2M¾óèšïoÇDÁÝw÷‡~¨óç#ß]ô¡‡òÝ_÷kÍ2 î1.A"€ € € € €À$477«··wžd­G˜.'å¬Ö•û´êÁ ᢺ«®ZÁF+·dYZsBUEÙ·œÕ^o ‘NRÒH„iJOŸxv3fÌЪU«T]]=ñ‡Yð þ>îÍ´”±àÔ € € € €S&ðÜsÏëÙ/¼ð¸ÆGk°¹îÁh³ Êu¶ó’^ªÙ¤àÖ¡+ƒ¾–îÐñævØX ‘JÓÑJÞì{=çje·Ûý?›\þ1Ýoëð¿>Ì“V:ç:‘³é¾îlœ:BîE@@@@‹L¼îÈÑ£÷?Õjký@]veeÙÕúîÿÔŒô9ºëÎ;”‘¥?c{÷º´uõF͹éò©ºmª Ûôˆî›¸tèiqõÛ×R¦“îq5§$ƒ € € € €@¢ Lh…»äÑ™cûµµ¼\/·ôiŽÑ×<77Koÿ—ÊûÜÝÿélef¦Ë¶¤\ÇZ:âÆØ‘ÿm eÓT¡¬'wëÔ…Vumfº;.ëågÖhEExy»–?7«ûCiOÖïôÏH¿'y»h+3Y¦<@@@@¢#`¾àÝEéZ¶j½ªëêÔz=ÐÓ¼íÕŸhYÉÞ¡Ù¸ë´*?SûÏy†žÕoI¹Úz²f ú†J­¸ožÒŒ63i™óõØöb{龓Z›gr·Ô7ÄíÑm)6Ýž#uþkܦHb € € € € ¦ îgž¯PeÓ€RŠ w·^©« Ÿ,,Û¥šªâð÷õ‡[ëÜGn…3gùFµ7Õ¦Âpz7«þÄ%(_~Óy¾Þ,àß8•>î7³ð@@@@bLÀ\gqo‹jÃ-SÊtòJ–g«¸=§t¸!(P¸K/Önñ÷6ÿüÝkô o|ÓQ]ô”ËÚ-ÝZw¸_ë"˜ÈŒ¼•ÚÓØ¯í­-zëB›zûúôqo¯2æ-Ԣʹ\ÁÃh}Üh²I@@@@80Wpﺮ‚(UÇ¿(¶ß=oŸR¨™JÙ_¬o$úǯ1®ú®\Ô»W»µÔ_-V2²ó ƒ¼ ¿Æ+à[áþ;×ñÞÆx@@@@@ÀRæZÊØ^½sçÀ:î·_k '÷¥åóÃÇ©ó—©ÔÿÍ­w?ì ŸçŸÀ¬|éZ3›¦ò×€ € € € €±-`®ànäÞþÔ(¾>úõáÐúöMZš3°Š½ûÒi:Í8•wwZè~#àHÏ·é¤}Ýù“@@@@@Ø0Yp·‡W¸oØ}H­^é‘ l¢ZöEÝnVãÑ?ïÙZ ¹™…øØe#òɰßaSê\ãqޙ̧ò,@@@@@`zÌÜS«lGa Ò† šg·é¾âêpä;žø’’äÕ¹#µ*/J×cuîÀµÂ"}z Mx<dØÔz”>îü% € € € € €@ì ˜+¸ù<ý¼ªœÃ$^X£ EsŒ ]z}ïÕ5 Œ©¯YÞHuà,GHóKgèâA îü- € € € € €@ì ˜.¸+5O;O_Õñú*-.V±ñS¶ã ®ü··Õ¥;tâR—Ö-fy{ìþ©Lmä÷ü©M×ß36Om¡ûÔJót@@@@˜*p§uS/Hš£¢uÛŒŸáîvè©_uêñ>»2ômNˆs3’lÊyÂXåÞpCŸûÛÛ.p„ € € € €ĈÀÄ îÁ$½ž65ÿö´Î½×.%'+¹×ø•9W÷ççé¾VµÇÈßBÔÃ\PbÓkk?¡àõ™ @@@@0#0±‚»·UG~ò7*®¬ùÝÎR|îZ[;ò® `ܵb†l¶OÔöú ÍùóÝŽÀD@@@@¢!`¾ªé½ ­öy£Û}¹Tòà}Z²ùey¢‘!ïŒ)ù%¾¶2ôq©I#X@@@@ð ˜.¸ŸúÉ7U=±°l‡^:~RÍï\Ò;ï¸uâèAU•:Ã#Ü{Ó_j çá÷{é†nôQt·s € € € € `]s÷îsz®²)˜•SO_Ucí6=Z´\y¹9ÊÍ]¬‚•kµóÀY]=}P¡²{]I­.x­‹AdÑHÿŒM·Ï·©õ¿Rpþl € € € €ŒGÀ\Á½¯/ܦ´¾Ak—Îñs–®Õ/_ª ^¿¨»FÊü¾ÍS/¼ € € € € Sæ îvÉLóe ÇL8=Ü|Æ!ãV>Œ*óÄ ]y¥_}`•û¨P\D@@@@K ˜+¸÷)¼ÂýÌéKc&ÔwGh…»GÆ­|U í›îZaÓ{¿¤à>*@@@@@ÀRæ îŽEz¼4GÝú缾u”ÆìžsúQep{ÕâUº?´4ÞR c5¥3t‘¶2V›âA@@@@Q"*¸w{:ÔÑ1èÇ#­úëƒÁǺôмeÚýò«jõtûÏy½Ýêh»¬SGjµ&Ý©½îÀЃ?\«ŒQ‚á!{ÿ½M¾Þ¯®Xå2á7 € € € €X[ iìð<ú§âLmhm¤[•=¨Êц×JþÃ!­:PNÑ} '.Kv‡Mó±éòÏn(oÓm € € € €ÿ?{w I]Þ}üWÝ=dz÷}/ » ²»"^Ë©ˆˆ@‚GŒB<É¥F&Á7!øê«$¯x5&0¯9<€(ȹäXvÙö¾wvv®>Þç©êêé™Ù9¶g¦»çÛKQgWW}ªº¦úWÿú €@Ù ô©„{ÉÖâéÖ’ÍŠU¿À‚K½ZJ¸Wÿ–f @@@@¨>”poÐ;¯]¥ºç¨¶öVº­Mµó^Oéö# ioun ‡/ÏiÿêœÆ-FÚê³¾ € € € € Pa}Ü¥Y§^ žZakÆâV¼@¢&Ðü÷DO]ñwT+Sñ”@@@@@ Ê† J™´6¿ð€nüìûuÑgoWôXÕ*WeõJ&°àÒ@ëoÉ–l~Ì@@@@,>•pȇïÙüŒ¸ãÇúÚG¾ ÂóVÏ|³šmfõ™!ï‘Sß(—‘v>’Õ”×Áõ¡©ÌJ#€ € € € €@)J¸§÷lÖÃÜ¡›¿öÝTHÙ‹sM-Ò ³AhÁ%ÑÃS§¼¾o`@@@@@`˜ޤÊ=}³®þüý*~üjÇûéB ï .Mh={ßÁ˜@@@@†D D{ѲÖOµ*g>X¨ræ¶>Óm•3Eï ~ L;-P¦EÚõ¥ÜûÇÄ € € € € 0¨¥Ü‹׫œy×UÿV9³æ‘»uÛu稡h @@@@S`P÷ޝעSÏÕ»Î]ªTÇ@º†X`«=»ö¾ŸâOœóje6üWVÙ ¡ûà3W@@@@è¯Àîý],¦ ùÓ¤½¤}M•RO\¨ÞÖgë/*]c[3O@@@@z÷¡7¶OL%=Sz¡ ª•qDž:l»Œ € € € €Ý¸wƒR̓–Ì ôâ¦ê(îõ¸¿²*§ôÁêXŸjÞïX7@@@@F‚ûHØÊEë¸d¶îE*¸sÌÜ@“N ôª…î¼@@@@@á pî-0ÄŸ¿Ô÷Õ›«' öjeÖÝ’bE>@@@@8T€ÀýP“ª2}b D ½º³:B÷yï ´í¿sj©’õ©ê•C@@@@ ÊÜ«|w·zK«¨÷:»€0ó­6ü¥Ü»ÛÖ C@@@@¡ p:ë²ù¤¨÷ê(áî¨ ­Z™õ·TÏú”͎‚ € € € € €@¿ÜûÅU/™-{pjõԳϴ﹜_®žuªŽ=µ@@@@@`d ¸¬í®í1³­Û&¥3ÕP'ëͽ8Ðú[©Vfîά2 € € € €e#@à^6›bèdÜè@SÇIk· Ýgö'EÕʸ¶3óG@@@@žÜ{¶©ê1ÕôàTßPÓÏÔ¾_Úõxu”Ú¯ê•C@@@@ JÜ«tÃö¶Z‹gUU{´à}þðTJ¹÷¶í € € € €ƒ#@à>8®e?×¥U¸;ø‚Ë,pÿϬ²UR7}ÙïD,  € € € €t pïÄ1rzζZª§ –I'ª(m»¯zÖiä쑬) € € € €•/@à^ùÛp@kP› ä¡û ¯VW8íO]Gµ2Ú'x € € € €™û‘ùUô»—„ÕÊTô*²ð .Iè•å”n®® ‡¬(@@@@@ ìÜËn“ ÝE{uÓcš¸,Ц;ªk½†n¯à“@@@@@` î•«‚÷yà¾zSõÓ‹®Hèù¯d•ËUߺUÁnÇ* € € € € PµîU»i{_±Ù“¥¶´=dtOuÓ ?(Û–ÓšoV×zõ¾E™@@@@†S€À}8õ‡ù³ƒ ÐÒ9^¬²Rî‰d S¾žÔSŸË¨u7¡û0ïf|< € € € €#F€À}ÄlêîWtñlé…* Ü}M§¾1¡Ùçzò³ÙîWœ¡ € € € € €@‰ÜK Zi³[Z¥õ¸ûv8ñ“Úx[V»§”{¥í—,/ € € € €•(@à^‰[­„Ë|̬@k¶H™lõ…ÒõÓ-¿&¡Ç>žáª%Üg˜ € € € €t/@à޽ˈ:©!ÐøÑÒúmÕ¹ÊÇ|$¡l+P­Î­ËZ!€ € € € P^îåµ=†ei–TáƒScH KÐF@@@@Á plá ˜ÿ«ÇýÅ*|pjLÏTc Ú € € € € 0˜[!ó®öÀÝ7P­‘ÅD@@@@ ‚Ü+xã•jÑž)mÚ%5[]çÕúâªÕºeY/@@@@ÊG€À½|¶Å°-I}m yS¥—6Woàî¸ñT×~«º×sØv$>@@@@.@à^² ­––¥Óé’Íq(gäÕʼ°i(?qè?+|€ê7’zò³µî&tú-À'"€ € € € PÝîÝlß–nUÖ¼_O4v3AÑ –ÏèÆÏ¾ß¦­Ñ¨Q£TSS£`ÅEúâ¿Ý£Í”½„zÜ}³M}CB³ÏôÔç²E[‘N@@@@@àÈÜ»1|ì¶oæ‡>mßóÄ¿iÔ´åúȵ7wžËÓ«ô…Ëß®Ù5¦g?‹Îïƾ0pud”ú>ñº¤6Ü–Õ®ÇGÆúãnÅG#€ € € € 0¢Ü‹7wºQÏÜóO:í ÷í¾;ý‚þêäË;Æ-¿R·Ü}¯nûö5:³0ôkZþ±[U ™û\«Ãý@‹´»±úCèú©–ÿ]B}<£\®ú×·°;Ò € € € €ƒ*@à®ÝwãuÕû/RP3NËß~uŸÀ_øÞWuS<åòk´æñuɹgé]ü¼îÛÿ¸®ŒÇÝ|©~PÅÜ“‰@‹½÷RʨÆ;(m@@@@(•»Úõì7¾ ›n^ÕÓºýºBÜ®Û~ø-J½½á$}vÕŸüÇÝϺ˹cÉléÅM#£Ä7P-ç=‘eC@@@@ 2ÜU£?}½®»þz]ý ºá†ëtÙò^6æžtÏÓùi–_§Ó;¥íÑðùox§âÙÜÏ“ÚÓË,ËaôR+áþâ¦rX’¡Y :4Î|  € € € €#E ¸\öHYç.ëY¯•—|B+ CÓª»ûÓº9Ô Ã;:×=§¸–÷3/}ƒ¬úóC_çë64œÍýj]ãUšØpèdå4Ä«”yiU6¬×<‚rZ´A[€êǦµèC M>yd¬ó a2c@@@@F¸%ÜÙšÒu@MMÇqõc:zŠ»RÓ´øÂx@£U\Sþ¯©ãÕÙºmÜQþËZª%䪥’d> € € € € @à>€}`÷Ží…wMŸ2ºÐ}¸Ž¢Œþp“ û¸¥s¼Z™‘Q{Œ>@µ-§µßYë¯?m@@@@(û¡?ÍWÐ~Ò2{Òh½–„õ¸¬à9|€êדzò³µîYë^E».«‚ € € € €À° P‡û6AzëÃúZ¾Ž÷'ž±§Œ.[Úë\Z¥L&“ѪU«´qãÆ^?#žà“Ÿü¤N8ᄸ·_í%výàß¼Ð9z€jVO}.«×ýK²_fLŒ € € € €ý¸âŠ+ÔÚÚÚ¿7UÀÔîØH©Ñã ïÚÖx°Ðݵ£cwiPq½ï]§;\"‘ÐüùóuÆgn²Nã&OžÜ©¿?=ÇÌ ´ÁêpokÏ©¶fd=D”¨ögOaZ@@@@.°råJ¥Óé>ÏàÖ[oíó´Ã9!ûê¯zâe¥u’l|Iw¯ÊÏüÂ7ë˜ú}PaiõøÃ›A?ß5¦>ЬIÒš-Òqóúùæ Ÿ¼øªo{8)·ç… € € € €¥¸üòËû5Ó+¯¼²_Ó×ÄÔá>ù†cÞ¨Ëâ÷Ýôs=ß÷t´÷<÷ â¼ý̳NPCǨ²ïZlõ¸¿0œo KÐF@@@@þ ¸÷W̧¯?V.¨Ü¤/ýç ]æ²Yÿï3W†½÷Ìã ݕбÔ÷Õ#4p窕°‡²Œ € € € €”§û€¶KJoûã ï¼ùòcõÙ[Ðæ;´cÃúÒE³õéûó£Ï¼AïYVIåÛ¥%^ÂýÕ‘÷àÔxƒFP ¨ÆÃh#€ € € € €½ ¸÷&ÔÃø†e¤{¯9³0öÚKOÓìiÓ4mÁÉút\—Œ–kÕ·ÿH SUFÇ‚éÒîÒ¾¦‘ºûT7Ü–Õ®ÇG®Aeì­,% € € € €å#@à~Ømq¸’é)õùUºûºBÝ2ç´ü2­zþ¿uÁüC§Úyº2ìK%=Szq„V+㛤øª¹¡{î¦, € € € €e'Pyið 6èƒ?Îéƒ}úœû©ÕþÑ¿ÑÓO¾ íMmö®Z+å¾TË—ÎR%ãzµ2¸¿nqŸ ªr¢ÅMhí·ÒÖätô‡‚ª\GV @@@@J'PÉ™péŽpN©†Y:iå¬#œKy½Ý÷_<5²Kv‰@§|=©_^˜Ñ¬sžCè^^{)Kƒ € € € €@y P¥Lym²YÜWà*eâ áP]ü±„~ù{eZFöˆØ„6 € € € €t/@à޽ˈ:sRTš{ó.Bæe“ÐèÙÒ#ÎŒøý@@@@èY€À½g›?f©U¡ò¥ÜÞø¤v?‘Ós_!tñ_ @@@@èA€À½KñƒS±j±*¥çþ1«-?ÏB‚ € € € €"@à~ b%VÊ‹¯R¥LìÑp´•t¿9©__’QãZ\bÚ € € € €  ¸³'ô(°Øœúò6)!\Ž‘f½-¡ã>eQ½(­ö¸Ä.´@@@@@@"pg/èQ`Üè@SÆIk·ö8ɈqÜ'“š°,ÐÃÈ(—#t‘;+ € € € €@7îÝ 0¨CÀëq_̓S;@ò]¯ÿVRÖåôì©Ïý € € € € 0BÜGè†ïëj/µÀýE÷C¸R£þã”V#«Wo't?ˆ € € € €Œ@÷¸Ñû³Ê^û <8µ[²1ó½ù{I=|yFûž£j™n‘ˆ € € € €À pA{ «ºh†´}¯ÔÔB ÜßôÓZñÅè!ªm{1êΈa € € € €Œ÷‘²¥¸žµ5LÕÊÆoñÇ’švz ßgQͺ†ŠQ € € € €Tµ{UoÞÒ¬œ?8õÅM¥™WµÎ唯'Õ¾Ozò3Ôç^­Û˜õB@@@@ 7÷Þ„¯0p§÷Ãî ÉÚ@§ý0©u·dµþ»„î‡Åb$ € € € €U*@à^¥¶”«åûêÍT•Ò›é¨QèþØÇ3Úý[¼zób< € € € €Õ&@à^m[tÖgΩµÝžJˆÜï”×%tòW“úåEiµìÀ«7/Æ#€ € € € PMîÕ´5i]‚ Ðâ°wä¾õ„æþ^B¼;£l³¾˜1  € € € €Õ @à^ [qÖaélÙƒS ûJ}Ò— ’Òo®¦>÷¾š1 € € € €•.@à^é[pˆ–ßëq§öY;‘ ´ò{Im¾;«5ß$tï3"€ € € € PÁî¼ñ†rѽJ™5[¤L–Rî}u¯›èô§ôÛOe´ãaB÷¾º1 € € € €•*@à^©[nˆ—{RC q£¥ Û‡øƒ+üã&.ôº“úÕŤJž ßš,> € € € €‡ p?¼c‹¼Zêq/écçüw'´èò„~õûeZ¹C lL† € € € €@Å ¸WÜ&¾wêqÐXñÅ„ê¦J^•Ðûy € € € €”¿{ùo£²YBJ¸|S‰@oº%©äôË‹ÒÖ¦N÷kòN@@@@ÊS€À½<·KY.Õ1³¤WwI-mT‹2 T;>й¦4å ~iÕËüüô´6Ý•U.‡ç@ŸÒŠ/&µú_²Zµ(­ç¿šQû|ûëÉô € € € €”ƒ{9l… ZÜ_àÁ©%ÛbA`w \”й§Â:Þ·Ý—Óç§õä_gÔ¼à½dÐÌ@@@@! päjúˆ%s½H ÷AÙ¤ÓV&tÆ)½õW)´‹·“Ö£ɨq Áû €3S@@@@J,@à^bÐjŸÝ¼©Rc³´»‘x°¶õ„×zã¿¥ôÎçRJ‘î~mZ¿zwZ»ËÖG2_@@@@({ GÒ,’‰@Ç̥܇`£¶» NþŠ=`u}J“N ôßïÌèg¥µù‚÷!àç#@@@@è·{¿Éxƒ×ãNµ2C·ÔNtüg,xßÒü?Hè7ŸÈèÎíZwsVÙ4w Ý–à“@@@@8¼ûá}Û@¸¿ÚÍ ª@²Îî.¸2¡w¾Ò²/$õâ?guÇÒ´6þ€ïƒ ÏÌ@@@@è£{¡˜¬C`©Uu²zsN¹¥«;T†®+°j}æ]œÐ¹¦tòW“zê¯3úÙ›ÓÚù(ÁûÐm> @@@@CÜ5aH/SǪ«‘^ÙÙË„Œt9ïLèÏXU3ï‹êxð’´làBÈ Ãó € € € €t#@àÞ ƒz ÷Þ†jŠD*Ð’'uÁK)™è®iýö¯2jßOð>TÛ€ÏA@@@@ÀÜÙ$ÕãN ; ¼AzS­ÝypâuI÷dJMVÊ}Õ1i­þF†«’7³E@@@@ «{Wúû$°d¶ôâ&÷>a ñDczówS:ãö¤ÖßšÓËÒzõ'Ôï>Ä›C@@@î#p£—b•Ï´a»t ™Ð½žƒ1)§&t΃)­øbR_Ñ/ÎNk÷“l¯Á°fž € € € €¸;ûÁ€ÆÔ:íø@ß¾—’ÓÂ7Í{WBç?ŸÒìwº÷-i=|yZ7¼á&à£@@@@FˆûÙЃ±š:'¡ŸËé…W o÷”óLÖ:öÏíÁª«Sª±ºÞòš´žþÛŒÒMl»R:3/@@@@‘-@à>²·ÿ­ý„1.?;¡þIF™,ÁíaÑ›ë&zí×’:÷RÚótô`ÕµÿšUŽí7D[€A@@@¨f÷jÞºC°no;)P]´êQ÷!à.ÙGŒ;&Ðé?LéÍÿ™ÔêÉê®ÓÚòsª*03B@@@‘î#r³—n¥ƒ ПœŸÔw™ÕŽ}„š9M?-a¥Ý“:îSI=zeFwÛ®gÿ>£ëØ–C³ø@@@@j p¯¦­9Lë²pz /é~Ã=”¦MpDëM^šÐ…kS:åëI5¾œÓ]'¥õ³•i­¾!£ÖÝ„ïGÌ›@@@@FŒûˆÙÔƒ»¢—‘ÐK›súŸÕ„îƒ+=xsfœ•о•ÒÅ[RZò‰„6ßÓæ¥õË‹ÒÚp[V™Â÷ÁÛÌ@@@@ ÒÜ+} –Éò××úØÛúú]Yµ´Ê–Éfðb$ëÍwBg¬Jé÷6¦4óÜ@/^ŸÕf¤õð¥µõ>´:`\Þˆ € € € PµîU»i‡~Å^¿4¡£¬z™ïþŠRîC¯?xŸX7)Ðâ$u΃)÷Û”Æ. ôØÇ3aÉ÷'>•Ñž§¹À2xúÌ@@@@ ’Ü+ikUÀ²~ÔJ¹ßõ›œ6l'„­€ÍÕïEô°}Ù_'õÎçktº•~϶K÷“ÖO–µëw×eÔô ۽ߨ¼@@@@ jÜ«fS–ÇŠL›èNK蟒Q.GøZ[ep–bòÉ^ûÕ¤~oSJ'}9©½Ïæô“פõó3ÒZóͬÚ÷³ýGž¹"€ € € €”«{¹n™ ^®‹N t°UúÙo \+x3öyÑÉ@³Þ–Л¾=lõè+Úøƒ¬~8'­G>”ÖÎG©b¨Ï˜Lˆ € € € PÑî½ùÊsá“ÀþÉùI}ûYí?Hè^ž[ip–*5&ÐÂK:ëî”Î6¥Q³ýêâŒî\Ñ®¿žQÛ>ö‡Á‘g® € € € €å @à^[¡ —áØ¹Þxl oþŒÒÍU¸yû´JcæZqMRmHiÅ“ÚrON?š›Ö×§µãaö‹>!2 € € € €@E ¸WÔæª¬…½ü- =öRNÏn Tsem¹Ò.­W93炄θ#¥w>—Ò˜|o&|Ðê ÿ”QëöÒŠ37@@@@á p.ùð¹ £}èœèªé ¡êØä½®âè9–ÿ•z_ŸÒ‰ÿ˜Ô¶ûrúñ¼´úô¶?H©÷^™@@@@ ¬ÜËzóTþ½"¡ V¯÷"p¯ü­Yº5f¿#¡Ól¥Þ_L©aq ‡.ËèŽãÚõüW­Ôû.ö—Òi3'@@@@¡ p*éü9r~B·ý:«mT2‚÷‚žW}´=XuÙ_'uáË)ü’Úþ€•z_Ö¯/MkÛ/)õÞ³c@@@@ÊM Un ÄòTŸÀœ).x] ¯ß•Õ5—&«oY£’x©÷Yçz“PóÖœÖ~;«G®È(He4ïâ„Æ. 4v¡¬ 4z®”H%ù\f‚ € € € €@©ÜK%É|+ð+úÈ72úõsY½é8n¬8,#5jF ã?“Ôkþ*¡­¿Èië½9mùYVÖIMërjÛ+ž…ïcò!¼ñq _?C yv%@@@@¡ pZïûiµ5>nuvíö¬N²’Ê£êCGìÎÐ÷Ð|æ[½éü¦ö¹Bø~Àxâw=– ÃxïΦ-Œ_òA|Ê/’jdzÿu¥@@@@ î¥Pd}8ù脎››ÓwîÏêÊs©Z¦OhLÔ­@ÍØ@—Éšîƒó–¹Bøî|ãiËÏ£@¾éiæ[}eB³Î ”Hv?n?˜ € € € €F€Àý08Œ*½ÀUV?÷UVµÌÙ+rZ4“ ³ôÂÌÑêí¹ÞL>åP¶}9­»9«§>ŸÑÿ|TZtEB‹þÈꈟÏþx¨C@@@@ú#@eÚýÑbÚ#˜Ôèýg$ôÏ?É(›Íñü˜ýðêd–|<©wØI`Ê© ½þ›)ýþ¦”f_è™k2úѼ´žü\Æê…gÿì„E € € € €@¯î½1A©‰@r~Rÿ~_V{ìá—¼n»óbñG’:ï‰q{R­;¥;OHëÞ·¥µñVê½ýt¸·Ÿ € € €T‚u¸WÂVªÂe°AjߟӨéFÍ´zègDíQö¬ïO.ÍçVì†aÁ@@@@  p¯€T­‹ø‡g&tå×3úíËYx7[Tëv®Ôõªè˜{“Ðîßæ´æÿeu÷ÉiMz­ »2¡9JÖv‚gZs:øŠºê6ÌÂõ8dl—=W3/ИùQ{ìÂ@-Û¤ÝOæÔ²%§æ°‘ZvXà>Faðð]ùQù€¾nr÷ËT©ÛåF@@@*I€À½’¶V•-ë˜ú@97¡¯ß™Õ7>¨6EPXe›¸jVgÒ‰^÷¤Núß mø¯œžÿ?Vêý­ÔûahîAú zËv+¡>Õõ¢0}¢ÝÑ1ç|×nã§ô}Ïfrjµy6oñÆ‚ø­Q»iƒ´ó‘¬Zòý>\Y/ïá| †£¥qK‚BÓp %å«f§dE@@@@ ,ÜËr³Œœ…Zùš„~j¥‡¿÷`N—Ñ÷r䱦å$hÑÞ$´çéœÖ~ËžC`¥Ñ=DŸ}^ÂJ«çCvk'ëJ·?'’qõ2®qøù¶î±Òñ¼Ü”SãK9íQZûí¬µ£R÷£f‡ðֽ؂y å}Ùƒàðó.§mÁ² € € € €å(@à^Ž[e„-ÓÇ-¨ü“›2zÓ±ZýÕ¼¨/±þÚëËïùuÕM”ÆÛ÷iæ[:KzU7/) ß÷¯Îi×orZw‹ ³0>Ó"y øâñã–Dý5ãø^v–¤@@@è^€À½{—> ]{û—ô·w®Õ”Ñ£{˜þ v\¤Ï]ÿ)-­ïakæ¤@>'¡/Ü’ÑW®HjÚÂ=v CÀKÝO8^ÖúkÙá¥á£ñÞÞøý¨T|ãZ©n²4åõfœhúY MxÍ¡ïŒåež € € € €@¥ ¸ÁÛùÂ=ºù¦û{™Ã…úã/Û$î‡uzÛI ím’>û(toUwðB¡¨ŸX½ó¦½¹ógfÓ9°Ð}»Uû´í¾¬ž½6Ö?ýÌ(|÷¾aQå_÷<•Ó+?Î*e×Og¾-!¿ƒ € € € Ð_÷þЦoÔ“Åaûr-_^Ñ©ãé§§«¦ÓzzxïJ«û@N_¸5£ë>T}-WOV G`¨ö0ã¸j™£ÿ(~ì¾çsÚjáû–{²zò¯rJU¡ô»ð£g—ÿw×D»ãÙszuUV™ViÎ e­Ú¾–V.'Íz›UËcvžùV«¦ÇîÄá… € € €ô&@àÞ›Pãwkûºhä™×[÷}⤧dDß®²pëK?Ìê‹ÿ•Õß]’PÊÉ ÊKÀë‡lRK>. ¦söàX…ü†ÿÌê±ç4j¦ð «~ÆJÁ[Iøú)åñ=NÌiËÏ¢’ì›~’³ý²_”Лÿ3©É¯ :=4ÖŠ»å§Y­¹)«G.Ïi‚•xŸu®ðÂû´þ [^ € € € €@W÷®"}ío٥ǟŽ&>óø}}Óõ"þ°¿¹5«/ÿ(«O_œè‚õòvF#€À øwvÒ‰²&©ãþÂj›±*hv=æÕÏäôÒ Y=üÁœŽVX÷{Xüé†ò!¬-;sÚtG²o½7V3ç¢@Ç6©q‹{ͽJ™‰Ëm>)¥›¬DÿýÀçôÐfÔ¶Ë.(¼Åx+ýn|%”èâÝ‚C@@@`Ä ¸pÓ·lzY«òï;kÚçÂÛºðRíŸoBõïÝpwV=/ÙÝd C2ð*h¦¾ÁéøÏɪj±ª[ŠøßýcV¼'gA·4fA 1ó¼±îùQ{´õ²ë—A¢ç ¼/«ÜørTMÌ«V]Ì®ßä4ÝB~/É~ê>ÿþÏ;eÏ”˜s¾7þéI5®J¿{:gëbÕÏäÃ÷i+ùÃiy!€ € € €ÀÈ pàvo?hEó¯íO|O_ºñn=ôÔ&í·aãÆ£³Þs™Þ÷ž•šŠpÌÔ¯¶×ß~Í¥IýÅ¿fôÝ_fõ¾Ó£º£û5&Faððy†U+3ãLiÅ¥v{Nƒ? ôàF©iƒ=ÕªæÚfßñƒ­{ƒôÍÒè9Â{??j{óù¶à]_»ŸˆJ±¿j!xÓ+Òìó-þãDX LMáÓw}úý!± KjñÇlyÛ삯£ÒïOüeFk¬4¿ü^ýÌT{.…_@¨d1=Ϥè1Ó"€ € € P±Õ¿k†ãÕ_gþíýZ~ùͽ¼íB­zþ;º`iC/Óõ, çãñm{¤Dm>¤Ïò‰:«nÇjØ lÖaÛ»{ì·‡Àö4Þ†O8>zlݤî+k¯ai@@@(÷m‹=zð[ùÜ-l¿îîçõ©s—æçôy]ó·÷é/>[7…Cî×Ù}—Úo¼@`[ó§ú›÷%õ…[3j°Ð}ùÂŽ k`sä] P©^GüX»=Öê}×ÊÊX ¯NÆ«–ñÆ"ò>-t.ka¼…îQ8…ôÙ6)—)j²EÝ>ÜÞs¸ñ²é³>]»´æ›Y=òG9M:ɪ¿±êwf¿#¡‰+ú¶l}Z&B@@@`„ P¥Ì7üžÍ´»¹Yí©éZ:â!sI¯½U5G_š~¥žo¾QK뙬×&LЬY³tâ‰'ö:m<Á'?ùIp qoÕ´ÿguV_þQV×þaR‹¬)/@ ´7æ´õ9mº+«Íw[<öšõö(|Ÿñ–@5c9Î\—w"€ € €ô&pÅW¨µµµ·É ão½õVª”)hTaÇÄYóuhÌÞ±¢©Eo×õgJW‡µËlÓ>+Q¨î‰D"¬—èŒ3Îè˜y/]^ï{5¾^·8¡«Î•>KF_¾"©YT…P›™uB!ð‡ÉÎý=o¢»†v?iuÏ[øþü—³úõ%9My£‡ïÖœ—и%„ïC´Yø@@@`Ĭ\¹RétºÏëë{%¼¨åd€[)ÞR©žGiܸμèmþ0/­þá¸hèÈí<{EBûš¤Ï}'£¯Xè>É#^ €G.0é„@“NHêøÏZU6»íá¯?J¿ÿîÒª±¿g³,x÷ÞJ›¬çØ{äâÌ@@Ù—_~y¿®¼òÊ~M?\Sö䟹Q555aóg·oè~-/éá|5ïÒt·ºÇy•Fà÷ߘÐÊã‚°¤{SKT BiæÌ\@\À¦ºà} ½é;)]¼-¥7Ý’T­ÝÖõÔ_guÛ”´î??­Õÿ’Ñ ƒÙc@@@( p/Ö@÷×¾¶J;ºyߣ7}>ÿÐTù§ïÐÑ=„ïæ½ ê]àŠ·Z=î3ýÝw3jKøô.Æ €ÀÀ‚D )¯OhÅ5I½ý7)]¸&¥y'´õ¾œîZ‘Öí‹ÛõÀ{Òzöï3zõ'Y5mä˜×zo;@IDAT<0iÞ… € € P îØŠ ǾE¿ïþ«5íý_Ò£k7«ÅêjÙ³AßÿâEzýÕ…âíºåªsDÞƒ•®}õ ® tÝ÷³Êd xJ'Ëœ@žFÙÅÎE—'tÚm)½kgTú}æ9 5o•žûRVw.Oë¶IíúùiýæêŒÖ|+«]¿±ã4w$õŒÊ@@@ªröªšµÂÙñè?iÚë¯îõ/»á}çªS{®§ ü¨^?ѵ×^ÛÓ$#zxk{.¬Ï}î”@W_Ѭ< P.^ÕÌÞ§rÚ“oö>ÓõRÃÑÒÄå&¬41ߌžM}ðå²ÝX@@@ œüY—ëׯ×üùóËy1)x=Э3õÔOh÷ó‹uÍÇÞ®¯ÝßÝ\.Ô·u½>¸²¼w€î–¼’†ÕÕúÛ÷%õÉogôo÷fôÁ³ Ý+iû±¬ PcçòfÎë—n²þ™|ÿ´´ùάöXŸ¨íÂOXhü±Rj4A|‡] € € €•"@M'G°¥&.=W_µ:l¿°ù­^»CmííjjkÓÄÙÇè¸e‹Ôpóæ­};*Ðÿº,©?ÿ׌&ŽÉêB«k˜ €@y ¤Æx]ðÞt,—ßdw`ä%à½4ü¦;²úÝ?D¥áÇØõê Ç[ixkÆçÛãK »ÐÊ @@@r p/Á–™8k©Nµ†×ð Lèï-t÷’îãÇHg,#t¾­Á'#€}ðÛ޲ªfŽ 4÷¢Ž÷¤›sÚÿ¼ñÏZ©xkÖý{6l·l³i-tïÄ](ùÃ]y!€ € € 0Üîýøü’ ̱zÜÿî’¤>wsF5V³Ì›Ž#t/.3B†P ew.M:IÖtÑÛöå´ïwÂGaüÖ{£ >Ý$?ÎKÃ[;_ÞCyê‡ÂÆG!€ € €„îìU%°Ø¾÷ù÷$ô¿”ÕO›Ó‡ÏIhîÔÎMU­0+ƒŒ Úñ¦¾Ñ›Î+ݲ=* ï¥á÷Yóʬ߂ùÚ Òìw$4ë¼@3Î ¨¾3} € € €ƒ @à>¨Ìrx–/Lè›èåôgßÊèì.;=¡À7¼†OGI ~Z¨Ï8«ã¼~øÝOØÃYïÊêÙ¿ÏêÁ÷æ4me`|`¼ýMXÄÅØ-º@@@J%@¥’d>e%PgÕ»ÄBö?–TS‹ô¡ÿ›ÑªG³Êdreµœ,  €Ààxýð“O´ìóIûpJmHiáe íx8§{^—ÖíKÚõ›?ËhË/ìoCg+0W@@@`ä PÂ}ämóµÆþ0Õ¿ü½¤VoÊ馟fô“Ǥ+ß–Ð)Çp­iDí¬,Œxz{ÎÇÂ˼I(k_w>’³Òï9=ñ—X+Í8;*ù>ÛªŸ=‡ÒïÕ´ÃdZ­ª¡ç¬Þÿ§sÚóTÔ4oÉiÖ¹VíÜïGÕñÐÝjÚ⬠ € €Ã+@à>¼þ|ú xÝî_¾"¥_=›Õÿ½3«9“sað>ߪ!à… 0²É@ÓÞätÂß'uÐ.Ên¾;§Mö÷ቿÌiìB…ÕÎxø>ÅêŒ÷éyU†@óÖŽP= ØŸÌiÿjiÌ\i‚U17qy %œPíd«nèΜ¾<£ôiîE¾_hú¶½SlïÊØÚ,% € €å)X§ÜG]žÛ&\ªÉ“'ëÊ+¯Ôµ×^[ÆKYY‹ÖÖžÓ­Jï?”ՙ˽ÿÌ„ÆQ¿{emD–$¯^fǾ[cõ¿·l³ðýmΟ¨v¢=xuŒŠšÎýÉÑ’WeÃkð|;íAa‰õ½ùRë^z=}ЂuûÛ>ÑÃõÖm»‡ì5 =o—=Vòý•fµñY5o–æ\XÉ÷„fž(Y×óû-ù@@(ðß[ëׯ×üùó‹—]7{Ùm’Î DàÞÙ£”}»sú÷û²zø…œÞwZBï|'”b,%1óB*^ ñe¯z&«v¡¶}¿”n²ÆBÝt“…»Þo26Ì_ÉQżww å-°÷ðwü±ÒäSK {î¯îÚöåÔ´QjÚà{®P-Œ‡í£f) ÖÃP= Ø]td=ö¯ŽÃw/Ÿ“ßåàá»·}[òB@@á p>ûªúd÷Áßœk¬×›îÉh·ÝRþás:u õ»¾:Ÿ€TŸ@ú`>„·ð=ñCù(œ‚û½Ïä´ër:h%ª½4öäS¬ymÔ·ÔBãDõ‡»^—~Ë逅é=Tßháú†¨}кXw¦YV§¾U 3/иÅùëæå!{íøÁ5òå K¾ÿ0§ÝOä4ó-¾_œÐœwÚgOÜÏ®¾ok„ € €À‘ ¸¹!s0÷¡Û ~ý\VßüyV3­Ê°ê‚éü˜:}> ™­»-Ìý…ïåënß'M:9 à'yoMÃQƒÿ7Ép¯Ï¼O¯>TH˜ËJ-[ã =_R=ª{ ~p“—ö·@}^¨{¨vÏ,`†šYš·Yøþ£¬ðVåЯsš¶2 ßç^¨žçÁôi—a"@@ŽT€ÀýHy(@à>´;B[:§Uäô½³:íø@hõ»çò¡Ý| 0šíΫBïA¼…ð²ÿ&åKÀ‡¥á-„=«ç>ÓšSë.EÍΜÚÂîü°>üÐñm{-ÜN~ϳ-l™>UUoó©ŸnÁyQ€Þ¨G¡úáêV/|X™u´î±úýoÏ…u¾o½7Þ™àdõ‹£fvn×M1Î>a•ÙJ²8F —µ»SvHÍv‡J‹=¨ØÛ~ì˜`çÎ㬺¬Ô¨>D3F!€ €= ¸÷$Ãð~ ¸÷‹«dï=ÓÜŸÕÏåôÞ7'ô¶“¬t!?JæËŒ@ú'àuÉ—„÷*NRc½x«[ÜÖ…ëQ°ÞbºWiS3^ª›,ÕN¶‡¿uÝt'(ëßvi·ó…-?ê{÷ÐÑ/–x59Þöþl:ºèÐ5ˆïèBz¿0‘HRöOŸ©K-àêší®”–üþîÇÖß¼9îß>Þ&¨÷}ךÑE¦l»´÷Ù¨Z¨± ¤ñ¯±ªŸ,€oÍD{qÃ1<¯¢ÔÛ‹ù!€ 0ÜGâV„u&pÔ~Ìòe+µó ÞŸ\—ÓÉ‹m%ØN9†‡«öƒI@AÀK˜úƒCw=žS¶5 Öã@½ÖBvÚ p¾Ÿ³ô‡¾ÆA|Ü.äã`¾½Ñ¶™]‰ÌúiÔ[U5uùvÔ óîd}éÃù¶½v±`»…©Û;Ú­ÖßlájëŽhXÎ. ôöÊõ¡º!ŸG²ÎJB[•B5ã¼ ¢v/ý>}Ê<Ì]½m…h|¶½èN¿«%¼»EvÇKÔÝœ/îmß/ý.—ÚIùý0¾[#¨×wéïéî”tsNûž“öYøîü¾ßEméÇ-± Þxâã0~ìB¶gß¶&S!€ €€ ¸³”D€À½$ŒG<“}M9ý·ýh¸ï©¬¶Ú‘Óí‡ÂÙËZ2§ô?xxa™ €T”€‡”…@ÞK[èÝêUvXHwÇAxÛn íî†8”Ãø: è;³6ßýÎ# Ïm¾]Bõ(d÷/ú‡G°ï¡<Ϻ©^B¹t¬Ù6©}¿7у„Ãn»ðp¸þø^÷¿õQ`…õu-,¶çðÔLðvÔ]ÛM·ßù‘HVÆù›æîä¥Ç½i鸛%¼«¥P]”ïÔã*£ÒæëF~Îïnñ‹qõva'¾«eÔ ×mçÛÞŸ¨¿ø…ïQIø8O´þ8à£*i<ˆoX„ûc¼Þ‘AÞ¢È#4±þ\ìÓ– »3>M<Ü.E³¬$~ÑúÖŒœõ,Ý7„9!€ €@wîÝ©0¬ßîý&ô7¼b¥¼î}:«ûžÎ©6%+õžÐYËMŸÀ‰û ãó}ȵ¶*¨³âƒ¼@ªJ kÏ›ñ’Êqitæã0¾£m¬…öí¢°±88ú®%èkÇ—ÿyLΊϧ­º¤(¨—ÒQXßfnÛã%´­Z%o[Óžïn-êöÜĆ!tÊ[poçoQ@oVØ·ÝÅ(r™¢ÆÜs¿…¼]ÆËú³ñû= ÎÂíÎAzÇðhù¼ßCäøØ…ŽD­ßÙàÁ¹7Q5QQ€éñ°øN—¨:){Omyo×;¯K‡%â£0¾ñ¥è6 _g¿È¶ ÝAǰx\Üîf¯[Þ/@tº e²’£:Jò.8U‘–è·€Þ=¹£"Þi#€@2V·\»ÝŠhGý^ßêãúòòcRBI;6%”°ƒœ]¢ŒÚeþ̘ŒýqËØ­ré|;cèÜ'l/ŒO+k|í¯¬rÖÎÚÛ¸ßÛÞŸ“7·°ßŒÃñÖï˧?jÜ Z4᤾ð2MTJànq!/èÀÜ©>xvR8+§gÖçô‹§rúØ¿dµÈNÊϲð}¥•Ò3·z÷gû:mfß>µ=ù¤ZŸxB­¿û‚TJ‰qãzn ケcùÒWèAš.—¶¸õëÕþâ‹j_½ZmEíÌ–- FRjþ|ÕÌ›§”7Þm·ÃþÙ³Ãm>H‹7âgë'|~\N/?!õþr[®r2bY(w¯*(,©kça2\î \Âå C†Ñíj¯Ù«Æq»uÀŠû7¶ïVsºQu– Ö'Çj”Õ93!9¦ÐíÃjm\šúÝQ oA¬=7înón äÛ-¼÷ÌÃß–e„m} »ãþp\a¼EÞmMF $Ú” Ú”¬¾§¤s­Ô¸ß k’a(lQ‰]÷m™ª³îZ M|œOW—TÊÚ ž²á©U¼ÄwÒ–8 á¼{LøãºØ£\»ý4-ú1j?úü‡‹‡ñLkgóß§x*þaÿ¸ Ç}/¢iâ¯ãûÄ¥±"ëèûÐyÿöaEßëCì;Æûãð2ïŸþß´Û¿Âüü~Ž ÷íøÇ~~ÿÎ￾/wo;Wãý7>Îvß_gÛÜßíÇþ/´,ò,¸æ Æ%® ÃóîÅ!Žw§í‡¾ÿÈ/ÕË¿;û~î³]öÝxœï×µ^ä¹ ^­Èzcû.5Z€~Àto{êÑðhüA«'Å ¬²ñ†šIkíQVdÝÿ.·ØÓ‚[¬Þ™Îm+oÛ':t1ÍÛú8ê}¾uÉÑáwÍçþíÏÚü‹Ï †ãÚ}š¢sß·}ÿ < î<Àóã´ûw :Žû±: ¶üžßç»|7¢cz4½Ïw°^Ñ÷¥ãØÏkÿ Ñ÷Å¿7Åߟ°¿0>ú>z šyÄ~K?ÊFv>Ì?®¹‘qèéËäë'\)úÛ–?Ž„~yÃÂ8W36½õ¿ü3ìt„à]‚ó¦1Jíœ¤ä® Jî°s® “”{ÉŠ½¿du,m´ó­©û”9z³Ò‹6©mÑFµµQ-ó7*SÓlǘè˜í»:…6Ü×-~u„ïQß±,Q _¼Ü‚ý|`þ>¿Ž}+ì*¸¹G|Þàmí«äïæ*ù¬5ÏYŒçØï>»Ð°t½ÚŽ]«ÌÄF¥¶LUjó4¥6MUr‹õ·¿G³w*;ÛÎ)gïRnŽ·÷X{¯oÆÚ¶ ÿÖŸ[Ecâs“x9z:g)þ[Pܿ߷q×±·­ ÿ&yï«~nëûr!„øè»ìÇ?ǃù|8w{Û¿þ÷âðµSÛù\²ÓßÒü¹²Ÿ{ú: Ö+>7ðïDÇ9t´ÍâsÕpœoÍpG|Njí¾†³öû¡/¯è»i¢Âý¹ãbTO¨|ºN®ò°|¸çѱ5:Äûü¡Ç“îŽ%¶wúqØÏ;Âã±Ý eóîϹEçccôÛÐ¥~1n0^~ާ Ënßõxü(wÇÓ…ý…c¥9Øl¢Þ¯Û3kó»\pŒ_½S pxÏ'Ö[ÁÃùV°œ_îå¼ulÙJ¸o´PµíÙg£µö೦FAm­‚¢¶ºôûø®Óy¿‡ïÍ¿ú•’¬ŽyÇ;4Úà}^#ùµç@N÷?Õ÷¾Óré3¬.Ê·XÉ÷£gu>éèu„q(Ù9¤Œƒ$û:ÂÿƒÙÝ Änûàõ›”[³A¹×*÷ü%víSýÂŽä5sÜ ½ìDk¯Pm}C¨öw›e›š:xæ‹y+9ï%¬Ó›6)ýê«jÛ²Énm߬LÚNbç̰f¦ †5˺gØ ü ûÑ2m²‚©ö#fòe½”X>؈®ˆûIQGŸ8Ÿˆg3ö£¦å ²--Ê´6ÛCí‡NØn±ÛÇmX›¼ZãóM¶RKcìGŨ¤Ú­K{*«¶„ ‡?¦í¤Û~,º¿ŸÂtýá\|îÝ>MD±QHåÛ¬óvõiý”5úq›ä-ª ì„ÌV:hϨ½å€}µF!µlYöÓÂJ½e¬´›¿’Y+ §šð„¿¦Æ~œZãû@§yZ¿6nÖõGIqP”¶JN3íV#m>îþ0´÷øg&ìÄ+}f`¿Ërùë$áççü¤8¿üöù55ö$ÂÆíx™|¹º.›Ÿl•òþ¤ÌïñÉdt¢\tâÜÍ g¸ÿØûŠOFý¾6¹(pè|!Å׿øÂJ×þèäºóIm|ò二¾GË-S¾? c¢aÿQÒQ*ÅÄ÷wçÇÙþVüc)üaeï‰BÂøXbmÛß;Ž-Ñ~ÛÑßýñ§Æú÷¦èÂC|Á!Þÿ;æÓfûdô2ã½Ýõ‡LqØÛõ»äû¯OüþŽý+ÞFñþõ{ ê?¤;8 ã2Âaþ],4ý‡´‡m£,€ »ã3ßöííË…´²v¿ãïV×P¼øXVø>ß ÃlÞÑlŸí›þS?„¥—¢}:žÞ×1<ÞæC‰Â>hû_4¼óßÈîÆÇÃÜ8ü‘ßÅ3þ1èíÐÙŒÃayïpxa˜‡aÑxhz{ùƒÞ^~ ðïN´Ÿzxí³Q»s¿_ öuˆCù04.º¸Tç–l¿õãbñ±%ÜWÂ釋zÛºÛoz[§žÆ{(é{B½«e¬èÅAºêÞïÃÇåÇ{Àîûc^Ñq É¾û‘a³:ÛFý>Þ§õíêpq˜V‡ç…ñ££ 8÷e;÷gÙãi£íÖ9DŽÇ ´íÇœÎá`|î}§ ç¤á1¾ãœ&úå§µ¿¾Ïú+örŸº¼GØ' Ýù~?Öú0µãíÏYÛž¥=5cuÆï±ã±qÕ8M¯Xéð£:ê¤ÛpŒý ËÄñïdü÷$>æþ®øùXÑßÂðøïN~|׿7¾\~¼Œ£ñ±7·»^mÏLPËSãÕúäx5?9N™ý)^~@£O8¨1'ZsB³ên3+;îÚ?;(G3Âð1:iµ»Z7Ô¨uc­µëÔæÍÆzµ{³©Þî‚M+5÷`x@jn“’ó(9ç€s(5Õæ=>ºóÏ—~슎íÞ¶!Þïÿ¬íß¡xÂþp¸‹Îm:ŽÏ¥¿{À÷?'ê¸ÖÆw¾pÔQ§8¬÷¿…¿}, `—›”Ù4Z­k¼©SÓK5:¸Ö.ÙùTÝ‘={ÁŸ?`M½W{d÷ÛŸâ~¼"óÁ:>õcAeÒL‹ÝáwfXků„ªÒ„™"På~,#p¯ò<«WêÀÝCR+rìÖ>Ò—WiÑòÐCjºóN´ÆÃÕQo}kÀŸwžRV¢y0^~2t }ö·íÔ>{úWcÛ.íkÛaý;¬§ýxhîTŠ%ü±\øÜQr%ú1Ýq²ÿpîøAíWГEATü$ªß¿gÏTm~õõÚ¾i¥’©š0óšø°õ/Ú­ÇVǶ@Æ!…—R‹C¤®!ThNàò!¦ŸH·îܪ–m¯†íÖ½ÛÕ¶·Òö»%;e¼²Æ*;n”20Û0ÿAÔñãÉBÖ8ü Oí‹ͯ·—ÿ@èËËFnG ?yÿYz›°à8iõÐ&ì͉ ?Z­dLs{nxØYcM­•KÚ…!›&hK‡ÚÚØ´µÕb?ò¼»= O©Z»u;j’ö~ïj-ü¬µÖ$m^©ý-VR©ÑJ*íSbû^+µ³[©ƒiÕ™¨úñSU?qºFMši·ÎÎVÍÌYJÍœ©äŒQÛ.0מٹS™]»Â&ëí|Û.Û>{wªµq—Úw[{Õ¯»7 Ø3¶‚)“ìDz®êg-ШyG©~ÁѽhiØï··ú~0”'Ê~¤õÕöÃj²›·*Øj¥š¶l.¦Ø•ÌÖ­J[;»{·¬ä—9…Vq;6+êOÚÝýyå2VÌš°íwçÄÝÞö~¿Ó¢Þ¶í˜1‡Ý.ýùL¦<ð‡lQI¯Â1)_B:³äv<ŠŽyñ]#Ѿ³ï“ôåDZ0€+„nAfÈyàÙrÚ…°¬—˜÷’ñßÿQÿýðà5î¶ 6þ{·m||ø7§ðþh>]‡Þ¾' s}X)Ö»«[àùvñRƒññÝÃLÿ{È«¼|»õ´¿z oç’ãÐ-l{`•/©èûT|Eã:ú{ Âú.ÒûÅÿ»ê^BÕ"n²Ä>çuÓGuÒÇA¼WÓ2niG?Îk×túùýf•ä(ûvzÛ»VÖÑmUõõå§Ýýx>îz̺-„lÞ*M\hòk­9%Ð$k?Ö2õ|ÁоÎûpÓe39´ ÖåÔ´.j{÷ënÚ Ÿ9á?3â‡0{ÛƒÑQÓíyÖ.Ì.YïÏë°ûµñµS­ÄÓTkO±PS4¾Îû§„¥Ã’Ìa‰ÝŽÛïã’†4{i‘ðÄnJ‘D¥£ŒþƒÖÃŽCCï.Õ*ØÙqG ÀÎ%“AÖ¼2N?7V/mªÑŽ} {Ȫ´`rVóZ4·¾QsS{4#»]Ac¾J—âãùä]«xñ°3au©×xbT-L¾]³paŸ6µ‡+qi?o{ÉÆR½¢`ª#„rþ¼¼*£°dü&+ï]ÄÉ8йúš¸êšâúæm˜×A?З×g–Ê/ ’ã@¹xxvï^%&M*Ë–P©8TÏ<…Ï“'+aMrÊ%ãnïÏ Ç¯äœ†Û̪½)vò}Óûcðߦ Ÿ`á¼åa`Þ%PvÖݶÓËïÊñÆ/úCoìLÚÍ­˜~x'N¼[ø^Ü.‹ûãiÂù57+gwJÄM¶KÎúýNŠp|×q6<žÞ×µæ˜cT³d‰j/V5Þöj–z;vZoz@@ âü™û‡ÃZûwÒ~{8¬žv]ÌënŽ»;Úv5ÔΊÂ÷|Ÿ²‡¾&ì™Q…€Þnúð·iƒ…¡ÇÛ]Ò¯M„Áºì¬ßŸ0œ/ÿÍáÏKˆöÜb®òle§Ô¼Í.„[;æF®µÓÅz»!¶ëžkÆy@m+,¤îÜtf7üî(ªuÏ´Fz!P÷€}µmkk{˜Ýpt¬Q°n»_x©›Ô¿í“µK~!¥Ùù–|;|0pQw‹‡ôÖï7x¸YÚO—müçžÝXҫݡƑ¯—{ð J»ŸˆßV“Nèà=„\éö9Pøž§¬¤‡²ÚñìÖX­cš|j ©o 4å Ö¶¦Ö€]ü ÷¹½V.+Þ¯|Ÿ‹Ãøü°Â8ë÷ýÓ¯ýÆ…üɾ¹U²è»çº/\$ë:}ØoßcsëõÕå§Ïᦷ²mó¶ãDïývZüž¢éÃýa´¯kÑ÷Çú‡ãûs¸õeÅîÅtX Ò÷âõЩùÞ{£ÒïwÝÖ?ÚJ½‡ÕÏX)øæúŒÖì}\/í}Lk÷=¡Ý-›Ã‡^®_Ñ=L÷}¼ýÅ+tû0ë÷ÛP‹_þyaði%Š=4ó‡B&=ئ—×…Þf²ôZ·3;v¨¥©M[GÍÑæiÇk뜵eúñÚ é v;ìøüÃL‹Âf¯ÎÇëJç5ta¸l%»ÃpÙÚþŠCõ0X·0> ƒ‡n‘*æ“üÄ7üŽÚE‹80ëôχçá0 Ôãqa°^°fM}»ø<9¯ê(ßÄÝaÛBy¿p“õvwãóÃü#VbÞ8ë%ç õ‡Ã»ŒKOWÔíÃ}™Ú_z)¬?~ ­?ÜÖŸáA|­ñaŸo{wï8 £@@ Â¼Ú»1, åÓÈÇ݇ôVnÆrê%Ù«¡”®×Q8Ÿá=,Ý…òíVsæ¡¥²;—Èö .ÚÍ¡=Ëa hå²(€ô~¿Ð‘ÃÉ|¿‡ùøœ•ê‡y¿ÚÍ›­dù¬(DïTbÝBõ1óì'j ï*èË®íçÞ^Þž+]pðŸÐ¥,øÑlÁ¾ßUðÞöm7aYTÞøI'Eý}Ù7[wE%×wæÃu¿SÃKîO±p݃õ)oLؼmÛ–ø9i~Ãn”ÏïwQ·oÓð»æßÁü±ø;èàŽ»Ã‹fùñ]§.¨EûY_¶Y_¦ñ’ûv£|â{o5Auê÷a~GIØöînûí·üðŒ­‹_Œ)¾óÁ÷m¿ˆp¸‹ZÑ8Ë]ìNž¦óïY§0?¡l0.†¿5íXØy{Dý~!Åï€àUîÕ±‡}-*9pû©‡ôü#·è¥ÝjÃŒFíS§9­3´xæiZrÔ9š:jž…êVØJB{XVÉ‘¯Š#Òãª9Šûãn/uš°ê*¼ä°—Œõ‚zXVcRððÝ›âîp˜—4õ°o€/ÎÚ_~Y¢ÅZÜöå÷ÊÆ¡Z\ÊÕCòð£^:ÛJÛ¿š¬tË;AYo'”¬YoÝÞn±šSæM•æO ´ l¢î)ãø£QìG7• à0öcFx1Î.ÈŽv,INœ†ðÅA|x ±cIø¸Ñî¾8Î. …|Æ{(ß´Aa©õ¸{“M7ùdÖã€ÝªÊ±ª†x ­@·ß{V]çïTG¿§ÂÀ>žÆ/Vذø;Wü>¯ÕÖÅÞAà á}Q¿ßÝS¸¨Q¸ á?쎠ü…ÈBÛ/Hú ûöòyÇwDwIK¯NhñGžûDsæÿå"@à^.[¢Â—£’÷¦ö½…ì^Š}GóFÍo8^ÇL8EG%—hÚƒ›ÔvçOuðž{Â*8¼Dh¨[}И'­¤pqµÅÝÝVÑÑ¥d±WWVg±q£¼ª›´µã¦Ý»m˜û) Ý{ ä= OX‰r¯#Ò‹K¬·¯[§äÔ©Q¨Þµ´ªUër$Uœïº{íWÂGa¼woÜaHì$o±=Œu±•¤8ÆÚÞLÏ I±ÝTŠ€W§ãÇ”B‡òÖÎXu<);Õ,Z¤š£V­WUcí°ñcM]¿žœU6$~ÇAzýúh½mݽ )FB\ÅOØ=ºs×jl|)Kj Žÿ=Š«(ò‹Ãþ¬îAÂ.°”û²†óD@‘%àÏðºÖ A¼•Š÷‡—^÷*b<÷Æòª^¿sÇøøÂWÆw„÷aÿA»ƒÄ‚ùâê|Â÷VEO¦ç«ÔÊWÙVõãÝö“h¨ï$©Þ-U¾kFà^¾Û¦¢–¬’÷Ãì²/·<¬w½ëð©õ‰'¢ÝJ§'¬Îk/>!DÖª˜ð¾8Ãø0œ·:Ä=Õö’¥aÌ]Buæüp½¶ØÃw^ÚœÓê°‘ÖZ=~µv%x±Ý.åá{ÄOËIËpm#>Rø±ª}íÚ°Ššö5kÔf·½ñ ‹©9s¢ð½8ˆ÷@Þz¯ g¸^þ`íð롺•àOû…|ãÝ~'_ôôçN¤¬jî\+cÏ×°*~ºVýÓݰ°þ~p®WçÓ%ˆï ²cw\EQ\eQ§gUaÔÝøâ*ÜЃò00ëð÷¶WgÖ¥?×ãúü}ìZxa$¬¦È.dí¹îãm“ö€ñ°ñjÂâî¸mÃâñù-‡kâs@@ :ËÒ‹Õ:Éj,Úxµ¾IàÜÞùwù.S‘sN,Vš¹ç@kãÓǵ¼N#V[ g%Pl‹Ô(6Äb‹X²%c ´aßç™™wfö‡>Ñ–öÇX›ùÜ3ïüf¶fïçýÒN²-øîåãxmNÍÒ–Ò§€?–†°‚ør ü{™ #Ýd¬Ÿ4ïžÕZ\—Ñ‘_êéñ:X·ïjÓo»~0FÇÆV € €@Á p/ØK—_ Ï×€û±_}_þîx“,¸f‰׋'Àž_WbRsé²ßüŒ À[iø×ßÒ¶ñ´`¾_ Þ/ ¿Hƒð³´v( ÞyýLÁxW2ÞšÓò‚ÍŒ¶Às,èN[yë­9›ò›nÊ ¦õ«´É†+°Òð^³kéy ÖÛõt¥êÓKà»RöñõV"_,3«`Ázœ×Úa?#Ö×H¬£noyÚ|YÚ|.Já[f²w/jGÄ®æƒËTn<Ü:ëƒÅ2ƒ²6Q§µíly|Ý•d YP8ÌP±Ì½†Ö—ƒ·Ì]Ï`ì}65àîeP¹f£‚¦¤¼&¤ô³fÍ.ûà5 ¨F–ig‡ÞX§/¹é`lŸ‹òùóå*ÍŒ²ê+ÔgÆwÊL}ÍøÿAf|ô£Âß b¿[8?@(%î¥tµsx®ùp?üæsò̉¯Ënû†|Pƒí …'¸¤mÂkÐÝ‚ï®Ië¬õ- ÃlñÚŸw­ÈЦ‰²µ¡oîÈ[o\ ºOöÔ’õèN Ä» ¼ä/Ys?P2 ®MþLÔŒ5 ˜Ð µkBª\òÖ””`½ëa¥ì]0]êá´-×ù¤^7¯¦C$ ƒ¥:?-èà÷ªà<Ì«6¶šÞ+}Yú¼n'nû`lÇK¤Çç-“ãJó²~‚\~@ƒVJ~zM_ >( _¡Aù©lÆÇšå²tºÀºíºÍÐtÎX¶ÌipÅjYi¯É®X®o ±ÿºMFó]. ¯×s¸Á2â.ë=mtëÄõôyËà˜¦Áâr½Çì¾³ÚNé5–‰cM“e½Ÿì¾ŠæÓ¦í~ó2ºô>ÉÕ`Ÿƒ0˜ž\·Ïu…uVîjš[Vë'£æPÐGÆr͈sµ‹²õõa÷§¹ZF¤ç¨–åjižÞ8°µio^½½ «\”È~ãMÑYí%ËðÈEí¬‘8íóæÕx jì„5x¬fþ=·ŒÐxæ¥Ë¬´±÷ÒŒÍô Mo>K¦§Õô±~Ò\í-Ûg–!?ìûÔÅW^‘ \·»½.vvzÈ3—/÷šôžmúL³çñŒ;îð‚ï3­f—>×ìoÅ,@À½˜¯î$ž[>ÜÿéõoÊ¿½õ¿äK5ÛeÞÕüŸÄÛ /e_ ßÑ‹~0>ÄÁy Ò¿¥¿©Þ×V ®×ßÇ”¿vV™TkKÞ«ÒÚŒ™­¯*ö—ù%ê§"x’ $@ ÈÖ„Ôåsç¤L×.à鯮$²›·q©_,ê• JÁ[0ÞÃ°ð‚°°@²ì7«4%µ-ˆ2¨Mߤ×í6ðJ+Z‰E °ë¸âCs&€ÕÔpÁ÷Œ~5NŸöúyp%ãË5 ãÕ2°àºÕ5ðkÁ_ ðYFMøµ ¯6Ûãënù4 Þ”Iáð­ÆLÙ“žÑ3ìrk*ËjÍhð0ãZØuÉöJoâJ·±Z1V“ ¬§eRYž ëc$¦»àºeV™Ï•4%5–¶ez…×@­Þµp×ÄexèØîS »krMô:yÍ'¹ N7ª?–xß,iÓ–ÁéÕ&²¿ SÉ™ng^`ÚîQs°{Jï ×ÄØPã¬Ûè5·¦ó¼ÎÖµ†eRY­;ßx3b^`Zïñ«¬é1W›IíÝro[½¿†,#Ò‚æYkñ¸¦²týPV‹Çî?ÛOzfeÖ Ï´ Í”mlzÅ3Ží^òú… ÎÉî«!Ï3vÞÖ|ÃÄ Xæ¦ ¬_ø·ó2‰íoœ×ÝËJ³[í½ôaPÿ¶{Ï4 ¾{µ»Žñjºà»½Ï¦­ùµR,ÃÊ °Ï}湋ç à^<×rJÏ$î—“—eÏkɉw~,_Zº]®qÔšpðüè¿àâ-ߣ¿‘úô;moRzmìMÛ2ï÷×%´‰hëÐÕ^~p^ƒñÁ´æ½½éµpÓÕ3Êôec‘J}ͨ˜üRŽù+OÊ@@`¼^°#À[ér¯‰! ê/¯¶†Ã> bÝ”~ Ür7Ö€‰ û6ycA/¸Ö-ÀnmÏçz°`ÿ% ð…ùŸÿÜ 2†ÁÛ µ¥/_ ´ÆkÍ„×#V“Æ-KÇ×k ÑMÍ0YP]›%)Ó _,,VJ>¬iŸ½Z:mc¯k†K¯uØDW0ï5ç¥ÓvxMuŦ½uñ÷è´«m;k¶É5}åÆ^XÚ·›wã±ö—`Á°0sAÓïe:è=꣫ƒeÖ4—‡]Ã4ë(oŒL9ÏàãÍ©…ÓvîºÞ2ȼ+šá®EüïGX3Ãþ–heÞåj°Ï»»&ñ&áìïExïÇïéØý_ï>Þ²øgC·×Ü&±š6^-¯ ¦—ˤN¯3–{ß2ú¼ÒéZjÝ•`·sñã±»Ý3ã,£ÓšÂrM«YÍ.;ž=¿ÂþM‚ ¼}¾G3x5tôo‚—‰¥5slœ5CK—{™Dæm†jšÍ8\[ﶯíCïÓôÌ£ôù¡2¥Âæ5ãÊîÅë6m’9_ýêhN—m @€€{\¤BHâTÜ/]”¿ëü¿åíþ3òÔ|KfUL\µèBð'¹°½ ¾¿«ø> Ä»À|¯æ5HoËÞÓ ýyíßïýàuA {Xa€¿Z¿ÏùÓ~PÞòñùh½xÃ^§MßXó7å4“Û ÌÞ@( `x¥h-溠|ú2Oë,è°[ ŠB¸¤¥ -plAdo¬o×OE|l@[pÖJºà»ÞjÔXÍ/  ¬[×Öe ÚZ&‰WÓÂÆÀK@s²lío{]à×2æì¼½`º¦»Øj y5V¬6†³eò¸ÌwMcãá®mz`Þ2^œ£äÿc¾ÖÜ•³¶`ª—ÙÔ>p5,ÔËD³ZA-Œæéâ5:lwÛzã`½ÝGVÀõkb5Q²Õʱà¿ÕÄ ƒñzO§é-X¯{k:Ìkæßÿ]¦ßr‹Ìˆ×§ÿöoûiÈÑÍëÕ®Ò&i¼à»àíõÒKÞý:ã#ñ2ÂzP×ñj…X?–Ñ¥K.Ã+k†–e´ÄãÓv]œ¯»F:ïü-CÇ­÷–Y°4DPÞÖš¹±Àû€6uãÆÖÖüÀÅÌåþú¤t¿—” ±íý¦p.{Mã¸fqlÓâíÕ§·OÌWjð>lÓ>XvÍL¿&À5Úí5Z€6ëÝÕbŒ € € €äF€€{n\ r¯gÞ{U¾¥%Ûë~ýåîßü|Až‰F`ª¬™ðNMCöÒó©Û =g¥ì­ýùþX§±ïkg³w$kˬYœ¨]û¤×N½µUoíÖ[àÞJÕWÁwkŽçšÊ2©òÆ~g²Ñ´èunëm§ÛXi|@@@@á¸ïS2kO¾û¢|û'ëeõo}YîúµÕ%sÞœ(ù.`¥ì-ðm¯h{ð{0áà-øÞ§Íà¼7ôñþ´å5`ÿ®® ôïõ_ö¦­É âÛP¡OŒú²ñt÷Ò ¾?]- ÖyÛëzûh½eLX‡µ×Î*“Ù³llÛŒýœüTñ? € € € ?a(uûyùÛãMrÿ‡þ³,{w©spþ¥€´ç\#ÞË?ÁѸ­¹+!QÛ©·—µW!6}QƒùÞº´ml™mgÁþÞ÷ƒmtÞøïžOÊ;çÅ{Y&€á-ðî¿¢@¼åÝòÙÁ´uTK›Ey›rR € € €¼÷‚¿„Wv?~ë{²çµÇäÏ~û¿É-sþ·+ÛïF¢°ær¬W{eF¼Ïö~ È¿û¾|âßÑ ük¿Ôu^`> Ð_º$bAwœ÷:¦Mé¤6³CÚ¨[¿£ÚhÞoj‡~¶+Ã2@@@«÷±ŠÑöÏü½´ŸÚ&_ªÙ.¿YýÛEtfœ ’€•¾wÓjÙõ“níÕ[éx Ä[€ÞÚ³wÕÕ!­[žºß¶½ÐÚ·Ÿ©¯iÓF<ü¨7°În+5#ÀoÛ?jãßæýå©Ë®žÍ»÷ÑÔΨ¹Ù@@@¼ àž—aòÑ~j»üð—OËúì”gÝ<ù àˆ €À8\`zþu¶ƒ‘ôÃ&™ô›Ë±@ü Ü'.·õØÖ]Ò}ùÝjÇ·ºï¨C[[ž”7{üq½åÞúËá6ö>k’§B3ü€½ßŽõÕe^é~+á_­Þzc›ÖWUl~:mâíb±5 € € €$@À}‚ e7\úî‰9ÞýCùòGŸ93o,”¤“N@`¬)×$hò¹Æ—)péR?¯ø¾~k _ü—vfkíâ¿ñ¶ß î»:ݧë¬i à[‰}똶J_³5HoîúÁy Òëô¬™~‰~;÷•ò5ÍS>m|éÎ!{E@@@ 0¸ÆušT^ºœÝ?Ý$ož]úèßÊ5ÓçLÈ~Ù  €ÀÄ LÓ€·Ìíå£ €[ ¾× Ègã-hÿÖ;~P~@KÕ_LŠÓ›Ú±ÒùÖ$N<oMîd ÐÏÐoåZßšã©Ð4Ûû¬d¾?ïïÇÖ‡/]Nëöå)óº.˜¿ßßßèÎßi1F@@@`*¸O…úóú™¿.ŸYü5™Yž³¢œSxv@Àõs®ïåkŒ=PmAû̶ñ³è/js<‰ËIIhg¶ç5€ockšÇÛt–ùKºý .·p½±nïæmûø²ËºÎ ^`Ô}?ø¯}þÊUúoŸÎ²L+u-Ï×Ö€ìÞ² »ÏÉɧ;´ € €¥)@À½4¯;g €­ÀÕ3ʼàësìG¤+†•ÚwÁx+Q?™ÃhßV{`@›²ÚÑ8™2o} \´eIyç½øvÁòàý¶ÝPMåòÜGsõ¬f†Õn°Ë`÷ÙZ“Á—yÍùóeþò –Cµõu6?dµPŠiLX3T⽬l:Zfóv½­ï;ïå5Ť^:oM2Ù2ëσ@@`ìÜÇnÆ;@@J\À•Ú·ÒáùtÞ¶³à¾̯»Æ¯ÁáÎm:šwõ+-n¥ä-oÁw«=`™. ÿžÎ¿§ó¿êKzëmþü…Ë) ØÛy¹€ÿ¬ ð_©Myy7K»mS©ç7S·±Á:œ¶ZÞK32¦³-³íÝr{µOtwV‰Á{išRƶÜ-‹Og,+ó:x¶ý]T›°? ëCÏÕÍ››Ý6ïîøúø{-3e¨´¤v&]–=i鵦 |ï˜q˜â/s×Ãî“+½G¼‹”ãÿì°Ï£ËTê× %û,xý¢èùºq!œKŽ©Ø= €@ž pϳ Br@@@`r,¸kA»®µãi“Á°ýs®ïå“ŒÍÆš\²àhÔ¤Mfé|WB¿»/ ¨Z ~kÉ.…µhã‚ံ¦Ü2o>XoËüõ~ÛýñõÃuØl4[= Ò‡ÓɰÃf ô»m,=~-‡Ô ®vƒeŠX͆k4óÇ›Öy{ìÕ„Ð’ÿ¶ÌÇÙÓæw2‘Á¦ÍOÕzpi³is󽓒n¬ƒ&†,Øoé´ Ž(¤Ì Ø[Ƈ­³ôy/=g:³Ci[eGº½Ë@òÖëõñƒæ©µ1Îëµ¶{ä¼Ý'úòÓ˜º™{iÔ´Z†¥=ÞL–»Çõ=aiwÓÞç[ç½eúþp¹^ûÜ[Ú¡] ×a·w½oÿ‰®‰/¾Þ]'[ÞwÁ½™=CE3PÒÖÛûܽmëlÞöëú ±cú5d´£s=›wµ_¼qÖù¨Ù3wŽñçÍÒg÷öpµ~üÚ@Ág@ým{÷‰ÆþçÀ®ïHƒÙŽf°í¢ÚBÁùgµÙÖÝW.Ã4Þy¼ÿyÐûNÓî/>+nÞî-׎m¯lE?x÷±™èËÿ¹„fv£3 P"ú§@@@‰°&—®Ñváí Z"‹á¦rïd%í½ 0Ðígˆ¸  h»Àî 5yä¹S›>Š‚Àñm-™è´í,°_Ôfpµ,ˆ>Gkk,¸>5èŸRcà þïaM2Å𮿊 ƒÙ—èòÞ÷ý’óÐv™:áX—uZƒˆ¶Ü‰–ùãã\´i‹¨Æ3P¢Lœ(XŸÐšÙjnx|uòƒûþ~ìX©Á^?i™®6Œ1ýÀnöÀ¦ÿþ‰ê´Ü¿g-öm÷«ÁaµYÜ´«éaëû´™ªh>ªrQýãËGLîãÖYÀ×z½±w½ôüÕÉ øš©›¶qÚ¼Ùº ¹ùÛ5Œgt¼oçmú:£ÃÖ¥~lÛ‰ˆì@@@@@îÜ € € € € €L€÷ @d € € € € €pç@@@@@@`¸O"»@@@@@@€€;÷ € € € € € @À}Ù € € € € €ܹ@@@@@˜î€È.@@@@@ àÎ=€ € € € € €ÀpŸÄ\îâüùórêÔ©\‚}#×O?ý´lܸ1¯ÓHâȵÀ'?ùIùéOšëðòV µµUìÅ€@© tvvŠ= (e¾•òÕçÜM`ÿþýò…/| J^ ¯¯/ï Êó>…“À„ $¤¼¼Ü{MT²/]º$/^œ¨Ý± N §§GÞxã‚K7 F`"Nœ8!ýýý¹Kö…@A tuuTzI,-000 ö,`@ ”ø>TÊWŸs7ÞÞ^9}ú4”¼ÀåË—óÞ€îWx‰Î“í¯‘²² ©¬¬”ŠŠ )[ºZݵWÎ&®pç¼@@@@@ `¸_Á¥ê9ºK*çÕȃ›ŸLÝKG›<òÀ*YPñËÿZ©ig@@@@@`\ÜÇŦoJtÊWïx zwM£ìnß'{v6Km¸ôq©ùâSBÌ=a@@@@(Zîã¼´ÿð ÙáÞ[Ó,'Žl—Ï­¬“û>¿Iö÷‘F·îÉûå»swŒ@@@@@¢ à>®K{Nžk Ãí²ç™&Yï~¶j™<ܶ!Üóßµ¿N3 € € € € PœÜÇs]{:eoGðÆšùDJ´Ý_¾ðcŸ’š`“{_’žñ‡÷ € € € € €Œ÷q\ª¾×_‘Áûjïÿ˜ÌͶ9 å÷Ýò?×iÈÝi0F@@@@ŠR€€û8.kEEô¦ê™³¢™øTù<¹¥Þ-è“A7É@@@@@ (¸ã²vŸë ßu›ˆÅè‡ÛŒu € € € € €*@À}®jÑïɆ öe·/Çx  € € € € €@± ”Û MÆù$Þü‘<tšzôؑۗŒxØñ6)3mÚ4yæ™g¤¬¬lÄc¸ ì=W]E^Šó`\Ø—/_öN`Ïž=…}"¤+¸té’Üyçcz\Ááx+y'àž_ÿú×ó.m$ÉH&“bŸƒéÓ§OÆá8y)À÷¡¼¼,$jxL"6‡š4ÁÁ±GL+âm}OZJÇv îcóò¶.¿zvø®·úÞ§Ó'.„ ªd¼÷Â?þã?JGGÝ÷7üļyóäê«G×ÔÍð{b- € € € € 0ñ§OŸËLíP]]-‹-íæS¶÷+¤o;ú3IÈ2É€ì{MÚÛ‚×ÿ®,ž9¾­ZµJìÅ€ € € € € ß´;2ŽëSµøw¤Á½oÇ¿Èñ7{^ù¸x{mÝG¤*ZÅ € € € € €@ pÏEy«Ô7º7î-ßéf‚ñYùvÓúpÙgk?N3 € € € € PœÜÇu]Ëåÿómá;Ÿ|àVyø©çåì¹srîôQÙ²zl<¬®Ý&Ÿ¹òí! € € € € €@‘ ”iÃô£o™¾HÆwZ Ùÿè=r÷#.²žm/5ÒvêˆÜ»0£…÷l³ @@@@@ €(á>î‹W.u›Ú¤½%l[&uO5 ÒvüûÛSU˜C@@@@ŠV€îpi}g¥ã¥Né:Q÷6]æÝ´Dj–ÌʵO.»@@@@@ D€€{\(’‰ € € € € ß4)“ßׇÔ!€ € € € €ˆ÷¹P$@@@@@ ¿¸ç÷õ!u € € € € €"@À½@.ÉD@@@@Èoîù}}H € € € € €@p/ E2@@@@@ò[€€{~_R‡ € € € € P Ü äB‘L@@@@@ü(Ïï䑺H ! )//÷^Ñr¦@À‰ÑOˆÿ¿lÜ…, ÷ò@Âîå~é¬9U3Gy6<'F Åfy/àßË~2ËeæÌÑþQç3÷—–ŽK` ¯Oõ••Uú;`ø]ð}hxÖ–‚Ï‚R¸Ê¥rމ>é×@"‘)¯Òß#<ž¥r‡pžC Lý³€îC_¼X3pî˜lx”•Uè—ìJ©¨¨²¥«åÑ]{å¬þÍe@ ø䩵Kõž/“ÕÛŽpzrì¹í²¦®L?•R©ŸŠ }ßÚGeï±s#¼—Õä—À¹c{åá5uRf÷rårÏòj¹®ºRÊêÖÈ®çO™XžCÒ°¢ÀúN–­úgiðǾ÷TVVÈÒÕke×þNÍTÍ>ðÈîÂÒâ8¶k­TVWKµ¾¾ÕÑ3ÄIñ}h˜ÀÉç¶Èšµk塇âµV×o‘ÎÌãYiÂ’Âè9¹_Õß•þßÿë®»NTHÝÚ­rôÜ߈øm\¸—œ”«@âÜóú{x­¬ò6èó`ÍÃò|Z`4¯žI†¼è>²3©÷Ü0¯ ÉŽÞ¼M> C`|Ýû’µÁ}_ßzd˜}t'w6 ÷ùdãîŽaÞÏ*òGàøî Ãü­÷ïóÚ¦¶dZ’yN¤0[°½#}çÑÏAý¶dWÚòHa¶¨úïNy6´éÎr~|ʂ¢8ÔR›rÏgÿ-\Ÿ<”ö˜gA^p’UàD[ÓŸƒšdÛ‰Œ_ü6ΪÉÂBè=Ò:½Ÿÿi9}7Ê·g%Üó5)Ñ)_½ã(u5²»}ŸìÙÙ,Œ †Ç¥æ‹OIŸ›eŒ@ ô=&[×=$FqO}Ux2Ú°¡e·ìkß#ÍÑ'dÇý5²ëŸH‰©|Hœ|Zn½ÿñ(iµdϾƒr°}·l¨Ø\/Í{ÏF xNDL¶€ÞËQûÎ#õÒº§]ÿ¦ï–¦†šèÜÚ”¯=ÕÍóˆ,˜*>ÄIiºõþÏ‹ïC#±AÁôÉK?t¿j¤¦&ûK䩈ŸÏ‚¸Ó.8»Wþ ~sx5 -²ïH‡Ù·[Â¥Rÿ…¿•x'ž!…,P1cÄÔÇ~xÛξ:hf)Ÿ…”ÛQJi=¾»1ÊÙ©iNžŒ}ï‘dc¬äûNйÇp˜,4þSû’MÉúšÌÜÊ!K¸Où 4µH9펱ÏOýÎdZ!˜”m™A`ª6ÇJs5îLFyô–²Áä¡m ±çAKX—çÄT_9Ž?Qgö5G÷x­~çI+´Õ¯RÛ~Fø LÔ`?ù'0˜loª‰>Á÷þŒî|Ê¿KGŠ®@àT²9ø=P;l-×ÔCð,Hõ`®ôoÿ†èoms»þˆ ýÉ a¨&Ù~&X˳ †ÄdÁ ¤Üô±³ –‰ý6®mÙ~FòñY ±ä3™7]É–XðqOJ´ÝOä©¶¨ùÚ–Cy“r‚ÀX†«64TÀ½ë`Kô#´qOøG6:ö‰Ø—‘úäÁÔf´SL¹@w²µÖe65$¤½äé—k-ÑÜó®5ω)¿t$`Â:¶Õ‡Ó÷œÊö-ûT²É}´Y?•ÏÀ„]v”wgÚc™PîÞ×qzÀïCywéHЕôIjÅ>ïyмïÌ(÷ij`”PlVÝæUEš“§²¤ùøî¨ ŽkJƒgA(¥@ÿñX”Z'jj2?Ÿ4)3b……)Ø §SövÇ­i‘O,Êì‰záÇ>%®*Ž/¥T'š‚sHÆ-PqýG¥µ¥UZ[õµm›´4ÅÚÐb¯?ûÑÃ5Í ŸÌOÈ"ùT³kZ¦M^|=^á.|+L½@ß«òì µ¿+‹gfIÒÌÅrwìcáU£æ9‘ŠE…*ðλ½AÒkå7®Ëü‹®](ÉÛîätS¯«0>N„q± œÛ/ «ñϪ¡UÚ¶i½Ö!¾ Ãâ‚8ó3i RþóçîxŒÎ‰­ B çÕ…M«6ìü´,Ì’ê%Ÿ{Búûû½×——Ïñ¶àYŠEÅ'à5µç𠬕}ßY'sÝYæé³ Û¯—dÆS$Ð÷ú+áÚÚû?ÝDñôÌY(¿¯ó^\þÀäõ¾µ2§*¾Ó†ÀÌ…+dÝWV„‰MtΛÝ×ípqlÂÚwtëkå÷–„fcÛˆ,Zz—Îû‘Ìý/¼.ë–ù_HR6b©¨Z*_ÛÖ,K;»¥òæÅ©m’º´õ½,Ϻ[^— ê‹ç„Ãa\ +¾Ü&g>Û­÷v…Üå»Ì±§¾);܉.¾^*ušÏ€a\\çdëgï¾½ÔȾ­ëdaÛš!N‘ïCCÀ°¸@ß³V¥ëè?È–ííò×ψeÉVW/–ºÏ4È}f…ÌE0xèÅ&ÙYÞxéX°¼Fî¿ç&9wl¿<Óþ¯rô¤ÿÙ¸þ×—É\ý)©»}~ìý< bL±ÀáoýŸâz=Û°çÛR åë³ ö¸*â+S`§Vë¦zæ¬ì©/Ÿ'·X‰G/Óç`²oÈR K ðˆ ŽºÒ¨–éÙJën¸ù–h?#ï2Ú–)&U`¦Ô­Ý$uCóœìú‹Æ°Ä—Ô¯–k@’çÄ`¬(Dò*™¿0i8+{Ÿù¾t_ü•¼ðì—ÇÛ¼âzfµÒöðïÏ>ß• ñJ“æŽný‚¬j=mh{Fê´¬À±a¾Ãð}hPV”À©#?Ó»ñþôƒH[ÛY½´Bî]â?3ø>’1QðòÓ£OgÑ![¾øI9ÐæªÁF'·ù‘¥¦q›<׺V¿ƒyD>L§@âôsÒ¸>(¦­€<|ߢ”Í×g÷”Ë”3ÝçºÂ„Üð«Ãéá&b¿;‡ÛŒu@·¼úº;›eö7ÿ  ó Õ½1y,0pö°47Ü%›cßµwþÕŠýÄ<Ës"¯I»R¾Wž–U÷¯íÆÑÓ {ý¹7øuÉw¥“E!Ðwl»Üá~L6î–Í÷¦þ˜Ì(ÑÅsâʈywž TTëÏÍ© ¾ ù èéL[½,}x¯ hòù äù5$yc8&Qó`ðž9ò_>ç×än/|N‡u'Ð#?øïAéE ¶·´—äþ'ä±M›äOì—Þû$êÍà€Üýµïyýyð,(¸ M‚‡ðKªë]ËtÒ¡¡µ]º_–'¶o—g_”Ž=ÍѻۇµŸ2ž‘ SE)0pòù´k[²~›¬ÉÒTp¾> ¸çá-™xóGòxPExáKö”úäéõ5a?;;¾-Ëb-,UDmÈŒ ëÁ ø>ä$…ÀYÓ~JNœ8.ÇOuËWV.I9«ªEuò×'vGËvü“œÐß< "¦ŠH@3j6´ÉÎu+eNØ&E¹Ü~ß&9Òê~‹<{øU-Àoã"ºòœJ†@Bþù›-áÒ–¦Ïˆ¶¶—1äë³ üøf¤˜S&P~õìðØoõ½N§OD fT¥´ç›¾ó—@¹D¿=ß’AËm¡”{ÕŒ!Ú).Φ§eË=7ÉFWcÚ;—zÙ¶ï¯äOë–HúÚçD!_lÒ>™ÚIüÊuÛåàÀ[òñ~éÇgÿù5ùÃZ¾+Å‘móX ïy2–Ǻï6ËËßìñZ•|_üÉ0ñßÙ´^:oyÿºß—ÿ²©–ïC¡ Å 0gþ¬wnå‹VIk­ý¼%ïêo€ünv<Œ‹@ Šïˆ|qMmÆ÷;Åŵ«ôÿûPµv6/º¿M†¡(zê÷ ×¼A³4,Ïn×OAž> (ážçweÛÑŸyÕå2’Ù÷š´ûgµMÓß•Å#3ÞÏ X ú2Ò&?ëÊ^Äýµþ <Ã;ï¼)œfüè‘]¤Û›v”îä³²6K°==ý<'ÒE˜/(Ëlª+“²²2©{ø¹ìßyô„î¼wõ§Åg`HV„@j¡€'7o–Çw<®?0í‹Äë¹ÐN#mÙŽ§OyŸ¾Ä&‘£H$b¯¡‡J©®z-Ï‚¡mXSUrg]TzÝ‹¥gIvÕ‹µ ùÔgAªsÅ#ÐÙ¶S\y´†m«eþ(N-ŸžÜGqÁ&{“ªÅ¿# î ;þEŽg‰'ö¼òƒ _S[¨ûˆ×‰ž{ cŠ[ J~guø ‘¶çOe9]mò;®DX½,_«›ek!0•Çv­“Üíª-”<Õ/}~Ű¥¼xNLåãØ*Ðÿ¦ü0ø&}àŸNIÐe^Æ!úß:”·¢\|2ˆXP¨•7Êgš7Ȇ ¤©©)㵡! ­Ô6Ø6ºíý7i™F¾ê%'Ý™ÖipEE…÷zè¹Ó™Ø’×äG®À™Ü ³µ…%žÙ©XZ˜ñ&ÄN¿Þõ$z~öã0éoÀ³ + ‹@@û5û†û‘\#Ÿ^yëç”·Ï‚$C &÷4JRï&ïÕ°óxZÏ$[j£õÛ:zÓÖ3‹@á ôvl ïýúÖ#YOdðÄžp‘ÆdGêfgöµDëëw&ù„¤ú0—Gƒ'’‚¿õZ])y°{´iã91Z)¶Ësý 4…ŸIn;’íCp*Ù\}ïi=dÛðÈó+Kò&H`ðøÎð;Ͷ´/<|š dv3åñïÿRÛšìÊ’¢C­õágA6´éSÀžY¨XT ý#üÆM&»“Ûê£ïC.ij @/8É^àL{R»öÿî×´d}.D;ÈÏgD d*ŸR¾tèMÖ´û`òLWW²ëÔ‘dKì¬ÔnÓ?» @üÞ*àžÔúΔÏASòà‰3É.ýŒik޾Œëg§5kð¦x¼8“ÂŒ‘Ѐ{skk²¥¥eÈWsóÎä‰ ƒ)þY± Zž…}/”rêïlHù»ÝÒv$ÙÝ?˜ìïNž8Ô–lŒÛE6$OøQ–$ŸR¾kJçÜã÷yæw¾•ÎPägšRA, -ÉCúݾp0©g'÷4Ç‚íúg÷ñ¨´Mü3Â÷¡"¿OŠþôÒþ¦×4&Û;üÏAoWG²µ¡&ö}©9y&ôH{_-¿C& VàL{Sx¿×6ñ<òñY@À}ÄË6U &÷5׆7˜+íž:®I¶ ~uNU29.,ÿC9tÀ]zf_R+Yû©ijJ¿Lp"Ù$Ð{¤uØ{8õo¾ÝïµÉCa• žtØÍT X)÷” úÐÛw¦d¢ò˜êKÇñs/ÿ^”p×ãó}(÷#LŠ@סÑ}'jØv(-=< Ò@˜-d®ƒImõMrè̹oIZe< ùª“ö y󷃥µrç’y[d.È¿gA™ed&”%ù$è;+/uJ×ù‹š¬é2ï¦%R³d>Ä|ºH¤e r¶³C:Ou‰÷ ™5O–ÜV#óç5……CO²Ï‰Içp9è;Û)/u¼*=§ËôéúW}ú¹iÉm²d~<Оyx>™&,)5¾•Ú/æóíÑgÁ«'ÏÉÅÁA9ñ¢ÌY°X>|û"í*xøgÁð>¬-,¾³'å•“§å¼ÐÑÌ[|»,[4w„“àY0«K@ _žÜKàfã@@@@@r/@“2¹7æ € € € € €% @À½.2§ˆ € € € € {î¹7æ € € € € €% @À½.2§ˆ € € € € {î¹7æ € € € € €% @À½.2§ˆ € € € € {î¹7æ € € € € €% @À½.2§ˆ € € € € {î¹7æ € € € € €% @À½.2§ˆ € € € € {î¹7æ € € € € €% @À½.2§ˆ € € € € {î¹7æ € € € € €% @À½.2§ˆ € € € € {î¹7æ € € € € €% @À½.2§ˆ € € € € {î¹7æ € € € € €% @À½.2§ˆ € € € € {î¹7æ € € € € €% @À½.2§ˆ € € € € {î¹7æ € € € € €% @À½.2§ˆ € € € € {î¹7æ € € € € €% P^çÈ)"€ € ‰žNùÞ¾ŸˆLŸ>¦ô\¼xQ®»íR·d®ôtî—¶ÿïçrA®‘•rŸ,œ9¦]ÐÆ 9¶÷䇧ûäú|Jî[>¿€ÒNR@@JU ,©C©ž<ç € €Àd ôÝ*Õw¬ß!k·IïþµòÚÖ:¹cýÝG­êÝ/˫Ʒ»¼WßQ©«¾C¼3m9"û¿²,ï“L@@ Iî@@&K bÆøôöIè»+f,öQ-ãß[þ¿SO.<Ó¢-ÅŸÿ—"€ €ŒM€&eÆæÅÖ € €Œ[ êö?•î®?ðçáNÊgJï‹#¼{£·¨¶yŸ|wÃG%1`áõø0SæèìñEL#€ € €@^ pÏ«ËAb@@Š[ \æÌ›qŠUsg‡Ëªg_+sª4´>ЦbÃwçD_qžg… € PÄ4)SÄ—SC@( ñÎo«¥G?µEV×-•²²2}-•ºÕkeûsGe åÔÏÉsÛ·È£>*»ž?+‰ž£²eíjYjïY³KRÛ‰s²×Y»zµÔ-]*KõeûÜúÔ~9—ºÓÔ#t>/[^ë½ÇOK™,­[-o}JŽM9BÊûúN?/[Z£ï«“º:}é±¶÷'Rûð'¥~óé:»dåüùÞ*÷Ÿ…¥;:¤ýø“•K¢öäoÝ–¯Ù°[þõ럓¹Á¯…{?S/[ï»IÖ·Ù^ž”æ§¾"Ï®½ÝÛå‰çÛ½±ý×ÔvB»wQ0¿BVÞ÷9ùÄÚß•ûwXyú>yßÚÎñ Ç÷ÉS›¶©mj“¶Çî š­_+Ú°]|Ü/ñnd¯ÈžÁ’šùþ³_ñJæÛ’º•÷É=wº’ömrøµY¾,p ÞÂ@@\ PÂ=×Âì@@ 4îþvl÷Ž1Sîùã?và'o†Ón¢Cj¤íÌΔ`»$:ålô¢éºY£|'l÷ÞW¾PÖ=q(,éÞöÚz¼?\¿èNÝ£ òG÷¸`»¿Îz~]ö±¨äyE°8qú€|ËNçß ƒíþóW¬•ŽmQ¹z·7Ñ€}Xp½ã—òF¬Ä¼m³üþ\š›š¤©©Yn™]¾ @@&K€î“%Íq@@˜PZiX•༥:œŠM4n’{æ§þ 8qT\Áq©_&Õ‰>éé š£ ÞZYþù°N{qòûåÕ¾u²¼JdîŠuòrr¿U"!}==Ò×û¶¼ùæ9é:ù¢lyàÉØÁýÉžŸw†mÈ7núC‰ÊÙG›Þþë¤öÁ6¿Ýy·¸rv¬#ÕÇ¥¦òeiÚög²êw–Ëm7-”9s—˦ǖ»­#€ € 0é©ß´'ýð@@Æ'P-³Æñm¾~Ù‡üV]b|ÿWÑ\Ûƒ² 2Ks.ÑÞ”+­n3}'Ÿ—¿Ùò_eãWl=mã´Ù_¼¸7\²ìCóÂ锉ªk£vçÝŠòEòp{³ìXõH°ä€l~P_Á\Mm£üéäþÓ ™ë5]ãÞÈ@@É I™Éqæ( € €ä‡ÀkH=u¨üÛÂæbR× 5×k­»xÃÙý[¤úƒÏl¯mhš›IÝÏ͵.¿0˜Z’>uË̹…+7I÷‰ƒÒï!6جãÀYÿé˼ÊÕ²ÿÜØö›y$– € € 0vîc7ã € €•@ÿ/~â7£gUßrPzû{¥»»;ãÕÛß/ýÞë{r‡6'#‰“òŸïÞZÔnh•ƒ'¤«»Wú“²ÿ‰'ä™Ýáz7ñú›”q˲ÃöÚÓVÎY´B¾òg%©é ;ü7ÔÜu›Pº=†Ç$ € €À¤pŸf‚ € €ÀÔ ÕºKÕ’Ïý?²­ÁÍîú TV”IEEµÜQ•6¯mÞ'_\„²çÜ)›Â&Úõ=ÿ TWVJeõ<¹«~},Øîï÷Á;æÉš§:u¦\î}䈄o•'¥¾fT”•Iå¼Yÿ¤KGÚxþJùf³_¢^´øõwß*•eKeéR}_õMòéGüfjDjåY³5  € €L®÷Éõæh € € /0cøÕ®Oo-=ËûÂm+ä†`uÕŒ ]—ŒÍçÊÚ'ze_kOߤi÷ùçMu.wÃL¹ï¯Oɶư·Â7¶î“îþÒ[ÝñÆ»þ6s–ÉöÞi®OyK0S+Ûöì–p·áyˆ¬Øô]iOIc‡t¥Ú½7×n}'Ú¤nn¶ý² @@Ü ”%uÈí!Ø; € €’@¢ç¬tü¤SºÎ_”éÓgɵóçËÍ7-’9©FgÕsú˜üää9¬¨Y×Ε[/‰¶OôÈÉÓÚî{y¥\wÃ<]…ìµÑ9ÛÙ!§ºD&s,”ߪíÁÇ7‰N%zNË‘_–_t[§{ïý­[j¤fÉüX†@¸9 € €LŠ÷Iaæ  € € € € €Å.@“2Å~…9?@@@@@I à>)Ì@@@@@ Ø¸ûæü@@@@@&E€€û¤0s@@@@@b à^ìW˜óC@@@@˜î“ÂÌA@@@@@Š]€€{±_aÎ@@@@@`R¸O 3A@@@@(vîÅ~…9?@@@@@I à>)Ì@@@@@ Ø¸ûæü@@@@@&Eàÿ‹ iƒÈUIEND®B`‚concurrent-ruby-1.0.5/doc/images/tvar/implementation-absolute.png000066400000000000000000003265251305460430400252270ustar00rootroot00000000000000‰PNG  IHDRÜ„»8óÄ/iCCPICC Profile(c``2ptqre``ÈÍ+) rwRˆˆŒR`¿ÀÀÁÀÍ Ì`Ì`˜\\ààÃyùy© |»ÆÀ¹¬ 2 UŽ +¹ ¨¨ê¥¤'300ÙÙå%@qÆ9@¶HR6˜½Ä. rвùÒ!ì+ v„ýÄ.z¨æ H}:˜ÍÄb'AØ2 vIjÈ^çü‚Ê¢ÌôŒ#Ç”ü¤T…àÊâ’ÔÜbϼäü¢‚ü¢Ä’Ô Zˆû@º! A!¦ahii¡ ¥"ŠˆqŸÁáË(v!†°(¹´¨ Êcd2f` ÄG˜1G‚Á)Ë„˜I/Ãþ©15C}†}sïPoì%¬´ pHYs.#.#x¥?v@IDATxì½xTÕÿÿv7‘ &6PÐoØ6Ø€W Ë´:ÁvI­L¾.Ô c Ú&ü\î–4üökèBƒíBx¬MbmøjÂÖ†ºýѤÖ$-ALü:¸’•¤&_KÖMjÆšHòìý;3÷Üsç_f&“Âûò„9÷Üóçs^çÿçœ{À‹H€H€H€H€H€H€H€H€H€H€H`\þb\¾é™H€H€H€H€H€H€H€H€H€H€HÀK€ w          H*Ü‘A î,$@$@$@$@$@$@$@$@$@$@$T¸'"ƒ           *ÜYH€H€H€H€H€H€H€H€H€H€H ¨pODA$@$@$@$@$@$@$@$@$@$@T¸³ @Pឈ ‚H€H€H€H€H€H€H€H€H€H€¨pg            Â= PáÎ2@$@$@$@$@$@$@$@$@$@$@ @…{ 2           Âe€H€H€H€H€H€H€H€H€H€H€@€ ÷@d$@$@$@$@$@$@$@$@$@$@$@…;Ë $€î €È H€H€H€H€H€H€H€H€H€H€H€ w–          H*Ü‘A î,$@$@$@$@$@$@$@$@$@$@$T¸'"ƒ           *ÜYH€H€H€H€H€H€H€H€H€H€H ¨pODA$@$@$@$@$@$@$@$@$@$@T¸³ @Pឈ ‚H€H€H€H€H€H€H€H€H€H€¨pg            Â= PáÎ2@$@$@$@$@$@$@$@$@$@$@ @…{ 2           Âe€H€H€H€H€H€H€H€H€H€H€@€ ÷@d$@$@$@$@$@$@$@$@$@$@$D$@$5OŽþê5àÊ+qá•øÜß®FVjßÂ푟·àý[îù²3RÂ8¼xÖžžv4Ÿú=.`nËÏEÆ%Ò"öœlÀ©w>Ùpe ð.ˆ<»wäç`N’í Íøý‡pÍgnÃêe1„sñœŽtà—oxË_,R\¸ røæ;»hN,Þ·œløÞé>sçW°l –eEØ 3zzNâW§ÞáG[_ÐtØ…³ž1û–{°6;1å¬ït ~ûŸ [þ/|ø!pÍõ¸ùoV`QFØ*BEGC *kñÑU"¹µßß¹¾"=›0ôS?`O~u Š6)t«tö‹ö&k rn]‚ô‹ÜÖzºDY~M”åk>‹¯¬^‚‰èºZŽâµ?^ðñøÔ ¬ÉΜúùx‰KØÛÞ„W~/ê¨Û¨ÉNð¥Ù÷N6¥‰‹ü'Žmä{O‹ºùŸÁus¸·/¾òûÈã:1†Ã5×ᆅYX˜•‘¸öú˜§D¦j}:UÆhV©¦×1ÿÒSõ™ÛÂÍFqºé—ðw1üîæUÈY”„1NÐF;‹=ŸCFMK I"p…&®IŠ‹Ñ \âº?€jd* ê:Q¹6KÞ«OûA¤-ßêµ*këÇöe¡ªŸÉ6·ÌÅò­Í"Z;Z›N7•`£èëêÄû#@rÚ=X²qÛ„mwÆò%@Øþc) &ùƒêx¼†¯›²-Ž:x;*«Q˜;þLµßšªó”¨±‡&KkûM}HÌmMKPýá“Wé»"_}ôf/+@iaô®±ëè>ü¯c]ü~„÷>ÊÂÿ[¾‹,«ä£èi?ŽSHÆg®û3Î_˜;s…]˜í:‚å ÖÁíó‚b›Ýv|é²—‹qí–ãÚÀþ¿¨#ûW{Óh%Ò‡}WÌE±ß²¨þö¯{cJÌùl”w$@“L€CÿIÎèHàÒ%ЇŸ—ÕXįzò¾·6Œ²"y†tkIÛ‹oHž1Ï/DšPŽóò¸q߂哣Ä~?~Y‡GF-žg?å–ð&ôF)S1Ç#^µ°¦<†’…"Ùï\”6ñv&^Âaûqð&LK»?ޏè5:áê¦l‹£ F¸jÆæUóñAc7¶Wé®ô[¡GQ 5¥†­J{”˜1Úξp5únžh/û |[(Üõžñ½ŽÔTåÙG¾/6Ü…}_[€bW@„¶"´¾ô8²çªº<øÙÿÊvá¼tË=1oÂù›{J»¼‘57¹á ÷À½ZíÖþÿÀ¯Ðó¸x#Ÿˆ©KBÿù{­iJJÁàk?‚U¾="öÒFü¼ès$FçTu/«o¸û1T§}]2 ×+ æ„ù†I_¾)“î-+fahÔ—ßIIIõœCË‘ýpl5ö»°jþ·Ð6ø,–3£Ô0u`è#üÑÀ䬯‰g7š“©HÏ ?—úoÚ1GÙqÙ~«¥Ž ypþí6<±)üýÈÖ’ÃÞ7.uhòã×UÆž5óÙÖŸ¶àáì5¢à7c™¦”Ái@á²IÂDôaà ×î_6´§vBûsSÚQüñßâ_n_‡¿eñªg°IÛ‰‹³dkJ6•LŒ–ŒÔ…6±&8YT(ÙÄs·úÜXôöàÿ¼b(ÛmÐ…ºÜîë”q¦‡Te»Íçì·…Â_„ï>€•sg¢[ÛƒL% O{5¼/j‹·^É{7¹âÕkÌXòyñN´¾ì#.W#º‡7b‰¡ü÷ºÎþ¶Ño2~àdÏ^deY¼ýš/Ý™=aN1‘¿?Ÿ¥(4 DA€Z²( Ñ pêðC`pã'.7Ö„z¥Îâú2hjR”×'g(ÚH ‡Äܤ¦Ï1•€2ÈÌ vãš;oÒ­c;ã‘øMGÎÚõÈQl. cÒçO¯Rç\+ÅO»öH× Ū|BÃx ¤gå`£ø ¼ÌMb©HžøtbïS>1 )©©r³“7¶ÔE¢MªD¿ý‹ø;Û:ÿ„¦ÿø£Gı6ÆñIaê@êU²è8V­”f_¸žMl2'/ôD´c)W ¥²ø—b¶û)))HM_ýõõhš—ç{A¡¹ oy¶˜oDL^*'6¦WðcC+¤Ætà'p—®1}Ôg4›QÍÐhšâ&¢ÿf˜vŠ3º\Ä ÙŸûŸž³Ïž«‡Ûè?Іß{€9 ë™ýÕ¥ÊûâÑR°¾òu¬ÿ¡Ø!6?X/}S„°ó´ã´åþ…kò³úÅ¢¼Ï‡½¼:ôQ-Ö1|ú06ùw¶U·âñÙÞíÿÕ° òôEï½x¦ivæó†>üè}GV—¯oΜ%X-×jÐÖý–XηÀ+õú@_10ê[º±>k‘%oŸj’÷öÕÙQ/]ü|–bÓ@$¿ˆÂ \îÄyt5»Œ%pŸ©ó%t,®­GÐ3Ÿ´dºš*Q˜¿W\q…ïoi>ön§®†¾úN7`wa¾é^÷'ü<ÚŽáÐ^0Ú׎ÊmøÉÅŽÊ£è ç)0¬ÑÞ·ûvïÆá“½O½÷=-‡±[<ßWÙ$dÇ9z»wü‹ÜyóvýO°O„QÙÔeõ?Ú‡¦Cû‡|ä.]Š¥â/7¿7¡/Zù¬!†¿ ÿÐ?fY‰Êʃ8Òbæ^_ûQoºwï;ŒÞÑa´9ˆr}rê²>°£§|áöœ<Š"t{™Ž#'ÃæM_Göm+D~n®ßO. wDSG_$A£z1©aBèëhÁÁ…Þ|0ÊäÒÜ|ì8x§{ÕÊPz9íÞ·Ï›ç»6XĘçFì;Ô"J–û¨^o f¾òR¡X%@C¥.×>ì>x¤»šD¹Ý-ž‡,ëÂïAšD9׉ ˆ<¬¬¬ÄÁJQçEyÕïаÿe¿>¹Ð/±·WĵûºÊsjZ2<½-Þ:½T¶z¨Dû¸ ¿og»/~ëÿéKÖâ¹ãeÒ²¹ø ´Ë¬ ®úǰ*w°GÛCôy1÷‰>¹¦R4dIXßæéÀÑV<äm¿ôðw<௻^þb|¡? ÈBó6Îzž°t™’è!¦ñŠÁ8Ú¾+êþ#†6aì0ƒÛ}k’cCÆšf5.oáÝuý äo;ˆöÚ+3L1fã…hëõ¸d7#M°)|î(ãóØæ0£”[[âl£ÌÄqTQÎS|}ŒoÜTÙ0Æ7ò2úã!Ù>Ÿ–c´ e»žb¡l=øá‡ e;PÞúr3t{q ¿6¿~Ú~óõ>»1þ7Çþ%(ò+Ûu/Y«¿…r·Ûü†ø8ºÿêmØï{ ¸ _[ïJÍܺÁÄü®½ÛÞ÷;ðžó.¸asÀá—£æ…Ö€ñ‹îzÿjð™Ç2œÓs1}L ÏŸ—âÐiϸÆâñÌÅâ™ËÄÐ@$èMåE$@‘œ?^¦‰öÒûg/mNûµR›ï^·¯pytWH?†ß¿¶íL€÷¶ gd¿Î ­{Äewcyd?°ku¹e<­Ía°Mãy_ZËô´^ƒZ¹ÝŸv{¹Ö?ت‰¡WȸÅÇ¥ç‘sÇ5gw>.­¾sHºÝ0¨U; 9”ô„ H‘Y|(Iºh+·‡L‡5ßZiiøüGºÈð|†í¸älÈgýµ—ÖkãJ¹RÖåfz‘·­åáå7ÒZZß-ÝkCm2ïÊÛúM{a «¢õ¼|Ož›y`× œ¶°ùaœª€Œ×4œ×Êd=µiõ¦hÂI¿YŽõrY䲆w¾Qó_üþgªl­¢¾´–…“Ï®éÏUn×пí¸E63Á&µœC Ì`÷ÝZ‰‘ñ+>ìsTÉÊZ>aÛ«í ûL´þHcÎoEØì&o]^{Eüá yÔ¼Šª©²(¼ôüRÛ±`¾~œÑÖÁþãJ{Y Q ñù±ÚHK™µíWä¶XZÒa×Ï™‘ɶ_p6š~oJepVkçMoᒯثuή÷/5ë±£ÚŸâSêÔÊŒ¾Å"»YK\ª­³Þì›C×­ÍÒ­Œtk岟0ÃUýÚK\VcíýNvÔ„Ôáú@S–Ðiö¥?ú¾m°m¬ñ†?G@yUú’À¾*æöCpNtºŒÂ5>Y¢ë»Æì?taëc¨z¡´ c†©´êØG*ž1¤É?º4ëñx¯þV9¦Pëžj.?®ŒA á~ã¨×qËN†ˆöáë¦l‹EÞŽÝŸ«ã‡oœ¡ÇgÏ<ÅâÇV¦…ºô·*탣6ÂøVí/¦Ë-|AèvɾÐ^zÜâp¨³N>«¶ ,Î,7f^”jç,OÌñœø°©ïÉH§Väm?lš+piñ;öM«ÒïÔYòW/—6žÑêKŒq²R^õ(†ÜJ`}fÖMhv‡áß×§èuÄ|îkÙîy“ß\,žùøØé‚./T¸_^ùÍÔ’@†´Z§9I­=ãSªƒd[I ’UŒŒœDØ ´ŠÚ:­¢´@¬¼Ïœæ€t¤Ût‰Wò´’òZ­ñx£VWQbQ¦ÈA”HÑ »ÚžÍY¦Õ·¶i­µZEQ& †vLø3Ó (¨#Lˆ}𔉃®¬J’ò¢"­¤ÈiÊgwj%%EZ¹¡± ¬t–­¬ºNsÕ–K徑ÓTüÇœSŠ\"|C¯2˜0i4y˜ùí,)Ó*ÊÌA²ÌKïÀU((ÊÊ´¢€a]·©>ñ±ä£¨L«s¹´ò‡Õ¾blEyÈ´Kµ¬*1ýŒtÖZã-©Ðê×êë*´‹²Ë©¹d(¼Ì ¡¼Z÷6­Ö­®8󤹔¶N/7µ®F­±¾N+µ,²[•pFKü_½U'Æ–=8öèl¢«›¡6ï¨á÷[Ú¼"­Ó¨XaòÕô«Ä¯´Q¡ê1Æœ§œS6…VÞšJVhÆøÉ”ÅjRóazŒÑ¬é“wb‘Éì_•¼ó;Pó¢L´£eb,æ°Û5»øs8 ´òÚãA‹ßªŸ¢Ú6ÙÎv*° ¦gj}}œ¾YeÜ—eã€5-RÁnÓÅ”à|½9Ö-S6ä Qæ­b¼'Öæåå+æ¸Úècô_}b–™(Çâ"äxæbñÌÇe"h ¨p—(h I@ìt•;¸•ÝÖŽ¸ÀTNúQBú Aœ¯'Cº“þ6e°!ž×ú·á™ hNë–\ïn'9`Ów—{ã´(*åÇ-ñhb߃º£Ï®(y̸uœwmÄÜ­`Q [ËL…Ÿ­¨Ö:h Ø™èכĨþS& Q¸;4W§9ì‹rdzÈ/[I¢ŒÑKÍÝñR)-زìåNE«¢ðiênTv‰@,6 î¨Òk:RËZh…éöŒ²¸[TWØÔƒ\e²«” ßi¡lWòTW\Õ¼=ož›eRŸÀÛ´je€.*€V¡LÈKê­<ÍTš&uP¯N4‚whZ'Žæ¤Apð¯#˜²)õEDe2‹ÆXAᦷúÎYP^ÏÔ™eʸCÉë$Äj9Rá^aÖ?Y>Ù¤[„zéY\ù­Èà«[N­þŒu¿\\áŠd˜yc9Š”þ¹aX©uÐ;9“d›Ífþ‰ü÷Ú¿b§·%¥ª’O¼õdÙ•-"TÙ–üRzÃ/°†Ûߪ(¥•2&ùÊ—sŠ2@´oEu– °‘α~+í`i£‘ÂÍUd´+¢_«>Œµ>:Þø º³}-réKcBA¯(âåæÛTzàC.¥íW/ǹê®þNÿ€žÎÀyŸZ'ôçÎòz˼Ñ|åX<ι˜O´óñè Ò% \Nx†»hÉx‘ „'Ðñkófcئ/Û±óÔ¸ÅÏŽ½é5(§Ü]Õÿ¾|î5̹%Õe()-AiþпÏ8Üñ l6ŽÁ³•á©-9Þ“MØòlÄq.Þ«¹øytqL¤é7Ó¨yš >VÌâüûŸà¹Ç×cŽÿÈBoèI™B¾V$\Ï5‹S/þUP÷¬É2Ï8L_¸\žÛ/2Tœé¿VùàPn[÷u)ôòš»ÄYöÍ~[gõs(ÌÎntCfîvˆÉ½ß®'^Ÿø”ÏÎZáOGîÿR–EýK«Ënõ¸(žÈóAWiW ãäÁµ¸]æ©ugN`ý"“”çµÏac¶ñ±']ˆ9øÆö‡¥4­o½+Íá ) r ^£õ^î#¯ÊsÜÏž0?ÖäŠæ×Ïù]öॽþÃ4ù¸)Ýoægäcãù²Þ°P~‹ð”ø`¤Tꢯ˜ç±ºÛðNlGe+aG6ÞpKndêÓpõXwîYò[œö ×¹j¬^¤äwÂÕÅŽ©…K£P,Ws3Ün·ùè÷í·Ð¡À¸Rfã N_Ý+Øv?²>øœº`‰là /Á¿8óòҟ§gÕFªŒÍKÅp_ òç­‚ÑJÛJ\8±­õƒ¹Á‘Ûˆü2¿uâDþmF^&!çÞ Ò}ÍþÀï) ãû·Êç¥eÈ1¼zmS°æ£M¯¿+ú=6«½ OnÉ–þuCJÖl—^Ž¡wHc³tSzü_EjGdälx}Üï¦5aÎ'–¡Do¸(e0Œx‰èÛ,AÛËñÝË,V©‹Ö¢F¼N`\5â,ÿ°W¢êyúì‹Ñw…í?ÆÑ&„ 3D&$j uÃCÙÕ¹ÿ PšA]¼ìûAiI JJJqãµc}…<1õ:jÙCðK¤UÕ†•˜7,°þ-¶­Ä†â*3ªÒã¨\oý¥ù0NS ó”Å÷¬“ãášgšå¸JyÀý" Im%÷aI@_(Ýå0Fîúò´Wà[Ö΋ddÐ_+lþ1¸Ý)æz¥(rʉ¦pç‚c±M}Æ$.…?=9hvA¶µ¶"´ž/E¦ðuòG¥ÞþÝQ±ÙÊ txxú_ìW:¾/h=sÞÄhÏ)ñ™Vßeßp‡o,’±üIj>òø¾’2Œ×~k” ï¶ù~_Á?âíO<»eµuÞìÌk®Ý‹w.ë|<ŒX´&Ëžî—} ˆD@|®Ìذáî%Šã9XóusB¹«æ·ÖE*.Ë W(Á}mŽå 3|v×ξNú¬Ú°Øû!·Ã -èêŸLBöÆíسsvŠˆ>Ž‘S¯±([d@© ±Êám¼V)(}$Ì0ÜÙ.ßp,CÚ¨øàÍÀ€åoŸÄMFŒÍMxËL’a;É¿v8W*£•EÇ­˜0‰1Gzh~ã]!¯PL×eG (WÎÆp@º<"å6™r4|{ÂÓ9G(•^×4ñvW%–$Â3Їޞ´ŸlAÃáƒxxSMD6-ž‹•[ ÕPÚêÂZUÙ®§ÆÕŒUÿôKßXU·JY„í/Œ ³­µµµÞ¿úãg0øú~dë‹Ê} bn¨‡]€ï=ä›Ãö´ÆâÃä3gÎôþ]±4• FQý.ü‚Ù¾;îóÛóò¯¥ßü»Œ ÎÁüc÷¼êÕ¸ŸÃËrzT€Û*vd>CñCwØDwk¶{ñÏÅbG']‘ÀåG hjrù!`ŠI€Âî8†b¹1˼»r…‚ü}ŸóÙ³á»åUõ$N}o-rҥ͘†¤ënð*Üõ(ÞîñíÈÊßR[vùãm®Ù ýÏwÙPPòœ_¿9þ Ý¯ÔËx–-™'ÍVC2fÝ +}𫫉¸ùè=3X×fÌ›¹Ù¼cšLùB‹†«#õƒ¦²'”Ÿ"X„¢zª\ž®ühßP\åàC°æ_FIöjË‚R¢ò<1å ËïY xw5ãÕŽ䦿zÒí÷®Ççg5£Jß‘|à8Îï_ ¼Úê¯)â$íÏÏÓkÚܫ͛I6½ûV›Œ15-1Te€Âˆüv,û¬w1Ñáêá%>Ū”ÁæòîG¡Pš‡ºö|¿û‹Qìí:DŸòØ ª\ëO»-‡„”#Ò†àPáêvi Ii^î}«?ÂÅiÚã×U»ä­{ï*ä¶ŠÞÒè.ERzKüøç¯cýölŸûán4M‘ý6\Ÿ"ƒQ )ÈZd2=ý ³ß»éÆëw¦1eN–zõáÓfbáw^˜ö=)m¶ì“ÍÆošì2^âDômÖÐsoù+«…ÿ.ižï­Œqÿv‡o|Êa"Ú½ô¿ÏNL[¦§1qù=¾6!ï@»D!£NsRvÔ—¢*Ïh/š±W¼®"G¹ö<ô°÷%sB¶J Ô¶cõ:jÙ•¨'ÂXR׆ÂÏ]‹¡s1>99#¼‡ö?ņ­|Ñ6ïÂÃÕw£i˲‰Ãf¨yŠxw w=,^!jÖåq£®¹k6.oÁuà9ãí@”`õ²TKX¡o¦÷m´çE¬3”Ëör<°,Ô$1Ôwãî¡!Œ$]‡E™V7©Y¹øag-ªø÷UÇÐY¾‹dýHBÖ²\ñHxG÷{dzE®ÞùŽÃÛ°xƒ¿ÎÝâ±<êË[ñBÀÛb†“ÀßÔ…+¼‹èzûî>ö*öÜ®l2r®¼z“˜;ë»óõ²Ò,4îkn= ùŽ©ó,”éŒÅ‰EóÂ> tæ>þ¹X¬óñ0К.{Üá~Ù ðNÕ=c}èVŽ P•í^Wñ¼‚nªgÏô+äÄnmý8^[‡c®)„U{·âv¡¼Íß×ⵞ×f¹sðãs—‰éG7¥ ý̶ZÅ}7ŠÈêfkÀ3?u³<.Æú$ÜÝ`À¾ßp}*lùæž”h¤}{Ø,ѸÇMoÓ>¤-¸=¤²Ýîtšo\Dxó®<û±^}¯àÇúÌ[¹š›Í#u„Ñr5ÿÔ<ÚL(—äfÍæèŽq™ǃ²_Éœ…RGcÐ"Šå&éªYˆ½§Œ­O´D8n’ì^(=ùìYá§R=ŸJ²LV›0ùcHqœÞêèï<Ž2ñ%ôÀËÝ\…­ënÇÜ™ùÊÑ®ü÷Z¯ÃÄÆzt K¼)ØŽ“í§18=·ÌnX©ÖÀ2?»™YYX´h‘üËÒï—ecý–ýè¬JnÿÕ|ªÃl7 ˰¿ãi£Ìq©œ§ˆx²VÝ+ÇU5ϼèí3<Êq2vqÎIfXy¬¦óíwϘÊí’íêQ”Vé™ÈÊù l7\%eå¡ÜÈâøÀÌÃIÐïpÇÏàÐ7›ØJñí5"7zpŸ¡l·ÀÕÖ‰î3(ñ‡ëÚºG•·‚T-Ô7§Ý¯à­7~kŒœy%zêM_óÔͯ¢«CŒ üaä- ÚlaF#FQ¤ÓtÊ4޹XŒóñP±ÓŽH–MyäA$@&±#Î<Ö†’ò‡Åàñc«²yÆ q–l=ŠøFÒUO¾„ï­Í z]pF¸ éПqÎcڵʄ4)9ë·{ÿ<½8ûÆ«8ñ›f<½ë€¤¸ŠoÇ‘û†ðÙ–Zå¨pß¼ÙÐ,Ó6®ñËðÛ8¡Ld a Cï¼áWnŠÝÂeÇÅY|·`t(p6"cñj£±Ë()A:Î0"M’µxEôc[‹â|êâ8Ò ”'%a¦ØÁä»Âå_‚DíÂc«Še`ö¢r<öàÝXôWs‘ššŠ}WÞUX°Á[:U hü!®úÅ&±KÆ7ºÞº²wì—G¦L¹Œ–CQÿÖŸð‰xtc6RÓ3°,g÷oËÎRÝá€c¯o×ûþþvù„?oìxá¥7±Eì„ ºåMЊ‡ŠÄ™¥QìÖŒ3ù£çÏâ¬á×Y ×þAg5÷þAº0\Z~ËÛ¾e©"wÖ¥Báî{)ü¾õ¯÷¢i{Ž×íÔËótÜfL j¶Âá«.°•|ÞwöóÖŠ¬Ggb×:sÇ݆/ÝlIûØ7—wcÇÊÅçÉE:‰ÁPc²›¨üž¨pcJÜ8틹F¸âxªQñï?^6¦ª6Ôžù¥øq@F‰o-˜STÃs~íø~¡¯o*«/AMžï`‡ªuß‚ó|SÀÇKÃÅ׋:ù­`çw÷`mfh·¢·„k³/õ[Ú‚‡³…2-e>–éÕNWV5¿€×ú¶ ×8 Ʀ÷%Ìšç;3ÖVÖŠyf¿÷ô‹¯ Žþʺõzi×,ñ¡:ÝN(ÀO˜q¸êñ ­ 1¿WõcÊKç_k P¿K@Ÿè¥mÓ ¾=²]ýŸ?9½/»ä¢HHn~wS©ž_\YÔþ#Qm‚fèr6"Ç!¢ímÁÞ'êÅ›=Ÿ@Þ#"'#â,Œ5úßú-(í: LJol|ö¿¼»¸Å²\èKm;ÆS¯C‡“­¹¼èÆG¼Š…™âè›ùÍ{€ëð·âMØyÊS1 ¾âl£¢Ÿ§Q¦à‹›JÅôCºñ‹Ÿý 3ø'¶2|qÌó÷pôßé9Fë;õ‚Ù×m;þòœ®Dšm³H‘«ûõÝè×ðYüλ £?¸c}OxàdµoÈQÿÇÿ‘ÖîS¾¹y¸IH\Òl¹Ð}ö=}"Ý5å*á°úw^«öŠÎVüÂmÃÝ+åOEvžxã·Flæq×@?uH÷ãv!{B”Ôjââ‹%Ç<Ç„¤%º¼ +˜Êx¤ÌTÎÊF€8¶Ú8_(gÌ…½’cñQF1èüIƒ®`µ^5›KÑ2`µƒØm\¹Ó« lØ|Ïbñ;„מ)ÆÞ½{Q,¶Ê+XR‘“·Ú h˜9;Ó;ÆÑ-›‹÷Ç#ìÛ?!'¾ö²Po4ƒÔ_ß3^ïwÕ¿p´€8°ôs‘@ñf1*þ”¬(2Šô=ß¼­UæmÝ…]»Äß©~Ãõ%þ›‚w›J Mÿò|ˆêàÿCvíéïŽè‹.x‰W@ïó!Ô~c–9ôG9*^7ýgßáÒÂF XCŠcÌ$3Qä®Â6‹7.ù¿â5ó|¡ú?¿ÔwßµÈoÊÀk建~;'îRΠ” h¨ÁŸ#>Oüô«Ô‰…þp/m»æ7pmp}yB²&*¿'*\…Rd£ÒŽEvh}ššv•ÕB¹óô4áïïÛ mlö›…ªÁƒÿzÝè7fãúëµ1£hzâf»§\2RÕfÞd¬.Aµ\ojÆíÑf™î ÓpÇ‹ò›#Š–;çÚ†Cñ»xµŒ@|W¡nog“Š›–õ¯ß­ö—¦xÃɳ­¹{ÑõH½~¡<ÎÀ½ë 8zBu-Ì-¨0ºWÜO§ÎDæMº6@¿\øÁ³'}FõÏIì—„¶ãÞÿÿDô‰j<±˜™×±ÄƒÛæ­¥8UL¼ÊÕ…'Äxĸòn›oƒ~/z=W$º¸²¨ýG¢Ú5L%¡Š1ácH%ìPÆ¡w_ã½bœ[ŒçÝÁgû§Šï«ªj}§4Dpã¨×!BÕ éY?hŒ“|–ÃÝÿi.|†xÓQúÁ ´Ý‰·G?O1eœs[¾ï¨‘ä›7x©úSgñšR6}›¦ßmmõGdBKï]Õøë€ØÀØéœ¬Úin+º B®¶Ñõâ©‚­Þ›êï}CŽõç¯Xásàz§ÔH†ß1¾N†…Ÿ4ó7eÁJïÇ\õÍ*ÞËû»°éL–ùù/úÜøÿ÷ú)²#„S‹»ønÔv/Þ¹Xìóñød¥/˜þ¨pŸþyÌ’@ìÄy´er bÖ¬Ün§™„œ{MŠkó1ô¨…Y¨ºpû…8ÚÞ…ñš{ÏIìøÒ98ÕwÐßéýH]*n^iÌ4öbMa%: õ0zÚ`ÓíÆ‘ 6Üø©T$eÜ%ÎÁ4üˆxf¢¡ÃI‰¯³Ú†åþ…ºXEÎ[¤ ¸Uw∜þÝî#èõxÐ×s‡v¬õàŸ•ŠúÍhïêÇ;çÈDa­y–ù†Å_Æ¡“]Ðßôõ ýè>ÌZéêá”o˳¾Šh~ þf~¹Ð;õŠ.¾¼í0º¼ù9 Oo;öåÏÂfcÇŠØiêÜÕšà4'öâɪfo¨Í»þ‡Zºàư§'Ä—ÄRßSÝI N½i”£Ð‚¤.yõ%FÙ6Ýw½^§S/ÏS2³åÂObn_b¾}±èNc!ËŸq¥ePhA¶Ïÿê$zÅ9ð“umZü÷8xð öíÛçÿÛm…ù¸bæMBº&ˈ€Æ‹H€¸«šh½¶ÒÆ€§!n‡ÜšjK?îAmÐ]!ï°Bÿ:µÖ~%Ìóš¾ZüÚl6˽޽ô¸éi°Mc«á'0œ¢Z·éG˜ÜF:ZÛ ùèx©ÝV`Øú½MüÙ+4ém¨M*#‹?{…ßy­Âi}Š…]°1ňÑ4¨‰Ý™þø­é H‘ÕQÞ&‡ãáu üÈ/¨ëTŸzÍádsW8¤?_¹åoHxQ¸…Ηʬ”fP«åÜ”7T}2ìœåǃëU8Ù”r$s¤gZùN™VÝG¸ÂW¸¼2‚[Ž™ ~f;føþUÃ3üEþujõÝz!ñ]Cueh¬¼-ÐÎŒ£ŒI>!Ú²6KyèŸ _Kß'Ú±óƃð¿jÿ GµìC:ëJÆdP¤ÖË¡3š˜Àá§DëTšVwuA{ñj{€]‘&ºpËOŸ(#t¤–K]‹³ ŠÖQi¬qF”E©×–>ÝO ”œª]är­®Ó,çáÛÄ ¨çq¤Ë—ä E¬2Só;\ÿw› â fXþ Cú‹NØ4×'1^ ª‡Ñµ'z\ñÔëˆuB„.¿Œ´ýб»:†]/œ–±¶†)´ ñUP$ýZ…Ýl¯Ê[Í7˜©éNÊ0nWÓ(Ý„lSÃ÷ƒmc\g­¦Ôø D²˜c4 Õò8Þ á|ky@?"ÿDÞ8+ZCøV¬FÎhâ­b–M«1¯è®/ OAÀQ 5¬±³ÎÚ§–7Ëd §Fu .äs…O÷cÖ k?f„îyØvOxŒk.Ï|Ü’¿$@’w¸‹– €JÀƒÓr{;¶­ó¿‚§: 4{wyÈm{8ÑvN|Î|Á´¤¢rºê×Q wÿ³°*vî8Scóžpï–ïëù<U4µÓw^¶×&u*;Qnõ¤l:±£â¸8pý5v$Ï0Ž>°î>ËÙùsÔ•;.U/6”7¶¡¾L<Ów´¤)ÏR–aW­<<Æ÷àc±Ç{ÍA᳃h,Ø áªÿ”ԶᏠÚí`Mßhž§™š–l>–Y6†5ݦoÓ$Ã{W³ 1ØiÍOÓ¡0‰2ÐzþEq¾{¤ý*‘o”¸ƒ¦`í»Q¡–ÅQAy#ú‡:!7ŽŠgî?|àua ú°–({å.sߊks%N{_ʈ3Ï¥üFŒŠ€Fé6ðAèûåyæ›(öµ»pÄG»ä&c±(ä.ŸU¶%_ÝT¿Å÷Ŧœ…ÏfH'^Ëd̾NiÂ8´Ù()«…ûÜ øPqNˆz…l2½!" zO~›²L {tF<á y¥|Qp•n…¿ˆíXÒJ DZl”V7âüȳX­œ÷™’µçŽWÈŸö"ÔwöCL”ë³ø`.…¤HÀ p…®z7nøK$@G@ Óñ&þoߟ¡Ÿ·xuF–-2´Žw=§Ûðú¾ƒ W^‰+/\À•×}¶[lÈÐ?ZæG¿¼væm׸ðá\ó©ð¹åKÞK˜Ä'\ÅQ#ÝÝïâ#!oòUi˜¿ ¢ö†3*üœïÃ'σÔt¤Ä;:Ð ÷8ÿg!á•Wã¸a~Ò-+Õ¥ú@?êÀŽîóÞ¼¹:ýÈy“•ù…é‰J­^NÞèêÈxùêOÌÁ ™y0:€®ž~ñ!¥™˜uÝ\a‰1 uyäù(úzÅy´‚gRJ*Òƒ¿ #µK×ùDå÷D…ŠôXíX(? ±Àé×ß@ߟGDQºs>}#ešm„§·ç‡F13mæÎI±’).n ⨱®3gñÞGÞê„«®½ ²2"¦ÕÓ×…³¿Ïë!ùªkÅ9øó0'R§âåüÞþ£Þ]À‡®Ág—~KÖ¡ ÄÓ'† '»‹V£NýÈ_…{H|¾ñMïŸÄð&s2³°xŒ< ÍdÖóp2ö“'K„þ#î6!B˜FCü&r "x‹Õ¨8.£íµ×ñN¿^ŘUŒ[?s£ 616ŽkÔg½¶5îu¬‘®tñQØÏˆv<¼"rÜQ*Œ¯Šuž¢G܃mWÌ÷*y!Q<3R‰Eqež’ˆ 1ÆW&D”1èíÀ[b|~AìÜø³˜û¥Ï[ˆ›–w)8˜aœnú Þ¾p%–Þ™{™~Ãs¬|Vë畈n.ß|<8hC—'*Ü/Ï|gªI€H€H€H*áý?@IDAT€H€b$ *ÜÅ1زÌ\Š1(:'¸„ xNDšÿ;Lâ¨$¼°eÙ%œŠN$@$hSr 6щdx$@$@$@$@$@$@$@$?±¾ë¸jæ»ØS°ÕŒÿð•íñ3¥O ˜ž¨pŸžùÊT‘ $ˆÀðéÿù¶Í–Ðìe!‡/ºX˜ð†H€HàGSY H€H€H€H€H€H #+®¸wIA# L{#–ú/’ë(ÃSâãì¼H€H€H Ïp$Â{     E`؃Þ~ï×ѧïÇ{C¥›v$@€ø8mÇÙ?à#ñQO\5[|ä63¾Ü’% À´'@…û´Ïb&H€H€H€H€H€H€H€H€H€H`2ðH™É Ì8H€H€H€H€H€H€H€H€H€H€¦=*ܧ}3$@$@$@$@$@$@$@$@$@$@“A€ ÷É Ì8H€H€H€H€H€H€H€H€H€H€¦=*ܧ}3$@$@$@$@$@$@$@$@$@$@“A€ ÷É Ì8H€H€H€H€H€H€H€H€H€H€¦=*ܧ}3$@$@$@$@$@$@$@$@$@$@“A€ ÷É Ì8H€H€H€H€H€H€H€H€H€H€¦=*ܧ}3$@$@$@$@$@$@$@$@$@$@“A€ ÷É Ì8H€H€H€H€H€H€H€H€H€H€¦=*ܧ}3$@$@$@$@$@$@$@$@$@$@“A€ ÷É Ì8H€H€H€H€H€H€H€H€H€H€¦=*ܧ}3$@$@$@$@$@$@$@$@$@$@“A€ ÷É Ì8H€H€H€H€H€H€H€H€H€H€¦=*ܧ}3$@$@$@$@$@$@$@$@$@$@“A€ ÷É Ì8H€H€H€H€H€H€H€H€H€H€¦=*ܧ}3$@$@$@$@$@$@$@$@$@$@“A€ ÷É Ì8H€H€H€H€H€H€H€H€H€H€¦=*ܧ}3$@$@$@$@$@$@$@$@$@$@“A i2"¹<â…Ç3ŒŽbIHMOÿó"         ¸\p‡{ˆœî8Œ+®¸Bü=€vO«4ÚÜ+’‘––†´Y³0kV’¯Èž£§…ò Àå@€ ÷¹|ªîÇ~Û1´íÃرtVmÚ…æ pšQì°aùŽ£zF           éF€ w5GG=8Ýp·ï VŸ«Î|æQ4”Þ‡½n㉠eupŸiCm©Ó°„{¯Uíòž          éI€ÇŒ‹ýçM•ã¹m¨ªqEË£=¿DžÔ¶ÛQßýK¬ÎLñú_²óY,[üI,^wÀ{ÿô‘“xxÙjžé5]:$         Kw¸co<¹+&e»žÍmÏýDævI}T¶–‹ò aìsw{ cNcxã/ À%J€;Ü‘ŒÏ—£ì= 30cÆ8ñd1jäQ1¡r¶'ŒÝðøú]ÁŽ’áÙ‘!<åýjj’› Àt&@…»P…ç¬ß‚™Ë£˜Q?†Â}ø4ùy·•üOÌGš?—NµãýD@WÍÆ²Ïß…{¾’‹ jÚ%YH€H€H€H€H€H€H€H€H€H`: Â=(w‡‚l-†»;`ìowï݇/ïmFÐgVìÅfØPÑx…¹™AðžH€H€H€H€H€H€H€H€H€H`šàîqdèȈïDv›×¯P¶û °Ù((p(!º±yÕ|Tžæ î I€H€H€H€H€H€H€H€H€H`Z Â}ÙªóîÕµ»¨?s¯7=‹ÊÊ0ÒïF©Ý xóÖÃühª‰ƒ&         ˜–x¤Ì8³Õ-TîuÕXe¢LJ_‚®V´¥­ô=Ó\7=…ÈN=²{î¹ÇŽ‹Écrr2þâ/¸–4:&iFà¿ÿû¿ÙL³ ?þ8þô§?Qá ¬KÍMêü[ ŸÔn|85´ü3ñéåâ\WÐçTC;`»dÉìÛ·/‚ >" +ÒÒRÜÿýX¸p¡õïH€H _ÿú×xõÕWQXXÆ­I€H ˜ÀÐÐô;¶ÁlhC$žÀ~ô#ïÆÂÛn»-¼#>! ºÂýR¸xîH<¹$Žl‘—«ýòF5 àÕfSÙ>¢>¢™H€H€H€H€H€H€H€H€H€H`Ú Â=ž,M¹ ÎÃã^ì9ÜaÜÈß“ÿ†bCßn¿ Ÿ‰ãüv $@$@$@$@$@$@$@$@$@$@SžîqeQ ¾²­Zú¬Ú°…ÐëÆè¨§âΕ[åóÒÇ6a޼£H€H€H€H€H€H€H€H€H€H`: Â=Î\MY´­懪¶æa^ÚL$'§Á–·n¸¶¾Cu{œ˜éH€H€H€H€H€H€H€H€H€.T¸G̪ÈçÀd>‹ÎÆ ˆO£†¼Jj[Ѷg RB>¥% Àt"4“˜´¤bã 6FXVn!šFÖ£Ëý&zþôgàÂàêyXrË̉¬¯2:#         ¸Pឈ\JJEÖ²ld%",†A$@$@$@$@$@$@$@$@$@$pIà‘2—d¶Qh          ©F€ ÷©–#”‡H€H€H€H€H€H€H€H€H€Hà’$@…û%™mšH€H€H€H€H€H€H€H€H€H`ªàîS-Gä¹úê«ñéO:À–·$@$™À/ùK¶‘ñ) @ììlüøÇ?°å- D&pÿý÷chh(²#>% µµµÈÌÌ °å- ŒMàšk®ÛÑEvA…ûE΀±¢ÿË¿üK¤¤¤ŒåŒÏI€HÀB`éÒ¥–{Þ ÀXÒÒÒ ÿñ" X\wÝu±8§[ ðøë¿þk’  ¸èºÒ©~ñH™©žC”H€H€H€H€H€H€H€H€H€Hà’ Àî—D6QH       K…À@G ßø£÷¬øÊjdŽñâzÏÉœzçCáü³øÊê%Ãù¥‚!r é° g=cö-÷`mvF¼AxÐÞÐŒßx×|æ6¬^6õÒ1Úw?{þx0«¿±V–Y£l^yå•!Á]øðC\¸ò,Y‘ƒ%™é!ÝL¦¥§ë$~õÚ;¬K“ q Â= -H€H€H€H€H€H€H€H ~o¿øÏX·µÙ@Y[?¶/‹ ˆnÇÖ•ypé®måè§ÂÝïy ßݰ :I{ÙŠKWáîyÿ˜çð¦ÃVÖ:%îîÛŠ Þ2kGëzCáî« [Ýf–D2ÙKjñÜžõ˜ÉÑ?;{¬ÄW÷X—&˜4ƒD€GÊD¢Ãg$@$@$@$@$@$@$@$#äó¤hv«§®gÏwF0Äor2 ’iÑ€T¼NUãl$OIÑÌ2›f‘0í†èÅmÞ»ss+ѽ—„»”é`]J8[=*Ü£gE—$@$@$@$@$@$@$@$@$ÔñX]-ª««QtÇõ±ù2®8~~#CC’ƒ8®õE¦”Í›Q}rÀ¼§‰.C\8½ 3I&       ˜,éÈY»9“ÝÅsuJ ’Ä›¦21)©X]¸=¯cÕ^ß1J '߯öìÇ(M| –¦ ³ŽL‰( \öúpô`5^ÿ¸ó¡Gqk²OWTâ¹#­xßËf6VÞ} ù–eŸ·ÒwºOT`W•÷txM›å»w¡`Í2ÿ‡YGÑ~äiû½ˆäã¹XÿíÈ  =M‡ðÌËç1ãÚÏ…¹WK¶áž“8¸g/ŠÙlv'6|³ßZŸƒPªÚÔ´dxz[pà±àˆðç=VÜfGÎ`›`0G\°«ìÎŒOÝùœ7¿‹ýN)juÎj >»Æ1>£}íxzÏ~l>Pc–8nÉÃExäkˆ¶¯ý(ª½0Ýx+ÜGŸFåOžCëÛþ\¹a%î{°ߌõ`õ¿þÌ÷ñ×›X›“ék¸÷$ªž~Ã3f˜q‡0}*oFûÐTSç^xgß~Û[&f‹¸ó¿zî¿72LZÿU?nðò›-ì.] gÑ·0'õ*é*ʵù€_áž"€>ñ!á{¦/kE³Ûw(¼ÍîÀÝù_ÅýkïÁ¡¸W¯ø8«!›GûNâÉ ïÿô1V#$‡lõe’E&™®­sÈ/†ÊF>7å5ý;4‹èŠ|°Ù­ìc#GºËÇÅ®ÕééU®¶r»ß]+pÚÂú·•6j2Wyìem243¬PiRíìZ«"ÆÈ¹ãf™ ÉÅ¡ÕKˆþèFºµ2%Mvj<ºÙ¡µÉ¸µj‡ñÜa‘A&Âo8^fpVP{Æò¸µÜ¬áâ-­ï¶ø1ÙÄÀY„ ëžZ—ôÏ0sVkçeéx] ôòÓÝm-+SQnžá.rŠ L)ÊCÝUU¾Ý;¯KKQRT ˆÚŒU¿„Q¿ÍhÏ,ßlìÖ¶¡¤¼ÇQWQ¡´÷]5›±éÉvaNÅ=ÿTjØb×ó¿“áHK± ûéfÿ­ w/;‚ã”ÍÓ^‰yÅ2h›£Õ.jË•3À±ß:xRº 6ØQZQ+ü”(\xdƒy¯Èw3Ü2áÂIšÏ™çô!Ì_µUú±9ËPßÚ†ÖÆZH÷ÍX·ØåHrùQN4£ªÆ·SÛî,AEuŠ28¸w­Â/{ü¹¢È£~üõªO.…X€Ýnýs8ÅR‹åR>d:|›æÝ#‡…‚eÕupÕ– “q¹·à[h÷÷Ú4ÅF> kgI*ÊKE‰ß5:< Þ’ØÛeàv8óÉ@G»cåVEÚ’ Ô?Žúº (‘ïÊû'œ–ÞgÓ»×dÔ ôµ ®Â¬ ýÏnÄœ¤¼%D˜Š«”É$Àî& šH€H€H€H€H€H€HàR wيݘqïpÜÝ] vä*‰ïo­0wWÛJµsþgjÜÎzÕ‡p vù ¥¬ÏŸ½Ü·ÓÛSs»ËýáuÖÈxœÕþË?"¼¨dë·ì¦w”·*©Ñ´¡N—Üш]îúîã€xì%.¹;]÷‡5ú[ Æ•”§ڤÃ:ܯ~þº[ù t×ãQ³³Vøß¬(Àý_ò§CzJŲ[²'^œöVC\œç¥bXßÙ>o b¶Nì_+Ïï·ÆÂ;H¾<‘8– ‰H€H€H€H€H€H€H€NÀ^þ ipF,ñÊÊkg_'í«6,ÆÙú|sC²m7#3#ٷêêNÂçx8°Õë¯öù6<š³Ú§€Ö?2i(ÉÛðùŒ !­l##K¹ùw •vðuçŽN¸ÔÓ•Œùúj€¢ä¶—Þ‹¬ èC3°„\°_ {dÄ\”((^cYÈ~Sb•Pæ×xµµoã=±`ý¾¦ÞcbøS%J3,£ýîÀ·çå‰Ãjü—øÀ«k{Žq‡áÎvËp,CÚ¨’p93铸IüzÅnnÂ[žµp7ù޾oàë¹ê?è”eø‡R;\»dÌ2NÓ Oô02¾ïúÁù¼rd/\þ(önºÇÞªGÛ_𓳝k[|ÁŒŽÂ30Ïàûx÷Ý>œïz û6Õ˜Q„4ÅɹfæZ‚.É=k¨lɘ–‰&ÔT%:†G$@$@$@$@$@$@$@$?åï1ÉÊßR[vù Í5{¡ÿù. J‚óë÷#GÙñj»[ìߊ‘ûÀ¿ãÌÞÕX’týúßýgÇ‹ýåÚC*+£•­û•z)ûM7^/ͪ!eN–¨ú`E—œ6÷jÕiÔfDzÏB$År©²,[2Ïò̼IƬôÝ×>Æ‚†ù<üŽlÕMôæT~m±7|~JÐY½ÑÂ|ä£÷Ìà\›1o¦¹Þ|`5%ø.^1ôíŽL̲>–wW_;Öò€ ÷?\ˆ%¡4‰;÷ «aŸ<Ÿß½7/<4„µY>òž®ühßP\eì5—ÑFeÅ>*G x¹÷Q¬X|±8‰òæÃº:|ðÔSQºžþÎ2~ñ \1#`%fú';b CU“ˆøH€H€H€H€H€H€H€H :3’ÇR½(êıtžÑD)ŽÙÙÖ;ö~PV,wû¼ºQµw«÷Ï!Ž*yÁØ=”…¯•ÙqÀûáË*Ô¿þ=,ÉNRŽ“qàk9™ÑÄÖÍü;Ç–¸¼;¯3ç*Gš„õðÀÜ ð`ŒÛÕ=ç>·óïÚ,Ž‹qy?<úñˆ¢Õ·•‚ôÿ1Ûb3‘7M»ÿÎ<æF|Ê´ñ\iÐŽþ™ŸºÙ{ôKôjëAŒˆâ íóMc…êÁˆØå.°¬ÕÛÑXÚ€Uþ]ò½èŽSÐÛ´óV‡Dgw:ñ~M\Ô é(a–ÍÈs>þ¦B˱Dñåç>‡k6Š'Œiå'i¬6nZ¥6ªÄHT˜èˆH€H€H€H€H€H€H€¢$ lölÿÏóÀ’*Ïþs¦ÂqÐrŠJ”‘…p–”ŽœõÛ½ž^œ}ãUœøM3žÞu@Æå*¾Gî»3}»—®ù&àU¸µ®7ð¨8—D'SàÄÒôñÄ`u®µÎw̉ðNÉ=êÀÀ°®OBêœô é1DÑiwK­WÙîsN56€7Ì#V‚Õö£ˆéaבmRQ­{¬hû9rCìÄzç ÉP_0yvË- ^0Hš9Sž‡ž4ò¦yª„ò5/ß)Ρ©‰Iî@ÇÚL^Þg£]xLQ¶Û‹Êñ؃wcÑ_ÍEjj*Rú®¼«°`ƒ<('0ÈqÝT´¡ò¡d³ûØóøÙáç¥\¥Î;Æ­üž§0yúÅ׌h-¿/íš…¹s犿;qʾ«¨î —…^ÝH¾Ö<ùÞuú$§¤"===à/ /W=ŽÇU¿Áhê§kdyósx-daìCý3c+Û#/: ãÃëüHOŠp'±þŸzýBÉÄ½ë š•ž-¨zç»ñé/Äw û™³3}Iš‹÷¢e ÐÐ~ø ¹›Ü^ꃭÁ~b¶ék‚öIzs–·bÿÚðe %k…8k߉‚>ß1lÜÉß“ÕÈÛº »v‰¿SýÂ>7®4áÍønE“tkúšª— «¿©¸*좃M·b]•ÛïÏŽ›?%2P|xö¾_M°ß˜tÍhoþÙÿV…÷¬åt¥Äf•f:ÏX]‚jñ\ßÕŒÛ=Œ`rÆsþ’Àø Pá>~† H€H€H€H€H€H€H€Lé9Ø[&5|¨Ú´¹Û¢åtz{{Ñuú$ï+DÚâur9lepæŒW±Š›¥ru/ÖV¢cÀP-þÿìÝ\T×7þÏ0ƒ€ 0Ŧh0 ¦qLõ±š4 I×q³Ú6Š­Ö ¸i~‚}Z nc6Ø•…njàÉ&@¶Å­à6Õöqì&?0)˜T6‹FÌF7JO*M!JÃØ@`†ù;3÷Î`€Afà3¯×tν÷œs¿ç}&îk¿s8·­§ŽbÛ*y?m=n•’¢ª×âµ›•D´ã´ÈŸòÒ‘$¶þ÷+6?”—ЋTöš¸LTŸï€ÕjEÛùjd®^åNp1¾ã‡V ²å$´ «æ8cq¶êAÃÁ]X¶Ã½â;;ý®á;ÓÕVì»o ”Eô¢›nøŽ=ŒÃ‡¼FC›4 ȬÌPî¶yÑ8ØÐ i«Õ‚SÇ 1ge–r½hWšøËîËܧœ3ï]ƒõ…ÇÑáØº§çÅÃNãTÛ¾(*þÝB¢°Pz£Pü%Åž}{°eIÖd¹·…1ä;¶ÄÑYÛð\™s„æ½Oâ`}3,==è±t áx1ÖÎKS¿o¿7ðW˜AAø~BlŸã~E"ý9“û»-~¬È«ns_f‰~ðÇ?™~‰ÝQ€ (@ P€ (@àX±û9T›”•Ãæg² ½½¿ ¨ªú܆8k~WHì€>#‘ßT¶‹Ä[¯×£©I^}ììÛ÷,Rî¿Šß v¨žŸù­Ë½†<úØ€”¼ˆÜ½‹ïè± i‹ÜIZ÷Mrñ£+”ñÜGj<|;RóÊ‘ñÌ28#pÅ"œôÂI-•]Ù„u”è|/ ŠÇrꉮò7»¤ØsÁÉ+XޤM?BIUœ¿˜±måB¸×È»[òjð¨kk]Â:4–g`Ù6çhM9âñµòï.î&^KêgÕ6•å`¨o°Ü8½ /ìvÍ_ôr‘"Ö¶»_K·–âœ)Ï}BU2ä– ²Àµò­sVóa˜RMcFjεãÐîÕ~ÿáØð/-(Q«î›QTƒ+Ý•gH—šþð‰³†bçCJ]ÑT.«¶”qv,Ýþ4r•ÿ.*ð¬é¼|‰Ÿð«€Æ.^~í‘ùU &&Žý×üÚ1;£(@ P€ (@ PàÚˆí>Z/^ÀÿkkÇ_z¥[Î@t\+¾ú–72éÓÆ)@ P€ (@ P€A!„è„ •AR€xn)ðSä ðöÿ­ÅÂí!¨]kE½LLä(@ P€ (@ P€ ¦‘îA4Ùwü½1_Öà¯Ù`ífÒ=ˆ¦Ž¡R€ (@ P€ (@ P€Ó@€ ÷ ›äeZ„Ïê7ØÐoeÒ=ȦáR€ (@ P€ (@ P€SX€{¸ÙäjB4øÊ¿kaN³áw[m¸û ÷t²id¸ (@ P€ (@€°´6àðÏ*s->07¡É­Þ`DJêzlIÿ, è1\óà,­¨~åm\7žuóÝH]ÍCæ¼rúCÜmøZêb„WÙu­µ¡ox3fÌðZ»÷êUôΘ…ÅË“±8!Úkkyr,c¼–ññ^ÓC@c¯é1ÔàeLL 222ŸŸï1€¾«v¼¾Ú†Ø¯h𿊴×x@ P€ (@ P€ Æ&`Amñ£X“U1bóŒ’:e&û”¸±³)PÁrªQ˲#ќęÝ+jT§ŠS°,Ë è‹påÌNŒœ· xI²ä_[F!·/îß„ØêMäåÑq"£aßþ·´´ !!Áß]ûµ?n)ãWÎk×Yè, ÕZ´½ÒÓ9¶kwcÞ‰ (@ P€ (@)*ЉÙQƒ’íé¹(((@n†ÑcÜe;VažZX=ÎNãƒÐ0eð ÂC•r BÃæ9C‰ ƒ¯[^D-ð=zsþfÄ¥”¢Ã÷&~¯9–1ú=v8í˜pâ¯@ø ¬yM‡÷ãýç™tâ©dè (@ P€ (@Ih(Þ†Íeî0 ¹GÐÒeÇ¡Òýؽ{7ö—ƒ½ûLéJ¥¦½kð\C§rÌÂT0¢®½}ÝÝèVÞ]h¿tU%ÙîA›w œß·KÓR€ ÷ Ÿöënr&Ý›žìGË‹ýA>†O P€ (@ P€ À¤tÖ"7ˤÜ:£¼µû7 aà6íáñX·ûê Jݬ|,Ê SUàºðpèÄ;\yG"6>©™P“ëþ>T7|0U 8. ø$À„»OL]iv’Ø^æ%-Þþ;þø*“î=[ŒŽ (@ P€ (x /Cìîí|ËñÏ[—ÊG^?“y zùŠéç¸0 ãní8…Ò][ í¹¬¼—¤`Oéq´õÈ vœ¯GñžL¤,Y¢´[’²{ŠãlÛ€›ˆæg£pß>ì+<Œ6kN-ÄzGÛ%8xÖ]¿ãl5öe®WútÄ´d=ŠŸÂáX;P{°™ë×;âY"úMYŸ‰âõè²Ñà1ùvFÄ~¼[RT^Â.eË?Õ6L48Ƭn·[v¢¾Ù÷¿<°v4 X8bßž}¨nvÛ ssåÒò ë•r”RrF;¯§œóZx°^lYduØd®O4ò<”7wî[+¥ñŽQéˆ Œ$ =4•¯À˜3gŽýñÇ÷)À¶×lö_F÷Ú;NÚ|ªÏJ (@ P€ (@ PÀn¿b/2À.rHŽwA]»(}ö‹'kìU5â]uÒÞÞçnÒRS¤ô%÷éùi°9×ånà*,J¡ìyU-í‹ JƒQ¯”¥û5^qÔm,¡ßô{‹*~©Qߥ:»Ø8Ç£?Ï1íU»=béj*Qê‹=® {Ð×b/2w/Ø ¹&û ±î‹vñ‡Ê==ãsžÏ5]TnÝ$;J<ûj0Öôr×|vÙË•¸Œö“ƒPº¶‹¿xPâȨ<ç¾ Jã›Wƒ=#Ýs^ÕãÔçÕØÕS7ú1z„ʃæ^<45À£´Û¹Â]ÌÔTy}(Óâ¯ÙðÉ{Ò¿s|Q€ (@ P€ (@, Ö,×1â¾;cåƒa>uH\‘‚ÔñN]X×S8-gbþš,¥>½U'q²¦Ê’x36.2¢^µÛÚ|+³*”vÆÜTÕÕ¡êH 2Ü»•`oÚqVµºÜùLgÇfS“Ò^.X[bÙ¹_=r‹*QSWƒ#%¹îú;°í¹Sr ç,¶Í[¹`DAù˜*‹DI~™¶ðœÝBp¹±êÓ‚ƒÛæÃ½›•Uhl<‰Ê‚ ¥ž9ßcaƒr,Öö£ô› ‘£Ì›4¶r˜LåÈVyåñp–;PtÛQõqª±fTâÊ¡­Ê|Êõ‡ú´ötŠ¿*؇UJ ¤§%)ÕÇ7¯R7f”U8çÕž‹’òd»'Ò3^nUF£ÜW*(gÇ9FNy@_þ'iàhV¸ËTï—Ú쿚×k·´ô˧øI P€ (@ P€ ¼ t5ÚEÓ¹BYŸgûúÑ.{‰²"vcQÇêc»ý’ÇJnCAϹr÷*tõªlg….{e†¼ÊÙs¥µ²¢ÙzQ•Çj{õõôª+÷ÅÊne܆"±Îßù:Y`tZˆ>õÙ•ýÙ¬F7–4)cË ÷®F÷ªx Ý^§þSÑó¥:õ_ ìu® »Õç¥vJ¢Ðm7åºWœg›œ3ªXÈ+Ü/Õ¸ÇïëÏ•ïâȽÂÝùý0èõv½ê-rŠ•T.iôÄîŸyÕÛËOªûm·—¨V½çV]R?ú1*MYé;Æî¾düYÇï·d„àÖö~+z:¤÷ø¢(@ P€ (@ P€CDÄ`™¼*zAæ Qm¤Ó=çƒòsWõxag2\ ß]Mã±óP#ÄV-Ž—9ç×hv-CŽI\îZqž‡×&ºjÈ‘Xz—²<¡òéŸúÜ*Ú™ê±:»Oõ8×™W.{¶ˆ½ ¹åÈÍËEÞú[!]µžÇÏräAdàÅoòèº1†“ÊJwÓ‹f±Ö|¬¯üæÀ¥q^ÝO,ÿ©€ël|òNˆ-q\GfTÔ4‹²Ô.ËÝ®¦@´SE!ëËVNÔžùH); ó"E¾H¬lŸ·òHõ¹&œ8°Ÿ‘ëÙP¬7ojB“ê=ðzkÓy=ñý1¯•/bë õcñíÝ*·>ùþ€ñIWÆ1F¥c(0FÏ÷ÆØ ›žÀ¹ZغگZqÿ:„Fi/HFD P€ (@ P€ Àä X/ã}³F˜\õg_Ÿ{•ŒœuP§H•Î"oÁ±¬¼Â‘éý‹ÜE¢ÈòÆŠÄòûNg5«–ÎNXº.ã£:ÐÞ|…Ûܼ(} (äl_=à 0;f®r®ló"\¨ÊÅßnNà ýHˆÆŠ­»±B©!RÙO¡L>6.E”Õ‚N‹²9‰ãJ„îÜ.JŽ!˜kñ¾e'VŒ”©–ûôøìC¯B–wyÃíwß#Z9Çÿ§¶OD9NÕΈïŽ÷èÕq¿Ï5¡¯™ïy½b3â<8 pbÿº’íÒ–5"aÀ×ã“öV¼u4òn>ùÛVá¥÷Å–8ûS?¶Œ^øÎ_¹·¨‘"†¥¼¢”’ª0¦1ªÚ³Hq0á>¼@oº$O‹¿´ÚñÆ:R^ÑBƤ{ Ïã£(@ P€ (@ \s‘½Tò¾¦3¸$òËI>dŒ¬=XºÉh]d4ZÞªRB_ºxžRö,„bÎiµºs_nõjuKs=ž/|9eòºkÏ–Ã¥#i^ø *‰ë÷ O_†½ÎÛÁ\‘ïx;+ê‘‘»éßzÉIÎdwß§»û0íÀ¼ˆîã!Jê1 QÅûéžÔÈCÉýyC˜ë¢b«ÿ]C¿ ¨ÚîÆƒ‡-îŽÄ¤ÅÞï;èl5ÞlûRã‡ÀQ_‡ÍÄboUžØæêB,LËqÔlÊOñíÝØè l|ó*~0ïXNø2FßúýŸÎœýø ß*OƒZë¿]ˆfiªpyûÏdªŒã+¦EÝ_Ûpâ6$ÿJ‹-“îübP€ (@ P€ ( ˆ[ʈ¸s•r-ZÚ­H6ù*µíAÅ7£°Í•0.iê¦ûvˆíbLŽµØŸõy® wß-ÑŸ‹qºJmµ…˜·Æ™°xÑžŽË®ýÀ«ò±øÉ@Zö<0ù,¶€y¢ñ Vÿò<]£¬Äv¶jBY~–ãm,¨Ã±ÝɈ¸éÇv1r\î}èÏ.Çm‡¾>̱ü\ù¡£kèzº™sà!¦ng–¶˜ïËŒ´ôŸâJm&¢‡ìÊ‚¾nqqˆ•ü‰©»Q“W5{*Ñö‰T9ãŸ×!å_Æè[—3BÂ9cŽo•§A-fO2îƒM¦Ô)ÁžüK-jÖÚÐð·6ÜUÎ)ŸRÌÁP€ (@ P€ Æ-0KVŠNK¨›Pò›sHÍau´å Ž)Yét,¿%-¿¨tm|"4Tþ¡ïU+û×8“ÕÖf<¥J¶²‹ðÔwDÒçã‰pÑUsÚL,ܬlö2º뢑¼i·ãmélÃ…wÿ 'Þ0ã§{ŸQ’ø¦œU8ún|õò»Ê¾æRþÐÎ;au­âWßT¡¬¼Ö Lò«+W Å\ùº×}Qœ-¾ YÌ‘—W·3|ѹ÷¼ÜòiEgG'¤Ÿ=tᑈŽô 2£¤¥ÛC±%Tïœ3ó<~ô>”n¸¾ÒህÞF9JWÕ‰ž×"šˆ1J·\0{‰ã=Âíyy „Lã±O›¡kÃ50ü‡ïØqêû¶i3n” (@ P€ (@_t¸+=O©hÚñêGxhC¹Ø·[na\ƒ[D>wþ²{ä38öú{JÙ£`yUJ^vnO*µ¶_À¹Rz9Lv"yq"b£ÉvéRÛ”rM>{P°{öìAáÁGò92:K“×açÄžñ]0å”~Ú.w#t¶{?tÓÙ*%«££¼ux³ìÇøñÅ»ì G¿J'£)„ÏÇR±Ÿ½ãeªÂ;C˜_8Q«ôºdþl±p\ÕÎ| §;”ËîBÛ똇8ñ^ýü÷y©d(Á?g.™øÅ({Ú˯² Þ[_® Ò ýêÁÕ¹ÒVA®—¨ 0áî3UpW”šj¨ÖáCS?Î<Á¤{pÏ&£§(@ P€ (@ øW 6y;T)w¬š“‰ú6ïÛœ=¼ +³”t;Šö;DÄ$8ö—"3çä{MÚŸ:ü¬’¨7<„Di!¼xê72œ‰o퉃v-±¶UãÉ9K/ö4ñy»ènœþyòóó‘#ö¾¹4ˆ,Éi©î³"Iž¸ÙòñàÍ_Ÿï‘”ÏΆr¤eíÅÞ½âýöå¼G!Ì— #p»œ¤6áéC ]8, 8 XðP²´=·/“(0ãGåõƒÚ5T”(çLºQ); ªÕôñ©¹(—“þbýªï›y{Eb¦øqÄûË‚Úâ,l,sü‰„¨bÀ7‰yš°yõ…ÇÙ1Ñ£P`ÌL¸™.øFÌÕ`Ík:4ÿ¬Ú|`Ä (@ P€ (@ L@<kt'i2¬šŠ]¥Çq¶µ­âÝ|¾Å™)Ðo~ÆC¶ .vëâïCA¶;,%í«ÏËK¦{Ðpp–í¨PÚf§ßålgmÃse΄ºyï“8Xß KOz,h8^ŒµóÒ”-U 6@yû=¹O¥«! ‘¸c¥O>Öe–â|§œNîA멣ضJÞ7^[¥$1Y™¡ô·yÑ8ØÐŒñÛƒÕjÁ©ã…˜³2K¹^´+mжñÒEÓ‹beý¾=ŽÕõÒ ûAï]»P|¼©íSú2e­Ä–âjt¸BìikÀ®{Vº·éÉÞ»œÔHÞñCÕ«\í¬°ZÚP]œ‰•9ò"F“”{8 Ž}iäS‘HΤôñ#C^u›|QõYô¸……Ò»…Ҹķ,‰Âš,÷v?†‚|¤ˆgè&l^Ua UÓ‡êŒç)0J;_-0gÎûã?î×;ÏöÛÓkoý•ͯý²3 P€ (@ P€ ‚[àbU]¤–|zrد nW£]¤«=Ûëõv‘öö8—]Ù¤jÙm?’áy}¤Ò+Ï9Ú7•¤»ú5Ú»T]ÊÅöšA÷Ö‹xöoÈ«“[ˆÏv{IúÈñòjì}ªV]M%ƒúxõ±¡¨ÑѺ© +{c‰QÕWºý¤cb»ì%Æq œ^PcïVî8qóª¶6º¥ÛŽ~ŒJ°,€ônii øH¹Â]ÌÔt{]‡«£uÄKjónsúBCqÝõ±¸UÜ/Z<Õñ²v¢¹õŠxØgæÌç‡éhPÿV´žmÄ™ÿù½3f`F¯ˆjîÍÐß©G|äÐýX…AÓ»çÑþQÆu¸>> æ'ºctŸqœèéÄÙ3§ñÁŸ¤{õâjï,ܶäKXœ0èg Ï›ˆ­nšÏ]ÀÇŸŠííÅÖñ3g߈…bކ•gókq4qóz-¢ç=E@£Ñ@¬pGBBB „ä5&ܽ²ÎɉL¸K£lù÷~üW¶ këtˆºI÷À™yFB P€ (@ P€ (@ ÈÁ’p¤»d;~^Cù‡à³+vÔÜoÅWßÒaæç™t¿†ü¼(@ P€ (@ P€ (0…¸‡ûšÌ±å¶ïj‘¸=Ä‘tÿì2w«#ÛQ€ (@ P€ (@ P€Ó[€ ÷é=ÿÊèõOjñycjÓlè»Ê¤»Ã(@ P€ (@ P€ (@˜p÷j:T»3?‘ º¿¶ÁÖˤût˜sŽ‘ (@ P€ (@ P€ðŸîþ³ úž¤ÜýoZhÄÎþon¶ÁÞϤ{ÐO*@ P€ (@ P€ (@ \3&ܯupÜ($TƒU¿Ò¢ûðŸ×A3J P€ (@ P€ (@ P€ À„{LB … ›©Áê—´èx«ïì±ZxŒ‡ (@ P€ (@ P€ @@ 0áÓ2ùA…Ek°æUZþ½g÷1é>ù3Â(@ P€ (@ P€ (@@»uóEïŸI÷×tx5ÙŠë4¸ù[ü}Æ»ÏR€ (@ P€ (0> NU›ñû«ÀŒ>ôÔÛ‹ÞY·ák©‹¹m/fÝ|7R—ÆûÐÁT±´¢ú•·!†0¹q 14Ks^9ý¡Nv¢¢êtkC5Þþðª˜ï“Ò{õ*zgÌÂâåÉXœ­j99űŒqr"å]§²îSyvý0¶È…ªt¨YcÅ ñïæçÿŠIw?°² P€ (@ P€ Ô–÷ðý4#Ìês#•õE¸"%ÜUmõ''-án¹`BÚÆ,GÔ“ÇPl^ÊÅÆ,!,» UQ9o)# YMʉa †ÜJ¼¸b‡­5±G?Ɖ‡½OOfO§ç¼jÔsîÔàÞcZüîÛ6´×óAª£Âce P€ (@ P€ F ż‘kX#¡#Ö™° ¡aJ× Â'1% ÏBh˜K8& ¾®ÀZàÙÇpGæü͈K)EÇp•&øÚXÆ8Á!±ûi(àë_Ó†CV Ä%‡à®~»Þ†55HIx¾(@ P€ (@ P€ €ß yhªØŽ¨¾¾á»‚c“È[ñÔ‘J|ëj/æ,ºqø6¼:F#êÚ»"«ÒC,WÚÑø›g‘¶ãçYó”7|»WLþö2J˜,Pà 0á>àÖXºÅÿQ@døÔ!–¶“Yv0§Y±¶^i»¾(@ P€ (@ P€ €_¢â0?>"·ëã+É6!ÙÇÚ¬66ëÂá ‡ju|8Âã#‘šy5­g°&ß¹!PuÃL¸˜­¦ˆ·”ñ2‘=çC£Ñˆ÷œ²x©0Ü©ž³È‰ö¨¨(D­xÃÕ ÂkÒƒSoß‚šû­èþ£=GÀ)@ P€ (@ P€h®ÑF׉ÚÃ¥(--ÆÑúV¥qÇ©ã(Ü·…ëŪl+N/Eæú,Y²ÄñNYŸ‰Òã§Ð£´P°v ö`¡h³)ª6ŇkÑ1d£}ø|ØãˆoKŠ”r¿S¶ìÁñSmÃôbAÃÑB¬_ân£Ñ,Á–]…¨oö=+eíh@±dUXˆ}{öCØx @IDAT¡ºyt ±åÖ+1F)%w¡ã|=Š÷d:åñ-IY=Ňq¶mð½Æ=wî[+¥ñŽQéˆ Œ 0u–_0ÐÑ\~ûÈ¿ºªþ~ø~zp8K2¹Òß÷Ä’›Ãç¢]ZغšµVÜ_§CX4Wºü1F P€ (@ P€ @°¸·-ñ!bËûøÑ掮 îÁ†äG£O<ƒœ½Òªkšk.£¬bÀÓ?›š`6•á¹¼4>‘¢Z¹-¶Mi«Ç¶y«P1ðö®6Y0¢êâ/š(–|÷emEñ†ùÈ2 îÈ\‘émÈ5Á´çªÿžf>°9Î…åªÆM¨xFzç ×tû×%ª®y)vˆ±Æ©Æš^Žöéï <óbÃmðóÎëÇ”ŽçÞ0S)K…†â-X™5HMf“ã/ž3›WÕ‚'Ró&µÏÜIí½†ã šN€µ§§ŽîÃ*%ëo@zZ’€µù°G²Ý˜[‚ªº:T)A†*νi?ÄYÕ_ Œyî”;«öšçU]²HŸ|üÏǧ¾‚´RjKŒO4Š|½ü”è㨬­ÇñÐF×"|lìÕ¾ü|ê¿aCÝߨ°ú¸!¡\éìsÊø)@ P€ (@ P€“.`zÆõUð¶5‰[×à–](ݺx¡êQ~òul]ël³õ!$m¹;\«ÞOžkǺ„xǵ†â'”•íúìJ¼þãMJzÝתÕèÈ;¼Ç2G‡gÈ–S‡±MYü.LZŽdW¶{éÒX}×1o•X.^æœ\Ô?R‹dñ¼ûÜÞq%ÛVä¯3Â󟘱OJ°´Ô„hð•J-ìâgÑ·¾mƒÝΕîÁ2wŒ“ (@ P€ (¸ÒV/b •!Þf‘ä½Ð5Ü'ƒG–Qù¢;Ùoï~T©xòýœeëyü,GNAgàEU²ÝQA—€‡N*+ÝM/šÇñü¾üæÀ%†¼ºŸ(Évùd|òN4–¤»ͨ¨ie©3 /]È«)P’íΊáX÷X¶³(þ·öŒklò™y‘è‘V}«“íbËš¡“írC‘ôöR’]~»¯8K­Mç=öÄI\.ÒåÒ+¯¸µM$–Þå¼*Õ•þÇËËç¹S·ÇÕݰL±p…»øÏùK9E(øXú- aaŸàÄs9¸­×p¸õû¶a¯+Û^`:‚?7bº¬u×ÎÐ`ÕÿÕâõþëÿëÇògµÃQñ(@ P€ (@ P€A@£QJÄzî!®4êꂆJÏ*µT#¾óWIªcgQ²—WÓ÷\<å~6Ÿq)¢ÄöÃeGÃÝ ¸]”iys-Þ·ìÄ iËóQ¿úЫ 1ïr-QÐÏíwß#Î8—Áÿ©íQŽSµ3âÁ»+ó=šÅ¯ÅÅsMèƒ ™ïq ›§¬ª—.àÄÀýá=[ˆ#iËšG‘æyá“öV¼u4&W^,Û*¼ô¾Øgªc}¬øÁàŒ}§³‘Õ Kg',]—ñÑGho>B÷ò~ÏŽ•#ßçNi"Æ4Fx@1 0á.ÒìÉ›v"Y!´"¬Ê÷„{G}¡²ç»>·»×Åb‹Ò×ô(„ÎÒ ¥J‹Wï±¢éÄ?ÁÿÀ¤ûô˜yŽ’ (@ P€ (0ÆGñ‹c™Þwãí|MÏ÷}*VdÊ/ÓÌ‹p¯@—OüôµïíÐÓ‚y1½HîÏ"K§‹Šq¬WvVP·3ÜÃõ,N„#1É×­nªñfÛ÷?DŽîõxøÑL,öVå‰ýh®.Ä´Gͦü4ÛÞ ®ÊZšëñ|áÓÈ)“ë-Þ¡ÏÙ×£K_ÆèÑ`ȃßdÇÿ\â.2ÐÚ;5Ðj¹Í´ì!}zûÏD}}–»}sgYåüÇÈůóDÚ¾çÔP¿¿úÞoÖ ‹Ñ`Ík:¼r·Zñ0ê/îfÒ=§‘!S€ (@ P€ &_  ²3^óÈ]ÄMw8¶‹ñ=5Ü%6+ãK,?W¸‹1õÒÍœƒõEu;³´ÅÌx_f¤¥ÿWj3=dWôI“2ÄJþÄÔݨɫƚ½fGmŸ8g°­¶óÖȹ3ÏÎ éé¸\Qq¶höeŒžñ uôq—M-L¸Ë>÷- wù€Ÿ&ÜÇüEž"½Ry°Då¹½H”4Å_ ñoϘï, g~Þ™tu•×ݤÁü‡ùˆ€`™;ÆI P€ (@ P€$ÉJXuø®’ë1ÔáÐÎ;aíöÜRFrÒED({ŽëÆúË@h(æÊèòž6ò±êÓ"br¦±Åc¥óêv†/"BU×]´¢³£SJSA‰èHÏ 3JQº=[BõÎÍjÌ;ðøÑûPº!ÑÝÅ(K½r”®†Öf<¥J¶²‹ðÔwDÒçã‰p1ÉÍi3±psÙ(ïä[õ‰£tç/ß"Þ¾ÅÀZÓS€Ñ1ÎûÙƒßÇ6×Ïé%MØ”äú‡Kü¬©ü:)úüOòo$Í¢nO¬~Y‡·³¡­º?H¢f˜ (@ P€ (@ P@ä²g»÷C7ý¡R²::zÀ[‡7Ë~ŒÿX¼ËÞ{î'|>–]ê¦*¼Óé}.œ¨U.,™?[,ýWµ3Ãéå²»Ðö:æÄÅ!N¼W?Æ}^*JðÏ™KE&~1 ªr•keA½·¾\5†_É߃«s¥}÷Ý•­ípA>N/‡é€ØÒyq"b£ÉvéRÛ”rMÿ|ŽqŒþ¹9{™îL¸á`9úm®_ßÄ?/dªöÄŠ˜é^á6įŒ£»©Íf¹èóùm·OÄ,Ó ùˆon²¡ãwLºn¶Y› (@ P€ (@ÉO\ŽlùæâÁ›¿>ß#)Ÿ åHËÚ‹½{Åûí+ÊyB˜/;G áv9ImÂÓ‡<ºpXp KÞàÆ€‡’¥葸}™ÁU׌•×j×PQ¢œ{0éF¥ì(¨VÓǧæ¢\Nú‹uô«¾wƒG,µŠÄLïKéÅ5 j‹³°±¬ÉѽÈè㎛Äþ‘·àÎ8 ·&ºóe®ZÖ¶j<™#¯Šõ}!sµñcLc±WVð³ÀhòRÝ`yMÖ_è‹×8/¼úK÷ùŠäÝp—űu9>ýà×s£ÅéçÈÚ%~EüøSÜÿ÷ÿŒ IâQ¾¬â ÎŽ_Lů¦¾¾^zé%<ðÀ¾VŸz7¦„`Å¿¿]gÃ}f ®¿ƒO˜hvJ P€ (@ P€ €Y™g\Ûœl^ôzO¾€o.KB´ éåç±ÌèÞ“¼hWš×½æM/bOûMÎÍè½E×Ý açcû€|gÆÛ”µ[P…Ÿd¤"Vl¤ÐÓրܴ•îR¤°v¶á¹2gBݼ÷I\ýþfù<„öYpÆüïÈ5f)[å@Œòí÷~‚¥KcåÀÆ÷9¦1Žï–l=z믿Ÿ~úéèx &ÜÇ0A¡aêFÈF}¬.›QöŒó–Ä]ÿ¤¾àsY§Óá?øþñÿqTm|®<¿ðPzÅŸCÕ~ÕŠµoê0k>“îÈÍ®)@ P€ (@ P€A- Þ¢w´OÛ÷JÚô#”T•aG…tÅŒm+bÛÀJâØWƒG—º2௛E¾H^¼=ðšëذ` v®[‡¦ò e'…Ь4Tdz±ð½I•ĆXwß”—*’þ®Wl ~}$ 7æ;NÈíäËògö‘§±bˆå:ºøu(/1bÙg’>?-Æ+‡í>“+‰Ï¦²ˆÐ†}¥Ôà…Ý+œu¢—㉠ˆ•ïÒ¡p\åÝQîpDz8œ¨<‡C›’äS~ûnŒ~» ;µÀŸÿüçQµ™1cƨêOVeå¿ÓÉ ï;ós)ÈÈ^€ñ€ŒÁ¯nœxç¿©dç®.w#iöØ©µZ­x†?ÿ®fpÔufáö|ö±5÷9“îs™tŸ(köK P€ (@ P€^ß ê}|¡Êv%‘Qªü‰²`Ò‡”ºÒb‘y¨ ·,ÿ>Öd¹¶pãÜÊFämZêN€‹ë¡ž+4´|(v"v¼o-ÅÅ¿ˆ‡Ò²œ«ÌÅYu²Ý]Žòü­H‹ÊÕ¯Ä ûq©îV¤¯Ú¦Z).×0¢¼®[Õ«Ûå1ª¶[‘k/Ýþ4rÅJ÷|G’¿Ïšþ+¶ÎC˜tRÆŒ<ìܵ)IêêáØð/-(Á:ìP¶›‘ïdÕàŸ2ð슅Øëúq¡éŸ8+ȱ*3ën7¨¤ÔWä²ÏcôrP|<1¤@°æ;‡ë‚Fì÷m©ÒôºnÁÁõQ®¢ÑØu K}üÇÅédíCíåè>¶ÕëŸùjƒŒŒ äççûÚ$ ëyÒ†KÇûqÿoubÒ= '‰AQ€ (@ P€ (à!`Û¢4½{íéÅŒ×áúøx,˜ŸˆèÉoFc=èéÄÙ3§ñÁŸ¤{õâjï,ܶäKXœ0Âu«Íç.H;‹¤¿ØòxöX˜ïñcÀXCòW»ÎÖ³x·¹}"Àë®Å­·$¹ ­hn½"â9sãÄù±/ZõW¼ì'04 ZZZ˜º¢â7ØïÓÓíî±ë3HGño°û&ÁQZò”Ÿþ?;Ì_³aÍ«ZhÙtŽ™c” (@ P€ (@é+ ‹ŽÇÒäû™OGx4¯HÁâÑv¯‹Dâ⥧¨¯è„ÅP/¶÷ˆSÄÄ~TðhÀ ¶@H`‡üÑñ ÷®øW-Âæõ_·¡ßÆ?¬p˰D P€ (@ P€ (@ L&܇ÅQí%3¸'/ûE ®4}΄h5¸çE-úº€“ß±»MŸ¹çH)@ P€ (@ P€ (0˜p4Ë‘ØzÌîHÛí‡F¹»Ô™ªý±L_í0(‚©|B¦ÁêãZüù¬§þwÿT*ÇF P€ (@ P€ (@ L3&ܧلÂp¥‡¦¦Tëpé?úñÎmc (@ P€ (@ P€ (0n&ÜÇMÈÆ"'’î¯éðûƒý¸PÆ•îc1d P€ (@ P€ (@ P °øLÏÀšiͬ Ö¼ªÃk÷ZSýÂþþ3­¾,(@ P€ (@ P€ ¦˜3œSlBƒm8³o{ºÿ‡ 6üñu®t¶ùc¼ (@ P€ (@ P€ €[€ w·K“$pÊÜó -N|݆Ëo3é>IÓÀÛR€ (@ P€ (@ P€ãà–2ãdsÿ|nm–?˜´áþ: f'iüÓ1{¡(@ P€ (@ Lakçy¼\ó.0cƨFÙÛÛ‹9wÜ‹”¤ØQµcå¡,­ xåíE…9¸{} âƒ(ëfi=óÛ¿‡øVxÄÞÚP·?¼*¾^Þ¿_½W¯¢wÆ,,^žŒÅ ÑCã\£+–f1§Å̺ _K]Œðkt_Þ†j úO_6ËSQ`þ7BÐ{ÅŽšû­øê[:\w“îSqž9& P€ (@ P€ðŸ@÷¯Â¸1klJÐU›‰È±µž¦­¬èh¾ˆË}@hÔ<$Æ»õ.˜r±1Ë,\ 8Ù%îîKouÁô}Ån)# YM¾…oÈ­Ä‹û7a2¹ð’kôE¸Â„»oÇZ~à–2~'e‡ã¸õï´¸%#Ä‘tïùØ>ž®Ø– (@ P€ (0õBÃÆ>ÆËŸÁ:öÖÓ³¥¥ ßX¸‹-ÂCïMƒÐ°y®±D!T5ª¨ªƒŠæü͈K)EÇõ&ò²2Ž˜0p•ñDJ³ïáøÝN‡×&E`ñZX?ÛˤÙpŸY‹ÐY\é>)Á›R€ (@ P€ @À D.ÞŽ+íy&Îuáè:ý<®ÉqÄoÈ«Á¯²¿kÏÀôz8&€'ö Pd£åÔô‚pujXðàS(ú–¨?7z^òì#(Œ¨kÿî«öÝߢ>X®´£ñ7Ï"mÇ3ÎQ™w ¼áëØ½‚߬ œfí&ÜýÂÈNü-pçþ¼õ¡ ¿5Ú`xY m“îþ6f (@ P€ (0tˆŽ¼‰GdìlepQ³¯Gt¤H€Ñ'JðVŸéŽ(Ì3«˜Œ­â=U_×…‡Cü–£Z9Žp±oNjæÔ´žÁš|i; ºá&ܧꗀãòI€[ÊøÄÄJ×Z@£Ñஃ"Ñ.þ!s“ ö~n/s­ç€÷£(@ P€ (@à[Œûüê<{…ûöa_áa´Y{pêh!Ö/Yf žµ(ýtœ¯GñžL¤8®iÄu –¤¬ÇžâÃ8Ûæ®'7è8åì·ð`½XmÅ©ã¥È]"ÚKï”õ™(=~ =rõ§µÕ÷‰8œ÷‘î%½×ï*Æ©6¯-ÄÒëÔ-vÞÃU_#î³>sמÅàåZÐà³ú^K°eW!ê›;]•¬8{ü öíùGT¸Î|Põ3îCim³ãLçùZ”––¢¸ô(Z…(\Åø·¤¨ï¡AÊ–=8~ªMDù—èe´s¥ÜxŒ…åÖ+-£”’»0ÚxÆ;~÷Ý%kGŠÅ÷¼°°PÌã>T7ýp·b‰c°óÐsæÌ±?þøããD×÷i¿ý•¯ôÙ·½o"oþ)@ P€ (@ P€SJ «©DZ¹æx‹‡[c‘A©k0ꕲԾ¨ñŠ£íÉ¢tórßêϼªû¸û5Ø3Ò=ûU·ÓçÕØ=þ¿þ+'í鮨ÕõÔå¢:Ï{ÙÛëFlC½ÅãF"Üî‹öƒÓIÝ¿ºœkºh·w´†ˆI_pÒ1nõxOv©(úZìEÆáïaÈ5ÙÕMÔ}ÊNÜv,sÕT"ϯÑÞ¨Òe/Wâ6Ú=ƤžT¬+p‡2*Ïy\KNõýȨĕC[˶Õ\,ûQ€_-?b²«‰˜q½ø«Wtxõ+V认‡ªòE P€ (@ P€ €?܉öô¢*üäÑT%!yþ`•r#±Úû×%ºŽ“‘ºaîͼ›Ë¤ö|*íe#¶‡üÒ£üäëØºÂµßüÖ‡´å>ìp%âOžkǺ„x ç=)sµÖàc»•»¦¤nÀÚå[\É.tbÅR±7}Ϙ”6¹¸Ø°‰®’SR±i㽈Z´ÙÙégîÍv,§a‡’O=„dWxëÖ}†=ÀèØ—ÜŒ_¿­ÃD÷,>|¦Òhߨý™‹UuÆrê0¶)¿UH÷(÷p¦ã–.]Õw}óÄÒËœ“‹úGj‘,†äùòÑN4ºXï¹ò¼»óÈ„•Qôz\V]njro¤Ó%/zÄïŸx|¿*4ç^ómµX?o äiÖgÁ‰ø85Ë~à w¿“²Ã‰ˆ¸Q$Ý_ÓáýçûÑ|°"nÁ>)@ P€ (@ P€Ó^@Ÿ[…C;ÝÉv $&q¹kUw^+'ÛeªH,½KYó ÏLjÊu€ŒÊÝÉvÇéX|{÷£J…“ïä,‹|¸²p½éøƒjżTaÅÃ!/7W¬,Ïí³#œmÂcpkõ{Æ®‡•d»ó¢xVìÂÅ[Ô xõà7œ‰néB^M’lwV ǺDz•6µg\ñYÝ {¨’÷JE‚tÊ™¼ºŸ(Évùd|òN4–ÈÑ™QQãÜ^¾.}úl'êúc®Ô÷X6‹»”d—߯·6÷Ø“ßñŒfüJ<ó"Ñ#­lW'ÛsML¶+@,L¤W¸O¤.ûö«@äÍ"é^­Ãë)VÌ¿öÞdäïE~fg (@ P€ (0ír¶¯d+’Âgì;ç­VX:;a麌>ê@{óiº—pjëBGG;Nÿ¦PµÝŒÜ´½Jf߈ï«ë¾â×ââ¹&ô‰@Ccæ¼êñúØx—kùü€–·ß}8ã\ÿ§¶O\…h9þ¹p{åPÚnçQ$„)'…OÚ[ñÖÑ|È;åo[…—Þ[æìOu¬0<£¿]ÅfÄ)Y -À‰ý븲]ba"˜pŸH]öíwh½÷Óâ·ëmÿ×øF“î~Gf‡ (@ P€ (0MÒ‘4/ÜëØ-Íõx¾ðiä”É›sx­6äÉ¡V¾j KÄžª<”¥íu]2#‡x»Žô† l4-±¡ZPøy<]£$õ­>ÑÓ‚y(†»q£G_rÅp$& ¿eŒ\Óë§úÆ¥˜7DNãø ÏÍYÜ=úlçj2Þ¹rßY]ÒãáG3±ØÛžØæêB,LËq4hÊOñíÝØàÚ×g¼ñŒvüê¨Ýåj¼Ùö=¤Æ{€»–/¥OÛìøK‹ô a¾$Vj  ÑC%0þo™ª3)p-âî ÁÝÿœøº †j b–ñ?êkáÎ{P€ (@ P€ ÀTK¾¥eç’Ïmµ…˜·Æ™L(`HOÇå çžæ¯õ8!õ \¹¸/<+üÏÈYqgoMæ2dIoñ`Ôšö£H‘öC·¶¢pí|ÕÃOUwÖ‹‡xê/£ÂµW¼rE,[W¸›oã¢ÔOA}®¡;ÒÍœƒ˜¡/êÊÄÍ•}Ý"”Hïá$¦îFM^5Öìu>¶í©r8&.ïq }ÖŒ´ôŸâJm¦òL€¡ëå£×ì8wÀ6|¥it5õ¤ÚÿfL£á{*î^Yx2Ðæ=‚eâY%o‡ÈÈH„‹ÌRsÚL,Ü,?µÔ?cŒNLÆîâoAÛ¥ ø¯†0ÿò§xFÞ»D<sÍ_F_é:´Û¯J¶Ptä)±ELâæD"2\Êž;¶,òÜV&4Ô½uá‹pí? x+:;:aguᑈŽeVQ}eÏœ·‡–ß…3M “—Üpà™Iš+9ŒÞFy®3“OFI#J·‡bK¨Þ9÷æxüè}(Ý0ð9ò|û¼ùÛ!Þ|Q`(~;†’áù€X‚/憠ö~+>½Ä?å ø c€ (@ P€ (tÖö ¸ G^ÓH^œˆØhg²]ºÔö¥†\sÌŸÖ¶zìÛ³{ö¢¾M¤ºE¢;>q)ÖmÚ‰ÇÎ ë¢ ¹÷ «Ô­øï7OºÎèQyîeìÜŒÄøXW²]\êìÀ%¹ü>K®ó1œî/¨>Û^Çœ¸8ĉ÷êçϨ.øXTßÃT…w:½·»p¢V¹°dþl¥<ÚÂDÏ•ôÇC¿zpu®Þ}YTžèxÜ7óR2”àŸ3—Š_J£ *W©P¶ñÔ{›k¥ ¿îã7d“(”¥ÅÂÌÔ¬µâ³+LºOâTðÖ (@ P€ (0"oÁ72œ)n퉃v±¶UãÉye³Øodœnwt{óó‘ŸŸƒ_7µ+ßS•¼îgâº<#ï~ƒç\…nE­ØšFŽar€‘¸}™œº7ãGåõƒîÕPQ¢œ{0éF¥¬”¾”3 H¸]Ö„§5 ¸.- 8%o›cÀCÉãX}=¡s‰™Þÿ @j‹³°±Lžî¸I|&4žÁ”gTQŸš‹rùÇñMXõ½Ãèñ¨Ì øW€ wÿz²·I¸#W‹¹«B`~Ðë_˜tŸ„)à-)@ P€ (@ P`Š è¬mx®Ì™®6ï}ë›aééA¥ Ç‹±v^š;™-6îxû½ñ-޼ñVÇD%ÎgÒÒP\{^IŽöXZqtß6ä¸òºú•wˆý¸£±|½œM‰ó¼ƒhî´ GÄØÑÜ€â̵b_q9¡ ˜N4BŽ0yÇ•{™sVaKq5:z¬°ZÚP]œ‰•9r;#ŒÉ Ê Ë{¿›N˜qª¹iϯ/RÛ§\1e­tÝÃyª§­»îYéÞê&{7îŠVªº0±sUô¸……Ò»…Ò_"ìÛƒ-K¢°&˽¥¡ )âá¤Ï<]êë‘HΤÌ5*6#¯ºM]e øU€ w¿r²³ÉXþ/!¸î Ào²¡¿I÷ÉšÞ— (@ P€ ¦˜@ôr<‘!ÉŒm«"*"QqXiÌR%Ûuv,‹Ã–ÃbÏô±¾âSñlž¼ò¼ Yk!B³K–hÄ=çc£’<7àÀ®Ç]n0]¹›ù™mX8' "Ƹ…+‘åú±@©P± qšLœ—–8Ǧà×GÜÛTd¥!."¡Qó¦J gy+¼%Â+²°lá|zVé~P!~šÊ@8ï¡qŽgÞJ<#/ G6šòR1®‡-NÀ\IC ¿šÊr••ƒœé…é/öæCý<Úô‚¼¼{…³ÉÄ#Ç2ÚO˜‡òù‡ ?- £í…õ)à›î¾9±V€ hB4øJ…Öå[[l°÷3éàSÆð(@ P€ (@ PàZ „ £Ð°™® bA¯plø—”dÈ[£xVÈ(ªÁ•î‹ÈS]núÃ'ÎJÊ}½õëÙ”º@ò¿BU‘;I 4¡IIL‹v†lÔˆ½ÜSb}„'nÀ¥º÷ fu×¢nÕÅ+h©ÊS½€O\’'nØ/Ú–»÷…WÕŒ(¯kÁõC6×boe¶G-|æêLƒçxo-ÅŪ"øÔã1d—£¥û«› Ñ—ç]GJݱÏÕPß0uL^oîcÇý}ð!eü"¹¬ÚRF{éö§‘«|O+ð¬i? Éò“^4vñòrž§D &&bï²ü‰(°Ã¶”y} s–jðåçœ øÀŽ˜ÑQ€ (@ P€ ‚C ³õ,Þmî@_h(®»>·Þ’„h9»jíDsëñÊÌ™'Îk­¶ÄÚÙŠÆÓgðá•^̘1âqó­zè“⽯ïéÄÙ3ï¢ã/} ½±_¸I î¥é–¶V´w[ÅJù9ˆ‹öìÃjAó¹ øøS± ½Øæ}æì±0qˆûˆè¬bKv±·Lh„‘‘Ñði¸ŽøNãƒ?IãéÅÕÞY¸mÉ—°X£¿¾ ×z®FŠ;Ðâ)^^LFƒ––$$¸·x ÄH™pÄYQÅÄ„» ÃÇ¢ôðÔW“­øÂß„`I“î>²±(@ P€ (@ P€ V XîÜR&`¿B l¬as4Xóªü¼ÿ]`k7lG P€ (@ P€ (@ P`TL¸Š‹•ƒE`æ< RDÒýü~|PÙ,a3N P€ (@ P€ (@ P ˆÆ¿¡Vž¡Om¨[50¼¬CÍýVÌ[¶Í{€¿/Míçè(@ P€ (@ P€ (0¹Ì@N®?ï>ÁÒÃSWýJ‹·Òmh“+Ý'˜›ÝS€ (@ P€ (@ P`Z 0á>­§z ~îê¬ü™¿5ÚÐÙdŸƒæ()@ P€ (@ P€ (@k.À-e®99o87­Ao'P›jÅÚ:DÞ¬™Œ0xO P€ (@ P€ (@ P` p…ûž\ÍS q[}/µbO÷î¸ÒÝS‡G (@ P€ (@ P€ Àx˜p¯ Û•Àíß×bÁ‘tÿª½Ÿ0éT“Ç`)@ P€ (@ P€ (àL¸ø1<ÿ èÿA‹˜å¼ñ5¬ÝLºû_˜=R€ (@ P€ (@ P`z 0á>=ç}ÚúË¥Z„Åõmè·2é>í¿ (@ P€ (@ P€ €˜p÷"»>­÷ü»¶Oßm³ÁngÒ=øf‘S€ (@ P€ (@ P °˜p¬ù`4×P@¦Á½&-ºÎ»ú¯áy+ P€ (@ P€ (@ P`* 0á>g•còY 4RCµmÕýxçïm>·cE P€ (@ P€ (@ P€˜p(Âãi'~ƒk^Õá÷?ïÇû%LºO»/L P€ (@ P€ (@? èüÔ»¡@P \÷gÒýµ{­›£AÂ×ù[TPO(ƒ§(@ P€ (@ P€ À$0«8 è¼e` Ì^¤ÁêÿÐâ?wØðÇW¹§{`Σ¢(@ P€ (@ P€ @à 0á¸sÃÈ&Aà†/‡àž_jqâ›6|ÜÀ¤û$LoI P€ (@ P€ (@ `Â=h§ŽO”Àçî Á—Kµxã¯løä=ûD݆ýR€ (@ P€ (@ P€SL€{¸O± åpü#°1½Wì¨YkÅÚ7u˜• ñOÇì… (@ P€ (@ P€˜²\á>e§–¯À-™ZÜúhjï·¢§ƒ+ÝÇëÉö (@ P€ (@ P€˜êL¸OõæøÆ%pÇ-¾°A$ÝS­è³0é>.L6¦(@ P€ (@ P€ À`Â}ŠO0‡7~%ÿ‚뿨Áël°}ƤûøEÙ(@ P€ (@ P€ ¦¦îSs^9*? h4¬ü™¡³€ß´¡ßƤ»yÙ(@ P€ (@ P€ ¦ŒîSf*9‰Ñi|D‹Ï. Ø&òVì› (@ P€ (@ P€R&܃tâöµІk°ú7Z\9eÇ©0é~íg€w¤(@ P€ (@ P€ @` 0áØóÃèL`Æl R^ÑáÃÿÛ³yLºØô0 P€ (@ P€ (@ Lªî“ÊÏ›£@Ä\ Ö¼¦Ã…Ò~\üi01S€ (@ P€ (@ P€  ›€>Ù%¦¼À¬ªu¨I±"lpÓ_ó·«)?é (@ P€ (@ P€ F`–p ^¦ÀPÑ‹5¸×¤ÅÉí6|dæJ÷¡œxž (@ P€ (@ P€ÓE€ ÷é2Óç„ÄÞ‚»+µ¨ß`ÃåFû„܃R€ (@ P€ (@ P€Á!À„{pÌ£ `yi!ø_ÿG óVtý“îE§™Ã¢(@ P€ (@ P€˜fL¸{™ðžó‡¡ÑhÄ{ NY¼TPê8[=[R  @DÄ2¬]…9QФlÁÁúfUM)à)°è{ZH‰÷Ú¯ZÑûg&Ý=uxD P€ (@ P€ (@à`ÂÝËœ½}ä_]g‡Ï¶Ÿ?¼ qú4äW˜]õ›`nrÍضj!Rö×»{Aæ)‡€þI-nX©ùA¬Ÿ2éί(@ P€ (@ P€ ‚Y€ wõìY-8[]ŒU{åºú¢gÙÚ|‹6?ã>iÈÆ‘š:ÔUU"Ûè>mÎ7"¯ºÍ}‚% ør‰Ÿê7ØÐßǤûR€ (@ P€ (@ P h˜pëÏkK÷!sËz±-LôiY>MÞï?ç®—QŽ+µ°!%É©›pàXN–¤+×ós*С±@OMˆ_9¬…­øÝVìv&Ý=…xD P€ (@ P€ (@à`Â}x÷¹½(«0bÆ:qÚ,¯‚OGcÑVD{´ÖaÅ·wCI¹7½…ß¿;GkL?í î=¦E×à¿vöO?Ž˜ (@ P€ (@ P€S@@7Æ0Î!„âK9E(øGÂÂ>Á‰çrP!ïÅî­wËû8&çÛ ÷à–p/•ÂoÁ±µŒœÇõR…§( ¥AJ•¯ÞcÅ;{€;÷kÕ—Y¦(@ P€ (@ P€ \€ w‘fOÞ´ÉÊDYV5BÂ=r ~X’‡%ç¯ bÁ-ðšL·œÁ1Õ¢ù>¥(0´@XŒHº¿ªÃ«_±"bpÛw™tZ‹W(@ P€ (@ P€ (XL¸šîAgŸGJæH|Áu¦¿Ÿ%ßn\Û#‡¬Ì ð¸î&gÒýµ{Å?"?ÿ›ÜùɈ (@ P€ (@ P€Pfòü<1=m Ø“‡meî=iÊÿéoÀ|»Ÿ¡§xw³“40¼¤ÅÛßµ¡­š{ºOñéæð(@ P€ (@ P€ ¦ˆîþšÈž6/ÌÛ€¬D¾¼¿»è»èÿgï^À£*üÿÎ93$A ‘€ TD J´ ’P¼¼âvÁKàßµ\Ú*ÅVº‹­Yt[.µÐ¶"­•Z‚ZðB‚€Zi ­Ò ª %–rfæ&—I$“„Ìå{úLç\Þóž÷ý¼óôÙýåå=k‹4¡7q{K1GS=I—›ü‚¥·ÆzTü6¡{4=}E@@@O–”iö¸•hëŠ_iâí3T3§Ý©4s¦Ö/›¥Á)õ½Qµiõx<*/oü*ð.—K†a4í!”I.Y¦<%½9Ê£o:ëÆ5$ŠF!€ € € €4I )yg“*nãÂÌpoÎØ»õXV‚2ê„íÙZ¸öC•ç?Ú"a»mÛzüñÇÕ®]»FV¯^Ýœ^qoˆ œw«©Ks-å_gëë"_ˆµŽæ € € € € Ðt³Î:«Ñy§? —îAÔ!-Ø]3j-3sÉz=0a°ƒ®óÄý³Õxàýô§?=ñâIÎøïa‹,^÷š:ú¹Ok¯µuÝ[.Å&3Ó=²F˜Þ € € € €Ñ%ðå—_6©ÃẓÌ6iXk o[:E—Uçh}Ñ| Nmþò1Õ5Öþ¶,Kn·»ö)ö£PàâX*/QÅL÷kßtÉ@è…?ºŒ € € €D„@¤æ,)ÌÏÓÞ©gi{¶Ö\Ôja{0ÍãžÈ¸ô§–/5´î&r>l € € € € ÐvÌpo;{žŒ@‹tèî„ôÆP[1¥ónåïh-K% € € € €4Q€d®‰`G κØYÓý%K[îóhßZfº‡âÑ&@@@@È pü1¦‡Q"pö@SWÿÆÒ†;<úâ]B÷(vº‰ € € € Bî!44æ ¤\gêŠ_Z*¸Ñ£¯¶ûš[÷#€ € € € €@Xý XE ºßiêØAŸò‡Ûþ–Kgœk„C³i# € € € €a/À ÷°B:€À‰|ÛÒß6+B÷²Ï™é~¢g@@@@hy÷–7¥FBBàâXêr­©‚‘•MèƒB#@@@@"Z€À=¢‡—ÎE»ÀåóM%\(½9Ú#ÏQB÷hÿ=Ð@@@@Ö po]_jG M ÃЕK-Y1Ò[ã<òy ÝÛt@x8 € € € €@D ¸GôðÒ9$Óehð Keû¤-“< € € € € €@+ ¸·,Õ"J®8CC_¶ôÅŸþ<“Ð=”Ɔ¶ € € € €DŽ{äŒ%=Aà”íÎ2”õªK»Ÿ÷꯹„î§Äâ" € € € €A¸Æ-„«@Ü9††½îÒßáÕÎ¥ÞpííF@@@@ $\!Ù*…­&ŸæÌt_íÒÃlÅt”ºâïn­†MÅ € € € €Q%@ÒUÃMg¨Hìgèš•–ÞžàÑþ7™éÎï@@@@– po Eê@ ’™ºò×–ÖßêÑÁ?û°4@@@@Ð p­ñ 5œVn7šÊ˜k©`¤­ÃºŸV|† € € € q¬áqCJ‡hš@Ï»L;èSþp[Ãßr©}ŠÑ´ ( € € € €Ìp燀ê=ÕRÚD³"t?ê„ïl € € € € Ðt÷¦›q)Ðw–¥äÁ¦ nðÈ>B葃L§@@@@ZU€À½Uy©ð¸â—¦Î8WZ‹GÞrB÷ð=Z‹ € € € ÐÖîm=<0LCW-³äóJ›¾åq¾ ÝChxh  € € € €@ˆ ¸‡øÑ<N·€ÕÎÐ5°ôõ.éÝï8É; € € € €4J€À½QLB º\gÊü£¥ýë¼úËCžèê<½E@@@@ H÷ ḠHˆéhhØk.-÷êï¿ tôñ¦ € € € €Íp5¿ j@HhßÕP–º¿>ÄV;'€ï1Ž¿ÑEêXÓ/@@@@æ ¸7߈h„ }Å¥üáNèž(u½žÐ=¢œÎ!€ € € €-@r47"=I†¯°´i¼GÞâEªÑ3òô@@@@ )îMÑ¢,Q,Ð%ÓÔÀg,­íÑ¡m¾(– ë € € € €Ô/À’2õ»pê8w´©c¥üël ßèR|O£žRœB@@@@ :˜áãN¯Z ínSM7+Öt/ÝÇL÷ !¹@@@@ âÜ#nHé­/ÐçK©cœÐ}„­c_º·¾8O@@@@÷p%Úˆ@ \úSK—©®»Ñ#»”Ð=‡ˆ&!€ € € €œf÷Ó Îãˆ$‹-Åt’6Þá‘×&t¤±¥/ € € € €M poºw €@•€iôKö¿¤Íw{äóºóã@@@@ˆ^÷è{zŽ@‹X1†®É³ôÕÒ{ßõ¶HT‚ € € € €@8 ´hàn—•©¬¤D%Χ¬ÌGÚŒA¸ã e®¶´÷^þ§'ˆ¸@@@@ðpß…2íÞö®Þ*X§7ó ´9¯@…'T–®Ìñ5bÐ5ºæš¡ê×;E±'”áD‚@l'CÃ^wéÕ«mÅv‘.˜lEB·è € € € €hzàn+ÿw õ“q³TÐàc U°ÌÿY\U2[ó_˜©‰· P|ƒ÷RÂMàŒóœÐýU—^j+¦£¡Ô;ZôÑ„íE@@@ˆ2&î;óé¾a“ëÚÓ3•ÞUÛ·¯ eìõMK9iØîº+6^)i}5bì=›ïÓë5Zveà r5pÔj°™@pðÏlÿÆBKënòè«|áÖ|Ú‹ € € € €@“Ü]gªSmöìç´ã`¹ž}t‚ú§:ëD¹uJ¬)sWªô@¡–ÌÌ”’bXV&HKnC ÔRo7ÕïSk¯³õ¯º‡úxÑ>@@@@æ Ô¿Lí:]izÔ×ô Ì.9¤Ce¶\®X%&ž¸dLl§¾šðh¾&Ô~û qçO²tìKiíµ¶†ot)¶“q}¤C € € € €øžá~J§m]³TMš¤ÛKªJÚÚº|ºÜ •œœ¬Ždô›¤5ÛY8æ””\D ‚.ža)åz³âEªå%Mÿ^ÓÐ5@@@@>p·w뱬eŒœ¨ÜÅ‹µ÷ˆ]ÁR¼áçÊ7¯.Qáb¼¨£–n«åë^æ"_ ãç¦ÎtÖ§z3Û#ÏQB÷Èqzˆ € € €DŸ@ÐûÖ'§jFA XåJìezeñŒÀÉÌœ9š?³ê©ÎÙ‰S—ó‚Ô€;D—€aøŒ%×ÒÆ;=òzÝ£ë@o@@@@È.p··kÑÔ¼*mÞSªIýuÚKÞ×ÊeU§3çèùEjÊ£+µ~~Uè^°Z»˜äù¿*zˆÀIL—¡A¿³tôsiKŽç$¥8 € € € €@x ¸—ÑþªþÎ\ûc H‰­8*ùh‹1ü½£Ô©ªÌÃGWííÒÇʪöùBhpÅú²¥ƒïù´õAB÷hü Ðg@@@@ R‚ ÜÝ’3Ÿ½bK=«zOúhc~ÀéšÝû±Ý34¾â¨P^8ÏD§@»3 e­q铽ú룄îÑù+ × € € € €@ä ¸;•aœð½r;¤7VVÏoŸ¦þ©•³Þý×ÊŠÞSåJ3éêÝ%®ª<_ Íq] {Ý¥üÒ«Ïx£™‚¾#€ € € €Dˆ@»;0Ã}òc˵זv®z¼æ%ª9W«—«Z¨D/Ï[uÐC;ÖñÕ%øFèèÐÃP¦3ÓýÏ3<úä„îÑù+ × € € € €@ä¸ÇöUÎìÌJ…e“ÕÕm¨Wvn@eö˜kä’­m«iRV‚n_\Xy-3K=kV  ”g¢W ±¯¡!+-m¾Ç£}„îÑûK ç € € € €@ø ¸;ýüÀ“š™^@æ|MÎò¿.µT›æMÖₚ2KæO ¼Hµæ,{ íÉW›ºj™¥ ·yô…ó2U6@@@@ÂQ èÀ]±½õè{´vÉlÏÎV¶óÉ™ýœö¼6å„P=}ül­/*Õ„¾LoÇ mFàtt½ÞÔå ,­»ÁÖẟsž € € € в•ÖƒªÖÕIYv>õݯ{þxXw”»•Ϻíõ qê ôgêØAŸò‡Û¾Ñ¥öÝŒº8B@@@@ „‚ŸáÞˆN¹bã ÛáD¨¸ð;–Òî1µö:[G¿`¦{ { € € € €¡.ÐpànïÔCYYzlÕV•´doÊŠ•¿hºF?´Je-Y/u!€@Ø ô}ØR硦 ®÷Èþ¡{Ø(@@@@¢D áÀ½ôsm.(ÐŒì %Nð¾|ƒö6#!·íÖªE©_\²†Mž§¼ÜíÎëUÙ@ºWüÂT‡žÒ›7{ä9Fè^W‡#@@@@Ph8pÏÐSk*³¢õNð>nˆºÆºë¡EÊߺS‡JìûUvh¯¶mX¥Ç¦–»cweOÎU¡ÿ®ô­þð>%6X@ Ú ÓÐU¿¶d8ÿ+µi¼G>/¡{´ýè/ € € € n†ÏÙÕè²½Z±`†nŸ±ì„âé™Ùد‡ºsŽÎŒ=Ó¹~Te_íÓgŸ~¢÷7/SAEº^÷¶™ÏmÖ̱_÷4GÇ $%%)''G¹¹¹Ç]áè°øôÆ0û°ÐŠŽNÓK@@@@:†a¨¨¨H©©©u·ÚAã÷ª–—íݦÿ{âaMÎÍ ª/9sžÓôûîPïDWP÷GÛMîÑ6âô·>£}z}ˆ­®7™º,—н>#Î!€ € € €‘,.{ÃKÊ7J±)}5éÑ•*=X¤õyK43'[éÇ•©s˜ž©ñÓæè…µ…:PêӢǶ×âˆéh(ë5—vÿÖ«íó< ç: € € € €m"ô4óØÄT 5¡âóè"[%‡JTRzXååþ~¸Õ¾}œbcãÛ&ã¡ YíS*C÷×Ûj—d¨ç]Mþ{adÐ@@@@:p¯Û—â+>uÏs„´œ@Âù†2W»´öZ'twÞ¶ÜíFB÷–Ó¥&@@@@æ V5Wû@à´ t¼ÌÐß[zû[Øè=­Ïæa € € € €œJ€ÀýT:\Cè|©+—Zzs´G‡Þ÷…di € € € €@ô ¸GߘÓc"B Û(SýÿÇRþHç; Ý#bPé € € € æîa>€4hH›`ê¢ï™kº—~FèÍ¿úŽ € € €„‚{‹‚­²²2Ù¶Ýb5R4,Ðç{–º5•­c_º7,F @@@@Ö p¯G¶lûr†á|îÒÖ’z Ô:UV¼M‹ºË)ëV\\œÜn·Œ~£õÈÒ5ÚKö^KŠ]ZOàÒŸXJ`hÝÙGÝ[Ošš@@@@N%@à^λ/<]uöÔiû¡­K—œ®É¹ËêÖR˜§YGª«{º¶ºŠº÷q„A Xd)¶‹´áv¼å„îACr# € € € €@Ðîµéìm[³@CfÔ>[ÿ¾½]?ȘXs-=GÏ­^«–ÌVfàì<¥{¹ÈÜ ì Ðj†ièêç,yŽJoOôÈç#to5l*F@@@¨WÀUïÙFž´íÔy¯èÕ·ßÕ®ý Åʇu¸ó½Ê[4Vñ¬ÿô+Sþ¢ÇõüÆ÷´xY^£¹ýwsµ¸ºtúlíxïa¥Uhfé¶[oФ„ŒÊëËÆé÷Þ¤ }C«×ÕMçH°b ]³ÒÒ™ýiªWW,°"©{ô@@@@ Ä‚ÜíÝk4¼ûH5b.x Aæ…Þ²æåú듳´¸°¦™ ïkÕœ@Ü®^œY¶WÝß_åMÓâìy'~½ú'pÐpµ”@f ¸;Ê\méõÁ¶Þÿ±Ôï¿Ý›J € € € €2p/Ѳ©õ„íééJw[XoxíœLˆQlTg‚+äÖe3ækÎçR¬bó•6>9CËêíCÕmךêëéstMåÔö:O½ò&ÇbžüÅ ÖüE‡ Ä:%8@Öˆ=ÛPÖk.½vµ­¸ÎÒß&to-kêE@@@¨.ÿ.ûHk«¯djÉú§tç•iŠ ®¶šÖ´É^¬¢ÁgÛŠY}êÀ½d×™ý™ã®T§À½µvSuƒsX‘ËlÔ®’IJdU™Z@ì"кgœ[º¿~­v u¿“WV´®8µ#€ € € €4;¿äIM®a{}?€ÒúNÖ9çv×&ÄžQsP{Ï•¬ ²«O”¨¼z—o8mgöv–—yÙÒ»ÿáÑÞW½§í¹<@@@@ :‚ Üô¸ú©ƒ2ºFÜÁâ>w>»}`ÿT;µ2úSã´°@Ò¦ÿÎÒ[ÿæÑç› Ý[˜—ê@@@@j ¸ÇwQ†±vg{ò7oUîDÑǧ Õ´ªþ÷ï}pˆ¢¡¦«"Ðe˜©OYZw“G_þÍ!½¢ € € € €¡&äªë)º}FŽf[¬ÂÜ‘Z0r¦ N µ¾µZ{ì}ok^ÕKS·nÛ#õíÝೂ]RÆçóéÓO?Õ¦M›|Fu‹.ºH‰‰¼¢µÚƒoüçÝjêèA)ÿ:[Ã7ºÔ¡»  € € € €@ lÞ¼Y^oä­Fdà.uz·Æk±–92uHWåÏœ¯»¿y™:Ÿq†ükœ—Ÿ0;'Ú;3ãû¦*臶ÑàÿXWû3§ö— ì¿s4p"¾Â$pØ„ÿîÕW_Õ¶mÛ}×O<¡Aƒ5º<ˆóï3uìOùÃ+C÷ØdB÷h{ú‰ € € €¡%0}út•–6ü>ÍÐjuí 2û>¤%#V„íÕÈ˪¼Ü꣓|§Ï×Á÷§(’æ^çmýX¶úŸøG„’´:¯Ê!{Î=‰I§-ËÒ=÷Ü£Ü܆p¨ˆË P!pñƒ–Êö;3ÝGغvKîBw~ € € € €Àéxûí·›ôHà '¸5Üx9&©IU8þü«œÙýUÛâ×õaYõAÍ÷¡6ª:oÏ̺Tñ5—ØC6èÿ?¦ÎJ7´n”Gž2Ötoãáàñ € € € €@Ä9Ã=^w\§Q©Aÿ#‚újå´°€ÿ¥©Y¯ºôIžW}ÔÓµS € € € €@4 4# ¶µæ‘á9«zí”ZlI1•/V-Ô¬Û34+ç9\46 f{ÇkÂJŸ&ÔêÎÉwã5âÁE*ÿ?Vá_¶ëÀ¿Ž9EÛ9³Ü{+½wŠójY6ØdCÃ^wéµA¶üû½îmæß"áӴ@@@@ Å‚΄‹7ü¼NØž™3[#گЌy…R‚¿±ºtÌ4©`^e£Ó® E·EÞÂï®øõœÒâƒC… pú:twfº¯qéL[í¥ón%t?}ú< @@@ˆ ¥½ø³…›÷(ÑÃúî¤é•çK¥ÎÞ€IsUº#OÕ+/~ä÷Ú¸‹@ ´κÄÐ5«,m¹Ï£}kYÓ=´F‡Ö € € € €¡/\à^V¤U/Íœ³Y“TÎî.-?èqõÔùØ´QZ’7³ò|á&í+ a9NWšºz¹¥ wxôÅŸÝCn€h € € € ÂÁî*Wun>fdŸ»—Ð9®ªLž¶ï Ï×§6ØI €@ĤŒ0uÅ/-ÜàÑWÛ}Ó/:‚ € € € кÁîå5:PÜp€×>¹ê†tuˆ«žû^S{ €@¨ t¿ÓTßY¦ò‡Ûú×'„î¡6>´@@@Eà÷ø$e¤WvgÖô¹Ú]OÏìÀ9[ë~ó|ÕQuîHà aBZàÂÿ°Ô+§2t/ûœÐ=¤‹Æ!€ € € €! \à®T Wõ*ÔÂ\uÏzH[öÖšéž#ÿ"2eÅÛµô¡Û42· ²«Ù#uA|ôš& €èû#K]¾iªàzÊ¿&to$Å@@@@¨0|ÎTÏíšîî¥yõÞœ®L'/((¬sõ…¥º--¶Î9N-””¤œœåææžº W@ Õüÿ3¹i¼G¥û¥Ì?Z²Ú­ö,*F@@@8QÀ0 )55õÄ‹!t&ÈîN\iš{ð=Í®šè^·O…Ç…íéZ¸ya{]$Ž@ Lüÿƒ~åRÐ.½5Ö#Ÿ7¸¿S†Iwi& € € € €@Áîþ&ö×Ãùåúpýsš–]“¼ÏÉ®jN¦fÎÏSÑá÷5i@JMä6@ íL·¡Á+,•~&½3ÙÓö ¢ € € € €!'dà^¢5‹–jgÅ›Q]ê=x¬æ®ÌWyi©.Õ³‹V8߇UîË×£SF)5ÞÖÖå)kÒ ÕZé=ä0h p*W{CC_¶ôùfŸþüB÷SYq @@@ˆF wi÷óÕë¶Ú[KÍ«øxÿí.ç;ÞùoçÅ©{·è¡ÑneŒËUÁG_¨´Vyv@pˆI4”õªK»çÕ‡?'t·ñ£½ € € € €@k ¸+ÁiVÞTu½HÅõ¶°D–NW\×ÊÍ«*ðÅÑzKr'¸s {Ý¥÷êãÿó†SÓi+ € € € €@+ ¸ÇT7*o²’ïZZ't/Ù™¯éý4dâ¼êRßÓf R|3 €á)ŸæÌt_ãÒ{ßóèÓU„îá9Š´@@@hY ÷xMx¶PÓªÛ²l¢’'-WqÙ!­Y0I ½†i^aõEç{ü½w TsÇö¯Xf¦Öv@°Hìgèš?Xz{‚Gû׺‡í@Òp@@@@ …üˬ·Å÷ÕÜÃNªž®Šyì‹Ç)yññUejáÚ§4)+íø #€!<ØÔ•¿–ÖßâѰ7 u¼Ôˆˆ~Ñ @@@@¦ 9ýêA¡û{Ê©ç¹ãg¿ =¥ù„íõØp "K Û¦2æZ*i«d‡/²:Go@@@@-мÀÝÿ˜øþZtøøÐ}¾žzø6¥Ä6ºDÂZ ç]¦.žajíµ¶Žì%tëÁ¤ñ € € € €@ZR¦ìÐ^í?\~òG¸ÏÕC›—hñÀ‰Ue¦êÎÇ.ÐüñéRy­ûÜ JMI_ߟ""÷ã\8Dˆè÷ˆ¥²biÝ þ5Ý-¹ÚºGÌàÒ@@@@ æ/)ÓÀ¸ŒD›À7ž4Õ¾›ó"Õ[=ò–³¼L´?ýE@@@èhÔ ÷ó³çkí%År»ÝÁKù—–éÔ›ÙíÁ r'„‰€aºj™¥u7z´é[]ýœ%ÿ96@@@@ÈhTàŸÚWY©‘ Aï@–°Úò¢¥µÃ<úÓ¯®xÂjÉê© @@@@ NÏ’2»—Ë0 Yio"Ð$@ 5Ü eþÑÒ¾|¯ÞŸåiGP' € € € €@ 4j†ûÉÛ[¦mÖé©ÝI µk×N…«¼Z°IŸ”H)ñ')Ìi@ Âb’ {Í¥W¯¶›,]x?3Ý#lˆé € € € hFà¾W‹FwÕä¼@]§ÜIO— å¬Êb\D"N }·ÊÐýµ!¶Úu4ÔcìéùÇEI‡@@@@:pß¶tF£Ãv¿?lŸùÜ#êâ"4h„ ýË˸”?Ü Ý¥®# Ý[™*@@@@62ñÙ«•s—U5\ÿœ²Ý›­écûŽØA¢M )ÃÐà–6ó¨x“7ÚºO@@@@ˆ.p/Ù§÷œëþmZÞMœ¦Ni#tÿœÊx=ÉYÑ=¥S'õ§EÿýAüák53;]JÏVÎøL¥gæ(¯ð€Ü)h3 ÐêVŒ¡¡y–¾ü›Oï}×ÛêÏã € € € €-/Шùæ‡vnÐê-Ÿ8O﨡wŒPJí»b;©wÿºAz|Z–]ù¾mùöR# ±îCYk\zm­¿ž-]òC+bûJÇ@@@@H¨Ÿ´»^ù±ÆM-p®gjóMNàÒ¢\@h†@l''t­2tqB÷ó'º7ƒ“[@@@@Ó*ШÀÝÓµªQ rŸÖæñ0@ ú:¤öªK¯µÕ®£¡ÔÛ›µúWôÒc@@@@ HqÚžÇ"€§8³³¦ûK–Þ™ìÑg¯³¦û©¬¸† € € €„Š{¨Œí@Ž8{€©A¿±´ñN>‡Ðý8@@@@hbà/w\Èõ!€+pÎpSßø•¥u7zôÕ‡¾ˆí'C@@@"A Qk¸×t´P«W®ÒžvÒ±š“ßëÐCóú*¶ñwPˆzÔ;L=èÓÚá¶®{Ë¥3Î3¢Þ@@@@ š¸Ï¸=;ø~¤Ï×Á÷ ܃äNˆV &[:ú¹*B÷á\ŠíDè­¿ú € € €¡+ÐÄ%eB·#´ ˆt¾?²”2ÂTÁHÊKX^&ÒÇ›þ!€ € € €@ø 4q†{ºf/™¡‹‚^R¦·X>ü~$´BG c®©MßòèÍl2W[²b˜é:£CK@@@@ Úš¸?V}›xW´#Ó@ ¥ ÃЕK,½9Ú£ÿæÑà,™¡{KùR € € € Ð&.)S¢òÒæ<Ž{@š+`ºŒŠ ýh±ôÎ$Os«ã~@@@@hbàÞBO¥@f ¸â }ÉÒïúôç„îÍÂäf@@@@ …Ü[’j@Ó-Ðî,CY¯ºôÏß{õÁã„î§ÛŸç!€ € € €Ç 4*p/?º§ê¾Ã*?¾Ž@ÚL ®‹º¿æÒ‡s½Ú¹ÄÛfíàÁ € € € €R£^ÚcøƒZ¸pŒŽ*I]ܰ!€„’@|O't_ãÒÚa¶Ú%JçŽnÔßRC© ´@@@ˆFGhRïˆè/@"R 1ÝЕ–޼ɣvgI‡ºGä@Ó)@@@i™‡4^ ùjSW-³´þVnõ5þFJ"€ € € €´ˆ{‹0R  ]¯7uùK×Ûúǯ<:ö%Á{hŒ ­@@@@h p†Q¦ U=Æ™ºr©¥OVúôb7[ÆØÚÿ¦W>/á{Týè, € € €œvF­á~Ú[Å@š%2”ÿSºÏ§O{õÎdìI½rLukÊÿ¢U6@@@@–`†{ËzR Rq] õý‘¥›>tëªg-•ìðiu[k‡Û*ú­Wöf½‡Ô€Ñ@@@kf¸‡õðÑx@ ñ¯1åÿØ¥>-÷éOxµe’Oþ%hÒî6”t9ƒm¼&%@@@@Z(p·u¨ø€öïûB_ùRr§(£šJ‹‹åNì¤ØzʉÍç  €@S\q†zÝãÿ˜úºÈ§yµá6ÌΟd*õNSíSXr¦©®”G@@@š9ÑÖ¶U 4Úp«crW]”ž®‡hàÄWd«LË¿™¬8w?=²b«sĆ jºº,×Rö.—2æYú|³O/]hëÍ›m}ºÊ+Ï1–œ µ1£= € € € ºÍÜm­yd¸Ò³§*ïøþ%ÅTžIòjÖ튛´\‡Ž/Ç1 €@H†¡®#M þK7êR—,C…ÿéÑ‹)¶¶>àÑW¼‡Ä@Ñ@@@i ÷â ?×ÈYÎeæÌÖœié•Ç þ¯X]:fZàºÓVì¬9f@ $ÚièÂïXº~«[Ã×»ä=&½‘eë—•;ËÏxtô Â÷8… € € €m.dà^¢6#Ðø…›÷(ÑÃúî¤é•çK¥ÎÞ€IsUº#O™U%?ò{í ÜÅ €@¨ œÙÇÐåó­ŠYï—üÐr–™ñé©¶ÞgkßZ¯¼Â÷PCÚ‡ € € €§O ¸À½¬H«Ö‘Éœ³Y“¤T´¸´üh åÕïIM¥%y3+ÏnÒ¾’@v@ÂDÀt:ï6S™¯¸4ÚYïý¬¾†Þù¶G+ϳõþ=:ü‚÷0Jš‰ € € €­(\à®rUçæcFöi°y ãªÊäiû^ŸÚ @ˆídèâXõw·®É³TºÇ§WÚËÎ|ü¬Wå_¾‡ððÑ4@@@hEà÷òš(n8@kŸ\uCº:ÄUÏ}¯©ƒ=@ðHºÜÔÀ§]ºe¯K='˜ÚùŒ·âE«[rl¿í ÏNÑj@@@@ Hà÷ø$eT½uÖô¹Ú]ÏÃíÀ9[ë~ó|ÕQuîHà aˆ+ÖPÏo™º¶À¥ÿæRlC›Æ{”׫\{Ì£}¬÷jº € € €§.pWª†Ž«zja®ºg=¤-{kÍtOˆ‘™²âíZúÐm™[Pل쑺 þ­á €@Ø œq®¡~³-eït뿲tè/>½|±­‚mýóE¯­ìakÃ[{×xåµ ß#qÜé € € €Ñ ü’2õèØee*-—âã]ÎLïRÅÅÇ+’_‘ºeÁ]8uY=5§n>àü±¡S͉&LÁ(Ža)pô Ÿv.õêã%^ý\J»ÇTñ¦Î¼ˆ%gÂr@i4 € € €-,ùKÊÔæŠuÂvÿí.ç;²Ãö’mKë„í™9s”·v­ò–ÌQÍ\iòÀïjkI=XœBÄ$êó=K7þÕ­Ì5.;(½6Ø®øìtBøc_1ë=€Å € € €„¬@ó& —ìVþKkôÆ»[õÅ‘†úxDG’nדŽR|CECþº­·ž™hå´ç 5wlߪã,ºóV=r}/Í*ðŸZ¦-Pÿþ‰òì €œ\ ã¥†¾ñ+KóMýs…¯bÖûŸ¦øtÞmFÅ‹V; 2äÿ«6 € € € jAîe»×èúî#U‘)7¶W™ƒ´ ±eCº\©vï*¬ja¶î¼©:l¯:›¦oM›æîó*Nä¿»KSÜCzDi„ž€ÕÎP±þ©#{%gžöjó½yJ½î3Õ}œ©Ý ÞCoäh € € €Ñ+äKSKô›¶W;)IDlÎËPWwä°ŽÕónÔÒƒ5Sþ¯êsnua¾@‚hŸb¨ï,K£þîÖ•K-þ»O¯ô³•?ÂVÑó^Ù¥,9+· € € € €@ ¸—|¤Õ©íã•W¸Gååå*--=õçßVd,¬’¨ó3Ó«†¢@C¦,Ò‘)Þº\c&.œèy^ø/¢è ; €@ tjêª_»të^—³ÌŒ©¿Ï÷êÅsl½{¿G_¼GðÞÆÃÃã@@@ˆjàw·ë°_òCê›"—Ë¥X祩§þ½‚MÈ RÖý‹5¾ºUË&«{œ¡»&MפÑý”œ1Ngæ¬ÕèTÿ‹dÙ@ZRÀu†¡^÷šºn“K#ßsÉÕAZ³­—ú”kûåõ²õæ-¶>}Ù+o9á{8Œ#mD@@@ Ü‚ ÜãÏUVUÈ<ï‘ßko¸+Ñþ½ù©ëÈeJ÷;TdìéŸ3M9Ù™Úü—†tì§Uµ×› \e@ ¥ ÓP×L YáÒ-ŸºÔùCïÿÈ£»ÚÚú G_m'xoisêC@@@Ãçl5‡ß+Þ°@ÉC¦VÞ9SkŸ¼_WuOvŽëyƒh Zÿ²30ß»l›îŠKײª~eÏY­%ߡĪ®•íÝ¢Ùã*· ªÀ´Õ*Ÿ;"¨™î‰‰‰ÊÈÈÐ7ÞPlhgôèÑêÞ½{CŸŽDÀ—õé£E^ív^°zÆyÎR49¦Î»ÝPL¢5t@@@Pøå/Yñ^ÐÆ¶iúôé***Rjjjcoi“rAîþ`}‘áÖä¦4;s¾æO û§–l]¤„Œªžg/Ôá•“kÚ8mÐèŽC”Wqbš>,Ÿ«ÞAü­Á¸ûDßøÆ7U7´óï|G}ûöm¨×@¨ð/-óÉJŸv>ãÕ >{³¡´‰¦:5äŸφ € € €§Gàþûï×±cÇý°§žz*,÷ "àJƒíËÿ£ia{Åm1 邵–­ÏyÕ‰a»¿ñ‰Wht¶”W‘¸ïÒW¥Î¹ø¦÷Ê4M9R¹¹¹M¿™;@ê˜nC©ÎÌöÔÛM•î¯ Þ߽ߣrçÅ$þ°öoÊ¿< € € €´®ÀO<Ѥø÷pØ‚ Üííš;nq­þe*gÚ@%ÅÕ:uÂn©JÏJ jY•ª ¡‡:o­w;Ùùz s@à4 Äu6tÉL«âs`£W;—xµ:ÃVÇË+g½Ÿ;Úë Â÷Ó<,<@@@°.p/=¢ýÕÝ¿DŸöËÄTw§Qßµ²ô‚©sµuâ³êÜìõ²í/ibåz2Rz–.8îz£žC!@Ó"<È”ÿsÅ>gwŸv,öêoûÔýNSiw:{@pï?-ç! € € € 2ÍNæO¿5ºÂvgèâÓ¿©™!\¦Œ„»´bËN•ضÊJеuÕ ¸h\ DÎŒáQgè<; €@ ¸âœÙíL]û¦K7ºÓIÚx§G«.(×{tdOPï#šŠ € € €Í.pôÊÇ®|ãƒæ»'³Ûëµá$ €@$Äv2Ôç«âó…ó’Õ‹½zõJ[gõ5ÔÓ™õ~Þ­†Üñ„ï‘0Öô@@@ú‚ ܥĴ¾V_•œC@¤ CI‹,]¾ÀÔ?W8KÎ<ãÌ|ŸâÓy·W.9ÓéjCþdž € € €‘#ШÀýÐέúóÞÉíLeO¹ìJ¥%J;·¾-çTÓ¶v)ºÒIéõЦÕLi@BRÀŠ1Ôcœÿcêȧά÷ÿõêí ÉyeyÚ½fÅù3Î#xÉÁ£Q € € €4Q QÙ÷®W¾¯aS *ªž³ù° ½2q/Mm"6Å@¢[ }7Cé?¶*>ûò½/Z}ù[Ƀ*—œñ¿pÕŠ%|î_ ½G@@gFîµ;ëö¹yijmö@h¢@—,SþOù×>-÷éß{µ%ǧÎKVÓœõÞ;^FðÞDRŠ#€ € € Ðæ ÜûÜö¤6øÊil{]_Ñè±Kœ—¦î㥩m>‚4@ ¬Ü Ÿãÿ˜:ü‘³äÌS^­»ÉV»³¤^÷™êþo¦b“ ßÃzi< € € €@Ô4*pMé­)uMâS—¦¦Ö=Ç €/p¾¡þYºì¿Míùcå‹VÿòC[)#*_´zÎu†Lá{ðÂ܉ € € €@ë 4*p?´sƒVoùÄiIG ½c„RuWë6œÚ@ˆTÃ4ÔíFÿÇÔу>íúµW™éÑæ{¤žLõü–©3û¼GêøÓ/@@@ð0Óô]¯üXãÆs>é“ÒÆÜA@h ˜Ž†zO³tC¡[Y¯ºd-½6ÄÖ«WÛÚñ´WǾòµÄc¨@@@Z@ Q»;¦kÕ£œ×¥²!€ €@[$ö3tÅ–nÙëÒ…SLýs…WèfkÓ¿ÛÚ¿Î+Ÿð½-Æ…g"€ € € P-Àâ0Õ|#€ &V;CÝÇø?¦J?«\ë}Ëd¼eRÚ=¦zŒ7Õ¡K΄ÉpÒL@@@hÔ ÷ê/]A@ ¢âÎ1tÉ-ÚîÖUÏZúúcŸ^¹ÔÖÚkmíZî•}„Yï5àt@@@ ¤š¸ÇËÒý¡q €D­@ò`SW.qéÖÏ\ê>ÖÔG¿òêÅ[ïü?>ǵ.t@@@Ó%ÐÄ%e µzå*íi' ¦…zhxV_Ås/÷ € €@£\í ¥MôL•83Þwþ¯Wn÷ÈÕÞ£´{%gœ0Þ?3ž @@@ZV ÉûŒÛ³ƒoAú||ŸÀ=x@îD@ iñ= ]úSKý1õÙkNø¾Ä«mÿi«Ë0C=@¾ëõ†L7á{ÓT) € € €@ýM\R¦þJ8‹ €¡-`˜†RF˜ü¼K7âR—oÚ6ÛS±äÌÖï{ôåßXë=´GÖ!€ € €„ƒ@g¸§kö’º(è%ez‹%àÃágA@"Y ÝY†.¼ßªøøƒöOyõF–­öݤ^÷™J½ÃTLGf½Gòo€¾!€ € €´Ž@“÷ÑãǪoïj¦S+ €4Wଋ ]>ÏRÿÿ1õé*gÉ™g¼Úú}[ÝFU®ï_zÆ?;ž @@@hbt^¢òR§Òø†+¦ €„€é2tÞ-þ©Òý>}ü^ýišGå‡UñòÕžß2ß‹à=|F”–"€ € €´…k¸·…:ÏD@ „â:ºøAK7ýÍ­Á¿³T¶Ï§ÕWØz=ÓÖÇ¿öªükÖ{áá£i € € €m(@àÞ†ø<@Pèt¥©‹]ºõ3—Òî6õñR¯^ìjkó}¶Š7yC½ù´@@@Ó*Ш%eÊî©jÔa•ŸÖæñ0@+ÖPÏ»üS_ï®\ëý­ñ–G½î5Õcœé¼t•%gBa¬h € € €@Û 4*pï1üA-\8FG•¤.î¶k,OF@¶èj¨ßYJÿOSûÖ:ë½/ñ꥟ÚJì¼hÕ™ßõFCV á{Û-@@@8Ý Ü{Фާ»i<@BYÀ0 óMÿÇt^®êSÑo¼úà1¯¶äøÔc¼©žMu¼”à=”Ƕ!€ € €´¬k¸·¬'µ!€ •îCçO²4b‹KÃßrÉl'\oë•~åúû/<*ûœ­FåƒN#€ € €Q&@àeNw@hm3{êÿ¸¥›?q©ß#–öåû´²»­ wØÚ³Ú+¯‡ð½µÇ€ú@@@ÚF€À½mÜy* €/`Z†º2uÍ\]äÒÙ ýùAþp®­¿<äÑWÛ Þ#þG@@@@( p²§» €´…@ìÙ†.ú®¥·¹•ù²KǾ”^»ÚÖkƒlí|Æ[±|[´‹g"€ € € Ð’î-©I] € Р@Çþ†¾ñ¤¥[öºtÁ˜*ú­W/v³µi‚­ýë½òù˜ùÞ "@@@BRÀ’­¢Q € ñVŒ¡îÿæÿ˜:ò©O;—zµù|)ínS=î2Õ!Õˆx:ˆ € € 9-¸Û:T|@û÷}¡¯Ž8ÿFÜ¢Œþi*-.–;±“b[è)‘ÃNO@@ ¶@ûn†úþȪøìÓ«K¼z%Ý®X÷=m¢©nÙ†\q„ïµÍØG@@=f.)ckÛªm¸Õ1¹«.JO×ÀC4pâ+²U¦åßLVœ»ŸY±Õ9bC@è|©«–ºtË—Rï0õ'œ%gRl½ó}ñ'oÃP@@@6hFànkÍ#Õž=UyÇ7>)¦òL’ÿ«P³nÏPܤå:t|9Ž@@“¸;êu©á]ù®KîéÍ›=zéâr}8×£Òý¬õ~:N#€ € €´‘@Ð{ñ†Ÿk䬂@³3sfkδôÊcçÿ!–bué˜iëZ]åÓεõÖx[ûÖzåó¾7 ” € € €A TODoÚÍå5ÅûôøšõìŵO®:›®qÁ=²žj9… €Ô0݆λÍÿ1Uú™OÿŸWÑ:C.@IDATïÞï‘}DJ›hªÇ·LÅ÷4êÜà € € €-%Ü ÷ø$eT½uÖô¹Ú]OkìÀ9[ë~ó|ÕQuîHà a@ZM îCÿÀÒMºuõrKG>õiu[odÙÚµÌë„ðÌzo5|*F@@¢T ¸À]©:®êU¨…¹êžõ¶ì­µTLBŒü‹È”o×Ò‡nÓÈÜ‚JÞ쑺àÔ“á£tè6 €´¦@òÕ¦>íªXr¦ç¿›Úñ´W¿?ÇÖ–[Ÿoö¶æ£©@@@ Š Ÿ³Õ_{§¦»{i^½7§+ÓÉã ë\}aG©nK‹­sŽƒS $%%)''G¹¹¹§.ÈU@h’À×»|ÚùŒW»žõÊtþÏ“´»%gÆ›jŸÂ’3M‚¤0 € € p ÃPQQ‘RSSOÃÓ‚D3ܺÒ4÷à{š]5ѽn ÛÓµpóÂöºH!€ €@ tèa¨ß#–²w¹tÅ/,ú‹O/]è,…w“­¾è•çXpsÚ°K<@@@ ‚Üý O쯇óËõáúç4-»&yŸ“]Õ­LÍœŸ§¢ÃïkÒ€”6î*G@NðÏ’8çZSƒ–»tó§.¥\oèoÿíÕ‹)¶þ4Ý£C…ï'ªq@@@ >à—”©§6»¬L¥åR|¼K%%¥Š‹¯H­ª §XR¦ XE@ ¾úÀ§ÿëUÑs^Å9óÒî1ÕýßLÅtdÉ™d¦*@@@ Q¾¤L‰–ÞÕOþNÞµh[Äë„íþ5Ú]ÎwMØ^¼e‘²œ²Æ]KU(Í € ºgö1”ñ3«bÖ{ßY–>{ͧ?œgkÃ[{_õÊëaæ{èŽ-C@@ÚF È èn©¤ò…¨ зåMV¿…ÿÐAÛ™äSÛ†ˆ§"€ €@4 ˜.CçŽöL•ðéã_{µõ{ûRêùï¦zN0•p>³Þ£ù7Bß@@@jFGßÛ—?¤1O  •·îÊ«üÎ{rªF¯®:Y]kïÃÊ«*«ÊŒ¾ÎU@@pˆM6ÔçûVÅçów¼ÚùŒO¯°uæ%†Ò&š:ïvCî„ïá2ž´@@hiFîG>ÿ@…y'fæ…Êklž}‰:7ú‰-ÝUêCþ?{÷gW]ÞûÿY{îÉLn“{€É$n‚P¼@­„¶ -ÄVl 9¶/Áþr°-ý—zL±ý—ЪGè¿bkÀ"ˆT¨Š±¢BÀ $J á’Üg’ÌdfÏ^çyÖo­½Öž½÷dç³ÎY¬=k¯ë{MÍÌw?óü@N`â¹)™x®ÈÙkRòÚZù~WF~y½/§\éÂ÷Éõolú»RŽ„ € € 0T=Ž¿O~çzMëdÑ¢EºÜ$›!»[×ý%ÏZö'òwŸû°X‡w&@@ \*j=™uµÍ)9òšï_ÏÈëñ:eÎǵåÌ¥dÔIT½—Ëóæ>@@@îz¸Oºè³âûŸ u@þùÌ r½†îKoß(?þÔâîÎÁ{ € €Àˆ}Š'6Àê’·~âªÞ>=-“.Ъw ßOZîIE áûˆøfà&@@@`D ô8pÏÕ/¼í«òê½ÏȬ™csßâ+@@`„ xž'S—Úœ’Ž_¶ÿ§//¬ÉÈS«|™©•ð¾OXLð>¿M¸}@@(C>îm²cÛ!™pÒi{áÛòÅz"sL޽P>sÝ2ÚÊô„‹m@@ ,ª<™÷ ›SÒü¢¯­fä'JKM£ÁûÌkRR;‰ð½,67 € €#^ {‡l»÷F¹y}/ýÝ.NàÞK46G@rsš'ï¼µBÎüBJÞ|Ô…ïÏþUZ¦À“Ùצdú¥ž¤* ßËåys € € 0òR}»å*™v¦ žÚ»iùgJ]ïvak@@ ìRžÌø`J.þv¥üîŽJ™|±'ÏýU§|çä´üêÆN9´Å/»{æ†@@@‘ ÐÇÀ½V.¿m£477KkkkÞlëߨ¾E»ïvYšU\.ÿÏg.§LÖƒ € €€hkOæ__!|¶J–~¯RÒGE~pQZ}WZ¶ýkF:š ßù>A@@JE »Ý^¥444HmmmÞlë§7Í—eW~J~¼ÿIYï“‹ÿ×C’.®@bHõœ©ßÛU) >’däiùùGÓ²{}F|Ÿð}ˆ §C@@z%ÐÀ½‡çž|öÆ•nã;¿&›Zz¸›!€ €#T ¢Ú“¦§dÙ#•ò¡*eìOžº®SÖÍN˦¿í”ÃÛ ÞGè·· € €Ã\`ðw˜±pq–¡#ûŠ € €Ç5Ó3>W!—o­’ ¾Q!Gvøò½3Óò£÷¦åÕ»3’n%|?ž!ï#€ € €C%0{Z~òÍ{‡ê~8 € P¶“ß’w}­R~_[ÎÌZ‘’mwhË™éiÙ°ªSönÈ”í}sc € € €@©TöõBìØ,[w•*ý…ªÖ«ªD:޼-ø¢\¿f}xšÓeb]_ÏÈ~ € €&P9Ú“9³9%-/ûòò]ùé•RÕÐ)s>ž’YMIÝ,@@@!ècàÞ"߸|‘\¿©wW»ôÖËdNÏØ»3±5 € 02æxrÖç+äÌ[Ròæ}yEÃ÷Í›–)K5×ð}Æ=IU¾Œïî@@N´À´”q·¸ô†»åÛŸ½èDß/çG@ÊRÀKy2ý)y÷VʯUÊ´xòëÏkË™iÙør`3½ÞËòÁsS € € 0¬úXoÞ øÀF9cÇA©²Þ1ÝMÕ£å”Ù§KÓ¤Úî¶â=@@¨ïÉiV¡³AûË_ËÈc—¤et“V½_ëIӦĶaB@@X>î"“æ,–esöb8 € €ÀÀ Œ_èÉÙ·UÈâ/¦äïj¿w ßucZfüŽ…ï)™ú^O¬:ž @@@ ÿ}ÜûjŽ€ € 0TÖÇýäßµ9%­»}yõùå ’>,2ûS2[`µ~ðL € € €}èQà~à… ²aשîûyÜžUÓåâ‹æKNÚßs±? € €@Aº©žœþ™Š`ÞûdF^¾Ë—G–¤eÌiž4žãIÃ\‘ú¹žŒ™çéR$UA_’• € € €@e߯þà&¹ìúõ]ví׋n—ýÏÍ—ñ}Ø•]@@^`âù)™x¾È’5)yk½/7éük_v~Ç—–—|­†©"Aõû8mOÓ0O_kÌú:UI?ðO…#"€ € €@© ô(p/Õ›ãº@@z&PYçɌ߶9wûL‡/‡¶H¾·lÓ×ÏûòúCÆëë6 ãk&‰Œ;ÃðV oUñÆÛëŠjÂø\M¾B@@rèQà~úGï’MK[¥ªª?R5æ¤2®nOKKK«H:-imšÓ0¾Ö9ýùva_@Öû}ü"Ñ9?<Ϥ]X+á­¾åE_v}/¬Œß%R݆ñAVƇ¯+jò7,n˜‹@@@ú!УÀ½v|“,¤Læòã¯I>íÍ’Ûtg©Üºîvù‹Ë¼‘c5 €”¶€µ“¿PÃxm5Óu²0¾ùE­Œ×Jø ŒId×#צÆÂxýÙÒUÆkŸ­Š·¾ñZ_›¼®Ççk@@@`8 ô(p?î…§[äå-ÏÊo^= ¿=éЪííR?þ$iš?OæLj8îî%»AÛ ò¹óÈêM…î`½Ü¸|‘Ü}Ó:Ùð…Ë¥¶Ð&¬C@ÊTÀÂøqïÐPýùáy¦Óªá]›šf äkÿæ4Œ××G-Œ+2V÷Ëö‹y̵rTþñÊ”ÛB@@ègàž–ýŠ|ò²ë»Tw'$–ß ënþŒ\¾xzbe9¼LË£·|$¶/’[ï»M.;cœlÖå57¯ nrÓêårç•ûåS‹ùrxêÜ €ô_ UáÉØÓ5T?=?<÷3Z¿5Q¿Md÷c®2þèë¢- ]ˆŸìï*ä5Œ¼þ_-G@@@z.ÐÀ½MúÜy²¼pyw|ëÖÈr—Þòˆ|ÿ¯/-›JïôŽïËeÙ{_*lÿ¾\ÚäêØþõ7dñ‚‰²àª5ÿݿA>¹øRZËÄß¼B@ x) ãçk???<·0¾Eø EMЪFÃøõ­×Êx ã+ëÃÊø¹É~ñ®R¾ª>ÿx/€• € € €@?ú¸ïzô–œ°}銛䮺XLÑJîöòòóOË·¾r³¬ Û­¬¿ù2¹åœ7ä —–G¥ûÆ{¿–e¿é‘µÙ°=Z9ÿŠëd…¬‘µºbÓ÷¶JË.-ãc£»f‰ € ž€…ñcNóÃó Œ×Ö4®_¼ æß~ö¸çª Ú¶¿ ë“mZýEùíÕëó]³ZVÉ"ùêcÉuˆ÷§.CåÆy@@á&„ñs4ŒŸ£áùr¯.ãõ‡^ëo­jšµü¾{Ü®Gvˆxú#­ üµ©±@?z]30>W“¯@@}J¾+ÇL‘Yê¹_ª*Úd“ìoÕw)í÷ŽŽ–à†é7iÔ¾Þ½EKWÈùóZäÎ;³q¼¬ºd¦nÔ,×-,í{n˜ÿ € €#H ãgëO®³=™öþü?¼ÝzÅ»0ÞÚÔì¸7ƧÂ0~®îߥMMM#a|¾&k@@(>îR™MÐå+_[/rÛåÚ¥¼øôü/6‡o.—E3Ê'x¶‚¬}Ó ydË?É¥ó]û/ÿýfYýû‹äæ°í̪ëï‘«|]‰ÌPüùò € 0êgzbó´÷åßýáÚ7>¨Š·¥Èk÷g‚òVoÓØq5|Ô¦Æ*äk'Æ;!þ‹ € €@i t—“¿#ý[Ù¯Y·V‹·×,—+'Ü'·ßp…öfïz¸ÙpÏj9•nL§Ëغâ‡-Åw6iä~ßKwÉ¥sâ{¯¿PþzÝ“²qÌù®õÌúGäù–ëä¼>|ÖÉdäé§Ÿ–5kÖô˜çŠ+®™3göx{6D@Xú& ãužzIþqìŒ*ãÝà­;+ã·‹ø™0ŒŸ›¨ŒŸ§¯-ŒŸLŸ¯É@@Røò—¿,¥zùE¯;N‰‹nRèùðç×É5k—o®»ù*Yw³Èò•7ɲŧÊD –_ù9¹ûæ59mgnyìÏ%‘K:pé­[þIù@¡›j8]®Pžuaw™øoz‹{÷î•矾Ç;^rIßìz¼7"€ € ¦Àè“=±yê²ü³}=îoò;×eÂònÛ1 \øîúŇƒÁjËšÚÉÚS^‡eB@@ T¶lÙ"ííí¥r¹=¾NOƒò{¼u— w=~‡\vñªœP½Ë&Ù/WÜþS¹ëSuÛz&»ñpѲA®ˆª×—Uš,Ô.&-?þ»÷Ë%A_™å²±ùA,¶÷7ÖØØ(+W®”Õ«W÷~gö@@(¶·}9´ÅyWo¹ºòaeüüDU|b×Ú©„ñeóMÀ € €#XÀ L¶oß.MMMÃZ¡î_t<×|©Ü×ù»ëÕìá ¢¶ÕÒ·È_ýåŸË²ùã‡5D¯.®*Q¯¾n‡ì×ó³ôòËõaw}¿üþ8¢WblŒ € ÐOk)có”ßÊ?PÛÆ[¿x âßxD+ãÿÅ×¾ñÆwŠŒ9-¬Œï2€kÝ4Âø|MÖ € € Ðw~îÁišäÊOݦójÙ³ë-in­’É“«d×+oJjÌ$™8®^ÆÏ£û~ÉÃ`ÏÚÓeÅJms§]ËjùÂ=$w\­%E‰éÀ†oÊQÞ¾ô™]f‰[å% € €À °ÁVmžrqþ…ÛVÆkønaü›?ÈÈÖ/»JùŒþo6ŒªâÃ65úºnº†ñ)ÚÔ䋲@@âý Ü[ä™G¿-÷ç Yüé”+ç7É$IË3÷|F–\“äsÑJyäÞ¿—K˦ʽV~çÓw‰Üym {ç5ÚLsï#ò7×¾G&×uÈ–Ý%+.»>«~Ëß^«.L € € ½@M£'“ßmsþ¹í+ã›·ù²ûGÙöUÑÊx_2mZjá65£fÆçk²@@ý9¹Ï=ÜÓ;ä‹ïŸ™­â¾}ã~ùÔâñ²çñ/Êä‹o,h{צfùØÂò)õÞpÇGåüUk Þk´rÑMëdÃ.—ÚhE/—ôpï%›#€ € ˆÀ±Ú’&êŸèoUòé#Zoa|—ªømYS§a|ª‚Êøy@@ +Pö=ÜŸùÊõÙ°Ýîº&µM¾wg¶/]y«\Ñø ¹~õºæÚëï‘å?¾NÊ¥›ûy×}C^š÷nùÄ%«$ê“ýÐ7Ýý¤Ürõyå1PlòÆx € Pö5ã=™tÍù·Ú~PÃø\x àßþ©//ý›/‡õuÇa â•ñóÂ`^ÃùQ'Æçk²@@ œúÖR&ý‚Üq½ ÑEVÊ“oÜ.çM×î– ò`Tð½ôV¹÷ŽÏ­TÞ9õ ¹Ø¶_ÿˆ¼Ú¢{ù¹Ëœe×É;®–—7=/;j©O»6Â=CžµP&•Ñ}–Ó7=÷‚ € Ð?êqžL<ßæüã´ra|‹ ભiöüÌ—W¾®=ãõuGsÆ'+ãÃ\ƒ0¾’Êø|QÖ € €”’@ß÷Ö£òVx—7=ö7.lׯ[¶ml ÿ§—gû–Ÿóþ+ô]{çUyåí6YÜÐ×+áI‡Û¢²Aæ,>Oæ ·ëâz@@bê±ÄŸgsþ‰;š5ŒÑUÆ[5üž'4Œÿ†«Œo?(R¯?Pmj‚@>|­üh«Œ¯"ŒÏe  € €Àpè[à^¥?ü†wÒ4.z%²íg?ÎÞßo73ûºvæY¡_­•MòÊÞV‘9e¸gï” € € PL jŒ'çØœ¿EG‹ ã£Êø}Où²ýn­Œ×`¾ý€†ñ³ôw°>Ù²fta|¾&k@@N”@ßw½Ú–èŠ5|wÓùуQ}û ²¸)ÕÛ¶o԰ݦE2jÛœÿ"€ € €¡@UƒñgÛœOÒqØÂxýDÃw«Œß·Ñ—÷Z¥¼†ñû´££…ñÉ65ák ã+ª©ŒÏe  € €À` ô1p¯ÊV¸¯úâ=ò¡»®“ÖïÿC<ˆêÊ enöÈ-òÝÛn ¯–L™ñƒuS@@ÊG ª^ƒø%¢s~xž>¢ÁûV×/ÞùÏúòÚ}®2þØ ãg†a|²M¾¶õ5ùÇ+5î@@àDdcñ^¼v¡¬¼e©¬½y½ö‰Y%3tNN·|ä·¤RÒ²ù¡“/­Y%wêfÁ´t™ÌŽ;Ð$wá5 € € ÐkÊÑžLx§èœž§º0Þªâ­þÀ&_v>à^{[dÔ)…ÛÔÔÏÔ0¾6ÿx½¾8v@@q} Ü•é¢Ï|Enº¬ÞÔÅléí²jÙ$]Ù"¿H†íºæ®Û¯Í¤Úe/¾D@@T r”†ñgiV~xžnÕ*x«Œ×0ÞæC¿ñåõuîuÛn ãu ÖBmj¬—&† €”•@Ÿw©/_Øø¶¼wíWå®7=ݧ,ù°üÍMWç…ê‹VÜ"_úügä¢D_÷²Räf@@@ ¤*ë<¦èœÆw¶Y|ܦ¦ù ãÃø7Eêf$*ãçÅ-kêg‹Øq™@@F®@ßw3«œ$Ë>ö×:l?ù~³|¸£JÆ7з½ë@@@`ø Xûø…Æ/ÌÏ-Œoy)¬Œ×65V%¿ëûiÑ×­»4ŒŸÞ¥2~žTÊa¼VÜ3!€ €”·@ÿ÷Ð&ݲG¶<»Q6ïÜ/R]-Õíº˜0EN]0_æ6Ñ´½¼¿…¸;@@FŽ€…ñãÎóÃóÎc¾~Y‚~ñA«­’ßõ_±òG_©UÃ'+ä5·ÊxíEÏ„ € Púý ÜÓ»ä¡ú[Y~ãÅ%­»¿ôÿÊÕÍ)¾ ï € € €%.PQãÉØÓEçüð¼³Ý…ñ.ˆwUò»¨•ñQ?9 á“òžÔë¯QUõùÇ+q*.@([¾îé—åsUseõñh6­•k.^+·ÞpŸüì¶+…z÷ãñ> € €”›@Eµ†ñ 4Œ_žg:4€×Êx ß­ÞúÇï^ïÚÔÝ)R3) áÃå\­Š·V5Æ7ä¯Üì¸@@ ”ú¸oø§Oä„íKWÞ"ŸüÈû匦©R%ͲkÛfyäî[eõÚMǦ5WÉÿiÉk@þžçÉöíÛ¥©©iX_lߢïŽi okÅ]k‹†í¶É¤ÅWË÷ýZæ^eñ«²·Ud}eB= € € €@ßR•žê.T—Ëraaü‘í®MM4€ëÞ'\e¼UÌW‹Bø¨BÞÚÔ¸×Õããs5ù @è¹@ß÷*ýA,<Ç»—èOeÇ™Æd›Ï4h»&@@@Á°0ÞÚÊXe{×)Óé*à]U¼«Œß{wئFÃøJýeϵ§‰*äÃci…|Íøüãu=>_#€ €#Y o{‡VJ„jÏlÜ.²°û¾ìõ7éÖVáÞ"º+ € € €À HUh€>[CõÙž ÷",Œ?úZX¶©ÙñŸnW«Œ¯íBü¨Þ‚ù1Ú{ÞzÐWŽ&ŒÏÕä+@‰} ÜN—¯Y·VäÎkÿ—|äý÷˲éEÕ²YþáF ÛuZ~™œ•Æ»5ü@@@`˜X_?KtödÚûr/ÊÏheüN ムÞúÆ‹ìøVFš·¸×©Z­ˆ?MdôÉžŒ:ÅÓ¥d—µ“]Ë/E(Ÿ«ÊW € PnERòÜÛlk9 ­éĺÊ:¹ì/ïY{®\'—ÌX"·Þ÷%YñsdzC­¤ÓmÒrà-ÙúÄ£²zù*ÝÂMwÿýÕ¢ãö0!€ € €”˜€…åõ:FY}“†ñïÍ¿ø¶=¾4oÕ y 弿–{´oüÑÔkÕ|û~7kéÆŸóÑÒô5EåómYƒ €¥#ЃÀ½Eþ}ùYµ¾»›Ú$7^u±ÜØÝ&úÞ5ÿû¹ì׺lj·@@@R¨ä‰ÍÅ&kWsø% ã5€·¶5¶<ðœ/o|×yÐw¶j ?GCx­¥òn™ÐWÕ?G±s³@*îx)›Ž àÁ8 € € €@©X»k93æ´âyú¨UÉ‹òÖ¾Æóo­×*ù0 ·eкæTmW£­krƒù( ×mô\L € €À‰èAàÞ Z½Nj¶–êê~\b{»TŸr>Õíý dW@@@ œ*Gy2á,ѹx`n­k¬¼õ“wÁ¼È¾ ™l@l_غFtµÖ5.˜Ï]ZëBùrþNâÞ@8q=ÜE¦Ÿw¹|ì¼w‘œ@@@ˆZ×L*´®yYÃø°w¼-nÖÖ5ß·ŠyÔwÕÖ5³ãŠødëš( ¯j(ú95«@@éQàÞ?§´ìzá yø?î”Gä*ùÏ/\.:x=SO¼JÙux¼ìoñe?ðõTí@@@`„ ­k´åÌœµØd­kZ¶Eƒ»Zy‘·ÿ[«äui}ë[nÏ1ó¢ÊødOù8¨OU?G±s³@Ê[`Ð÷»6Ëã?(kVÝ,ÙñV—¾[t ÷Þ|Oy¸O”ÿs§Ìž*ræLO.<=%³§èŸ@¦øá®7”l‹ € €˜€µ®¦è\üwª£oXïs–ûžÖ~òÚÊÆ¾Z׌i˜«a¼¶®ô”z·¬Ñ2|Z×ð=‡ €ÀÈÐÀ=}`—<ñøÃ²vÍ*¹3›²'@÷1hjB£g/3Çäì©Ûä–+dã˾<­½ ÿö›ÒÖ!rá|OÎѾ„‹4„oЙ@@@F`Ô Òu–w>^кæ•.­k~ãË®Gã >m­kfjø~Šö“?¹ëÒõ˜¯Ãïr……Y‹ €@i ô?pOÍO<&®ýŠÜ\0ew0+n¸U®ùèrMíã÷I•þ©âù§Ùì°kŸ/?Ûâ˃:8ÐY ÕçjønüÉ“ø­Ìì† € €ôH h]£-gÆèï`Ŧ uÍK]Z×<òÚºf·Û³a®«/Ìk•|Uñs;7ë@@àÄô1po“›Ÿ–G¿¹VV­¾³è•/×ýãp¹\tæ|Oãö¢N}ycz£'~·Í)ik÷å©­®úý;Of¤3#òîÓ]ø~†VRÔÕðÃY_ŒÙ@@è@кf‘¶®YTüw²£»âÁ\³­k6&Z×ì©ÖÖ5õs\E|4¨«µ°‰ZÙÔL¦uMžû"€ 0½ Ü­/ûcS¾²juÜ—½ÈÕÜþä~ùÔy㋼Ëꨭöäâ3lvG}Q{ Z뙵ë3òêÛ"gÍráû¹:hДqÅÐÈkâX € € €Ç5]ƒs'ž_x[k]säU­’×Á\ê ®¶lÖ¿v~óQ¥¼HúˆVÈ7ѹŽÖ«QÚÂÆ-]P_=–ß ³@èQà¾gÃ=ò7]£n‘“/]!·ÿéJùàâ#ò‰—¹0¾ªÈ¶¬tÓ´Ï Í+Þ“’í¾<ù¢VÀk÷O2R[íªß­ýÌü“<©æOýyp@@@ ¯ÖºÆZÎØà¬Å¦ uÍËÚO^s‚ù=?÷eÇ7Ý×­oº=æDƒº&ù(˜©Ðb.&@èŸ@÷¾•¶/ÒýÊ\%W}è"™?=¬do{FfôïzØ{€êëØº;·uÍQk]ó\FzÔ·½¶®Ñ®QV-¯Á|´ŒúZý“Ö5#çûŠ;EÊMÀÓ¾Þúùs/¦¶òÌO‘o|õVY³nSÑoºo“ÜråB!v/JÔ£7eåÊ•²zõêm?µwø²ñeWýþ´¾Úž¹`¾«~_8SðÑ>ñL € € €O h]³#·uMÔÂÆU΋tèÙ>Y«ãOÑ*ù¼¥ èkÆó{èñ¬y(7+Þ¾}»45iÏìa<õ>pOÜLË®dýÃ÷ÉšU7ËúÄúøåR¹éö?•+—_&‹›ÂUã7yÕá¸w½Ì×÷ºê÷§·edÛ.‘Óõ‡ tõ\OšÈ=]½ø@@@ çAëšW£Ö5Ñ2î-ߪ¿‡­kfE-k¢JùÜ€¾¢–ßO{®Î– €Àð{üÚdÇæ_ȺoÞ%×'[ÎĈ,Z!·ÿÝgå“—Sõžd9Þëá¸'¯¹õ˜/OiÕûS[]ø”þ ”Jà>ð-Ök'ÉâK?Ì·hË™ÿzø?ä+«Vi9Ó'[vƧäÉi'UÈG—Š´èöO¾èz¿ÿû3R_'rák?“’ùúCMu%?¸ ãGÉ¥!€ € €%+ªð¤^«ÛëupÖb“µ®9²Ýµ¬±Þ*å÷=íËÎo[ ïKëaëš™qëšQ:È««˜ú"•£‹Ÿ£Ø¹Y P¾ýêáÞs–6yyÃOäWfÊ—Îg ÕžÃI©U¸»µLÆ—_kuõ}·ö3o” ç»U¾[ü¤±ü€RÌŽõ € € €'F ímë¯UòÈ'—Q@ßö–“éŸñÒÁ] µ®±€¾n­kNÌÓ㬠Pn#·Â½à“¬•9ç]*s ¾ÇÊ‘ Òæî‹fj+ÿ™ò'ïÙßâË/^ðåg[|ù?dt°Õ(€OÉÜé"Ö ž @@@(P;YÇ&Ó¹ñì´®±êx­ˆ?¢Ef¶<¬¾¾ýÓL6 o?¤¼VÂçTÆw èkù¸°0k@Òø–2¥gÀŸ žüÎ96‹¤µ·Þ³¯¸Ö3·~»Sš[EÎ?ÍZÏxr¦þùß8þ<ïtÖœ©ˆ@¥öÖ;[Ãõ³ç‰üÝf÷Wýþ¨þrÛºŒÌÕ?¿³¾ïçžêÉÌÉ"öç#L € € €”‚@å(OÆ.‹ÿ.Û¶'®Z×ìú¯L¶•MÛn ÜÇY¯Õò§hùD0ôuú×â)ÆJ+…o ®Ê\€À½Ìp)ÞÞÔñžüÞ»l9ÖáËÆ—|yj›/µ6#‘ æ{Aÿ÷…ZA0º¶ø,¥xï\3 € € €ÀȨ¤­k&‰4.)ü;nкF+á“­kŽìÙó³Dë+ÍBw«ŒƒùÜ€¾vbáãò:È« êj•òû¥­kÖ%Z×hÛhmYcƒ¹ÆË8 u­kÊꇛA"@à~BØ9i_št°›ÿàâ”is}ߟÖê÷oé§ú•®úÝÂw âk«‹ÿ Ò×ó³ € € €ÃQ h]3_[×è_…›Úöjø®¡üëó»¨Uòa@ßö¦îc-w•ò¹Á¼ êmXZ×f= BàÎwAÉ X;™÷,´Ù˜ñåý󺧷eä®Ç2òú^‘³f»Ö3ÀO[üŽ’àÂ@@@è…€µ”©(2aqáß‘­uMëQ /÷üBûɇ}ûm]£c­%uíÐ[‹&@`¤ ¸Ô'_f÷m©.ÐOàœ\!´LäÐ_ž|ÑUÀßõ£ŒŒ-r¡¶¦±ÁWO³ÑÝH¦Ì¾¸@@@þ Xëk5caº\XøhÖºæhX-<çË[+÷žo­kl€×.­k¢`ÞÎQ9šP¾°0k@ ÔÜKý rýÆê?ÜÐOì?°Xt U_~½Ã…ïÿòÝNÙsH‚žïVùþN­‚oÃ?òY‰ € € €@k]3æ4ѹøïÒÇöiønýä5€·^òÌïÖ¿FúÖ]"£Dj'‹TOð¤f‚.Ç÷ìu…þµ; 0œ܇óÓáÚD "åÉ™³lùÓ÷‹ìmv¯þô7¾|ùû9EG‚·Ê÷s5€Ÿ«—Òí™@@@@ o5¢7jëšwþý:“ÖÖ5Ú/ÞÚÓ´ï÷åØ~[Ú×îuó‹ö:®÷ƒíl›ôaýw©*aHïi`oA½~=>~]­¯ƒ_Ã| òíueƒþ¾¯üL €À` ¸¶0Çvµ¢ýCçÚ,Ò¡ÿÈ?ûª/Omõå ÷é@1ÇDÎ?U{¿ël!ýýäž @@@NÀ]µ–36k„Þ«ÛÀ¯A8oA}ØÇ¡}ÛÛ"Í/XhïBúl˜¯Ûù.˜Ây âêú𼮍éÝ5öê†ØÊN€À½ì)7Ôëån­eΙçöÚ¥ÿ(?¡ÿ8ï—¾üfdÞtÑÊ÷T°ÍÌ)üÛ[¶E@@@` ¢_{Ôwó¥í-«œÈõñëæ-àÇa¾ÛÎUÕ§ª´J^ÛßÔ„mo\homp\pïZâD¯]U½mS¥UõE?Ðßa/@à>ì8”Óõ“íß¿Àf‘¶v_6¾äz¿?ôTF{Á‹¼k¾ èÍôdŸpå£á\ € € €ôYÀªÔÝ€°vˆžÔù¾ñ{­Š> çêú¨Š¾m·È¡ç-¨wUõÁú0Ì÷ÓÊkk®ím¬o}Ú'|×úÆ­·×Õ=¿Æ>£°# Šû °rÐr¨ÕÜ.<Ýfw7/½éÂ÷{ÏÈêûDÎhÒÖ3V¯íg,¨gB@@@òð´i|­Žýfso‚zÛ:ݪUõÚæ&êU„öA`ï*é-¨ú(À·mÒG´ß|u8¨lÊ»*zk‹“ߟ>ðu»¨W½]3œ8÷gÏ™KL`î4TÕ“?¼8%‡õͧ¶¹þ›À×ꟗ]V¿¿ãýDºŠÜJìñr¹ € € € ¨@e'õMzH›{SUŸqUõn0Ù¨rÞõª·ðþè.‘ƒ¿Îd“ ªë£ªzýë|°6èQoá|Ø» >@6Úw óSdúü9ØÈ p¹Ïž;ï‡@½þ£¹l‘Í:ðŠþyÙ–"OoËÈ¿ý0#¯ïY<'ê ï‰ ÒÊ„ € € €ôDÀú¾×jÏx›{ÔÛÖ飹UõAhVÕÛ냿víoÜzWio¯;µª¾¢NÃz­äïÚÞ&X6ª®Ï ð+ëõ*©ª7~&w¾è§€ý£rú)¢s…üñ%ú×a_žÜªÕï:[ߨƒ¤œš¶Ÿ95%§Í©¬ €ï'9»#€ € € €@ÊQZU?Sß°¹Uõ™Î½ê­zþ˜UÕ¿®yǦ.UõäÒBÄθª>çêún_ë ²ì§*ÉHìI1•—{y=OîfŒ«÷äÒÅ6ë'ÄúÖæ®ýÌš‡:e‹È9Ö÷]çwÎödBÿ° ƒGÆ% € € € 0¢RZX7E‚¹7A½¡µr•òÖî&êIß~ÀúÓ[ ëíu´M¼¾ó¨VÕrýñ-|/<˜l¢ª~|üºJ³&†«ûp}2\WYTè?Xgi°~Öl‘•Ù£ÿ=ñ‚/?ÙìË¿|7#3õÏìòÝø9Sõ“]ý³1&@@@@ TªÇêXvcõjgÙ÷<×Ȥ5|ßëBùä ±Ñ룯‰xÖUÕÎZh¯¡~‡VÕ‹¯½öª“Õ^õÉþôݽ®§Ù ½êíA1 ¢û ârhº LÒ„.?ÏfýEÿayö7ðêçïÍH[‡Èy§ºêw é´O< € € € PŽÖN¦N‹mîMPo[·từ¢«æµªÞ‚y›¼f¯Ã¯Õö­ÚêwLÔ‡UõAh¯Õó6Ðlw¯+G“Ó˜=ÓñÜoÄ Š@µþÃr®ìçž*ògy}¯ö~Ñ—‡Ÿöå¿“‘ÓNÒ÷Âö3M“ùõAy@@@JN zœäZ­^?Ë.½ç™Ig»†ðû¬õóa@…öV=x»®&¿W}PU¯§©ÑªzÌ»ªz{m­pj‚ð>l‹£¯“•÷AU=½êKî{¬?LàÞ=öE`NšèÉ•6_(ÒzÌ—_¾äªß|2œå]ó]õûÂ&ý¸¦çÿ˜ à%r(@@@@ d*ª5S™¦Uõ:÷&¨÷} êZHoô®rÞ“;Öÿðv[Ÿ[moa~¦M¤j¬†ña( & ÷¤¯Nô§O¾¶Ap™JO€À½ôžW<,P¿è6»›Ý¶Ë…ïßüiFþ÷n‘E3]øn½ß§é'©L € € € €ƒ#ày®ŠÝ*ÙEÛ÷fêÔ¢ÊcZU´»I´·‰–=üн—à‡!¾…ù‡ô#ŠDU}Øö¦k…}à'Ã|}]e½êu\A¦#@à~bÜ9+½˜7Ý›¯þ­”´´úòÔVÀßýß]#r¾V¿[û™ÓOÑ?iâÏ”zeËÆ € € € €À` ThQå¨é̽®ª·à=¬¤wmp\ ½>¬cƒÌ†-r\{­ªo«êãŠzkuãzÕ¡}"ÀÏ©ªgLÁ~+¸÷› 0´6˜ê%gÚ¬ÿšñeËë¢|Fîü¯ŒìÒÿ]2G«ßµ7¼-mV&@@@@ÒªêÃ\E3žÞLm®ªÞó®ŽUØ ûÖ~Idÿ­ª· ÞÖ[› ö­W}ª:êSomp\@Ÿ7˜¬÷ZIßµW½—êÝuöæžJi[÷RzZ\+]Rú?dï8Et®kß«ÿcÙâË­~· øÕ~ªþŸx5%§Í©àωºò% € € € P^µZU¯9ͽªª×ÂΠ¢^Ã÷¸r>ñZÃùs0è]ße«ª·b]¯ú0¨×\Ê• — ú¾]o9Mîåô4¹—/0¡Á“Ë–Ø,’îôe³Øñô6_þi]§<"b=ßm^¬ýÆÆÕ—×ÿ˜ø‡ € € € ЫP¯it}ã¤w¹Qú¨«¤OVÕ'_·lÙ§UõÉŠz{ÝѬUõÚ.ÙUË»ªúb¯ûqkCº+ûrs2†N R«Ùß©rôÎ9"+/yKÿlèI­|ì9_þùáŒÌšbÕï© ýÌœ©úy§„ € € € €@o*GyR9J«êO²={ž1e´`4ªª·ÊyÒ»^õÈ·íiÖ<ËÞó$ÕÛË:!Û¸ŸvNŠÀÐ LѾ[ËϳYÿG«Ã—gt` «~ÿü½iëÐWµï»U¿Ÿ9Ë“zÈúÄ@@@@&Ò‚ÑÚ‰ÌÇ ê}/S:î%ñ˜¸HV ºÊ“óO³Ùwû[.|_·!#_|@dÁÉ.|·þ”I=ÿTr`¯’£!€ € € € PZî¥õ¼¸ZE`æOl¾êÝ)9zÌ—:† ¼úí_d¤BÿZÇÂùsµ~a“~êXM?(ƒ"€ € € €”¼û`<Ât›´´jŽª:i¨…x0ˆ9æà Œªñä¢wØìαõ ßµõÌÚŸddÇÛ"‹fºê÷sµúÝÚÔ0!€ € € € €€ èï„¶Ír]Ý"¹ÓŽ»èvÙÿܧdü@Ÿƒã!0„§ÎðÄæïII³Ž8m•ïÖûý?Ögd¬†aÕïÖzætmCSUI?„†S!€ € € € 3÷} mrÏõaØnÇU#(0;ÁctÄé÷že³H&ãËó;EÃ÷Œ|õ‘Œ¼uPdñ¾/™ëÉÄ1„ï'øqqz@@@@! @ð—ï¿I® JÛÃ6àÁ9ÃL •òäŒ&ѹB®}¯È¾f_6hõû/úrÇ£™Þ(Aåû¹óRZ!/Ú ž~˜=B.@@@@`€Ü4½ã!ù½«Ö ÐÑ8 ¥'Шí¿}¶Í"i_6mw­gþñ;ÚŠF‚AW­õÌ;g{2v4á{é=a®@@@@àxîÇêÑû;dõåËeS¶e#Ê_Àz¹[[™%sEV]&òæ~WýþÃg}YóPFæLµê÷TP?[_{|ùWp‡ € € € €@ù ¸À3~üﮕ›Ã´ýÖu÷ɛ˯jÝ–C”À´ ž\q¾Í"mí¾<ûоª¯ÞòŸéètÕïçjõû™³<]Kø^6žA@@@F˜{?øžÇ¿(ß¼>8Ê¢›~*Ÿ½|’|´ŸÇdwÊY ¶Ú“óçÛìîòÕ·4|×Þï<‘‘[¿-rúÉ:ð꩞XÒDÂ÷rþ^àÞ@@@@r pïÏ=°A>qñán’n¹HËwŸ‘–þ“}a/z|@IDAT³¦xbóG.JÉ‘6_~ù’ëý~ßÏ2R]%r¾†ïÖû}áLOjªàGØ··‹ € € €””{ŸW‹|ýÚóe]¸ÿÝ[n–9¦™ièó1Ù‘-`íd~ë ›E|ß—­oˆ<½-#ÿ±>#¯í‘ åŒ…ïgkø©ã ßGöw w € € € ?÷>>“Í_ÿŸrm˜¶¯øê&¹z~­;R‡äT¸kþ΄}°TO;It®KEq•ïOkû™,#ô“- ßÏ=5¥mhD*+àûÀÌ. € € € €(@àÞÌ–î‘E×Þéö\q—üëu ã£ÔŠ+ÜÇÔH]üNŸ^uvvʺuëäµ×^ëñþŸùÌg䬳Îêñölˆ@)ŒíÉûβY¤3ãËoôÿ$¬úý+ßï”=‡D–Ìq­g–hõû„Â÷Rx¦\# € € €Œ\üãrìØ±² pïÃ#ÝöƒoÅ{­}Ln™øœìÓ5£t>úêY½»î?äúO?'²÷¨¼ï/ÿQ®œßûf3©TJšššä=ïyOtÔã.»  PÊ)OÍ+äOÞ'¸»W¾Å—¯<’‘“'ºê÷sæ¥äÔé")Ýž @@@@`ø\tÑE’N÷¼?È=÷Ü3|.¾›+ñ´O²ßÍû¼U@`óWÈ¢UQ÷öXuëÆýòÙÅã ¼Óý* ÏW®\)«W¯î~CÞE@ =íËæí.€z›/‡Û¢Ö3ž,žíIÃ(Âw¾U@@@@R°öÃÛ·oŠ“‡óµSáÞ‡§3jÚ2YyÃ,i¬+Ô0¦Už\½FÖÇ]*7Üt¾È¾V™?ê>P³ ½¨®ôÄÚÊ,™+ò?tï]û|yRû¾?úŒ/·­ËÈÜiÀ§‚þï³§¾÷˜@@@@Š Pá^”¦¯o¤åëWT¹U—ß%­~LÂáTût@*ÜûÄÆNhk÷å™—Ýà«¿|Ém/çêz¿Ÿ5Ë“ºø‚p¬D@@@N°î'øœ¸Ó·Æ§n>&öU÷ø`¼Bþ ÔV{rÁ›Ý‘^ÙíÂ÷ûž‘[¿-rúÉ.|?WCø„ïýõf@@@@`¤ ÐçdŸ8Àƒ Ìá臀µ”±ù#¥äp«/Võn}ßï}<£Õî"¼Ÿ;Ï“…MžTWÀ÷ƒš]@@@@!@<˜yÌ`œc#€À@ Ô×yòž…6‹d´×Ì‹oˆ†ïùúcÙ¹Wä,pÕÂ÷³µ?üäq„ïiϱ@@@@r pð'Ù {З øq9  •@*åÉ‚“Eç ù£e"»Êw«~ÿ·fdòXxÕÚϤ´ HEüP=΃ € € € g÷áüt¸6ãë=yÿ;méìôå7¯ùò”†ï_ú^§ìmY¢UïVýnKÛ– @@@@`d ¸ÌçÎ]#€@¬š}Ñ,›Eþôý"oôeÃV_~ú à3Ò4I«ßOMðó¦‰Xµ< € € € €ÀÈ pÏ™»DA°~î:×f‘ö_žÛîÚÏüýýi=µžñdñO¬O< € € € €@ù ¸—ï³åÎ@`ˆª«¬¯»ÍîÄ;÷¸ðýû}ù§u™7ÝøTÐ~fæÂ÷!~<œ@@@t÷A'æ 0RNžä‰Í¿whµ»/ϼ¢¼¶ŸùË ±N3Ο{ª'gi‹šÚjø‘ú}Â}#€ € € €@ù¸—ϳäN@` ÔÕxrá›ÝE¾ô¦«~ÿÖÏ2ò÷÷‹¼ã7ðª…ðÓ ߇ñ£äÒ@@@@¢îEix<¹Ó<±ù/NIËQ_~ù’ àïþïŒ4ÔIPùnáûMžTWÀÞ“àÈ € € € €ÀÀ ¸œ%GBú$Ð0Ê“¥‹lÉd|yñ ‘§¶fäk?ÌÈû%h9c­gΞëɤ±„ï}Bf'@@@@`܇™S €=His÷'‹ÎòÇ—ˆìoñå©m®úýÿÿAF¦Œs½ßmðUۮšÁ3!€ € € € ÷añ¸@ °À„O.]l³HºÓ—_ïpáûíwÊÁÃ"K´êÝZÏØrÜhÂ÷ЬE@@@†F€À}hœ9  ÐoÊ OΚm³È'> ²û€ ß²Ù—ùnFfN¶ê÷TÐÿ}î4Ï#€ï7:@@@@z!@àÞ ,6E†“ÀÔñž|è\›EŽuøòÜ«.€ÿü·2ÒÞ!rÊ$O&Ž™Ð Ò¨•òº´Šù‰ºW/RSE ?œž'ׂ € € €¥/@à^úÏ;@‚ðÜV=÷T‘?S×÷úòú>_{À‹ìmöeû[¾l|Id_K&X×Ü*R_+2^ƒ÷‰c óЭ}âµ²ž @@@@àøîÇ7b @ äNšè‰ÍŦNí¿WÃx ä÷éÀ¬ûl©Áü–.¤·`ÞÖµ¶k5¼†î¾[•¼UË[@ïªæãucGѦ˜5ë@@@@`东gÍ"€Y«ZŸ2N‚Y£òìú®/ÚµUÍžf å-œƒy]îxÛõ.°×]3ÄkŸ×¾¦KK›ÑµÅÏÕõÜ| € € €”š{©=1®Bjíó>£Q‚¹»`þè1 æÅÕòQåüÖ]®rÞûƒGDRš·[_ù¨Ÿ|T9߬s•ó´ÍMm5Áü>fN… € € €$@à>@É£j*RW·±qá¼k_ôÚÒÆ–Öꦪ²ûóäg½#€ € € €ÀÐ ¸½9gDF¬À¸zOÆiûœiŃòÎŒë#UÉ»`Þ—moú²a«UÑk0¯mnŽ£½ã³UòAŸykkãyë9o•óÖ_>e¥õL € € € €À ¸20‡Gè@…†ã“ÆJ0wׯ¦#­¿&úË»A`}Ù¼ÃUÑï~mïp½å“ýåƒ0>Ùs^ƒù†:BùÞ=)¶F@@@®î]Eø@ $¬Ì´ ÌÝómíùýå÷êÀ¯/ïŽ{Î8¬·ìkµ|¡þò]*çë´} € € € PH€À½ ë@ÊFÀ`=y’èÜ}P~èHT-Evðåׯ‰ì×€>øµZÿåt¿ºÖ5V9?QÛ×$+èÇkÛp– @@@F–ûÈzÞÜ- €@±£=«±ÎžZ<(ÏhùƒG$he…ðû4Œõ-_ž~É‚y7ðkK«H}­ 棞òQ ?1heüZQQü|E.•Õ € € € 0L܇éƒá²@†Ÿ€ ¾jÁ¹Íݵ±IwÆUò{›Ý °ÌoÙé^ïÕ`Þ…mm§!¿UÌGÁ¼õ—wá¼ ë‚yÖóæ‡ßwW„ € € €@®{®_!€ ÐoJ­ZŸ2N‚¹»`þXG<ðë> æ­mUÎïxÛõ—·P~¿ö—OwZøî‚þ‰c¢@>¿¥ÍèZBù~?<€ € € €@?ÜûÇ® €ôG Fû¼Ïh”`î.˜oi«ä-”ß×,²ç//¾ž;ðke… æ]8﬜Ÿ ýå­¯= € € € ¼ûÀ›rD@T ¡Î“†:‘¦ÉŃrßwýå£*ù ˜×p~ç_ž}%î/è¨ÈèW-µ¬iÔ–6q+W9o¿Z¥> € € €ô\€À½çVl‰ €À°°ï’Û,ÓŠå:𫵪q|ôÚ—­o¸–6ûÂþòGމŒÕÞñQµ¼-ƒY[Ú$×Ù6ÖÛž @@@´x @9ŽO+ÁÜ]›ö´ðÚº& æ£ÊùMÛm}΋thykSãùÜþòÉÊy«ÒgB@@@ ÜÜËý s €ôA ºÒ“i´X^çî‚ù£Ç\0¿W{MVο¼;ì/¯¡ýøU4oÏVÉ7äVÉ7†Uóö>ýåûð°Ø@@@`ظ›GÁ… € Pz£j<5IääIÝW°:âªâ÷k0¿W[ÚX8ÿæ_~ýšë/¿WƒùCGDjª4˜{Ê'ú AK êõ=k›c0!€ € € 0Ü܇Ûáz@(C±£=;ZdöÔâAyFûË[5|ԾƖV9ÿÊ[¾<ýR<ðkK«ƒÈZ ?A«å'K« Ï­œ§Á¼µÐaB@@@`¨܇Jšó € €@·6øjPÝ®Uìݵ±éÐþòÉö5öÚ‚ùçwF½å3Áûmí"ºGÁ¼-'j(ïªå]XoëÆèÀ¯6è, € € €ý pï¯ û#€ €À Ti;™)ã%˜» æÛÚµ}¶ª±66nðW÷úÕ·ãuÖka}6„·*ùlû ã-Ö®%”ÒÍÉ@@@ p/Á‡Æ%#€ €ÀñlÖ“&ŠÎÝå-­nà×}ÌG•ó{ùòâë®rÞÖY«›Ê ­×ê{kcã‚ødK›¨õ¡ïþ|Ç¿r¶@@@(U÷R}r\7 € ˆ@Cô„Ÿ9¥xPîû¾ÔA]ƒJùæxØ{|yö[Ÿ Þk>*2ºÆUÌOUËÇUòQK› Ö_¾¢øùäÆ8 € € €À ¸99'D@R°ïã5$·yî´âAyg§Vɇ¿ZÅü>micË­oDmm\0ô˜ÈXíTÊk0oËB•ó6Ð,ýåKí»…ëE@@‘,@à>’Ÿ>÷Ž €*`Uë“ÆJ0w×_þXGT%ïù(˜noÜ_ÞªéÓ.äzɃÊfûÌ»Êy{¯^«ô™@@@N¼û‰\ €Œ0ëó>}‚swÁü‘¶¨2>î/¿O[ÚlÛå‚zë/oõ)ÍÛ]•|Â7¨œ·¾öL € € €ƒ'@à>x¶@è—ÀèZOF׊œ2©xPnýåiïx7àk\9¿k¿/›·ÇýåiúÚê°M²J> æu kmlª+‹Ÿ¯_7ÄÎ € € €@™ ¸—ùæö@@ ¼¬Çû8 Émž=µxPÞ™Ñ_µ~¯UÅ[y]ZùWvûòÔV[—‘½Úsþp[ìeǬ©rA½-­2¿Ö¾¶×ÞËèk}/¹mô^°n¼§ÛZ5~CƒÆÆÊ¼B@@r p/§§É½ € €E*4ézÀk{wmlìÝŒ†óV5ßÖ.r¬C—:[ßùàuÎ:÷^[»m¾lî§ëãý£uz|ßÎ"RY!2FÃy ÷Ãà>äÛ:öG¡}2Ø>Ⱦ~@ûgÌ@@@`h܇֛³!€ €Ã^ ¥áüøú®—Y¼z¾ë–=ùº=íK³†úÉßB}î‡!¿†ûöu›®?ö³>pA~î‡Ép?º«¦w}\eUÝGA´ŒÖgÃ{«ä·à?ñ!@ö= öi½)³D@@H€À=’`‰ € 0dV[ÏøÜiàB}ëmŸ ô»©ºþ Ø×–;G4ð?è>ˆ?ˆ?ˆ×‰ttº+¯H¹9Ä»pÞUã[ˆù¹nël€ŸhÉ“ÝOQQ1p&¹Ö|… € €ƒ!@à>ª@@à„ Xo{6¸;ÝéKK«Và‡mv’U÷Q8ŸS±¯•úÍaë·mTáï*õsÖ釙Œ»z87ègƒýüÖ;.ð×g÷éÒ’'ôÃÖ;¶Y1!€ € €ÀÀ¸Œ#GA@a•Z}>Ø­w·ª°{ãÇúÞÇ­w¢Àß…ø‰@¿K~{d6mêGÕø®Ê>$7ìà þ ð×õyëÂÊþDUêWkõ> € €#E€À}¤ô¹ÓÀØZ¥¸-ÑF'Û~Gƒþ°‡~N彄k­wŽiëlõ~âÇd·×õQë*ý­cTM×6;a Ví» ý(Øw•úÉuÁkZïä~+ð € €À° pv„ B@@`h¬Gü`·Þ9z,¿Â>g€Ü¼`ßZõ¸À?Þ䯳ÐßZïXWœ:«®+ï£êúZ è TÝGáº?Ѳ'1@nöá1i½34ß“œ@(u÷R‚\? € €ÃX`TT·ç^âÀUég2¾=öÃÏVè[oý¸ê¾k5þ‘6_öµD=ô£ ÿ¸}On«wå•.ÔOVÝ'[ïZŸ\‡û®%O6Ð+üi½“ûÂW € €@© ¸—ê“ãº@@@@RÚ„ÞÚî fëötØb'hŸ“ ÷ÃõaÐûVÁ´ÞÑõñºÜ²Õû‰Ö;ùúZ}¯U÷]Ãùh»­àÞK†ûAe¿ùö^¼­ˆ;À„ € 0¸îƒëËÑ@@@ Äª+=©Öߜƌêz#`û~np„ñA¸Ÿ[uo}õí=Öç¶ÞÉøög÷O[ÈïBk½“Jå†ðQXŸ è»´ä ýp]\¡o!¾ë±úa¨_§=ú͉ @éî#ý;€ûG@@*`ýá-°¶9w¸;­äæöap_ õŽ ì­U/û'BþðC€(ÜZï´êúv ÷m²ÁqsÃy ùÀ>ÙO?òÃsA¿«È+÷ík ömà] ú™@@á.@à>ÜŸׇ € €ôSÀÚÉ fë«ÒOöÒÂý6«¸«ì£€Þ–¶þ°öÒßÛUì»jüh@Ýx}_÷ïèt68nnûœ.÷ÑûÒGúÙJþ0¼ÖG Dmw쯷ŸßhìŽ €BàÎ7 € € €@¿,¨]+Áœ{ ©J·@ß*és‚x îµB?ê“oïůã ýä>ÉÁt£Ö;¶OGX¡…ï¹!}ÿ+ô-Ü·™@?÷»ƒ¯@(G÷r|ªÜ € € PFT[»›s§ ôsû¨ò>nÅTæk¨ïZêØzW[îÄ!¿½NôÐ*ùíC¸åNTU_VÛÁ~80®{íZèDÛåôËOVïØÇ*ôma&@8±î'ÖŸ³#€ € €œ` ô»~PŸ ìྛ } òíø‡~æGíz¬‡¾þ@PE…õÁ²Kdå¾ÛNûå'‚üøu~U¿mO ‚¿Q9= €@I¸—Äcâ"@@@JYÀªÕ-Ðή"½k{ìà¶Éq¿õËo¶@_Ãûd{ ~b»¨Bß}«¢‚|Ø[ý°_¾òq`m—?®Û? ôûØú *ôs¿=ø @ $ÜKò±qÑ € € €Ä…}{`Bý®A|ÒÇmt’á½m¿·¹k…¾…ûù!»†þ ô«¢@_Ã÷(ØwUùîÊþTèÛ¾:x0 €ƒ-@à>ØÂ@@@¨©rUéù·10!v{— ¾'úû[òÃû® ƒæjËLFýŠ8Èè }ýüï Ö €#U€À}¤>yî@@@a"P­~µV¡çOè§µ_[åd«ð­~Ð:Ç…öîuÔ[ß–¾ì?ïììŸè£Ÿh½c~EʵÕIVâ»×P¡¯­{*©ÐÏÿö`  0 ܇áCá’@@@@`àª+5Ðפ!ïè§;}iøh„ú…z«Ä?xDÃþƒÇï¡oÕþè§,Ð×%’½òª‡¾·J˜@ú/@àÞCŽ€ € € €#XÀªÏê4Ð×9w˜»3èkß“ú6(îÛ9ááúv¬t§úz©ùa¾…üÚNH+샰_ƒùøu¼>¯ç~—lûЃ  î#á)s € € € P²6àk½†ù6çNb[ Ÿm·£!}üºp…¾µÜiiõeOs2üýœýÝûa Ÿ æ5€;ʵá©Ò{«Ðþú•ZÁ-+õkkÑShé¶ó²Û[oþ®Û&厩ÛÙ.Xž?¹ç Œmîóâ+ î#á)s € € € €@ ôGkè<º¶ë:wf4ÐOTÛ·iÖÀ¾Sƒø´¶Ë‰–Vioísl̉÷ìCÛÖ> è<¦¯Ûf÷ ··€ß­Ós„Ç‹–Éó:oWkå3ªÆ} ä£ßÖù¾ýu€û à6‰¢’Ø>ùþÀ¡Bÿ!¹}¡²×œw`žaW¾FâîÅmx@@@@ Ÿ[˜Ÿèï ØúòÕº ö]xï>Hn—ÿaû`!ÞÆ}pTÿR Øñ¶nßè‡BD&DKÛW?ãÈ™¢–AÉ,äÂ{ ü£Þ-õ¯¢÷ |XsŒì‡ñ_DÇŽ-s?Tˆ? È9^óER¤ì&˜(÷xH\" € € € €ÀÐ X_þ1ÚöæøÓð£þÿÅ‚ý(¤wK÷A@ðöW]þ: wÛøƒ€céð¯Âíó?,ˆ¶µe÷3yŒä3°N?Öš( ï UøGï¹e÷ûg?4°ãº¿ ˆ>$ˆ–¹Çtç?¬pûÛ&:F´´ï-¦ò p/ïçËÝ!€ € € €ŒP¨ÿÏnøÁÖ–Èøí®Â?û¡BØ~(ÚGd· ÛÅ_»ZÓ¾$?pˆÎ-séö‰á®/niµ6r8dôœÑdX؇öáëþî/r?Ȇûá‡É¿ÈûúáAô×]—Ñö¹8tÿáDp­]®Ïþz…)_€À=ß„5 € € € € 0L,ص^ú=›†oœÑÚí/ºüõ@2´·P?öãq’ÛþÀígíì­ºÔÿ/Ç9_¡vEÁ5ä}(àaãDSnhïªÿ£€? ö“Kû+‚äûÉ÷â âA”íC#û€Á¶¾Ï6ò°%{Rƒ× € € € € €À XúÚêÞxx̾&îÅþ YáŸû!Aî˜ñ‡ ñ¶}°>hiäþ‚ £Ý-íCŠR™ÜKåIq € € € € €À ð´'Nµ¥Ê½J–ûÿáÁŸK¢´þtwz-ÈgB@@@@@þ ¸÷W0Ú?Ý&mmiI·µÈ–¶h-K@@@@@"@àÞϽgó£ò¹.¯ªNêê–ÈûÏ#ÆÔ‰·ì£òõÇ_îçÑÙ@@@@@ TÜûñ¤^¸çÓ2yÑe²zíúð(›dý¦ðåúµríÅseÙçêÝûÌ® € € € € €@‰¸÷ñA¥_¾_\³&Þ{é rßc?•Ÿ>r·Ü°<^½~õr¹åÑ]ñ ^!€ € € € €”¥@¯Æ’-K>ÞÔ÷|%Þså]²ÿŽÉøpÍE—~XþàŽkåüUkƒ5«o\+Ÿ¾ô³2)ÞƒW € € € €%,àû~põ¾¸¥è2Zg¯mJ¼£_Dëâµn›ðk]DÇŠ–ÑâãÆÛt}Ïí#8½n}mËäk{Ë}nž;Ü&g?·EöšòÞ‹2^—Ý;ûfô^öð…Á½_«{Ëî#z/Zf·É×ÖDǾçÖGïÅÇ´W¹û„Û„»gÏ7z/:Nv£à€ÁqrÎçŽ#¾Ì®ûç7Ú>¹LÞ|M¶…~•=°]AtM=;f°vŸØÂΗ|Ï7:fð–þ'w›`ï.ûÅ[ê¶]Þ‹¯Õmåî#ÿ˜ö®½¼ãEGÞK÷>=Ÿò«õëÃ=WÈÆÛã°Ý­¬”óþø³²B÷ rßô y¥EdRCŸNÆN € € €À  tfÒ’öÛ%i—ŽÌ1]v„Ëäk{϶Ñuº­½>ÒqP¯Íý‚lý⯠ÖÚ‚)û vø‹·­Ì® ·pë‚/ܚĶѹ íì—=qöEÎñ³û%Ž™]Ÿ2wŸÄ¶ƒsþĉCËœkJœ?Z-“{ºûî;ZñÍ9fò(n¿œãçl7Ú+¹môü#§àšÂ{rÛ‡ÇO&¹´_κ=x‰cFçL^kñó»ý í¼7¹òuvï^?ÚËÎÁEËä:Ý®àùãý£ëŽŸ“½WèX‰uñË^œ?ÿœîLî`vþN?=wö¾t}|ºpÛp»æh]tüøxnímã–ÑÝú®ïå~}\köEkÝ2:ó`-=±DÑ¥Šž¥‹á×áIƒmÂ÷ÜööF´.ÃÝ¢÷¢eô†;n´}xÐh=nÞöÙM¢}l™|­_e¯ÕÞqïe·)p­Ñºcpôä>Ñëø¶É¾½ç.2Ø·À1íÝè¸vyÑëhÙõZ“Ûg·É9nîy“÷‘Ý>tHÚÄÇ ÷Ï9¦½_[ò˜Ñ;ÑûÙÛÎ.ƒ½ 3Ú/8޾ŸwîásŒîÍ-Ò&¾ŽèþÃçÜGô^×눶þK÷¾<£–­òàúpÇ¥ï–yµR;O.ÑÖ2k×¹÷ª lÂ*@@@ÀB¤lÈíwaöñï¶Îà çÇáw’Gayˆ‡ë‚c…Az[úpF¹ó¹íަ›sBeªZªR5RéUI¥.ƒ×©ªp©ë³¯m»jU9.ü=$ŽÿR¯+ã„ ûË~ÎûÙÀ ¹iô îñ=qR“AF°evó¿¨8¿5šâWvþè«h™{þh¿x»è(nÝW´ ÖfÙõX¹ûØWñqw~·ot„è«è¼Ñ2Xß‹óGÏ*¹òuö<‰cF&ö^¼mâúÛ&ÖF‡Jìcp[ÄÇI3»KÂÉÖ%½Ž–ÙC;ÇÇM¼ŸØ¿Ðùã³Æ×?§Þ?ºÖø:âcº t×_]‘ãç˜Æ[']w¡kMn—|ß´woÏí—¸¦ÄµVx•ªv9îæYÇ×yä/¾îÄ6Ùcæ^G´­;nbûh3]z/Ú/úq_wÙ?{ÎìÖv´àÈÉû°wã¯'æ%_Àÿìñ·[¸÷å!4œ)õÕ[äÌöKݬyR0LoyN Ãv;Åÿmïn€£8ï<ÿFoH` Ì‹%p0¼F8°>ˆ/Ø–œu /ˆMœø‚…×lvËåoÅfq’ÅW&f÷.†ÊfÜêxÙMœx-×ÅP¹9œŠMå ±ÈÙ/18AÆ`$ô6’îéžîžžÑŒÞæõÛUC÷ôóþiy,ýû™§ÛÒe@@@`H:ìYÜn Úšµí¼}çìÝî¬oßy“73Ü ‚·ªÝ x{u“f¿­öÜ-Ç ¬vÏo_zDÞäšà÷Ènq+hªÓ*kèP^;vмD¹9üyè^ ö € €À@øj@r…ªZ¾NUqË^Òί/“o¯^¤;XN&®  € €Ù'ÐÙÕiÏêö í¥JìÀ´ P;Anké÷Øõ: Ž÷5àí.âÎìÍôî´á­Ù†Vð94›Û h›½˜¶fx»êð±;ëÛ><¯(î ð耷U¯[§UOQ^1³³ï?FŒ €*@À}/lKým¨™«î’3¦þßþ‚ˆ·24Õ!€ € X ¼6·o¶¶;‹»ÏoSÖä ¼cÔ½¸7¼M­×¼¾[Ë „‚×n ;4Ûž}݇€÷°Üáº!¿Ô^þ$n=Q3¼­¥R¬¼…y7˜ {Ìï«zýã@@þpïVOy[êõÒ–¿Sõší¹68«Ç¦n@á  € ¥]ÎZÝV€:zæv(hí±ÝYÝÝf€Ûq§lTp¼Û pÿC/MÀÛ t[}°6kí܈eFüË“¸3ºí™ØáYÝÑ3À s†‡g…GÇCÁï8k€›€waÞår³ô'a#€ €dª÷ë¾²M:öãÒÒ/®Q¿®Êµ:¼{½æ•Åz¢ª?cÏǪ­­ÕÛo¿ÝsF_êO<¡»îºËw†C@@ »ì‡Rš€³äv—ñûÕîÒ#ñgnû‚å=¼#g}·u6{Á}¥?àíûgi»KøÏ¹3³o0Añв$N@¼ÏïY³ÂÙ@@H¦À_þå_ªµµ5™]’¶ ¸_kðœ6=8Ik|ËÇHÕÚzàÛúJÕ4 nNNŽ&Nœ¨ûï¿¿Ï==ztŸó’@jŽÎ ävgn‡—3 ?h2VÀ;î p3ÃÛÊ^ï;¼¬IxVxxö¸XwLiͨ¶Û¡@väƒ$­¥E¬`v(¸š™í¼ý3»­õ¶í:|3ÂíÀw·€w÷u¿ rŠx0åPÿÀQ? € €@ZÌ›7OÁ`°Ï}Ý»woŸó&3cÀÌöéJfÒ·íFí\2JKw‡G°vÇa=ñØ<•†O]÷‘<_¶l™6nÜxÝuQ €¤¶€õkY—:Õe&i=P2tlýÛaÎ…ÒìóNš›'´7éf©N¯slj°ê²ësêµk1ù¬}d;ºü@m-κܡYÜîlðˆ€¸ðv‚Üö ïpÀÛÍ–·ÚmY¥ÌuÚ‘ïP;ôPÉžÞ1g€;³¼í ¹ð¶f}ûÖ·ƒâ¡àù9…<˜2µÿ w € €Ä:{ö¬=99n¦HŒIØ)0ŒÄwáøÎ•¾`û2>»Yó&^ßò1‰-"€dª@((Û×€«/øêe€¯Ø5__€Ö ÿÆ úZ³–­ ªÈ$¶r„Ȧ¦ápý¡ôPþp ÙI·ËºÁh;´ê§?0íÔï¦íà³iÝ?š×7OŒñ{yLZ( mùY}²Ø!K·Nwl[y:ÕÒñaŸô¬u¶s9&Pl^î±Ù[ïíóö±•’k“½<^~;ÔÊo]!3ÃÛúEÕ”vÎ9u›üÃÍÌm+(íÎÞvƒØæÜð¼‘æ|Œ€¸ð¶g€Çx‡‚äVœSöù¢“@@ÒV€€û@.]ðŒ~àMm¯Öá†mš7˜ÓÚÒ'Ê €C ` #ŽVpÔ ~ZÁE'Pê[¡G“ÈŒpµóE\£‚¯nvÛN 3"¿Ó¾Ý¦9vövϬ€§×ÇPð3ìtûÕO§;ŸW—ÓFÄøCÁÒÈñ»uYù­ôÈ€kD¦®P_­üýtûå´i÷!\¯ßË*9žP]Ö¬âž6+¼jh»\MðÕ ãZÁY/@kŽís¡´ÈÀ®¦Êk—³êç·Ã¹^nšUÎ=¶¿ñêròÅ ûÛεÚ˱Ú4gM½fþt¨~w¬ÎxBÁe+Í7.;¿UÎ:gµç?¶G1žˆ|Þø±øë5µ…Úqê‹J 9[}¶Ê†Û¶ÖÓ¶Þ³!€ € €¤·÷\¿àÅS:è+÷‹][ôjK‹ïLäakëX-~â1Mf|$ ï@`Ð[.èüÕ“ªÿ𤽿põŒ½¾q÷Ùµn`× æ†Èùœ€®¼ŽÞ¬ aü ©|ŒpŒ fú³ñf冃¤vh2œt”n 2¼ -c\Ã}µêÈuœn4\on /*àjÕ9·Íp¾‡úi·5þp]N½¾u~î°èËÇ{@@@bîn¾pRu^¹Z­_U뽋}P©WpmÃYè@kðšê¯žr^&¸nØÍË ÆÞT²Ô‹%ÐÕÕ¥†–z{9˜óöë§ìãKæÁ¦£ oö–ƒ¹·ü˲–…¹©ðŒ2`0 € € € €= pïÙ‡TÈBæà‡zÇ<´Ô­îîsùæ!¦·ÙõÛKçªj£öCM r ³P‰!#€ € € €D pá=d@gW‡.5¿mëæ¦f9˜ÐÌõ“ú õ¢ÆM´—ƒ)1Uw޾ÏÖ§¨´p|ÖØ0P@@@@þ pï¿%@ šÚÌ0fw­uslÍb·ÖT/7Auk˜ù3}æÖÿ¤›‡T¹9ùi8JºŒ € € € LîÉÔ§mt`g»óÓÐëî¬õæ`“ýÓ²¦Øö»Ç}F·Ü0M#òoô>P! € € € €@v pÏÎëΨÈ÷[ßu–1KÂØ2=©‹×Îjä°±ö0Ör0¿ùÏíuÖÇŸ¨œ@NFŒ›A € € € €¤¦÷Ô¼.ô |­×Ìò/gÂËÁØËœRWW§n1Ù^fòÈi^ùÃöìõ¼¾Ò"€ € € € î‰q¦èƒ@WW—Þkù£X·Ö[wg­_n©×M…·81¢ª š@ûÝTtKj%  € € € €‰ àžgZA(kíWB1½zÒÖCë­×›}~î0{–ºPÿ“ÑóôàG¾b‚ë·Ù磪à- € € € €)%@À=¥.A ó::ƒºØ|.j9˜“ú°­Ac‡Orf­OÕ]c0öÛU2ì¦ÌC`D € € € €Y!@À=+.3ƒD 1WÚ.ûë¡YëÌÚë#òK½ÀúŸŽû´ŽX­qÃoUnA‰¹2´‚ € € € ¢]‰P¦ 2L ½£U®ýÞ, c-sÒ^æü‡ÿOm-ÞCL'O×ÜñÕ&Ð~»†ç—d˜ÃA@@@@ »÷î&œAŸ@CË;¾Yë&Àn‚ì—šÿ ÒaãM0}ŠÊFLÕ'ʾhïÇ}D@ÀWšC@@@@²G€€{ö\kFŠ@-Á«zçêi; ^ïÍZ?iè9&˜~›PŸZ:G÷ßR£2h–;¼ÇúHD@@@@ Û¸gÛg¼Y/ÐÙÕ©÷šßv–±–ƒ±–…9¥ÆÖ kf¨—Ý0Õ<¼tªîõ ûxTáÍYo € € € €} àÞ%ò ¦WÛß7ËÁœòf­[ËÁX³Ø sGØÁô²STqS•æO\aÖ^¿My9ùi:Rº € € € €@ò¸'ÿЮ[ £³]ï^{ËÖOùÖ[?¥«Á÷5~øGíå`ÊÍÌõYc˜u×§ª¸`Ôu·I € € € € )@À=Òƒw¤¼À­Í0ÖR0&¸n/sÒ¶—Üä-3g|µ ²OѸᓔÈMù1ÑA@@@@2A€€{&\EÆ‘mͺpõ÷ör0¡»µÖúIutµÛË¿”™uÖ'•Tèž›²g­åg¤ƒB@@@@ ]¸§Ë•¢Ÿ+ÐÕÕ¥Ë-罇—º³Ö­s£ ˼å`î+Ĭ.,W ÈX† € € € €@º pO×+G¿ÓR 9Ø~ˆ©³Þºµ4Ln ß,3EåfÖúôQÿ^Ÿœ°ÔžÅ^[˜–ã¤Ó € € € €d£÷l¼êŒyÈ:»:tñÚÛÞëî¬õ+m—4vø­&°>Å^o}ÆèûíYë77ä}¢@@@@ZîCëKíY ÐÔvÙ~€©û SkáÚ Ï+ñ–ƒùؘOé³·þg7ÁöÜœü,Paˆ € € € €dŸ÷ì»æŒx€ímz×yˆi½ ª[KÁœ¿zR-Á«?â£ör0·Üp»þݸÏÙ³ÖGäß8À–(† € € € €é(@À=¯}rÆ– ¾Yë'eÍZ¿Ø|N¥fé—2³Îz¹Yoýž›¿`¯»>¦h¢r9CÞ'@@@@@Ô àžÚ×‡Þ ±@kÇ5½sõ´P­³~Ê^w½««ËÖo³×Y¿mälÝ[þeó~Š óF q¨@@@@ÒU€€{º^9úÝ/ήN]nþ£½ŒµŒµŒµ$LCË;St‹·Öú´ ÷ØËÁŒ*,ëWýdF@@@@¸ó3q×Ú¯8õÐluk9k{An‘=K½ü†©š1ú~}jâ2Ý<|²òs‡eœB@@@@Ä pO¼9-’@GgЬ«~Ö·LhÖú‡m gbj-SnÖ[¿kÌŸÙû’a7 RËTƒ € € € €t àÞÝ„3)(p¥õ½Èå`̬õw¯½¥ Fy³Öï÷Y{9˜±E“”›Ãv ^Fº„ € € € €@F •ÌèË›~ƒkïhÕ;×ÎÈZgÝZcÝZÆz˜i[G‹n61µ–ƒ™Xgêf);°~Ê^¦±õ]-šh/Sfbzçèûì@{iáxè@@@@@Œ àž1—2±ù°­14kÝÖ­å`¬û…«gT˜wCh9³ÖúÌ1èÓ“þ£Æ˜¬¼œüÄvÖ@@@@@ pO0xº5ìl×»×Þê¶Öúµà>Ù™µ>E:îÓöCL‹ F¥Ûé/ € € € € 0(Ü…13*yß,ýzx©YÆÌZ¯¿zJM°½¤`Œ·ÌÇoþs;°>vøG”cÖ`gC@@@@ pÏŸ„¶ŽfL?ZÆ÷ ÓŽ® ½¶z™YfòÈi^Ù—d™ebØ@@@@@z àÞ³OZ§vuuérËùnËÁ\n©×M…·˜`ú{¶zå-5ö~ta¹@Z™Î#€ € € € €É àž,ùAn÷ZûßCLO™ãÐ’0ù9ÃB³ÖGLÕŸŒž§?òû!¦¹…ƒÜªC@@@@²[€€{š]ÿŽÎ .6ŸS½³Æúy+°nޝ´½§qÃoõÖZ¿kÌv }ä°±i6Bº‹ € € € €¤§÷¿nÜ.]Ê{S»Þü†=kýÂÕ3‘_êÖ§höØZxëJ;Øž›“Ÿâ£¡{ € € € € €@æ pOñkk-©Þ’sEЧkîøjû!¦#òG¦x¯é € € € € }ÜSüšwšÐ6G÷ßòHŠ÷”î!€ € € € €Ù-“ÝÃgô € € € € € Ž÷Áq¤@@@@@, àžå? @@@@@`p¸Ž#µ € € € € €d¹÷,ÿ`ø € € € € €ƒ#78ÕPËP äwvªôg?Ó{íí †^Æ…͹÷¼»J·Êyy †ª«Ô‹ € € € €dµ÷¿ü]¦Á’å˜WWk«:ÕÙÒ¢®X/“îž•GR  @Œ€¼Ì·ó±Ò­sEE^Àß à»A~ÿÞ)3•–››âêt@@@@è¿÷þ›%´D0'GMsçjÔúõ×Ýn— ¸»yw˜÷ìÝtkïå±Ò››í 0*àoç‰SÞ­CmmR—¹…—7ðúV`?Æ ˆà~Œtfù_÷ € € € € €@/Ü{ʤdkfy`ÄÉz%i³géGë½à¾°÷üÑùÜô÷ßßðç‰ øw«Ç¤+ìu–¿Ðàûgïûþqóøþ1óXéÌòOÒO Í"€ € € € 0t܇ΖšcXÁì\óÒÈ‘1R‡þT³ü£öÞÔžÁßi‚þѳü{¼™`ݰ귂þ½Íò÷ìÝ¥~"fè0Ý«Ã*o]6@@@@TîƒÊIe©.Ò³ü}ÿn³óÝ€½3£ß øwËã+ïÞ,ˆÈã¤÷:Ëß èÇœï›áïðã|À½YЭ÷†³üSý?ú‡ € € € ÐOîý#;×+²³ücìÝÀ½½7éþ~·YþNyžèòn==ÎòwòÑ|óÞÞ÷’.“Þ-Èï¯ËM7{6@@@@S€€û`jRi ²³ü£þÝ÷Ñéѳü£ÒÝ`¿W‘µy+„IDAT/½ÇYþ¾€~ÌÀ½/=æ,ÿ¨ônyüéÌòOƒÿbè" € € € Ðwî}·"' ’@*ÎòïÓüîzþ¾¥}¼µü}}/Èïäsgö»7z\Ëß÷ÏÌwMz̾t7ȯ‚‚ÐzsrB{+Ào^óÞÞ;ïåK·èÛ×ô@`~"¨@@@È î™qôC %gùûön`>"p+Ý?Ë?FzW[›ÔÑ¡®ÎÎÐÞ[ïeÞ[¶Óœ÷ÞqéöR@ÑÎyæ# ØGÝðnøêëíAoéýºÐÏþôÖ_Ûe°}¸ÉýÈ{@@@RJ€€{J]:ƒÙ"ìYþuî °÷‚üÎ /Èï»`ŸëáAoév=”·oB8íõ·?éo¯ý‰qÃýAbµó&‡{c ßPp¿ÑÐÛ ûæ„U§ï†Ç@nXôVþzú“”,ÜäèÇå@@@¬ àž•—A#€X3¶ÍÆb2óH)ïÆ€€ïá^>ç†C¢nôö û&õ Ów÷„ÛW»þ$þcg¼î ¯ŒsÃÄ?>ïx|z½ÉµäÒõÜ@Hµvòó0/¹7ü{ç8à?g ˜O„XçÜ4³·Ëô”'*­¿mÄÌïkßî_OmD¥ÅOmÄ)Q&Nß"ò÷Ò·v™žêvëqòÄl£—ò½¶UÞkÃj› @@, àžeœá"€¤—€;󜛉»nnpß½Aàè»7¼s¾ö¹è›¾ôXõõvâ·ô˜ý±¾‰âÞäègºÚÛ%ëe¶®®®ð·,¬ãÐÉð>ꜿ—<Þ S6fþ^ÊG”‰jß_·ÝÉÞÚˆS¾Ïm8å#ò÷Ò·v™8í»yì}OmôR¾×6â•·ñ†øëÛ4þ ½ÿØ4íìýçýÇV÷|ïcæÊãÏJr>U­z|uYi±Þ÷ØFœòeâä±ÛrÒ"òG÷#Ny»Lœ´ˆqôÔF/å{mÔ·¾¹—3|xÈΪÏ}Yßšrcìí›–±Î»ç¬›œî±Ùw«ËIïvÞ)¯~«N»LTýÞy·M_zÌ6LzÌó½´ï•ñÕoµÝ[ûÖMì€yF›×þV™Û×ûxã×¾wÞ­Ëé_·ón_côßí›]&FzD]¾ôˆó¾öíóö˜üƒ €@úpOŸkEO@@ ÜäH2M¤¥€ý«çV°>*`óÆCT™˜ùݺÝ}Tùˆ2Qiþº­âÖûˆünî>Nùˆ2qòØm9iùݺÝ}œòv™8iãè©^Ê÷ÚFTù˜ãˆÊãï[t~ûù3×®y?^ûVÖ˺ùgöÝÎ;éöÍC7oÔÞ.ã”·ërËøó¹éfïoÃ;Ž:oÕc}›Ç}}¼öýåã¶mõÃmß{e¢úó¼“g°Ú×F¼ú­1Ùe|ýwÇQ—/=â¼;ƾn=v¾òþóö±õßË@7s£'f ¾—^_À¿ÛÍ«'ÝËïÞè¥~¯®¨ú½ón=¾ô˜m˜ô˜çcµoF÷×W¿Õö¶ïŽÉì½>Gµïw󚛯97ÜàÝ@ê–îæó×éž³ÆëÇJï-mË÷«ßn¿œöTÖªÃl-k—sÚ÷ºÇ}ª7Ny¯n+ , àžå? @@¾¸ËŠÅÊúó?V ç@þ X7C¼à~TÀÞ;ï øÛ}÷}Ô>Uo8xãèãøâŽq€7<úÛ¾—¿¯¾Ör‚V^g|þòö±ùÆFûÕ«Þ:k|îËŸ×þéñ¥ÅÌ•Þ[ùˆôžÊZiÖæËÓ¯²Qåû]ÖW~@eò.ë¶R¸þ­›HÖ·t¬Í½ùµ¿î€T}n;õÆh?"=ªŽniQ廥ûÊÇLó•™î”›æ”›>å{¬Û´ßSz¯i¾ñ»×ÇÝ÷ZÖŒ-]~ç$àn]h6@@@H k™¢t ª¤@ IÖ ­®¶¶ˆ›þV·ð·Ë…*ˆYŸêS¾OeÝÖÞ÷êsÙå{*kµÑ-=ªÿÝÒ{ë—¯|¿Ëúú? ²ÖÍ6³ùËúcŽ7z<¾þ[ùí—]kêÿCÀ=õ¯=D@@@@ ¥¬gE SªOt&³º¶oO‹š§Ð°¥²ÀUó«³gϦr餠@ee¥Î;—‚=£K ª¯¾úªjjjRµ{ô RT`×®]úÖ·¾•¢½£[ ª_øÂôÛßþ6U»G¿@ …šššR¸w¡®p´KTKK‹‚f²ÁÜ:̺gmÖ×sØ@~œkFùj  € € € € €@¦ äeÚ€1žà…WõœóÐÔcÇÏK3¦õÚì@—”ÉÍÍÕ /¼ @ Ðkn«LN÷R\öd£@GG‡î¸ãŽ~}vd£cF°@WW—:;;UPP>É Ћ€õ¹am;wî´÷üƒôEÀú{å¾ûîã`‘ hoïÄ4ß¿ÖwŠÚpÀ…É>Ò+õnÓ5ï8ú Õ;Q¬þ,üÛ¿ý›êêœè¾W_ÏcÇŽÕðá}[ê¦çšHE@@@@_àܹs²&þôu+))ÑäÉ“ûš=iù¸_'}í±ß+¨YêÙtJûjÊ«?¡)…khÁ‚²^l € € € € €©-Àº#¸>ÅSîQ[nûÿÒ›-î›ð¾ñ_Ê·WVÝ¥âpG € € € € €(@À} µpºª—¹·kÓ¿žpß8ûz}í*ïÜÕwxÇ € € € € €d¦÷]×<}êk[½’»—N×S{_Qý¥Kºtî˜6-*ךCNråV}ióÛ=,@@@@@ ˜…éû¾2}†" lXA|úA=°Þ¬Çª¥BµgjáÄn+¼ÇÊÌ9@@@@@4`†û€/^žªÖÕjß³ÞÚ2‘5UÔ¨öÍ_lTá € € € € ±Ìp„KlªWÝoOèâÕ6S[ÆNš¦Šieb^û àR € € € € &ÜÓäBÑM@@@@@Ô`I™Ô¾>ô@@@@@ M¸§É…¢› € € € € €©-@À=µ¯½C@@@@Hîir¡è& € € € € €@j pOíëCï@@@@@ÒD€€{š\(º‰ € € € € ÚÜSûúÐ;@@@@@4 àž&Šn"€ € € € €¤¶@^jwÞ!€\—@°E-Á<å©YMíù*-.¼®ê(ŒÙ TKKÐhž ùu1®:cD`°ZššÔn*-**V#ƒÍK} €d¹@PMMÍR0¨ ‰x—šß7RH„î)t1zëJˉ½ æµDÇšzËM:d³À¥ãûõÔ’*ò‹Ìº³õàœ*)R j‰v¾r&›i;Äh:wD[žZ¢™|ó¹a}vX¯|Í\´\;ž0¿È²!€}8¾s¹ŠJJTb^ß«kì[!r!€@Öœyi“–,_®Ç<Îk¹Iߤ-YCÂ@@ Ï:¸óiU™¿Y¬ß3JFÒ¨Q%ÊTiÓKÇSæo–@—Ùú<&2&Uà•§«tïúC¦Õ:zåEÍ*NjwhRTàÄÞÇ5ý‘çzì]åÚZ½üÌB1ß½G&Ȧã;UR±´çñVoÕÅ—kLϹHE,°& MÄSØ|´A+g•zï9@ŽlªÒÜ5Vl£§­Z¯™¸Çâ=!‘†@v ´œÐSs¦kc]üaW˜XÇ‘ˆu0Ã=þ5J”`“ŽïßâÛS§[ôRO xæÇ‘ÁöÊÕzþÀaÞ·G««Ãý=´±ZöׇOp„Ù+<¡¯GÛ«µùù}:`>7ÖÖT„]jWè{O„ßs„D Ïh­/ØÌ{@@jÒoåÛ+TQû%S>\ €€'Ôþ û‚ízöùª{ó¨öl¨ñrÕ™XÇöcÉÿv]*-oãáp` ´èà¶¿×yTÛw×B‚ôIàÕ½ß ç[¶C Û“;§lÞü/é?l[ª¹+vÛy6®Ù­Çç?ÉlÕ°Gd¥@ýáçµÝyå~y&;_©š¿X_^ð¸*œoÍlÿï?Ó·Oó>WÜbì@³ˆªö¯ÿ¼zþŽN €@ƒ.¾R¨Ü¼CW΂èU xîe-ð¦¶WjßÙ—5bè–ëviÖô›4ý‹¡ßBþùÇGôÕY󓺦;3Ü{½¤ÉÊЮß}o=ÁödñÓ.i)Шßrg‹Ôèèæp°=4œ<Íù‹'åÝû­û•~Ïó ÒòJÓiSàò©£^uÏïXëÛÝ“3¯ÖZ÷Mɰ¤þâêvƒ=¤ž@ýþ¾?„S¯ôRD å²Ž:ËATÞ9>E:E7@ ÕŽþð^×îÛíÛÝ“ÓÌs§ÜXGÝOOšïÒ$wc†{rý{h=_[³YϾ'³Æò0 ö~ù½5ÚÝÃ:E=TFdƒ@ÓI½èÆÛ+?¡)±h/œ¢ÌÒ2îgøšf6ü`0Fzxÿƒ+N†JMëWà.»U˜¬<<ÕÅ`žÀ¥ƒªY°>ô¶f³j?ñU½Âû@ åüïå~‡BÙX@@>\Ò‘ýî'Ç2=úɲîeò¦iW{³¾oÿ±’—ôçÕÅú«ª{§9“BÍ[¼Ró¼–ƒ¶€»ÇÁt(ž©olÝ ™'Ttë”Øk6½®ÝÿO™Ú»×ÂÈ2yS«ó7˜Ïƒ|‹ñ`²ã{¿^rfÊhe™ÃEÞ.iËÃ(tÏ¿B¶¬ÔÄÚ%½"²T ýšw_ýH›¶íÓ¯^?/ëöIÉU}©F_þÒ¦Ë×Lþá£5ëßRŸûl•ÊbM<ŒQåPŸâ#l¨…­þæA«‰Š@ S Uµ|ªâï’v~}™7£DÕ‹tGŒàZÜâ$ €@f ä«l¢ïà¥^û_ø…ÚÞÓ¯_üg=Wë~½®RµO}6é³E2ó"0*ÒWàØ–¿Ö*çàÕµ/¨Ê<<æxkúއž#€ÀÐ œ=úK¯5<⇩¶v»V=R­Ú7wiá4ßï'Q9y‹Ù#Ðrö„Ǩ۸IŸÞxȹÑï3xn£V¨B[¼¤åU} É9d ÷ä¸Ó* P–ú#zªj¬–nwgÒŽoAü ›ÐË@c¤…@Ó?Öóð#KW9ÁöŠP¿«Wk¡ó`¢´D!h:¾M³W9_[¶GNò6iÒ[ ýг²r…óûEeÖnØ Õ5•¾Õªzzµ^b!; ‡d­@{{ès#ô©a‚íÎÇG…ùüX¶Ì¬™ëmuZñÀ$m;žìÜ%îÞEáÈ@3Sõ¥MËUT>Wæ&°·m>pV1cÄóà|ù%fnH…*_d%ëFyS[­™OíW‹/+‡ Å-ÇõõŠ€yXû?,æ0YüãÀÐè›@£~ùÏÎMºº:=»ïMuÜ¥gÖ­ÓwvÔ•Ó´Ì«èøÆË<;Æóàœ¿JÌŸ'5Ú÷æE½n>?¶m{Qí uÚà»g·bÕÞ¤?4•€;?¯ €@F 4éØ7ifQ¹ª×øZV¹V‡Ï7ke |Å*#Ù P<ã1½Þõº¾Þ¥æ†³Ú·ÙúÓ7ô혺 ô¯'’?c$˜i.Ф¯ªðžï°£îûšåûÚ\þ°ðð†åó䇰Gd»@©–ì;«Ó§ßÔ›gôäüi Å“«ô§÷„Ïmÿ©Ns§?ìÁ˜¿J*ôüéš?mŒ§‘W:Cëj_“7×ýÐ>½‘ä?YXÃÝ»< €"<§MNÒߌv™ÿõl=ðm}¥jšøàÏëÌ0H€@aéDÍ_¹M‡[ÞÕ½kB3Ò^üÙ)ó ™Y h&@ ešÞÐnßýüÿ²A¯×59FT£ø-2÷ZçK4ù‰ëQÌ–bô0f>N"€¤…@£v. ¶¯ÝqXO<6¯Ç_lÓbht_Àwƒ®rm­~ö̘7åî^¸Hrîƒß jDôˆü3v÷Æq‡pÈ<ÑžPñ'úöº¸ÙH@,Cë²çåÅ G©¤$K0&ôI xÒ]öìu'–§L‘>2ÛÜ­«˜y'ïПŽ÷ 7ô-Ó €À  ß¹RKw»Õ.Óá³›5‡º ì@ Z ù‚~åüNzè§gÕôŒbÞœkþàb¸¤o©ˆðIŽ@ «ŠÆëKVëÖ©¨¨û’1ÍxMÏí}¸TÖ¬ÖÜ Ró“bÞÐË*7‹@– XZ.qžý°ºö¬¾³pbw‘–SzÕ‹ªÓÈî1ÝËp2[ ßw£¿öœÌ¯1¾1רÿs(l·¾“Ì€{2õiLàýÀ‹¶WëpÃ6Í+̨ 2N è&Ýaeÿ][·J?:¶DËgEpœÓw—­ñ†^u—Y‚ ²[ ¯L‹×}G‹ã(Oìôî?¹QËg°D*N#µÏ=W«§®TxæÅ‘íë¼çChõgtQ«¬ýaàx…w¨Æ3;: Ÿef zhnoõò´¶›µÝY€Ùóàl(žþIó›„ôœ…ph•Æ.iÑkߪÑ̉c¥¦óúŸß]¥/®·§ØL{–?È7cl þA Û õÙÇwHÛ—ÚÛ™.½·Oß\z¿ÆµëÍŸïPÍ‚UÒ†¿[Úífž—˜ ƒ@—ÙÔÍ\—@“v.*ÑRûÿ=Õ:zåEÍJòÝšë…@`КŽmQÉìðÿdzo R¯]9¨9|–ôNE2YÀ|;æ©Ù·i£T?ØGôX·ðñó“‚Ù)à_6b³ùÜXÉçFvþ 0jb\:²Ecçöþ7KÍÖ×´kùœ5p ²Uàȶ%š»Â[C7&C…y.Õó\ªdÏ+̉Ù;N¦¸Ñ±¿@t¤û½HY¹|+¡%¥Ï4Š) `f¹?sô¼ö¬­ŽÛ™Šê zíl3Áö¸B$ €@<ûO†ód§À˜9+Õðæ>­6Ï6Œ½UkÇá³Ûcãp¬˜³|—Nتxk÷¼¦£)l·.3ܳúG•Á#€ €a¦úúmÝI5¶¨  M*(Õ¤iwjZËÈ„•8B@Áh4¿wœm#€ € € € €dŒ÷Œ¹” @@@@@ ™Ü“©OÛ € € € € €#@À=c.%A@@@@H¦÷dêÓ6 € € € € €@ÆpϘKÉ@@@@@@’)@À=™ú´ € € € € 1Ü3æR2@@@@@d pO¦>m#€ € € € €dŒ÷Œ¹” @@@@@ ™Ü“©OÛ € € € € €#@À=c.%A@@@@H¦÷dêÓ6 € € € € €@ÆpϘKÉ@@@@@@’)@À=™ú´ € € € € 1Ü3æR2@@@@@d pO¦>m#€ € € € €dŒ@^ÆŒ„ € € âÁÆzùÀ車‚~õ´­­M£î¼OUÓÆ¨ñÄAÕþï·Õª4ÿ/ÒÄÂ~U•F™ƒ:¾ÿGúÕ¹&¾ëszhNYõ®"€ €d«@ ËlÙ:xÆ € €@"šŽmQÉìUk²r«®\®S[ª4{Õ!SG¥^»rPsŠV]Ê—j:¦ª’Ù²GúìQ|rVÊw™"€ € À’2ü € € (üaoér«‚¦tþ°r§Žå¼¶Ô/iç4cgñ§þe ‡ € €ý`I™þy‘@@ ÏøŠ.~Þœ{•äêÊoþI·=°Æ>U¹á€~²úc ¶XáuÿV¨RóöþS#€ € €@J pO©ËAg@@2[ O¥cÆtbñ˜‘Þ¹’‘7ª´Ø„Öû°TL»W*3š2sXŒ @@ ƒXR&ƒ/.CC@HÎÇi¸udï&-ªš©@ `^3Uµh¹¶½tL-C¿¤—¶mÒÓO?­¯Ô+ØxL›–/ÒL«Ì’Šl/éàÎMZ¾h‘ªfÎÔLó²êܲ÷ .EVÙ‰W´å©åv™P_šYµHOmÙ«ãõ-D”k:÷Š6=¾Ä”«RU•y™¶6í=¢Æö|‹Èé{cú¸çÓZ4Ósøµèñ-:VßC'}Upˆ € €ÀPðÐÔ¡P¥N@@ú!Ðt|›J*VØ%ª7Õ‹+ã? ôø¶%ªX±»×Ú+Ÿ=l4:/”¯éˆyé\û¤ª¨TEÝ!Õ¹5˜‡±6˜‡±ZËÕë_ÑÒò{¿öjí;ý¯š?9rQõ#[–hîªø¥¬¦6ì;«uó'º­Úûs7i’³”NDBÔ›“Æ#Z2jn}”6>«•ó"ÛŠª’· € € ‰3܇„•J@@Hœ@å² Ú±g«VW‡Û<´ækÚ_ײַŸï=€TV°½"œO%ÎqËñ¨`{µžÝñ¼j÷lV¸ÚZ-¸í¯uÌ7a=xfoD°½zíVí;|Xûžßªe•ávÖ/ø†Žû&Ÿ7ßl¯¨Ñ³[·jƒ¿P¸¸ÛI½ô·á`{EõZí©= ûž×†šð VÝ»JG|}ìV '@@"Öp"XªE@@`è*õü›?ÑCÓ¬ùéf[üª|êÓªÞxȼ©Ó¯O\Ôü²2;ÉýÇ K×ÕÕhß›ÿMó§…ד?²e7k¼bõýüïkŒó×ÂÂ/UkËC“´ªÖªe·6ì}R/.ŸaWyú•}öÞúgmíi=³p²ó~žæ?´X÷-ÿ„ÙnͧoÒ5kí{r|“ö®[êä“*×Öªö™…βõËõ•šm*¿74ãßËd´¼¡ç·;g*žÕ/^|Òž™o©šÿ¼Ûi_«#§5g–ãâa‡ € €ÀP 0Ã}¨…©@@!X¶çûá`»ÝF¡|ôQ¯µC¿»à»uªPíùÁvOèkìhºÉ¶L?ôÛíryµr×kÞL÷Ú2«Ç‡¶Ñ“ï65ZÛ2}ùA7ØJ³žü:ëãá™çùÎéà¹CúžÛœ œÿÐ ¶‡2”Í[®º­áyõnm2{oâzÝ;ú£oƼ•gΗ¿¦ k×jíÚ š:²È+Æ € €‰`†{¢¤i@@A¨TÍ‚è·ÔÞÞêµRâù–­Óƒe‘´œ>&w⸪g©$ؤÆ&g9§hQÞMºÃÛqòCu²i¥æKcæ­Ôë]+C¹‚A556ªéÊe]¸pIÏüF›–îö5:l|û„·†ü²u_Pxž}8ëŒÏ¯TåŠÚкóî频¾©>§Š¢×µvë_iÁ=st礉*3Gëž™ãæf € €@Â"ÓNxó4ˆ € €(шü6_=ëöЪ.¾FÛ¯½~W»BåE1–s ç°ÜÙêÖ›¦3¯èŸ6ýW­ÙîN[Êõö¿Ùï™uûXï8â øÆðºónBÞd=µoƒ¶/Xïœ9¤+ÌËyWQ¹L_ùj¾üÙyc/]ãd € €@bXR&1δ‚ € €@j´Z ©GnEîô–‹‰L‰÷º‹½Õܤ’Ûîl¯¬©q–›‰¬çÖÊ¿òη¶GΤÌÙýÝÄùëÔpú°žõ?!ÖÉVwh»V}ñ^-Z¤ƒ—úWo÷–8ƒ € €@ÿ¸÷ߌ € €d”@ó~Z*ÆŒªúÙúÒ|E Ý^Wš›Õl¿^Öl³œŒ‚gôw¬ñ,*WoÖáºÓºØpEÍí]:¸k—^سÌKwÞ:ô#oI÷\¬½·^{Tbéäyzò;/ªËôóü飪ݳY««ÃkÅ[ ß<ð—EÈ= Ž· € €C.0€/¡yŸh@@(?²Ìk­öø”_8OÅÝ–diÒþ-¯_`²Ž¼[O¬œ/]<¥SnÉšªýÎcæ1©‘[ý½^­sªÌqhù™ú;­œ5ÏKsýsï&€{.XÿŠ6~wŸšu£|ío4¯¬Xe“gi¡õZ¼Rμ¤êÛªC뾟zÇ~Àj©[˜= € € `†{i@@T(œ|·V»Üýˆ^8Ñâ¾óöGvhÁªõZ¿Þ¼~Ý:_­ ¾äº?~ÊS:KÛ®ÔiCuDçM¥¶>¿G^µÞ8¤yë~¢}}¬S3«Ý.\¹ZNתjL¬z9‡ € €ÀÐ ºÌ6´MP; € €¤“@°±^u¿;¡‹WÛTP0B7–•éÖI“UÚíAªáQ5ž;®ß¹¤öü|¸qŒ¦N™ÎlÔ™sfÝ÷¼"7Öœ‡ìÍ¢5ª?Q§g/Ê´¦Òò‰ºcºYÞŸ%ÜŒwl<§£¿y]h°úX`—ýèÔ UL+óÝð²s€ € €@B¸'„™F@@@@@2]€%e2ý 3>@@@@@„pO3 € € € € €dº÷L¿ÂŒ@@@@@ !ÜÂL# € € € € €™.@À=Ó¯0ãC@@@@Hˆ÷„0Ó € € € € €@¦ pÏô+Ìø@@@@@"@À=!Ì4‚ € € € € éÜ3ý 3>@@@@@„pO3 € € € € €dº÷L¿ÂŒ@@@@@ !ÿ¡o("¼ª\"IEND®B`‚concurrent-ruby-1.0.5/doc/images/tvar/implementation-scalability (1).png000066400000000000000000003572501305460430400261520ustar00rootroot00000000000000‰PNG  IHDRÜ„»8óÄ/iCCPICC Profile(c``2ptqre``ÈÍ+) rwRˆˆŒR`¿ÀÀÁÀÍ Ì`Ì`˜\\ààÃyùy© |»ÆÀ¹¬ 2 UŽ +¹ ¨¨ê¥¤'300ÙÙå%@qÆ9@¶HR6˜½Ä. rвùÒ!ì+ v„ýÄ.z¨æ H}:˜ÍÄb'AØ2 vIjÈ^çü‚Ê¢ÌôŒ#Ç”ü¤T…àÊâ’ÔÜbϼäü¢‚ü¢Ä’Ô Zˆû@º! A!¦ahii¡ ¥"ŠˆqŸÁáË(v!†°(¹´¨ Êcd2f` ÄG˜1G‚Á)Ë„˜I/Ãþ©15C}†}sïPoì%¬´ pHYs.#.#x¥?v@IDATxìXT×÷¿v!¢ $h5yq»j1Y̆±ÕõÕ¤Á:˜femßV›V±•¦ßlÅÝm(nµo±«…´«ð¤)˜Mq#¸µØÔ±›BÓ-&)<R‡4P…MaSh eÚ€až½ï¹3sï=wþ13 Šú½>8çÞ{ÎïüÎçü¹çþιçÌPÄ$@$@$@$@$@$@$@$@$@$@$@“"ð¾I…f`           7ÜYH€H€H€H€H€H€H€H€H€H€H hpDŠ           ÜYH€H€H€H€H€H€H€H€H€H€H hpDŠ           ÜYH€H€H€H€H€H€H€H€H€H€H hpDŠ           ÜYH€H€H€H€H€H€H€H€H€H€H hpDŠ           ÜYH€H€H€H€H€H€H€H€H€H€H hpDŠ           ÜYH€H€H€H€H€H€H€H€H€H€H hpDŠ           ÜYH€H€H€H€H€H€H€H€H€H€H hpDŠ           ÜYH€H€H€H€H€H€H€H€H€H€H hpDŠ           ÜYH€H€H€H€H€H€H€H€H€H€H hpDŠ           ÜYH€H€H€H€H€H€H€H€H€H€H hpDŠ           ÜYH€H€H€H€H€H€H€H€H€H€H hpDŠ           ÜYH€H€H€H€H€H€H€H€H€H€H hpDŠ           ÜYH€H€H€H€H€H€H€H€H€H€H hpDŠ           ÜYH€H€H€H€H€H€H€H€H€H€H hpDŠ           ÜYH€H€H€H€H€H€H€H€H€H€H hpDŠ           8"  ˆ'Úê¾ãÕÏáHU#¬ùEX}é^YŒ ë7ÁöÉ X•:/E)CÕ¯oþé=ÜòÁû°~yJ”r<ÁºÏžÂKo¼ƒ™s?„Oo^…„0¥9{[ðãso ßspߦL¤¸ŸBu ì7̈®º7:ëªPQ]wg eþr ¾±o#Cè5Ø~?ûõïpÓM7ôõÞŸþÜrîùÛ•HK &)0KM k¸UOU þ»PÕÚð/ßÀÆ4UVäúj2¯ë_g/ê~|y$Wð§!Q§RÓ‘qo:’¯z¯Ê‰–ºã­!àƒk?Žå)áÖÌrÑÙ3?~ ¢ â½÷n‡ÿn=RƒÇÄÒkcýhø¯W!²5&íwˆ˜¢¾åìmCã¹7ñž©mZFHàÚ~^F˜Øéä=hÝÏâÑç•6È#ÝŠ÷Äÿ·ß¾©w݉”䨵×ÑöѦZC—Ðýßáîl€ýg¿ÁeÜ‚õŸÛŒ…±CkDr=¹ÆD_ç¿D_GMÓ-ÄÇ×/دw ¶ãôO~›nhëoǺHÄAï'ïÝ‚û>¾wG"Ïç@Qó L'3qL'…¨ \kÆz°{Ñ:@qKn)ž/Ý…Ô«Ññw¶ 3i5…Ž–âfœbÕÚ†º=Œ²es°Û¡ +ÅÐù];ÜD´•ebÅnU +šG°J5ÔÑ- _áÝåìGW߈pÅcÁ’T$^u#§PÅt¸P·w²©€¼‡UpjÅÉ)˜&y˜jaBüZóËñLQž¿¡3KU”«¿+dAÒ ¥­Cص<1 }C(7-o¹0ØÝ…wÆE©IZ€Ô fåmeHZ±Û|1è™Õ­'±uùUX“ò¿¸yO¬ ø*4áÜè>±K¶Ué^skºP±9U?§#8hÛ.¹N¾ý®ßdîk¯'#óÚ]›:ÍÁe’hrSu7hÝ”Úâpã¶æ–£²4/ÆáèûháêzEýI,Ííß•ªch(+Då¯ÞÅûg«SBï¾û{Ì]ž‹¢¼ ¸»§c(Ùý¯èžý~÷D‡@¡Õ0ù±Á¾Íi¦Û®á^4ÕŸ#èÄ{¿À¢¿]+&\{‰Ù=«`;â@yëòDß.ÜÃÕ{ñ‹l^ïRÿÜG@÷‰<ñü7Þvì}ãØè™9cò9xöæ¯Ùï½Vˆ>å &œæE>›"å LCÓÎL1 Q% N`¬ c»a~¦äì\XÓ…êÝ8uè¨nàtÝ%g Ãk^ØêàGx'^§½A'ÄGØ×{’‹kªåvîLÏ …¯—HÎ#ÔÍQ™í5Ú[„Ñþ¼ÇhI|Sí×Õ…HÆv‹ÕŠÅËÞ?!'iú5Ù‰%GjQßó]d™º5W HÈG×O —E1R«u1’âE7 J}eÙÓÞítàá%+"pŠŸAÒ±mÅ|ü¾y»V]%£»T—&]ͦ|ß/–[;àèÓ/àë›C &tC^Œºí’ÊáäÛï©A?S{Â$ù´Z¸ ¸þLýšõ!¶íÑ8.ž>ññjø‡u%¾( îî!ïÑAÔ­r÷?B °þÍì“ÃØn-DkÕ~Ó2ûоކ§¿„u»½ÔÆx²n=®_x…5Ñ-ÞðUT&}V(3w˜íÁ~ ók¼H-žž†Ñwñ;-5Ù•xùøŽKÉh^åßâúìZ9£.—ûr\\œ˜Ù߇³§æ•%رnÑ£h9ýÝ*ñ.|µ¦ŸKÍYz‡,ãN]+”;^Fžö2圼¾¦ˆ¦ã‰(kš90Zƒ¥­¸ §ž¸®1Ož¨ÉubàR+žÊÉ‚˜Tæ>vþ'¶‡üšÁãïZü¬û'(?‘PÑø,Îö>†“³]‹8"ÖyÚ·]§ˆ‚ˆA›ã';„Ì`ÏK?¼på ˆ/Üz치ã‹·™×Èoñ³“%ØRàÈl,ÀsM9Ø—y•mÍêM³`ýšõ!¶ŠÇ#ñNanô}øI±XÄ}‡|ߘŒâüíº±Ý¢ú tˆ° fŠyg{…ÉØnËÎÆ¥ª*÷¤‰#9«1뎟÷ˆaüÇ—rÜ¡K>±"ÄÚÍV‘ϨÂË­=¢˜®©ãù{µæñvùÉk8$ îæ9÷Ãbi;»výZó¬}ý†¯ãªç³¯B<' É Á}ò )Hà†% :•§µN¥UtD c»Œ¸ddîª@ëÌw±b§§§úÆ…w€Ôàžœšâ/œ#˜_cBY"âg…#é ûIœ­ØmëVëîH´H¸mÍ/1‰iØ(ÊÒõcø¤e‹÷® ÿüíÇÑ /”ŒŒÍ[ˆðì™·{UÈÆG5c»z%úF’¶«â7Aú \z©H—„›ÅŒ2ñ/Áè:%$$ 1y=×Ö¢A[®§±œ»¦ß—%6°çs'þ=À ¾cwˆ²¹<À=^’ Lû¶KV–îɈE›ã«A™Áž—¾"x~$ÍÄœDñ¬0?Ñ=Š$'cóÇQû‡>± ÇØÙøú[4¸›²)H¿&D}ƒ‹•ä&y$`kÅylý–.“̇:„"®9Û°=i…wŽ õUè}?çà€7ˆ G_>FßÀ‰ïïÛé cÉGóK‡°jž0i?ý/(Ù¾âµãPÁI<¾þ ݰ>xöìT_GÄ$œ(—’K[»^ð”Áªúv<³#ÝTbo¼ìNŸ:dàZPG‚‹¥›‘.ÔÓç%ˆí ¼‡ ÷ÞîàÑäòY‹‘¿$@$0¼o:)C]H€HàÚ"ˆoÊö¨lÝ„U¾Æv)1–õÚÚˆ€ý\'Ƥ{ªsLl&Z’· 3fÌÐÿ–enGɉ³öñë>u ŠÙÎeÈ.ÓÂ,[†My{q¢¡Î@aB\ì<‹²½yÈ24–enÂÞ²hï!mA"ÆÄFœ"¬®‡ÐgS^ Îvû‡S7²ª¨¨@YÅ)ôúBðÑÏׯz^VR‚=ì¸P»üß9T‚Žá×oµ¡â@ J@E]·$ï©«ÇÄý!C Ó=Aüš× ½g»ÎÅÍgY&öVœA¿ŒÞ–:Áâ1ý«‡KõÏáØ± TœhñËsM~à_õ%.𑜾'›Šõ›O¡MG=Œ†"¾Š2œ:ÛëöãnÇ)¡Ã?åx¿²Üž+;†Š² œ:}&<}Eyk8V"ÊÛ&wY&ÊIæ¦<”hÀ 5Òáö3î¼8Prý®1´*Á&wÙZ†cíº²nýE¾–ìÉæLQ–…Ÿe‚mÞÞ24tºï›ÿÄ™25ÿDùêwÁ7<åÖ[6=c\h?s öþ«‘'µße@”“† åÄaxg)«ðˆ˜ꈬŽEšÎP1k÷\"Êp@”5ýÊê"+“.±áî~í-ºŽŽ±0‘ç°ïõY‹&à¯ØÌÕ]ŒömÆŒeؾGm'¶p‘·‰"5mg*°=SŽc2·ïÅ™¶~­D{pBpPÛŒ-gOˆ²&üT4H¬"Ï›PmW¸íÔ+š." gû1&Úª2ÑVyꂨKâRQ×é *6Å;S¶WÔ3µŽyêÙvQÏZ|âî†SîöãØ©6Œ‰ !Õ0ÆsA*ÜχPý£Þñ<ÕúZ ÁZýaÔU¨Ïñ¬zû>É»%þm¯+žñîg”hw=½ß~ÍÄõÁ@x»X7]LŽ9!ú ¢íóôoÕ[#DP—Ÿ±]õ©à8ñ˜flJ›ŸA¦´®ù;½Ë«XVà‰A¥K7âqÇ Ï;Cañ=Ævõ®˜tñ ½}?Ç«xKïJõ£üñwøêÿ÷iÝÐ/ Ë9ïž{ÅîJÞ£êgèñ醾ñRƒû¦C<ùss…~n«ûQ¼zQWÄ}ßÙsN|é=¬™¸'Ù㞸_8‰|ްêÖ(æm•–hþ’ €D@Ý4• @4F±œ¸"šT÷_ió@!£JW‡C鎎>e\òÙU[¬ËÐd™ •®Q)À@“"Ìü¡ÃX‹•9’ÑV=Œ­´U¦(Í¥Ù¡e‰¸Šj{¤0"ݶ â÷êWXÓ!…S”ÖR«7.«Ò<â½D7_¿ÍÅ– zZ•†Ÿ—÷,ÅJ œj.5üت©II餧^ ¹U©éÐ2¤”Z‚p±”*C’\§™©ØÌÔß‹éJR(éSÚêÕa¤Y/LîtZ‹=ù<Ò¼|m\2±¾ã}•7›Rk* r>C±ÚÌùf¤m\i*]ö¬Eµæ|’ÒgÉÍU„Á×ÈS“ÛªÔ÷‰ ù7×)(bó5Ñ@'#£\ùÖ“ÿ¡&;«tÈuOxŒ¸ŽIz‡•NM©.œ=7}u(Ù^iß&£Y‹TvCŠXóUç_îÐêÆííRŠ­†?ß|PÏ í]¦@·‰ã=Jém’µÐ®˜4iU„ÉÀ[W•…¥TÓÛ*Õß(ò&TÛ¥·ƒ&æ“ åPÒ%Wíš­°HÉ–òJ»îùue@+°!Ú0Sý‚"–½2)éÐë²MÑš#‡ÉÕs³®ær~º4U#×E~åf›Û2Y7KQ½ç¹"Oä6Ç·>ʲ4·þÜ C¦¬§©LEU7ŒçHDíÏP³ÞÏÐÒàû[Úd.7ZÎü½’ºT`â‹Aë¦ÔÃZnn{ˆi5úV©ÖZjó¶±RŸI /‡3Ú|sÂ7äs£6¢”kí¨ëEM{QF›(üTê}I!·s@)ÖÛ‹Rk%Ú)äÛMýae Þx®k÷¤òïî×HçrZT·VÇŒöÈÜføú·7ù*ñy=_Z‹|å*5¹ÞvÃViNkИD˜|O˜ÂÚ>“¯‘fí9lÓûÐ=5žø-ùµaÊ7‰”NLyScê×Iy*úØ]v=Ÿ|ûFb¯‡|Ïh£‚ô ¥| 7ŸUå£é£*±n«$Št’ €Lò Ý$@$@‘ð©±å+µÍÊÀH8æ\al5 zî—[¡Ri·+Õ¥F^½nÕƒjç]~°)¥5µJS}­R^”«wrÕ0¶r‡‘éåOîwU›Ã–+µMMJmM¹’+¿![qèIòO·_nq¹R£†Ó_´ÆË†ØAW蜯ä×NðÂmfj¼8›u’ÏŒq(ù5^ƒe–êËHQ~¾·Âü/*_Ù÷O¡õuøPlJqeb¯.Õ•jÞ‹ï˜MF6OÞ¼=~<åAK›üRæ.¯¢îÔˆ²_Z¨<þmåÒ‘”>C¦U),*R óÍåê˧0ö–Š´Š<ÑóÞ<)õ1òÊl5wPcŠæA¼Þõ4+ER]±ø¼ÀGUÇ"M§¦Nã,^G•&Ó šE©vL4 £ Ô~G•jip±ºÃÓuT: ë5ÏÒïRn2„[”ÂÒJÅn¯Tò%fb«ioЦMuGÒMl¬W×*­­ÍJu±¹Lí¨PQb%·‰†òR” fR¸°Ê ºí2b æ ZébÉVŠËË•|wO]òÔ³"¥¸(ߨjýÍÕŒ^RšÝõZ çɳêÊR?£½l1ʂԶ‹ŬžO*]²Ñèb¤Ë`hÍ.TÊ+ý»Ÿ;a´9· aÈ4ô”ùO¾n„[ÆE…RÄ2åú3Ó"ú2Õöz¥¾¶F)2 T†Â`åÝsýJêZ“Pwê›ÂÐjìóhn'õç¹ð8_ rüF›¨OÜGë«/ÒóÏÏ®FÙWk´A&6hšz ã}½d4FUm ÓS¶ yf@ÒAï§I휻­Ž¨>eÒš[¤TVûÖ[1  ÎG{푞|¥ËO”ÈÐÚbч¬©ƒŸ6›bµZÅŸMÉ-,Uš:L#B©.Y •Vm@TM·ö¬³)nªãJ®»­VN£M„®¹ØèÉåP0òÞR¨*ô“>Ä€´µ¹¯P.¾zÊDˆ~aù¬DÕG•ø v“o« ~t‘ €/Ü}‰ðœH€" 0ÚUc¼ è Oß":ÓùE¥Š½¾Yéôº%^²$£“­Ô<ËrTÌ Ñf+b–»Ú‘—;—¢#nš€"ntt“É·#ëMc‡4Åw–©¦Tk3s ¿$û¼ÌYò•fí…À-w@©Ôà ¹5ú,eã%L2 Ñ- _!ßÐY H/7†(Ù•o ½?úK‰š7¹ÒàÙ›q&½$‰|µ•6ùÌê3ͨ5Í’7ŒÔ¦ACx—™©ñâÀ«÷Rk¹ñb¤çu–j`Ü”úÊ/_–üjÅ”Í>³å´Êy¡¾Tg—֚Ê—T£l[”òfé…\èÚS¯ÍâRóKóµÁ)}î—õÜJéEO̹n–°´R5ñ!Ò¨ÞvÈÆ w|â%YlzfüùÔyÊñâé‘jp÷ŸÉ´ŽE›N)œç«al—^ UãiuÐY‰Á(ˆëbÖ¡ž_’¡e¼Gnÿüë•<ûRÍGó¤IñÒ[¨}ñ"ìªÙ%ò6Ñ­Eò,þ!©ýVë‘øGhÆ3=Oõs;¤¶•æmFô™—îú Í@ªu^jÛcTÏ'Ÿ.¡`”ºéRZ”JÓ—!J¹dL6ÍF Ñæå ‚6AÍï2 = þ±¨a·³rYm„ïž<£?œçÛÕ]eå^Ý}¤®¥««Ëç¯Ci®­ô™Ü ¾ÒžwB§@ù*«*Çopõ©ÇáöÑä<4M²ðÄØUm `fWvÈjø¹G;Œ ê×Úa~&xê”»oA:·™Únµ¹’Ÿ[¢š+Má<ÏKñ5¡÷Ë"«ÏûCXêð$Ç+Ϙï«-íŸÊÒøúÁÈ+ÉØoêkšˆá‘¡ÊñëF‘ÏQõQ¥xƒ¶*F^" ×p-> ˆ–@Bêf uÔBÌÖô;vÙ¿êÆ™Kæ'aÙ¦½b]êaÝßX§;½§Öb<½k•~Ou$¤nÄùÚ¥Ð?ª^œ‹ûÅÚê‘»ç3H•7*×—¤Ã»ª¼ÛÏDÿÍM]é]‡9Ÿy0ÕÇ{"–ßë‰K½ïsW;­~^ÝÐIÞHjv|ã(ĬÏq´ çÍKI³ÇÐR¶kô<´¢¦ãelM kYIÐù““F~íÉÒ™Ç-ü(Är1Þã(NŸ“WëÃïÖn¢¨¾rf‰íØ6>®7ph8ÿ6"oÕ8vq4ý›ˆCn‹€”Œ]F ¯ŸFTÕÇpíþHÊ Ð hÔS0G>žÙ·QZ¿7ÙÔ~gW>ÍéÞÅtE4q)kñY­®¼óÇ€û~7} Ë "T"6ªÔÛ=ù!ÚöØÔóؤ+ºäVŸÄŽUr!ž‡Ï=ñ˜žiÍÞÖÝAÛUá#ê6!¢v,Vu#ÌöG<êô¢àøoüÖXÔÞÍdÕgGQa! ‹p×­ív~…u7rmŠ\G°zÉ",Y²Äço)Vgåà¨ö0±×T ͧ_7Y¥Âî£%X°-_ëóU¡ÖÔžã¥×{QØöà’j%,É€Öº;NýBï]|Ù³¸ØÆó}ÞÓ^¼tȽ08`Û„»MmBw…Yr«ŸÁæ4YXüìgu1¯KõV¿:±c¬û{È:âÕ×ZŽGÍ8€ñwõz¡‘_f¢¨(ßX/]ø´ï·áþ›äU»Ða/Ò•°‹~´7&ä–7ãÉ Åf9gñÏ;«„Ÿl|#Gzû按?­OªK™Ø‘|÷*½Oç8ržœqá?~Á؆½› ¦gmö^kÄK­ž}P\½¯ë}mñòƒ;ƒt7õ ƒj,Ÿ£í£Æ´­ ª5o €› î,$@$0IÉiëq¸AÁPµÕå(ÌÍÖ ¿²h‡ýÖ-ƒŠ6ñpܰ¾ˆw‹hÏÕµ{»„q¯Cü=¹ßQSwü¼úu*v¤Ã5æÄà`?:ÛÛp¶¡e_Ü­o)ÇÌ=O£Î YŠRô8œÃƒèïíD[ËYÔ(Ãc9jg>Äa-E–¯Õ_õž¸;õ·àÆú’ú%Ä¥dà1Íø×ø,~Þk¼m¼vêY]Þc›Wêî`ŽñqÝt€Ü‚ºÑä?ñN¬Ó V¸„ßKÆ“¿):þcÔ’enÁ„ŒuµI/NË‘ärbxxØô7†÷ãnM@c.Ø´«(xd­îö8„!¸V{q²VÏïšå;…d‹. -—|dˆùº¥ŸGšÙ¶*ü˜8ÂI§Ÿà ÄgÇËH ¼\ú+-õ]/b±CX³hêĆ®Ú1Ù:m:s–ÎÇêÝvM 5Û…Ñ!ÈÛ¯î+ClÌY¬å—0ÈlH—<ÍÃÆÏjÆl`¿ØhͰ³ã=½<ذá¾-\ʃ{[ C b<ÿÈ݈¼M”ãÈÅ–{ec¨¡æÝ÷ݯŸü®?úz£ ñ:¢Í5x,˦*ÏZüiø™JÜ¿bêM:¤ºbÚ€OóbÃ+ðL¸6±†ÁÄGŒêyLÒ ]løüCi~É–("Éïnà “mKõ½›ºvŸu+n×U8Ë,ucñ8ÛÞa§hç­Â¾ƒqðà>¬ÔgÐêŽ+¬»)î«{òÊÏ;c«@D}´8|dû#züÕÏ·Šm‚½Ç` žÖl{ðiSPÍ‹éW ÈÿÖtÔ¡Ý=ëĹÏ3Éš_±l¡ûhhìðÄÓšY7ûS«¥ÁC“äO¬ÈÎòmE “Çpë­9â1üWÉ6ýRé7>…dýÌp8/þLß@Ôa+†øÀ Çľ}‡Ñ Œ ¾ÔhLû×á”ÔoMÛ¸ãC]¨·× ººÕ5µpô "o•{HÃS_q„çVÿ –«vuݽÛ1#~fÍñ3Ä&×èԟÆ^A]‰w!KïÒ4¢CÍ7W^ÐlYú@ȼ{Öêƒ/üØ3Ð÷«WtÑÙ›VÍCÿ~¡,lGÔ}Ô˜¶Ua«K$@7(¿WÕ”“M$@“&¼0ëÕ¿­y8XQ‰áÁ>\höÊbªÒæ¦;WáñÃx÷ÕZ=λïºCwËŽ„y©H÷³y8qöÄ·ñÍâØ ±r°ˆÜÎî³øvÉ7QpÔ0Î…- i¦ÏÌo-d,Sçó¨ ^ÂoÅ ÷òÄ©~ä$ãÇÄœªÆ#îxk»°q‡0ˆY0'µYS(Äz÷›‰¦gàß)o–§ûª´0ñ˜³XKcì hZ,Á~߾ЪßJLеùN¼¾û{]>ì;±`ÖNã<ˆË_‹l¤-Hðñ-S€mÂ0Í‘s“eh-g}yb+Ðqð(±-EÛ á@ÖWOc´b³˜Ãí9&SÇb•ÎÆ_AáªõAêk Ty®u¾€½i{ S (¾ã¹9w.bÖ¿~}ç¾¾ªåa¬G ¼w¬÷á †îYu$ 5Í`ÚþÃÛıv#Ûr,ÒÄÄ%Íu‚êÉ0éýI¬ò&z ŒI þµÏ¸ \×MgòeÝíZVɳ¿¾73.ÝmûP°¶=Fõ<&éŠ.~Œtz‘;&Ó&„›\ÿ&Q7Â.ãq©Ø[[„£Yû½ê5âø„ï÷ÌbÍÅ#eã3ÏÀ¼€åJJÕ•Ö]Š:Rgù<,MÔ.€ãÈÑ+ò°[L¼ÐŽu«ïÔœ>¿ú…>^Â8º˶* =é…HàÆ&Àî7vþ3õ$@“ à3Á[ÚÚÄlð6ôû3âêù4ÒåJµ SY7BT€äÔ éo\ç¿ßЃýÒl¢F'.M2r#|¢G(=ç^–OýÝQôÑ–mü‚.§Úþ:\Î_ËɈ%—…5SZˆPg@{ìÂhz6þìç^¹›a2æ­Xã}f:pîgxå±ÖR”ÖÄ]É+íÏÅ£ús1›×¦„ÐÀ—Ký î%>>x?:P(gû`›Ú…²–bg¦÷0.6zØÙŠ›Q±k#RS"sÇAtUç{Dˆ¯ºŒõÞ‰Õ¯%Þ¹B°×~ßù^³÷^>2|Œèw~T3΋Á”Šç w‰s?†EÁºÎzL“sL¶“¶jrI`h € î7@&3‰$@SCà÷nÓ7þüMÝØáÂ{Ú”Wá!IÌø^°â~Ýë³/¾¦»eÇKûç`þüùâo-ΉeY~õŠÖñµ ºãGص9Ct¬ç!1ÁkÑk°÷ÉB¸]qQ»Ÿ] ûá]ÈHOżäD$x;Êý¿Õ}h>Í¿özžŒÕ‹ïê›5 +l,¿Å×5dÝMÀÇrм>øá÷¾û)¯©Ml~ú± ׎õ]$åÍé—Œj=jÕá¼€ZÍŠ‡Åx`‹¢)HlN†q¬ Kÿôùb³Ø)Ј¿Õx‰´·¿…ø„D$''ûüÅá•£OâÉ'ÅßÑŸ†6¢è‰Ÿ…”;5Œ¿™…D?¹É˜5ð ž,rÅßOû¤Ê£Ë™^W0Nk*\v³ˆIÓdFø[Úú ÷2Ni[¿­Fˆïûñè¿ [Òà«§uüs÷áà®<äíÚ…]ò_^žxò€þ‚ŽÆ§qV]‡6a–{-h<×äýT5 ú_Âwû6k¿}>ò6q\ŠÃ^‹_k‚Í¿òF}ËÝj¾©žÍ Ð@þ9ì¶Ô_àDWµ]…¹Â÷źîojvuSÔ½°ë{„JÇtªçÓG—+Ö&Èõo2uÔ÷ÁO\ýgq`ï^ìÝ[‚³êây‘’º·îÂáÓç1Òe׿>ÃÅÿ6¾~ $ò ëHýšd ]|ëlý²æˆŸiÔÉ|i6ûÖšÈ ¿"žÍ”1±!H°(úh ikQä}D;^xß;ñ¼Þß(Êþ¨¾TZ¥Ëbô¦lÏyÕnØvªVb1t[øÏžEó,Øìgÿö{lÆbCÖ{A9QD~DÛGi[¹Ú A$pƒ ÁýËp&—H vçý¥.¬±`µ¾ª~QrŒuÿG´M‡ÄB1#9ñŽ;õPÇþ2ñ™µ@uŸE¹þÕêüU¢ÿ­®9wÜîkeu¡á©oêÞ€F$9 ±éçÃÞ]«¬w¥ë2zý¸úëðÏ¢ÔâJà—=ˆ×Ž¢o·ÈRÝîî3ú策œحGjŠ© 6{NæÝ·ÉcüoGvnƒ¶|{v°ÍOȘ5w¡wæ•XŸ²àÎ0äµxJŸn-þR}^Dˆ ûRÒlã%Þh¬Çö¬…±—­öü¿x]n“Ì ' ©+ÏÜ«¶áùNÿéQÃ-•ÈÚ½û÷‹¿sCA$ù^NÀÊ ™úÅœ}^ÚhS»<Œÿø§,ì?$䊿·ÇX4¯‘þ2®†!#1)ø‹°³·ÿðð6]ŠÅzçó˜Ô1]l„aôr ‘ï(×Ã6¬Á±°vQÃO*µõ˜bah zÄ-Åmƒ§íG$ ä÷{1ž~á—¦`¿ýÍ;ÞóŸu–éVˆ“,ÏRÍèÞ¯«ðïþÖ?­qK°!Wë[îÇV. !·¤|޶Û¶jiaP ‚ î7D63‘$@SA !í°K+®ì\1ye§ÐÖÝa1Ó\]&¡¿» §Êö`Ö›a¼ŸäÞ­ÚÊçeâËÚ4"õ3ëùy¨ët~ÚßY‡¼µk ƒn©ºöx2Vn²y“" XEÇÐ=ìÄØØ»[P–÷ ØDÉxù²¿ÜŠÝ{Eœ«OõL‹iÜÿ;Û §5æDË™2<¸ ËÐYÖϽ@šE|Å`C^Ùt»—…FÛ©½XbÓM2(xä>=ÎX;žÿq úÅÚŸ¦#a)¶©Ë÷˜^¬Èù˜ö’gòð$.å±L†f°cÍOÞx<¡åجØY¥‡ÍϾWwÇ‘³ôPVV†’’ïßìÉÛ„³ G¸ï\•UØè;å( ¸e,Dž´¤Ð¶¥c-Ýv\—X×¶íL æ¬Þ­ÇVº'+ìM ÿ>Ï3+J -Œù¿ç„(˪AßgJ6ÍÁN­([ËaKó\Ò£ Û¡•»˜ ÖÖÝ ñÁHDGUÎÃ(ñÉ“½{öâÀžMHZ´Þ=Ï„L+žzÜ3 “:‘–='¦?‚Z}I+ çá#èìÕ¸:ø*Šõ"ž‹+ývo6üŠ×ðŒOö/¸góeìü²4pµÛËê0( ËÙº²<¬ÖE6Ø2Ä zÄmbÖ?~@×þ{µ7Ï¥1±ôÒžûW‹ÖË{ä?{5[Ž˜u¨k‰M?yà”Ø[ÉÁÞvÛ»6©žiÁcù°íŠe1¥òÜSÑ€~ñœqªÏ…{±HjÛK mÃñ]z@ ÷¥«¡K 6g²mB ™Ó<‰ºX`È«‰wÜ¥×õ#YY(kèÔRÇœ½8u Gß|Ù²Ú; Tâ•Õ=¨âFâ+½LŽnAŽhÃzÕú0Ü‹{lØ¢·6ܧָ„’ìž–³@[{ŸîIš`+rpª­ß]ÛŽaó¢-ænŽJrDÙGKPÌܖĨY‹Äf—qòÅ‰Ý Wé÷y¬IOѦ­]ïu{cËÎÂÝzì{ êШEû\*8è>œó.}£>ë?’깘ˆŒlã%¡`Í|”œjÁ X>ÍåCoÛ)lšcôóU#úÇCöçzqxg¼ækŸ’ú[‰øÐzÏ»Aãþ5Ø´÷Ú:Ûqªd;,^c¾¥ð¡ˆònѪú°âF¾7ãð·ÿgƒqêv©kðGXP|$øžÎçèú¨±m«|5å9 øPx DO`Ô¡»¬"šÖ0ÿòLjÝh‡"¶5š l¡Ò5î 3ÚU3__Y¹JǨ;Úªˆî¸;¬­´Õ«À¨R“ëë?ôyvu‡;¢”ÛBûÓxd—kqy¢t”g{õ·)­‡€º)J@¿BŒ£ÜæÃ@ÈRÓ(#­åf?ÙÕŠÉwçH«"^•Ìr,E¼š®åW;ÌDzÄÜ0·ƒµÙ‹ÿYøLu¶¥MŠ·Xâ‚°T=ã©–àú(åÙæôjñ˿֢z“.Aã24U†š}òȇ«G¾U©ï“R"}Ñ#J¥^6—1Mok¹O¾IºiÎG8:Ê|²•Ú¹¤EYÇbÎÒÖ!-^4F 2°ùÔM³gQ^*µº Å"òwÂC´…Z9Rå—{º®šBS}ÑøË¿ù5]†øÛD5 £2×/agò¹æÓöŠpMEV?¾aĹ*ÇZ.Z=ïmÞ¨z†ÑviÑÈ¿r94µ)èbÔC(~åA¤È¿®È×°ëhn©M5â’êHÄTÔs#®pÓå¡.F\ætiùNÞheÝÓæDÙ&¨Jùm–¼}ªnHñ˜Ê›–è€e'P}ÏK¿z(Úô]PHÇ•Ô=”"á´~í©è?h}.Sû$¢¡ÖR£-²•+:¢zEL^6î…pu<üþ„oÍPoȯŸWéîL>Âu‰Á^CK‘Ò'j2¥/W~hþ‚•Géz¸õA´Þj‚ýÊùá›–€a1_ÆHÐüËUš}Ù¾âºjòÝr,…µ¾·e¼Ków‚Äãÿìóàse¼C«¿ò¬¥F™ôñª ÔšúÅ–üZSPó>Q[*·o¦v'D>+B«hú¨þuzrm•–Fþ’ €/ÎpOh$@$5„t>?„úra6yXQT]¡ñÃH—gï$¤áàx*ÅÚˆ[~9ºFêË•$¤nF_S¹yæ‘Кڮ!ôÔiWÄïEïºÆ†‰ú'™ Øü­”«Ÿƒ8rK…¾£]úZžªÇoÿèö™¨¥ÁVˆÊRc,¦¨ÆãyËåKâ³_íT žÒM\èHÿÔ~è“ϽâÆÅòò‘¸ü}V•z½(çcÒl ÙgwârTŒt¡TæãpH3ʬ(oêÁá­éÁ…èiîÅs'soœrH‹Õ†Ââj8úFp|W†ÿ罂¥F6ènºY²×í§ï<äA}§õUSåóZÇ%¼'rõ½?½‡[>°^‘Žd¾A¯›s×p?¯wbàÏ‚ÂM7ã¶”,^”j”“¨SêB§=n¾7'߆Á75Å(ÏQ‹ö èËb ˆo“ãgÅ ƒD²¾9°·)9l›¥®¤P± QwÇEüþ]wµÅì[ïÀ’Ô”mSDm¢šw»ø.ýN-£ïáOïÝ‚¿^öa¤Kmc $«Ëhõô¼wÅLüì$,Z²‰SV·'j»ix¥®©›ü%!Ç.â³Ubôô±Æ°hÛ_ÿ þ F5ãož‡Ô»—ж=8W®žOLëÊéªÍ‰¶M%3hÚ£¬Aå…¸áe¦õµóxkH­‡â™)ž›¼ËKZèúTäÔ=¨↺–ã—žg èÝ!y~ >xwæùv?B ‰úžX:°·oüQHˆGÒÜEXA'+š>Zï™=b )ÕÈ+ª»P±Uu_ÿEU®†ê¢w^¼€Á?¼‡ññ?‹z‘Œ;Ó—!5ŒälÇK?¿„›þr2—”¸ º²qN”ÏÑôQcÞV]Y$ŒHà @ƒû5IT‘H€H 2Ζ2$yן¦âô®å‘  o ¸áHw±wÂPCžgóߎL7:a”eÎñlÐ)æÐ·Žœ†¶GçN†é'  p D3E%\ÙôG$@$@W€Ø„ªûw˜=ëmÌÝí׊ÚNcûÌFE$pàKÂu’‘L „I@ ÿ»ñÙx秇½Æv±ˆIq!íaò£7   °/-Ó ›H€Hàš%0ÖþXdÙiÒßZüUdÄ~eSœ=Wlж0䆌Ó:-TŽH€®ç`?œ¢ E|"RæMéÎ×W!uŒ’H áÞNüöw¡6s[°ðFÚ>Þ#  (Ðà4!          _\RÆ—ÏI€H€H€H€H€H€H€H€H€H€H 4¸GAH€H€H€H€H€H€¾~>ú@IDATH€H€H€H€HÀ— î¾DxN$@$@$@$@$@$@$@$@$@$@Q Á= h B$@$@$@$@$@$@$@$@$@$@¾hp÷%Âs          ˆ‚ îQ@c          ð%@ƒ»/ž“ @hpƒ €/Ü}‰ðœH€H€H€H€H€H€H€H€H€H€¢ @ƒ{ЄH€H€H€H€H€H€H€H€H€H€| ÐàîK„ç$@$@$@$@$@$@$@$@$@$@$Ü£€Æ $@$@$@$@$@$@$@$@$@$@$àK€w_"<'          (Ðà4!          _4¸ûá9 DA€÷( 1 ø ÁÝ—ÏI€H€H€H€H€H€H€H€H€H€H 4¸GAH€H€H€H€H€H€H€H€H€H€HÀ— î¾D¢=walÌטÃαh¥0 À5J€÷7Öy3fÌÛÑæ àAº4Ø^‡½Û31#~fÍZW%aNÒ,ÌÈÜŽcg»%Ÿt’ \Ïhp»çjþÝ{5´µ½óÄÌ·dáPU£×¿¯³± 9k– sïp¾{ȼD$@$@$@$@$@$@$@$@$@×Üå u9Ñ^W†5û5º|ÓìvuŸÂÒmGŒ‹Ö|ÔÔ7¡©¶ù6ãrã!Šêú t‘ \—hpóÏ* oû&±,L,Y»ÃÊ蟟xÚð—[‰¡†ÃØœ™Œõ[qøô8šË³õû‡ ª0¨ŸÑA$@$@$@$@$@$@$@$@$@$p= Áãxýéý8Ze ‡ñZ£6 >­¥;l ‡UŸ{ºÉÝñ*Þ ½:)4OH€H€H€H€H€H€H€H€H€H€®=qמʱÖ8.(EñïÌÄÌ™ÄËO J[‹=PtÎ 8­ÙÛ­÷ã΄žîÄ:±´ŒfÇà…—H€H€H€H€H€H€H€H€H€H€®4¸ 3{ÆÖ]ÈÐóÔ…™µÜ—áËåEXÖ9„Y‹ïD@cºó>ï{ÇR"‚FÏÓ–€¢(nÝf̘1mu¤b$0Õþçþ‡íúTC¦üiM€Ï‚i=Tî à³à f4Ó–ëÀ´Í*v…¨ý!õöž+œÑ\—/_Ž(µü¿ùæ›ø«¿ú«ˆÂ]iÏ4¸O†¸«%.B4£°¡¼þëx$3 ±€[WW‡%K–`Ó¦MakzÇwàæ›oÛ?=’Àt&pöìY\¸p<òÈtV“º‘À”Ø·o}ôÑiß©˜R~C8}ú´;ý‘ô‡nh`LüuGà7¿ù žyæ8pàºKDá`(\Rôw½øå/‰Ÿþô§ÈÏÏ¿^“ÈtÝ€Tã¹6¹&œä?ù䓸Ãþ0íßca‡ÇuègÇrÌÆöÂÊ&|qG’cœÚôôt”””ÄX*Å‘ÀµA@½Tß¼¼¼kCajIS@à›ßü&¶lÙ‚}èCS "I`úPêÁgÁôÏ+j85T#KMM ëÀÔà¥Ôk„ûC×HFQÍ)# N@èîîæ³`ÊSðµ@@5¸_  îQæRû±]È©Ò碩§ '·|Œ&¿$@$@$@$@$@$@$@$@$@$@×Ü£É3W7¾£[Ûmhª@F¬§µG£à \54¸GÞ5p R¸Ÿ/ÃÏÇÆ¤+fçåËó±õ‹;Ê ðf0<#         ëˆ îQdæèÛàÐÃÙ±·]? ì°âÁ|ܳáU         ¸>¼ïúHÆT¥"1 `×xÀË!..@|ˆ»¼E$@$@$@$@$@$@$@$@$@$píà w¿ò¸7ÞgË+pòT3ÞqKœ‹ÕFÞ㟠¸Nõ`{ÊŸ*Çþ£îÕá=:Xl(=°¹—{7fu¡íÔ³xáMÉåùØúÅH•—ñjÞÛp Ͻ2€™bëÒ[?òYäeΞ”n€ØØòÔ·qè@ìn ­‘ÙùÛûø£ÈHMöÆ,ÿÜŽÙbÞtˉgpèß«aoTZ`µ­ÆÃŸÏÃçô4y ·ŸÁ3§ÏãòÌT<òŸÀÛ§ËPt@„Á*/cGºÇìlócç‘*#2‹…åãñÏm„ïž›ƒmgPùÂyàkñ;î…ã̳¨øÎI4_òæÊâ úˆÍ_¿÷³‹‚à\ؼ›¿Žõ·àè³/blfèe[.Ê× ª*qòô«¸xé’»LÌqoúÔÃøÌ'21/@>ª töžÅ·E]C„*@ÒXÿ©Ïãчfãvƒ@ä®”UxÄ x·.ð/ô={ú?QUuÍöFaÞbmõ|êáÏà¡Ìt˜íó“+ÿþ ¨WÔòþ´(ïcî²|9a%¾¸k=7) ‹WI€H€H€H€H€H€H€HàêPxLksæÌQ¾ô¥/]åÙŠ(î¿ÒÖ¡Ðq޶*Ù^¿°–+#šï‘fEØ/Ý2,¹¹ŠX±C—©ÉöüZ•ú¾q-”û·UŠßì×+#»\éqQÊ­†Ü¢¦“ÏÉR*ù©ìNB7e´K)–äÒ¯ÐÞ¥ë!³ äW»f-nÒèŽÖR«ÎËj³ènÕ¿–'=õ¥¦ëš,ãתԨé•C®UÉÍ6Ë5ÂA±Õ+r®Èáš½"kFÈ2 ·UѨªŒ÷5e&`¹°)µ]£’ÖgO}ñéõèa+mÕÃŽ8Êõ0òu݃æjÒË+«tȉ˜H_¯µØ[&½£-cR}ÒòYS±¹Ô¨—*Ûòæ@å]óÍ_       ¸> ¨v‘žžžiŸ8®á.rŠG H›?:Žõ̆˜y]T„Âü\)¢F¬{ò%1w×s¸zOaÅNm¶¶…¥Õ¨oªGMy¡˜î=ªv"çé6q’ˆ‡¾\¤]Åþç®ËÑ/ŠYØÏ6zÏ,ÅØ&æ!G©Ä õŠO/A&OhTXZ »½ùbtA;ÙÅÙ‹€[s‹PY]Ž|›B¬bRð8êú5 BE÷Ƶž7ÓèõÎöcX´n·~nÉ.Fms+šë«‘«ƒjÄ–¥6“.Æ&®8Z噞oÍ.Dy¥YÇþuøQ¯¯>jtÆæ¯³ß¿LLÒ·Âj5ÿÙ²%n 0kG΂5Ðr°¡¸²öêRáÒ;²–<Š6iOz 4"Þl——£(×7.ÃKx.†{[pà“k e«¥8iú7?c8õe³¾¥5µhª¯Ey‘TŽ °ûÙv#ʨ˘!Âp¹p¶l;VïÖ¨YPíBÞªy†ºH€H€H€H€H€H€H€H€¦i?$pƒ+xÍÍp—fꊒ® ·R‘çã53a)Rú¼ù+ÏÏ®•Cb¦±0Êzf,[K÷Ü{S<ÙŠÃgbtWu®Ç¿—]Ùá‰Å&|ÝFZååÙŠyBý¨b/4f¥çÛ=£lrzuƹüÅ€9LQ½FAQÌá„ʀ>ëZÌì·y9ˆtÙJ›L³ÑA³Tº/Ïž7˵(•¦YÒJ¹4ë½°6>6¥Õy&»<ÃÝ]­VÅb±ZyÒ~mærªŒ:ŒÙø–BÅwâýHGµž9^%Ê2&‡+uƒWš$fb¤A©öùjÁ/xH€H€H€H€H€H€H€®cª‡3ܧרµ¹ârÑñ­çã&¯ú*µ)ÍŽV¼åÍ<.ÖG׎ÙCžuŵsÌ»…•Åb–|!Š6Ý…Yê ¶åkSº«P{nP÷®ÎHéßzÏ…¿—H÷4g¸ºá‡‡wkPT_Œ 9Ab%íçë÷ο­»5Gnõ3Øœ&¯ïž€?ûYí6_÷£Þ´Öâ¸X«{žwÖõXç±Óî &fí?³+Cl*)Øu¼b©÷ÑXð<ºÉêºÇÜê“Øaš%=Ÿ{â1ý~ó…Àúè8\ýu°­Ø©ßÆ~ܘê9wuâ;šâ¹8ùäV=Mnq …ÞÍúLwûÉF‘ƒbåòÞF<­é=yp£i½ô”Œ<8ÄDXG£XÝá0þ|]º€ÎÞ1ãjÂ\ÜŸí)_¹{>ã·G@â’t³È×n3‡Kš=†–²ÍX£3³¢¦ãelU¿ÒàA$@$@$@$@$@$@$@$0­ ˜íuÓZU*w­°–~^Z¢CÓ~\s¸ã½g·Î5¶¾<ºm).Öâ Û²°Êr¦$cÕŽ'°Ê2ÙþpÄc ¯~¾ÿ˜±Þc€lÁÓ^϶=øHŠ1_·q¼§ذᾓÑÕáÀ¸HZüÜE>÷­ÈÎòž¥;ãã—õ³$Ýev<²Öta|\W¹MºÇÄ;±NØ «Ü†êKøý(j²ÓÚðù‡ÒtïšCΕ`úh~ý~Ç:ñÅYúÒ,ÈËí<‘¡{ëjƒ6üÛr$¹œvšGfŽw‹nµpÁ¹ üM§wI"±ºú¾OLoú'vÁ*F!´ìÖ#•[!Û´Pl°+]¼üGôþêUÒ6çušE/ ¶¯ëÝå%yÇÏ‹?Oטª³ï¼ý6ðÚK¤åq$¹’3ü2&Μ¥óMŠšíbÀÆ”‰¦ûü-‘ÓG7jrVðž0%©›ö¢Èrû=Ë‹£±êûÏЂÜÂGýÙÏ #͘^žhÙ€|ìÆáÉqäè8´é @÷O~ jó?o5ÍŠÖ [·±Ôk³¬­÷á!ßÿH@jZºÿe÷•$ÜU-ë‰/0GÖój­ÇòôºÛìˆÇœÅêÌlHm@Cöèš|?2·º¾ýRwx¢«r‡‰ùø»¿7DÚwbÁ¬Æy—ªã[¯Õéw—ÿµÙ­ßH¼ ÁHh~g}y;çÏÁot¢Ä¶Ô»>¿Y_=ÑŠÍâ»õpâì‰oã›Å°œ¾&>èoØe,¨ÏÆ_Aá*ï`Ò~CÝ~ï >þx(/7Ô½¹_ûþ÷ÿ¾¡ÒÌÄ’ L=¨LS¯c¸ÚfÆOT4$³mÄS¢¤N,+²¯uk¿÷L§GívÿÙÄR%§µÙÓq©øt±GÜ»™Eíù¯#}Uœ´œŒ ŸÎ3›'sˆiëú¼òÆîÉHŠ0¬ˆUv.ÙÜ=°S,cbwϬ¾p{¹mÜbb•FÜI¿Ëú±=­X FžÞ‰¥‰ÀÁ=%¦á‰“µ¨žŸå¢¸øÄGHpõ¢äÁEÒF¹’±al¶åTy7Ÿ•îL‰³qž~p»V%OJþ_ÌŸ[3–š”°ë pÜÂI¶ ×&H€H€H€H€H€H€H ö|Lc±€¯!3 ]Û~=¤‡XÆb¨OŸEŽ±Þ¶4zW\22¶>áþs÷ãâë¿ÀË?mijûèqÙ ÖàÔãؼÐc‰^¶ñ Ь¢Õö×ñb]}9™Ül,›œR¬ÛµYÿƳ~¼v®ÿº0<8ìf—ˆäDÉJ®û™¼£çlµ´ŒI°ª;Œ7êõÈB˜šu?Ñ:ºOíÁºýF\å­ßGf€å{FßzݳTŒˆH09¾ëCpú—˜¸Y³  ãÄ „ŽÆïéùJG}@$”§P÷þ÷›1x¤’í>}P+VâÌŠÒš¯Šå„Ò0N"Ôüíëö,•òC\ŠÙ‘‹Ö‘oaös°t[•[êîÕEØ0~Øo0#’(ÿâ¶Ûp˦M‘¡_         ¼/Bÿô~X´â~=uGŸþ>ämHõ^Gç‹Õº1Ôj½“³káì±ìÝ»%ÇZ܆ëÄä,ÏØˆ]ûã¼2{¡UW¡ÿu²çHH[+–¢ñ¸/<ïx^׫(û£òq-Hd¿ ‹°\Û—³ñ4^ ¥ÿ%̳‡ç‹¿µß>™ü|Ëùsú¥7‡t^@­n_Œ÷»w˜ ìu2Wíǰd‹º˜çȯé@ÞòÀ¥ þVcÝ{{û[ˆW%’“}þâðÊÑ'ñä“âïèOÝe`ñªLMrYÄí¯^iöа ºãGص9©)ó¼Ævqkx}‘DßÒÖo`ybÒ¶~ Ez¸#xôßÎêgt LO4¸OÏ|¹*Z%þåÝb.¯÷h,À—µig¦_gç)<œã™y«ÞX¿6Ít?ò“Q¼ö\:„‚{Cf"2²ÖbMÓ¶S°iO¶çžã¶íF`·>[î5Ö{7GêJÄÝ+4*øZ¥¿Ñ³¥ª\º!íÝkǬ¹ =I‚ áì° m'žÒ ÐÖâOLjF´¿tï•ÁØ,9úíìÒfÞ¼ $¤®kí{ªmx¾sL;Ó‡[*‘µ{?öïç†Ü×?p—‘Þý_AC¿îÝëèÇ3_)ð½èwž˜4ÛïšvÁÙÛ€xx›v ‹õ1xäÄŸ÷n&€¹¸ãöý¾ÇáBÃSß46j©ÍË÷ñõ©6û!òFÙj_wëœô|þ¨µb@        ‰ Ðà>1£ÇGrkÓ¹£9+¹§ gÛ»Ñßßîöœ(ÉCÒÒ-ú,rXŠ‘1YÃv"îYí¦ŽCؘWÎaÍ(;†Þ¶SÈY£V-¸ëæ¥nÒܦfÝ™%l¥Ö"±éh°UW"ÌÑŒ_Öå«FÏíeuó ý¨+ËÃê»W¢ ¶É®B·¸”Pœ¯q²cÍœ<ÔujSîÇÐrlVì4Bò³ï !-Ú[½8ðÀ:ÃØ,Ä|àý¿Ã©S'pâ„Ïß±héWóq!òªsõ·-ý{ké†@—ˉ¶3%˜³z·~¿tO–ûË5½tK}#Ö-ØŽ3íýîÙïcƒí(Û¾@ZöEîç¨Êy%ee())ñþÀÞ={q`Ï&$-Z‡£šm] 7=õ¸:«>+7iõ@ ²C÷°cccìnAYÞƒb)-ÏûË­!¿ñS(‚ ‰é ¶PËs çá#ðwˆ@½’ L-™$§VÉÿÏÞ¹ÀEUæÿÿ3/ h aŠZŒ…µXÖ`XËñW–›—ÊÚÀm[Á½H¸énØÆBÅÛí®îm¥µŽmam2-ZÁ˜ƒŠë%!o 3sþÏ93çÌ™a˜¾§×8ÏyÎsù~ßÏãs¾çûÐè}G nõËÈÞ©—„LÃÆTðׇÅÅ¿€=aˆµU÷cpÕLØßMÖ\AÈ7¬ÀtöÑh40%5T\›ùó„‡Çáq¦®°k xð¾\šÜ}ÛØ0¡ x{kK¡’%ŒY˜š„BHÒ¶¾€^îkéÒf{¥‰™›‘¼q „Ê$Mg%ÆIÃ8ÉI¥1ß™“} ž—šÏ¡B>)k‰(Nw6»¬qáBz”¼âXŸ°|öTØcäíý´™»ð¸”šFùë*dþ²Èzû{¯®JF¤§ºX0‡nKQ\ó âmYqfÌcoM¤Zo(ÃÆå˜Ê>nÂå+üÕ-ùàãü{t¹íÇÖnÊc¤[ )¯6aW®=ÒݹKFQ>X› lZ*] áý5"Ó¥¦Ï|ÝZd¿g$[ùÞ'Òp 27ïB]û«H´mÄË· ŒZÈÖ;Oz³Á¡Ÿ6 ÅÇPSœ)«>ŠóBª£žßcâÊ pzÊÖ †a²j{± Ú0:*ñ7Æ ÿ÷Ûívg¨Dˆ D€"@ˆðk³,ˆN똫]5L©*q”E¹ÇåÓæ©~½ˆ}d\c‡ïOq¸ôv”jûÛ}4=MC¼B€w¯`¤Aü@ëñxlj ]Äw=ÿ)܈åšdìÚ‘‹„„[Wc ²ºæ£z$Ý—*x¥É.ó?Á½ù2’îƒY˜]Öà‘à.÷©ëåÒ¢¨â ,Ž íº©¯ZôÀG_™Bã"@ˆ D€"@¼Ià|5‡ºÿp¸éo®õ©ÉJ¼;Ó„Øç”&Õ›ìÊX‡“os8òG Îâ8(«"PbʃJŒ»Žî‹²–d§• ît' •[0nÖrG_´K‘¡ÁX|‹O YÐóŠ- 07ò(ŠO€Äpú+€€áV.ìÏÉRÙo ˜d3Æcód>uí‡Kf…ᛲ:¬Œë'ѽ'>víµ D€"@ˆ D€ô;C9f\¹Â½˜>:R°x¾xÕ‚«~æZ”ïw'ÈŸh9ËáhGó-9I«žP"b‘ª@NüÝÃ<†czÞ'/Q í|b J¼HÀ1y–¦¡ˆ@ŸhÜ{ÄvŠÊjÀ•¼Šg×®ÆêµÏb{ ‡ÓF=–JF´ôe4JçT¬tÙ¥hçÚÑÒÒ"}šêp¬¢i»×©ÿ ûÁŽƒJD€"@ˆ D€^àSƒ|ù‡«R;—Ÿ¦±ÍSæÑ橽>@¨ÛmÁž›°cš ¾àpËv’öª…ÿ¼ØÎ!bŸWáÿNªû‚ ßîçðN´ »n7 gLßQÞÿ²ÜCÒÌÎâ I$äô@#°û¥ß éF¬v§¡¢a;ÇEtp#^m(…V¼bHÅ›UÍâ}V£ fÿJŸ PDÅ&bCq1$ÍÝP‚#t; Ö»€ü"D€"@ˆ D zÞ‚ÉK•1¡ó” áI ˜Øïc¼KÇà$À ä|4û»šv|²ÌŒkÐP³TCj\ò÷ò¤R¥@øJü°H{ΨɢܿØlÁ[—šðɃ&œý·œ…Ä÷Áy× \¯ÜßÑ×'²|(`Ñí/¬sÅyÆLĆt $OgJ+Þ0ujÜŠÊùX– €Baÿ$,[ƒ•gœÚÊNMõؽmR$`¦ØoæL,HYƒ×JªÐQÇ­ÇŽü¬_¿[vŸ©±9) ¬}—m‘Ú×WíÄzV/·E1s6í¨D«lz‡"³¥dK³e˜ 3Ù'aA 6½V‚z·FèÖ‰©¾ù«–9Ù˜€5ù;p¦“ùZkËŸå¾ÍLX†œ×vw#ÒÜ„JÆ}}NrrÖcý¦î¹¸ò*<JO`\4èɺnâ×5»Ï˜ °YŸ"­ÃÌ™ HY“ÊÎÀt0£—>v*ˆ D€"@ˆ ¾'pñ‡ãLþ«®¥'…’mžÊr¹a›§Ò1¸4áðYšo_f—Û,˜ùŒ º/Ô¸úI/éüAŒ3‰€ ¢Vâ¶5î:¨Fðt>K5ãŸW˜°/ÝŒoðîÌŒÎû‰G‡_7n÷ä“Oúµýi\CE.ÿÓÔúÑæruÓÞPÍí*ÞÅíÚUÌ•VËz´×p¹:ÛXâ˜NßÚ =×äºk©³tÑ’.û;‹ÙÂÔ›¹ïhçÞÛÆíM5qçÿç»uýf¯™Û»ÒÄm mãÞ½®;ô¢‰ãï':^Cª©©ñ{Ǻ~ÌØOhZ"à S{÷JÍt n†'[^ªC¢‘˜€„„DÄG‹=š±ey$Rõâpd£¢¢ EÙÉb% Y:èrÊ¥s°xêmOÍA¡T£CîÖb”î*F^¦½ éHýK•Ô ²M2a4Àhº‚Sí6ÌZ!ŽªAFnv•îÂÖ¼ { ”ÂXþr¥}ÌÖ*,ŸähKöæ­ÐåB'µÒ#iêc¨ìr/µð´Ð\µ‘sS¥æš¥Ù(.«@Ù®"$KþpßtvË’å7WæcjRº½Ÿ.›õzå¦Iu@Û$ç,»$Mؽif§Úâñ¦§&4²ûõ÷ΑÒi²—"ZÚC·÷ëj,(€Q°U‹ŒÌLd¤Éî6ëÜç>„ÉÙ-‡óÞúè0"@ˆ D€"@úŒŸ>äÈ-¸:ÝóMPù´3“æ)pü¯åÞg åå‰Z¿áp0Û ýö?eÆ÷(pÏ)5®ß¨Bð´îE³wÇ´ñ×+q}®JH9£yZ…o>å 2Áð#¾*¡û©;,©­—øý#!n E¸w~eQàÅ=ÂÕTaò–r¥uŽOáO—Ê#¹µ\©hÝb”¢¯¡‘EeÛÌnª.’"¹¢ÇeÍL›fm–rŲh{¹_K‹eQøü¸,òš èÖqYT¿hJY¶NšK“VÄ9¸à½¯Ë3J`=Ž—zð…&.Oö6€.·”s"æð¶€6»ÔÖ»ËÓÚ£ùu¹e£¶ÓË"ÎO~P«Ü >Z¾+•ù h¸"§(z¹OìG%-{‹@£±D~â·n³ãÛ^XWaÞdÇqÊd÷™&“;-zßÅ®ôMˆ D€"@ˆð7ÕL\I’ão‰žØøÕGfÛ8>BšŽC€0ÿø¡vá …ÒûÛ¹¯þcîwã/6Z¸#fîÔ¿úß–~‡1ˆ ൊp÷ÒC†xB "lœ'Í\´iÅ;VHõ™¥/">T uêÃãW‚¥x±µ1 p×qk9pVKîïâL‹ÃelEù¦…˜#ùªÅÖê=XäØÐùÌÀÞ"0íçë'Žàp­,á¼ÖHFõvxë"$î!l_70Vऋ7 z죳OtNˆ D€"@ˆè–vÕ/²èöŒî'U˜p‹*ö{õ™÷ùx2:ü™Ópqú] þ­5᣻Í©Àü#jÄ¿¡Æ„9Ý_{oû:l¬W>¦doMô¿-ÞöÆóŽ™ÿÛK÷Ü_êüJ;Ú$á3÷Ý(¦™qì5㦛YE¡Pùõ™ó¶‹áHyu?ûXOM­Íhlnƹ¯¾B}}ö½“#K7cëâü•¼w„;þU3~‚Ôª`Ét-ÎÀO–$!Ns "ÂC÷ðjÈ¥êÖc•({èb̶wolf ·ì¡¾3ع “Jp¤y%âºÐ©eÝŠíí0$§Ïw•¥†AWb.— … Oà&ž‡µ_”.ë܆péÌ^¸uÍ1igˆäŸ&ÈÜX>=ÌÞ•2ËôX؅خa)k_اfåó¨=ø ² lO ŒY˜ù.ŠOW QX‹Þ¯«6÷YŠÑlÞ/ûáê–í‰ö©Dˆ D€"@ˆ@g8 ‡/þΡ©šÃ˜ ¶é"0†m¼ÈoÆH‡wœ`/z¼\°øž Ó~ªÄQ¶yꤤžõ÷Ž4Š;æ65l=oX¶–é¿Taò2TÃéï;fT?ô8ª|CÏòx€h¿h~+«ê€Odš›m:®!#j°Ë¦»‚‰Õ“Üü­Pò§[órËÁ5c÷k ÙéÐw¼(o責‹½ NñˆZ°™š¬³g(Ìÿ±$g<Š¥> å oÿþûØú˜4±o¿àXr%ö:¶pVóI±t16f’Tv,`Üd>úßê?Ÿ¼ßŒi›ÛÎC£#æ!Ü;>øq‰NÑõŽ­&'=€”‡c+mgÏ>9ºéH¢îHzz;ZòÚÖ£wëÌxãðÄGOæih=‹’“÷¤éhóÃð…¸tTÔð•œ$D€"@ˆ°øÊ`Aå/˜HÈtÁðD%Nê-hú‡fös ‹yâ…wáÃ"•‚måÀP»sÿðQχXïër<ÏÝî<þ䕸ü7&|÷%‡QWg>ýuÞö-‡£ùε (Jë²T˜t· ­Q­ Íë¿ÜH‹þk0YFä&N›ÅN­jyÙ£¬Üµ€Öz¸ýÏÓrë0ºÍhzUcOàÒ$ݱ¬9ã«øÝM‘sG¤M°uº¨Ñb©æ »Pá/:F= £°0k+p뛯¸ò(ÈJ>ºìRl_—_#¤‹Ÿ8Yââ´‰¥­éùyÛ –.F/Dï_lw§ˆ"äRGb‘·<ÂìÔ +æÉÑÎm4¬KÂËw4`e\ˆû†®øŠ­ƒ¢±úb…%Y =ˆ@o¬«8G/¿=òу9T 5‚†ó åÐh¢VŽ’—D€"@ˆ hú‡Ê_›ÑPÉaæ3*Ly‰„J»Hȧ@if¿NžgQïüçëÿ0a1‰ñÿT#™Ï"á­b¼Mˆgç#/cº= î®SÛ9(˜Ö>é.;ߺ¨6FˆE -°àZ¶^tô/ïNr8¼Ñ‚ã±`â\ny[…KfÓÛý»*4»¿ ÁÝßWˆìë”@ØtöþŸí0f¡r]"bÃÅŶïCl—jtI³Ä‘Y0ƒõ ¿›O€˜~\ÔåoV&¶k‘»õiÌ»)aã‚Èr˜åT™ÞuZ™ŽÓêÄ/^-|šÏàèϰç#þ²n£-fœ=jHŸƒm‹Zpç¹¶Ç/¿ºòZ˜Z: áê#¤¸kuœ\™$ÖÕì.’ùäîÇH#í‰ñyéÓe[%;Ý õ¦æF4¶ò¶384Ä)ú?MÄÈw–cú’BÁœÔÙ™˜×¾QîÌv÷4Éþæ[~Ÿ®«;;¤zøÈÆ3<wF<&ÍB"@ˆ D€"0Ø ´~áêwœ(²`ú*%n~]õÈŽB°2€ ê,ªÖåŸ~æ»Z&IJ ñUjß´–9ö+Kp4/Äãã¸êg$ óìþÁ‚éª^?Œ¸r… Ýe‚æ·JðëCGßhøœåâgicN½Ãaò%’>c¿£O¥µèû• "z$5Wl–¨#nA6ŸµD8 ‘YP.ž¸þn,Gfª=<é¦HΉXq#K}1>otÝõèžéÂÌÈ1¬lÂÁËluU¿‡• ãjÛÙ¥Æzœ–zyZhÅî-9X³f r¶” ©o‚BÂ?+×nÀ~® ú ­4Ø™s-cφ®¯:‰€À „„„8}Ôø¸à9<÷û|$O.åi!rÖÍRÓí’Ê…æ#(–ôöɸd‹rõûËûš‹'®‡°°0ö¹{탄˹Ï#6HèÅÏ Sì€xìÅÝÒYw ¦š*û拌‹¯ÖÕ3Ë|á£g3S+"@ˆ D€"08˜/²´&Ï™ñÎU&˜[9Ü}H˜u®ÅöÎ<æ£àGOV›.Îø• 7þE;?QãþÆasÈ법‚Ø^ýœ_¾Å’YñƒOÙÓú5‡Èz/ÊŽŸÅÞ"`yàOþ“âTûÞý³ÿ¶`×&”ÜnvÝq5~ð²ŠÄö¾_ šq Á}/™ÎÅÒì …>u6Rò­"µT)«°êÖÙR„5ty¸_Èù>3DÕ^^u!Ú7—cƒ$ÔkqO|µg÷‹ébÆcâçqöÔK/HQñîiNïìû{:²²²¾\ïB°B|R¢è•:uÒÄšÂ%xûp«x&}7–oFRê:¬[Ç>{¤z‡‚‡6Ž!D…ó} éYØíâ!Eåk/I¬µÙ÷èA¯„ø¨À¸nJêfg(v#o£X7WtÈ:ÃG¾óGÒŒyÖ"ûÓÀ"ý·vRçmWƒ‚Ù; nŽæÚülÑéªF{ B|¶®Ò4]ºïcÒe"@ˆ D€"0dÔ¾iÁ;ÓM8ûo·Ô˜ýg5F\Ú{Ø ?æÄ¥ÙW Âg+Íh;?´Åa>º}ú/YDºÚ;¼…ÍSYjŸ¡|ð.6°7-XZ—ó‡­þœÏ•ïÍÃbâp¢Ð‚w¯mÇjÆå Xð¥šß©x‰wÖÓ›öÒXDÀß ô4 ƒ¿ûEö !ቿFž. +lë+f£ 8ƒE?€™YޱüåÞwñÄ}©R*0¹XŸû(WùCÄ'ÖY:áŒí—¡/&'"”iè­gÊ‘‘4Û¶7 CpÃÖÇÀOlÀ3™[±î^¶aišOïÇ?r2Z …xC¿§õ)1ìAWG®™Íx1? óS"ðÆBt/è·¢¶ò_H“nDƒi—óªtRŠ’±qIP¿dúÐVö ~<+Šy× ã{Â,ØÈ]•䔪Å:œþ Y_w9„Dæ¶¾ZZ0QûVο Ùi$mämÔcθW?ƒÄhÞ»V”oÉÀìÖ”/|ÿ´¥7ò_ìùHžÊÔÀ ì«ÇÜ0k¿Û¦† î؇xzQ’]¤ÏÕ1YÝýó(Š3^FR–õ¡ÇòEqÇþµ°Çú[û._„˜¦G™YâCˆ‹øöl FàÖm´Ý4BS-^z"A(ùf]Ýûâ>ºëOõD€"@ˆ D`¨¨ÿ”mˆúK‹ zßðÛÌñG}_xéJLÐZðù“üàOª¡‚ÜÁφ}Ùç–zÏÿˆ+ØšZEæ1,}Ï@;ÌmêJ9|ÿ%S%¾ã؇ÿ–œëÏͬ-ÇöøU2)@=ÊúÓÙ[YàŸÒˆe E`ÿQ8|gýZëí×Ô£\ókoæpì¶*ËÑ>"\˜§T¸üÇ=w²—ø{*æÝÇbþàÕ ²aüøñHNN¢‘[Þw¥õ8r~<érýÔí,ZßÂâA5—ZUmIf¹U°+5L÷6ŠAìBeŒM ƳóÖãÛ0bê}bs¾“QÝ’hTbÁˆY‚¸¬Ë­Àö•±Ž}ëK03l®ì{DÀŒ1:mf)JÖÆÛúÖ#Yd:·ã˜¶3mæ.|°6AÈUÎW5Wå#X³Âe[W•Zfo oos%R‚gÁ³QÃl”#K+2bÃâûP­‡±fÄtö(¡³#ÇÚŸµæeoµ³ÊeÉ®Œ•­³a³A\v]c™ÛmŸÀ¶€-®y‰üC ®+{ø±eA0Ø‹ ìб|ôÛYŠ~ÂîûÈ@ D€"@ˆê.œà°ïI3êØF§1¿Sbêc,ÂZåZ\ô%«ÖzÿšaÂ-zBoê;±ß—>ugìÝ‹Lcl»Ó¯«¶Ÿ­bŠ3S­®ßè=!¿«9{s¿μDZ¼çœý€CPËõ•*A0WH¹U@w>çEu[Ýh«ÀÎoÚëê~noâÐZÇ~•¬¿‹lî–¯­ß­ì[¼vñÛü—ýª+ç‡3¡žáË­„Þ¬ÀŒ_+?ôîÛÞ¬5õíüfÕ555ˆˆè,D³l“ÏJ›ä4¨

ŽçJ©Rø:¹¾­MÛŒš»ØÎ_ŒZˆÓ¥y}øzáЦ¡øXjŠ3Åö}çùÝCÙÖ¥âF­A®Ò¸°Hð=ÕÅHf‚¿x8‹íiy» —Äv¾U(R^m®Üd±K‡ïŒ¢ ±o0¼C»Î*‚ÅæA±Èo:†\G#eb»y¥5Žb;?p`4žm¯Áæ4­Ëitiyllb»­¯IóÇð§—r˜ ¹zYJ¡ù¨ÙE#­ýÜþ©Ñ!só.Ôµ¿*‰í|ÛÞ¬«hkPpW)„Ä–VëÄ3Ï}të] D€"@ˆ ƒžŸ¾¥rµï]ÇòLG)0ÿ¨ÓØF›®Äɾ€È¢Š¯{N…²Ç̰´­¸ÆæcξÏaÚϼ/1M[¡Ä‰¿[`úÞ™~{c›ÅšñþMØiBÍëLœ«À]ÕøÑ¾¶Y¯ZÈÿÃ&®ËR QäÓW©pe²RØŒôòJ\z»RxP2S!äJ1Q€ …Ûû9 ØÚޏÃ÷çǺæ7*ðsÜü5n+Qã®XX€Åíj,8¡Æ­ï¨qm–‘lT~ž‘ìåö;>fõ;Ô$¶÷Å šcH w?_nŠpïɵâÌñ£8^{ßµYû ™„èiW"\HËÒŘ­¨Ú¿'¾nðam¸Ð6Wͼ1²Èjç!„>Pÿ];°G!ôŠiˆ–µo>S‹ºF³ ACC¤èrça:ž›P[Uýÿ;‰¶aÃ0¬Ù4a 4×jÎ6uw˜ÏÀxà0ê€aÃFalx8&GFÁ÷ÝÙY}cmöUŸ› mÚ0úòɸnV BÜ›( ×\G¿ø†Wý0r ˃? ¡¾2²3Ü]óÙºº›ê‰ D€"@ˆ茟kúh¾UO[˜H©`¢ £®èûˆvw6~˜`béeX¤÷Ú‘íÎîÔ—§˜™8 Ä>ïŸ?œk„é¨G¼/èwÇO±-ÿ@…Osj‡5’O3iž—ÝÍ„ó;øuÿ¹E›éX'o@IDAT› %Âw?¿ãHp÷ó"óˆ D€"@ˆ D Oði:*mrVÏzA‰ñ7ø‡+w¾é(‡?0!±\àiƒ_xm9ËaÇU&Ü]­ÆÈI¾ñ÷Ëm̶ io]ò…ðrùâ9–*¦Ø*°ŸÙÉa4Ëf1‰ ì—Ý­ÀøPÎs/ã¦áˆ€[Ep￟VnÑÑ"@ˆ D€"@ˆ D€X ðy±?^bŸ¯ýºl®¸Çÿ„vq­‚¯´æÃ棾o7 ~É¥zƒ÷³ô$>Ûy®—éØûsç>³`üõ}·öçs8Íòœz‡CÃgBãù(v–:(GÅwß<\ï#ú&D``ü?ýöúõD€"@ˆ D€"@†,opøèn.ÿ?%´ï²íþ/tòPÖüÄãµÀ_Ò øâjû–ñW,B4¿/ÆÇä×|êO”8ò' Ë…î[Á½ý‡ªL NþÓ‚öop–*&:Õš*†Ï©N DÀ$¸{B‰Ú"@ˆ D€"@ˆð3œ…Eýþ—ÃX Ë=rð‰§ßµà“‡Ì¸î*Apõ3ünÍáâ¸{P`Ƥ»B ·ð…#/[7í‹Ô9SÙ¦ ÿºÚ„Y/p6Ö7÷ú÷§8îb›ð²·nÜ¢Bè”*fßžd:èW¾}4د®ÑäD€"@ˆ D€"@‹ ‹ž¶àãe&¼5Á„kÍà…ÏÁvTo0ãÓåfÌÙ6°ÄvqBoT"b‘Ÿ¥™ÅªAõmjáp8ׂ«ŸìYiÔå a3Ú/þî›{½a˽?Û„Ëæ+1g«a?TB¡ô°?¨nr†—úæ'£Ë©©’"@ˆ D€"@ˆèŠ@ÃçKÒW+¬À ÿO…ÿþÔŒ»ömÚþ̘ñµCÛì3r‰WÜ«ð S‹‰Ã!ögö+}{¿]z§–‹À×Y¼ö æ/™Qõ´ñìMЉÚûp§¯îiš‡ÏÐOÏ8Q+"@ˆ D€"@ˆ >#Ðô?|•Y¤í[a&T¿`ÁèÉ Üú/5î9ÀÄMµ°q¨£Øn5'f‡žcQî,ÍÇ@=Îf)=âL3Cí{*¯ÃþÀ‚ßì5äZŒë¼™íο¶óJî4#` poZظõËm¼ÍÞŽøÏ=&|ù–æ‹=¿Wjßä0|¼çö­¤¤P°ÍSS¬›§ºóÝÓz~ÿƒÏV™Qý¢·ïV“Øî)8jGˆ€G(ÂÝ#LÔˆ"@ˆ D€"@ˆ€÷˜[9©Ë¢Øße)GX${{pi"U"þM†“G±w>/Ÿ/|lŒÇ ,ˆNíÛ¨ãÎ-óìêÙ[°ç34¿Sâª'žý]yyÃK*¼c¢ÌùT@¾N6ÀÆ-ÐmKé‚è[׫҆ Œ{T âoŒAH¿ÿ$ì’³T D€"@ˆHxAôÓ‡Yª&¶‰V üG ü°H…ñ?èžèéìsÌo•Øs¿W²`UàÀÿ÷G3Œ¿µàæ¨péí}1íÌÐWç#') Y¯DùcfÜYnÁ}1×÷g8!ùÄÛ”¸>—múÉ"ÂåG`˜Bx qÕ@ólóÝ" öþÌ,<ì‰ø±RßÇÅ:ö‘÷çË|¾ss+ØÛ·sîç­s^¿l¾ÇÿlÁ5¿é¾èßr–ÃGw›Ùï¾ÀíÕ€ú»â-†4 ¾'Ðï2“ï]¤ˆ€o Õÿ ÷¥º5IvYbƒŽàWI:ð=5Ùeý&¸7Õ#é¾TÁþþ´Ã-ÀæCÈHºOà$p ïZp—ûäv\é‚Eo`ql¨TÓç…øØç6Ò„D€"@ˆ ^!À§QtÇÔ1Ñ{¢eØ•žÎ¢Ü™9¢Äù<àŸ¥Zpö‹°ù+ÿða0ü†Ÿ' Íø_®¾Èµá„Ulx@‰kŸéZˆš¢@ÌZ•ði¨äp‚‰ïÝmB@0„HüÈÅJðmœƒ°`ÆjʎלÛúêüJÆòã%f\Á*tÃŽÆ*&¶Ïco0ß®eÚ:?ð•½4. CÀà||<ôÖ‘<îGÃ'õzöñ`»õ×0\šyr`?Ú!YáT€HØcód>9æâÔ€%³Â°©¼Þŵ>ªê‰}dMCˆ D€"à=ß`)=^·°èc•WÅvÑB>—ûÁìÞåçÇòåwÛ· ?2ãü!NHé1ØÅvž%/ ó›ŒV­·àBmÏó§»Z>ÿýsL˜šì™Øî<Õ>ëþï¤|ú› ,ú½8Ö„7šÀo*ÚZoµ·îcf;ö'/ë?±·=ìf¥ð`àô{žsäì|x«IH…sÝØ§èg&tNˆè Špï =êKœdêXq}0¾owºàt:rB8 Oo-ƒ,¥Ì¸éZЩ·è²K±mõ0µš¤!Û[šQw¢/-OÂF£µ:5ãXV²leè D€"@ˆ >!ðYš3Ò•>Ûyƒ'ÌaQÉS-8þW ¦ý´ë(gŸ8ÙÅ MGù”&„Å+ðƒ—Yz•€þo»0׫—Ç^£À´Ç•ØûS3ÛÖ;rLÃ>öð"‰ É,¥Poל(0q®u3Ô¼lÝ_€|ß÷¤‰Ý[ \<D¯b)‹†õÿšño ý“—ÝÕuéQ¶·Áçk̸ùõÁ›¶È«7* Fˆ@¯ xç'|¯Í ˆÀà vY$BÃWÜË”àßHør‡Sìæ÷ð‡c2ów_† j8ŒŽtý€ã8ìK·àK¶QìíÿQcìÕ®Ûùƒ?d ƒ‹€ü¤\LÉ›!Là"ìQÔ]chDÉkùÈÏß„m»k¥æõ•;³~=r¶ìf£™P¹#) 0sæLá“° ù;*Áö©q}˜êQ²%‡õY€YŸM¯• Þm'×CyRkª¯DþªeÂ+yükyÂgfÖäïÀ™Næk­-GNʇ~3–!çµÝhôdb¡ ã³mÖçä 'g=ÖoÚéž‹«1Ããð¨ÖÕ[c¹›/ð—|›‰)kðZIš;t­ÇŽM9X¿>»Ï°ÕãÙ¬O‘Öa&ã’²&•é0f/}ì0U"@ˆ D€ô5s‡Ê_™û<Û¤q¸oE¿‰Z%F1ò‹Í–¾v³Óùø(ãÝ Í¸q³jÈŠí< ^ÈŽËW¡b•=O‰â ÷ì‡|Îu³¦ÆÛb»ó\ÃÆ*0õ'JÜúŽ£}{ÿ:Ïíî< HH–¯þh¾ëûÜÔÂa÷}lsb‡;ËHlwÇ‘ê‰ð {ȧoƧQ‰pG ùžY²BØ T›}3ÆG-OîÙˆôuVÖâø®s((´å<Ç1aÐàåÌ]¨X›Àb·í‡éÌn,Ÿ4…ö*kÉÖ':{‰Q]o<ê<„«óÚ’MˆœkÝpÕáºÑ€¬üG‹­Õz,Œv ?¾3S“Òºð'FC¡ðI_’c-Ï¢+3Ë7-ÇìT»·yeuà=ë"£}ÞÆØÎ£Ž 3B,³ïúÝX暥žñÔd±%ÊFÍ«!.BóؘšnÝ÷Ôq  À=/ÖÈØd½]§?@B¸ØQÖÀ©èÎG§ftJˆ D€"àÇø2G]®Àåÿ×71o–^¤ìQåþˆ²ßS¶XÌüà Nm·E³´*Cý˜˜ Dx"KÕòk&˜ÿ¹ëß œyÚaÁ§ÛR¤ÜÑ7÷”³ þpΧ•Ùu‡ š§ßæh­ci‹XäÿˆKÁ"ÛUP¤{ÎÖ‹l C‰ÀÐýÉ<”V™|í3úñ?K²2ƒeú·}V&ÌÚÄvíÒ ämÎCšÎîŠqÝ\¼W+‹¨o­rÛuÈÞ¼ú¢\&³‹‡ISCeÇÐl±ÇßÍU[ÄvÍÒl—U lW’5â0Ü7]‡Ý²õæÊ|±]£ËÀf½E¹ib'ö…Ç6•Ë΋&ìÞ´L&¶kPdl@J\¨sC7ç&4²ûõ÷ÎÄq¾‘&{)¢¥åkŶ§äb»¹[‹Qº«y™Éö1 éHýK•ý\¶¦FIl×"#3i²~lÖ¹Ï}ØÅû½õÑn•ˆ D€"@ú/þ̲`ÖFߦ’‘{8q.Ë?‰E¹ÿ­çÔòñzZnoâð…ݰ—mŽú_eLb»„’ÛáÔ;¾.u¡-5t*œx‰í˜qË–|‹í<–™ E)pò-û}~¾šÃÎ8BoR`Î[$¶;Ý>tJˆ@ä¥>š¦!ƒšÀËKYùä`7>6áĉ™(ܳ1ŽßnÚóÕl.û‹BòÃ÷ zÙmXaâ˪ë0?"\è_¾i­Ù®I+‡Ï-F¨íoøüûuØ´0©z¾i!2_[í)1B¿žýÑŒ×Ö.—ºêrÙÆ¤+ãmÑö±ˆÛ+®^0É6Ÿ¿}e7JVóÙêñÚ¯VÈú•aûÊ8Ûù|Ü3O‹MÕ "¸!]㿈C”Ôš/ð1!:g!æ°ëÖƒ‰íÕ{°Ø)ŠÞvúÔYPl×BsîœXÅB鎑çºÍøP°ÏÖ¤õ(‹`·•5,Ú¾ÜmŸˆÅ÷Ý‚àéK¬ .vOŸ¼uùC| ðëÇbÜl›ÿ%{Q‡DXWÏnZO|”÷¦2 D€"@ˆ€øü7f\q¿!š¾²å£ÜËW˜1åa”ê¾›_>ï÷7›0n>ÿéûT:þµê][3|¼³^T¡<ÙŒyû¥âÓòì_kFÂûjŒg\é®\¡Ä¶y*Ÿ^æ«–¶è~3ff² dï»\´D€gáîL„Ή@/ðéBô,ZÛõÇÀtÞø¾ã'½aÛ…~¡xhõãÒeG¾²–M‡ñWI€NÆ2±]h ŽÀÊWˤHwý†näI—¦“ ­‡ßÁ IïÎÆ+’Ø.6 góU`©íÔþ6޳`üÖÃz°L3Öƒ¥cyYÛ­UQó±Z tgZlmm_Á#[Q¾I.¶ó)kÜ‹íRoÏž‰ìâGº`+œ8‚õ²„óãqóRk˜~òª:¤¶ š#ùæ<”ý<Õ´‹í|}HÜCØ,¾n`¬ÀIoôØGûÄT"D€"@ˆð Ÿs8ù6‡™ëûþWo>ú9p‚'^µGÿö%>åÉø8nú›Ú#1¹/mó—¹&/aùö#8ðl×Q7£êi3n7Ø._¿ˆû8ˆÃçO™…œí7½ª"±]ˆÊD€ô Špïì4é`% Ñê aî.tTÁ妦é±ó:]D!¯z8R^ÝÏ>ÖÑL­<Ïfœûê+Ô××aß;9ÒÛÎó‰çÚÜGd)jÄZùêñv9ºéH¢îHzz;Zò ¯òMv¿ö'¼½Ó¾µÎs¸:v)§»jÙy'>v>‚õê·ßqøôpÿD7yb__·¹~ª¡cè—•¾æNó"@ˆJ¾|Ë‚–3®úyÿ¥¶˜”¤„qœ5E¦0ѽ/ŽúO-8ø{ î,SC=¢oæì ¿|5ÇèÉ \³†¥ÿa©enß­‚BagÆq*~aÁÙÜÁÄö‘—Ù¯ùÊž8îU+•ˆþ…#ÉÏ@\?²™ F$¸ÆU%ŸúÀÅv>Š÷wOqù5Bº1ËK×ýšàkÝuy‹ÈÛV°”*z!Êûb»;E<!—Ž—wCä-0;YÊVÖÃðzÙˆ†uIxùެŒ ‘Õ:;˱Õo£(,ÉúXàè9+hªEΑ6!Þi<K5çPhË£ïtÕë§ùèÁ¬-,ÂßXC‚»ˆjûŸñÐ1â}"@ˆ DÀ»Ì9TþÚŒë7©  è_Ïå^±ÊŒÈ%¾r¿xŽÃžEfÜð² ÁÓú×oﮨoG‹^¥DÍk&c9Ú¯L±> á,ÊS؆³Ÿq¸½TÝooIøÖsïŒ>ê º×¼C’F!DÀ[Hp÷I‡ô#–“›7A—]ŠWW^ SKG!\=b„w­îÅsšÝE²”*î~Œ4âÐN!t\ à ü§Ë¶JvºêMÍhlåmg¯K††8=¾HFEÓ1ò嘾¤P7uv&æµo@”;3„Vü4‰mMk‹Ãg9zøaŽoV&¶k‘»õiÌ»)aã‚ȃ;ÌråL—1èdün_ò̆KÇ)~oÿEWuu D€"@ˆÀ&Pý¢AìºËîêûÜíÎØ&ÍcQ ö&/õ0ÉGcò “˜Ï‘?î¿9øó9¿©mÜ+*”ÜiÆeó•~ ðÉ23¾û¸ål6ÖwëæÏ\È6"@ˆÀ@%@ÿ Ô•#»‰€Œ@À˜péL_uA qú¨ñqÁsxî9ö)ø¨³L-ÒXî ‘³n–.mÿðTv(4A±¤·OÆ%,û$Y¿¿|°Ï¡¹xòáºq cŸ[±×ž*^¸œ[ñD€~&@ÿöóÐôDÀ£n@š8Pá¼}¸U<“¾Ë7#)uÖ­cŸ½ R½Ca¸g™ÝGŒ¢Âù¾†ô,ìntE8©|í%)š]›}4ñJhmMë6¡¤Þ©_ãnämëæáŠYgĨý¤óĆ̆9ØrØI·] v¿Mmsm ~¶h‰4ŽF{ BXîö³ûŤíã1q‚ó«&”¼ô¤g 2“&é²Ð}»’"@ˆ D€ôÏ×°MJ—*1öjÿ‰J棦Uìkkßðàþu©Õ/Xÿ¦ªáþãwŸ-º—&šùŒ •l˜R£}Wõ(bé%´4  D O ô4 CŸI“"Ф%cã’¡á’é?B[Ù+øñ¬(–"¥Æ÷þ„YºtiÜUIN©Z¬—ôoä`MÝå™K­e…–LÔ>•óoCvšIyaZ9ãRP\ý £ùÝN[Q¾%³WXS¾ð½Ó–ÞÈ¡ x*SÃ:k¿¹aÖ~·M Aݱñô¢$»HŸ«C„µ—Ë?ƒbEqÆËHʲŠãËmÄû×ÂëoíV¸|bšef‰!.âÛ³-CX·Qžõ^‹—žH:ݰ@Çž$ð× x&s "ÖÝË6¢ @óéýøGNR $¹ú=¨O‰|ŸW—÷ ÒS{04u!D€"@ˆðsŸYpêóøOt»èfÌ:>ÊŒˆE (”Þr[ë8|ü€q*Eyo\Ñî¡ô0Z[ÿ¥Æ˜éLsgifè D€I€÷¹ndõ !à:&»gÎñiVòŠ `Õ¹ X>{*–»J›¹ ǺÙdÔPˆ,»–ì¢7‹´˜¼ +™ŒŸ˜¹ÉgÁ*ñ i:+i4ÐÖ Hm½ÓŠŒ˜nÿQ“ðë7±n:²„ë¶~fÊÀ+ÇIµ®9126C—5Ë*Ò×áñüyØž+õ³ŒHOMuªs>]ŠâšWoÃ2cÞR Õ*Æ6.ÇTöq{.GX᧨nÉG4käÚV·½¥ ®ûyê£4 ˆ D€"@ú‘@Ešü&¥ÃÙþ9þv\¶@ãï€/·qˆ¸ß;öñ)j>^jÆ÷)qÅ=ô½7Ö<$Æ;kã [h "@ˆèú±gܨ ·§,.ÕzR€˜1%(X–ÊED¼ÚÉXR[¾M(R^m®Üd·2Š*ðÁÚacP±Q@€Ã bµÛï`±yP,ò›Ž!7™ßrÔv8ˆíZä•Ö`Ãâñªõ;0϶×`sšÖ±Þv¦KËñ¦g6AI ° ÷BsfC®>CG¿"UB »h¤tÉuA£Cææ]¨k‰öÔ1Q qº4OJ›ãÐY›†âc ¨)ΔUÅy~WX¶%­h«ÃšÊZÚ‹bKkxæ¹ö‘¨Dˆ D€"Ðÿj^·àb‡+ꟿf+ ĬU¡j=ËåÎ68õÆQµÞ‚öóÀu9þé³7|¤1ˆ D€t—€‚ýCëi»;3µ÷ˆÀøñ㑜œŒ¬¬,ÚS#"À05žñÀaÔ}׆aÃFalx8&GF!Ä®){TcmöUŸ› mÚ0úòɸnV BœôqçI›ëãèl7 €ŒÃò¥OB¨¯ŒtžÜ“óÖFTí?€úïÚ™‰£zÅ4DGØßh>S‹ºF³^CCdx2<µ!D€"@ˆL-Þ‰6!._…ðDÿŸù_ÿßÕ˜ ù WÜÛ;;¿*±`Ï"3?SctEeŽ;™¼ D€ø7þáqMM """üÚÐ.ä0¿¶Œ#DÀ uH8bã³™»iì…êˆ$°Ow Ð(IJß!ˆ‰‹wk^Px„Ñî¶] D€"@ˆôªŸ³`ì5 ¿ÛùE¢Ü3͸ü–Ë =9ZβT2K̘ýW‰í=H}ˆ D`PèÝ#íA†œ#D€"@ˆ D€"Ð9ïOs¨Þ`Á¬ýo£TW–_±P K‡xj{Ï^v·˜9ìYlÆäeJ\v7I ®S D€ mô¯ãÐ^òž"@ˆ D€"@zA`_ºSV"øªžE‹÷bêuU(í¹Ü{2€qì¯}–䄞ð£>D€"0ø пƒÉC"@ˆ D€"@ˆðoÊ-8ûÍoÖ¯Ö‹0}Ï¢ÜwXºEåÌN ŽýÙ‚›_WA©ºå 5&D€"àëÿ ¼à0 Aˆ D€"@ˆ D ·ø H?Kµ@ó´ÃÆ,ñYˆrJ…ªLÏ÷ïOqøä!3nú› #/Xþöv­©? D€î Á½;´¨- D€"@ˆ D€F ¦ˆƒé;S“æ¯Õ(ÐÞÄáô»]‹îËÛþc3¦>¦ôûaéæ$D€"Ðßæÿô75šŸ"@ˆ D€"@†,^hß÷¤×od©UT3Ú›·ûšßxåþy†ŠÑüCvÑÉq"@ˆ  ÁÝCPÔŒ"@ˆ D€"@ˆOà`¶ã¯W`âÜý+uä.žãÀçfwwœzÇ‚…,oûk÷á‚;ߨž"@ˆ€/ ìÿ;ð“"@ˆ D€"@ˆ€ß}Éá›,ˆ}^å¦ÅÀ©æ7>å£ÜO»Ü/Ôr({ÄŒ©0âÒÉ?pVƒ,%D€ÁB@=X!?ÚòØ{ò† Ö ãÛÐÖ6·,ˆG(ݽÝàæ¾ism9Þß{’5‡›$ |@qmFåN¾¸Ð†ÑSnBbl¸ÕÑæZì|/.°{ËõÝÕ† ¬OT âoŒAH¿ûÜŒòïãd0åÖ»è~Áè  D€"@ˆ@¿Ø·šå2gyÛƒ¦zò2ªÖs8û—ÞaÉ3·±¼í÷›qÕÏ•˜˜`¯ïWø49 D€@ ße¦ÀˆLô fè3’jèÙà¹MXÔ³ÎC²— õÇá\;< QávvGõ¸OX-Êš˜àn¿äÿ¤šáWI:ð·‘&»LÜ›ê‘t_ª‡ökQTñdžzØÞ͘I÷ ~d—5àîÄ4$ D€"@¼A n_Äaþ‘Ý.ò¢Ü×Xs¹Ë÷}¿¶ ` pÍS$¶‹¬è›"@ˆ€'è_NO(Qß8×óa[ÛM=ï<{6±hêtLŸ>÷<0ÉæÍä@¶‹“x K|°dV6•×{ÐÖGMd~ÈÝðÑl4, D€"@ˆ@p‡Š4 f>£bA,ƒ#º]Ä0å!¾?Åá«]ÖÔ2_¾eÁ—Û,øa¡ åàòUô™¾‰ D€øŠE¸ûŠ,Û ,ÿ¨8éæju^¹w*Ò…Èwн‚¸`À©ƒBºŸ.;`Z´Kaš5š<ïil~•Æa¢L³vè?€Ot٥ضúF˜ZíwQ{K3êNTà¥åIØh´:—šñ,+Y º³ðb“éD€"@ˆð!/¶pàÌ¢|´2@«3”B.÷Q‘ ”§˜qË?U |¾ú𡡉 D€Hp§¡ß…„¢cö’@„1]<Â&…"„ÒY‹8zþ8ÒÞw¸£ª‡ÙgУ æÿ ´ÿ¸ DPH"6£dRÍÝP‚#Í+×ñ¦´hÈ1"@ˆ D€Ï´7sø|7¿>x#¾§,WâÀïMøPkÂŒ_)O/Ä{vwP+"@ˆ Žè_PG½83¡µµ&“=жƒQW‘Ë9îîh¬Úœõë±>ç5œ1µ¢r[Ìœ …b&¶T5Û»™ê±{Û&¤° Ag*ì:û°v RÖ൒*ÈZÚúÔcǦ¬_ŸƒÝgL0ÕW"} XŸ™Â')kòQy¦Õ>‡XbsíܲžÙa›Ç6ß‚U›\·çûuÛ>q2¶Ñ¦à³|®™X¶ŠÙ}¼ÑÖÈ„ª[°~ÍïQh«9QüWää¬G~Éq¡¦ñp òóó±)j;¸Ä¸îÈDzù $,[ƒ•gDCdß½`ÇÒc2ºS ãÚN:tÛž^úïÒ»·7±ûùdzÔ.MÜf#tò¯ÈÕJܵ:Tæ× ·¢Á  ®”[*¬¥8¦‹om6W#_«¦2Ži°ÂxšädNã¶¿–Û%_䆲.çÊ-­q\˜žØÇÐrŒËÖºðEfk†þÇÉ|±ÞÓö>l“QÁ;G-W&¿ßÛk¸\i-ìýäãh3ôœ¼‹|¾n±ã-é ‹– ‰¹.·Bð‡ÿ£É˜'Ýòz©Xh(•ÖHæªå÷AOì‘ñî–ÿ2?¤{×fcY®ãÏ—¼²:Ñzú&D€"@ˆð1ïN[¸÷nhç w·smMÏÖÿÛZ-\ë¹Áïgÿ“& ˆ D 'xMª¦ÆI[ëÉ@>îC­ÙJ9{·þÙVÕ1öYÞ¶±r F„i°"KŒ¶]5걎冞° ò@ky_*÷ž@Àp>+9“ÃÙaÐÛq gâ­ØöÔ)²Ð!wk1Jw#/3YlÄ:§#õ/UösÙ–Æ‚kºh‘‘™‰Œ4Y?0÷¹mùå[±ãÉÙÒ\]Šô»°«x+2—Zmä'H“Šré¶ê¡}hDþÅ<÷ü¨dän†^¿i²hí,ÝcØ}á,HKcv/µ‘b͵K‘‘‘†G£/á;ÃÊ‘/Þl¦[–G"UÏ×ó‡ÙEŨ¨(CQ¶!K]N¹µ ÿgØñ{Ê‚ïۓÄÆÚr¬¿w[Eë¡É^Šh)ëLíé±ÿ®|0a÷¦e˜*þ|Ñ ÈØ€”¸PW©Ž"@ˆ DÀ˾)·`ç &\z›·lg¥ þ|æªá 7øýôò­BÃ"@ˆp$àcA` ßÞÄ‹s¥ÈX&к°n¯æ˜ìho«I把wq[7gÊ"fÙõ¥EŽÀÝ$Bîîó#—æsuòå£ý Mw¬Åq¬&éMpQвhcö·…CòfNSÜPfž†&“;Í+ï£ÉælñõÒ„ò(e)‚¹‡ö5UÈïÑ¥\©Ü8®…ÓgØ#ÿÓô¶§~ívº<£d_°s´ßïM2Ù›¥`9ît©Ü-W*:,çà);Þˆ²s—¯¡<Â]XC­–Óh4öüï._Ö9®±7ìñøÞü·Gêç ¯Õ´s¥Ù:ûÏh¸¢j‡w ø^t"@ˆ D€øˆÀñ¿™¹7CÚ¸¯›}4 Kˆ D€t—¯µP„;£àÿG+Jò×#eÙ(‚¡IJõÈäÃon@ØR“‰cùXœ˜€…¯EIS¤àÂ%x‹ÂÜER>ûÖdãÕ•‰•"”ÙTãq³-ºRªö¼ Ÿ#÷Ýè èKÃ̸éfV.ο>s^ª ³:ô„…8Sçß|zŸÇDeí.žGíÁOU`µY˜ù.ŠOW 1œÿËÜ{{ºç¿Ý¶åÓÃì'¬”Y¦ÇBۘР D€"@|A í[»™aþHܫƈ ”ZÅœiL"@ˆ ƒ€\&쾺ñ/×¥ç"ûd‹á>ü<ö¼œŽÂÎøÆÃØ)^×dãµÝ:MÄw³¬×…ü߆Ÿ£quBÜX@Õ½%ÀroOr _—†lÆî×þ„²Óá2Í»ÔÎuAžÕÜu [­: kŠ3Q´ÎVa@Ö ö±i´Éxôñ¥xà®x„:˜ÚMûZk°K |¾ Æ- DTtŒxÒýoùºXLróSB<^È /þUpžÈcvRÇn²úu^˜œôRvÍãÙç#G7é~ #’žÞŽ–ü…ìgôΞîû/LÚáÃ##.n–¡C{wí8|käÜ]rõÁÓY~Òú%zÈ-<9Lˆè„À…ZÕÏY f/•ž¬`ë÷È+Õ0ú7£tƒâÒùÃþ3ß„°[¸á*ZóA±ªä D€þ!Ð[ §¬ö꬈_¼ñÒ˜& /î\po>qHÚhQ»äF‡t#Ò0!˜ÇN1Ò°'šSB!$<Þ-°o>èÜY|6Õ"çŽH›˜ê4£F‹¥šs(ìôÉŠSŸ.N#×¢áØ­x奾QTÅ­Œ†¤ò¶q뮺mHàS´ôÄ>¶.¸\¥qéÂHO.ËçhrßA=rÆ»¿Ü½+=aáé ¥Ð ŠÆê7ŠQ–dý»zôZظ¾´ÇS»mí ë’ðò X×»GvßÕÿ}ÜÜÍÙoó^R!ìfOï “gD€Ï ˜/r8Ä„öêç-˜ò° P÷ ¾Ø\8Ááb=0‚½TÈ‹ð£l"¼\ç¯)”ôoŠçÄý¯åéw-øäA34¿S⪟³€"@ˆ D€ô‚ îàñr[çG€CÄÚ&8p”ëÆê0Lãó| ºk³ »nHµ¾"p|û³2±]‹Ü­O³,Ñ„ @^?Ì2¢Lï2­Lwì ‰ŠÇê ì“ÕŒ3§â³ò=0¼ùl”Âëõ˜ûÔ{hÏŸÚžØÇn>)uöjزÁ;™hBc}#L¬VÄô8?‰pjî|*Ÿ#Øù¢ý¼ùäéÁS'º¼½C'¥þX+Éœ IöH}æ/ÿC±_ía;@T4ý#ßYŽéK 3Sggb^ûÇÔU’žÆ^­À¼Ïe?¼<ëF­ˆ D€ j§ß³à³T³ ¦'–«|UGáÜÔÂừøÎ ðßNé-‚•Íߣ"ØGˆŠ·GÆóòüU£;Ž9¨¡0çf›Qý‚ñ[U˜˜@ùÚØò‘¹D€"@ü’ î=X––ÿ[<&\2R,vúM2W§x|pÑ„ƒ—ÙÆÕ ¨ú=¶é¤“ðÜXÓ^šÙtf7²^*fÑÑc‘ôÄ/„ð¨XÌç?ì ŠÌã; ›ª³ ÔGϲ(õÚ‰XñAŽa;öÕ¯dÑòNNœùã&% •šì2ìg錺uÈçÐãóÆÄ»®>º§Dvfä©ÜýBYt"—=L5Uö‡.MÙÊô¯=¹Ï#6ˆýh^ü 2™ànMR´½xJVÛßÅqé U"@ˆ à…óÏÒÌhüœÃ¬U¸â^÷B«z„c¦ƒ}\ ç|Þo^xçÇùºR&Èa­3½I‰KnT°o^w=ŽG†S#¯à¤”ÿ„Ý,åÞejM¡uñ\ˆ"@ˆÀ'àþÿ,‡8˜ÎÜŠºik‹Ø˜I5¥kýF g÷ }˜ã1q‚“ØÎDÕ–úÅ Ú7¼wDZ¾Ú‡uYYÈÊJÇÛFûqø ùžh»g¬»wöÔ¾ ̘¥µ kÀ3›w‹SHßå…yRy^ôD©,ºôu"fˆÆêñ«åRW©Ð\Ž ©bÚ-.u¿ÐSžÍìþ¡Xsm ~¶h‰4F{ ÛkÁ·öH“¹-ðï&ðGÒŒöµ4¤ÏÁ–ÃRB!kú“"@ˆès+‡ªL3޻΄±×(pwµºS±Ý“Á‡U`Üu \q3~©Ÿ¶Lû®š€…ߨû¼ ìÉjŠ,(žeÂ[—¶£ô^=oFý'ð)mèè[ߟâðïx3LlsÔ;?%±½oéÓlD€"@?Ü{°Æ¦¯>ÅF›–[YåYŒ4Ÿb¼§‡ÙlF;Ë«íé‡ãèÚÁdÓð¡àüÁ„éÌ-8ÞØŒÖÖVÔ/Ǧ”;0w(³Ì?{*ÀÒsöøš8MHK°1) ›J£Õ6Zks-¶­_ŽtÛ=£™Í‹º=·/~ÅSÒ\¼»lÓNÔ·²¸ìæ3ع)³ÓE¿tÐÅGH>‰R­~•ÇkÑ,êºR ± FâëÅèSgÛæ°Vµž)Ǫ›gÛ£ÂÓVãFðÒ]z΢ˡYƒÂ勳irrrlŸõX³j Ö¯Z€àȹ(ŸË@‹—žH`=|k'6‹m‚bEq†øðX¾h#Έé›"@ˆèSÿ²à_W›Pÿ)‡Ä½j\û{Ô#}Õ̧“áÓ”Ä<ÅDø÷ÔXxNÛJÔÿ‘òÿ³w'ðQUgÇÿ÷Þ „}GY4l".ìn¨  .(ŠµÚºàV·¾Šm­ÕV«ÔŠÖ¶Š­Š¶[Që.nhPQPA@QP¶ dî½ï9$! 3™íw?ŸqfîÜåœï¹˜™gžyŽÖÏ5ã"_O6êµÃ£šõK__<¨`%ïå«5°ÕÜxõ»æ‹C¢j;Äр絸„j»>•\GÇν^‘ãÜq#v:ÇÎýÎ-ûo¤†v5¶¨à|eÿ–ô·òûááÄeÛþ‘Æ»=Û¢ük§ì57fÖšm›ÛG¶]¶ÿ?gûÝx† €€_€`6|„S‡…ÏuØ~ñœŸr&…k‚ð«—ýðÃßFÃI‹Âÿ6Ükë´³ŠÂ‹†ßÏ BÆ2>öø!?|²Ù–pÙ“©wħ‡@ô¨_¿þN±§Êã7 —-[–ò$ÃÝŒâî,f/1ÅIÊYòibi¢ñ‘ÚgÇŠ&åìRÞªH$¢k¯½V[¶l©òmˆÉ°ÎŒ¥Q¥ÝÈ©[R*¤üír;Ÿ®o-Íßî`Gjââ5Z6qT™Õ‹´>öS„•±Qã]•š)ÙRêã3š8fD™ãÍÕÜÒìi³Úœsòâ ¥5×kÞ>©óé·™¾39Ùå-Ã4î­eºëô2e^rûè¦GGn¿ñæ­¿»¨[²z[_ìšî< ÅÇlçW¶?GŽÓ²‚»Ô}»ÝjfWs‹m“È6Ú®TNi§J:Wþ}a5n²V=¢ò¶ý#Ýö”pTçÚ±+Ù¯nÎSk4ê£1®/mÿ„Ëм’ŸO”®å €Û ԜßûzaŸ¨Ö̶Ÿa²s±5º­ÃÄ>Q53%_†~Ñ^§¦ÞÇŸºÍµ3ï½nõbÙïg¬‹hÀ³µ:ÂÑw&ÿ­Ó£±,ø7NŽjý§™?ž¿ eÇ.žKà×ìŸ{³¯cÌ/ òÎH½ë žýåX €¤‹Àºuëªï´±ÑtYû•@º4¶vÚ™¯‡Om¬ cÁòašµáy3ág.œ§sëõØZRc„æ< îÛbu±×μGÍ»:öxà˜šrU5'®ÜzÊ-ZhĈ¦6øèÁÓ* ®Õ¼9kõÆ"åä4P«½»ª[Þ¶(ù_/ת‚¨ê5n®Ö­ši‡pg•OS²atírÍúp޾\³EuêÔ‘ù¯:uí¡ÝÚ–ìÝi_4_ŸÏ_¤ï6ÉôMªßdOué\ÁyL£ù«µÊÔ–É©gjU6j¦Üªt6Ö¾µô[ÛŸ-úaKCíÛ³·º—1,éûnßïŽÅnŸ¼œ¤Z{Êi"«@(+°ùûPoŸmÊ®“:œíhÞ-úÞí©ÓyÙ`ürB YfRÔ&8:hŒ§F[:¦ì$âqÁ7¡–ü;Ð'·ÚçRS¢æ&7áåpÑ]så¤@o õ˜Œ¦:MÍ{Ûööæl½™Çíìã’uæ=mã]ëæ5æßÄO}S+_ðŒ©§ßj×û쪼Ž €ÉpG&Ã]yyyÉi@ÏJÀ}'¨*ÜMNûÓ—æèŒ‹w>n¾¹ [™#}­? j§ë¦¯;wƒ.Ý> ¸Ì¶•?$à^¹¯"€ € |ÿ~`²¡}µ;É5AvW^GßÏ2Ò§Ec™Ý}þâÊdv°1±Éd¾Ê×úa,ÐÞþäÌú¢aãÅý[û‘éß=žÚŸ’9ýÛ¼6ÔË=¢:ä^/V_}“™¸¦`E¨M_ÉÜv¸7ë Ìë^½­Aùñ6H_Ϭ ¶„zÇ|µç1®™ÌÖ\ÿ9™}ýóÿB@2] ]îUÉoÍô±ªAÿ":þçc¥/‹í;þÂý´W·ôóc»)gÓ—wußÒ`»ŽÕOjl¯AÃØ@@ Žõ5ç† „í8|[¶E_GC>ˆÄ2|'ãëÈ'=ÕÛ#ó‚ŽÑM¡>¾-пêvkJ²xòr3¯Ÿ övtÔó}õbûbañ¿ŠÇ¼a^ú÷õý+|µ=Þ)ý¡¡I\«¬_¶tRá·e‚ñ[ƒó«¦Ùà|ñ­p•ÔûvW]¯ð²ðÿ t@’%@À½†òº_¤É£žÐ17§±>g€v.úÒCÆ]¤mÅKjx2vC@@ h~ï2_ßÍ5øÍˆšuß9ðjKh úŸ§hâAÑXY–‡l Ê—sØ´Zõų¦|Ì5¾šõrtâ‡5츳AZu¨ µ™û{cJý!Ð+½¢:à7®öûEúfp/{<Ðw3C4§êO×d±·‘¹9jqpÐØ@¨%Ìy§°‹·—=IDƒnœ ‰w”$³Ìë=†kÂü7tJ^Õß4–Ù›‡ € €T*`˧¼vXTE?(–Å^^°½ä¶”Lß¿zê}‡§©'ø²™Ñé¾|õ’ùá¨>ú¯Cî÷tô„ì¶—Œ[¤¾£Þ£=?=¢¯_5åXLàýÛ·Òo\7™Ìô÷ÿÏ×áÿñ”Ó(ó¿,)?î@@ s¨á‡±æ­¹-Ъv¶Ü:jÝ¡[ÅdVó|Ôp¯&›#€ €Y ðåóf\ìë€ë\ímõÊe¬êÍEMùSë}Lq­÷t"ûê…@óF*Êuào=u8Ç‘ë¨]òH ¯õÕæG}îLÉAÃ0Ô”ã}57¥ì—, € €@eÔp¯L'Ã^‹4j«>ýÛfX¯è € €@ª ~«Õ¾ä?A¬4ÌGUÿ«Ízn­ë~¦¯×úð´©ënÊr¤òb³_=š@»/¿P:ðwžòÎ$Ð^vÌ:ëªýÉŽ>2µü_Ü/ª^tÕe„+ûÁ4U—Ïþ¨pU¨·lOÕ1¢] € P}ê¿C¯þ9Ø@@vS àÛP“ûZ==Ô‰³#ªI°½¤ u››ºî¯zjÝ߉Õu_==5K‘Ø@ûO×)ÿèw¾ö¿ÎÓÐO"êxŽ©WNV{Ép–Þ×iêèû< šèiу^ëçkÍGaéë©ô`ý‚PsèˆñyuR÷KT2£- € ÜÓcœh% € €@ ¬zÇÔ+ïUóÞŽOOFºt²÷ížúÞí顾ŽõSF8 B-{"ÐËÝ£±¬v›Ñ>ôãˆ:œi2¶M»Y*hq°«!ïÛ/&M>&ªFú±<•ïU{¯ÑPÓÏõÍ/\5=ñ¬=y΄ €µ!@À½6”9 € €5Xp·¯7OñuÐ7ŸÚ Pã¹äáêØ·"šÿ—@ï^•¿9yÑ6оô±@/Õ'£ýX©‘çDdۘʥQâ9ñ:–ýbbßÿ+þE€-Ûòb·¨–?™¿d˜wK Hi¿kø8¯ñæ8 € :‘Ôi -A@@¢B͸È׺C?=¢ÆûÆ7Ð^r{o³ŒmFô;çøú__G=ë©~ûįì¹íc[›~ùã¦Fû­¾"õ¥^·yj?Ì!Ⱦ#T ž×ÛÓÑ‘EôÍä@ï]ákñ¿r¯§F]jo|Ë6û»™Þhˆ)‹Ä¯ÊÊð@2E€”‚LIú € 1ë? õêÁQ9f.É!ï%6Ø^‚fëý¢§¶Ç×uÿö­ÄgCÛÒ"Kþm&ù4Ù× Æês§gêÓçh¯SÉh/—xÝïyŒ«“æEŠëö›k˺×öÝX\J¦ï]žæ%'à_Û}æ| € }d¸gߘÓc@@Xöß@ï›Lä·¸±’ µÙT›qÜóžš÷uôÖ|uÿ}¨ó`@IDATnW™¨œh_úŸPÿÑWÝ–N¬\N»ÉŠ3óN‡³““v7õðÛŸìjêШò?ÕsTüÇw§o]1ë—švwÔé<ƺ"#Ö#€ €@ú pOÿ1¤ € € …šý«@_<hà+žZ–¼ ¤Í0oÜÍÑ›§FµæƒP‡<à)R¯òŒähA¨¢ ŠÝ¢ùö~Ûó¢ü2Í6+^ T¯£ƒMi“¶'$¯ŸpÙÔ¨ Íz::afÄL–k‚î‹CõçÉ«[ùøÖèDevZñJ ¯^4ÔdÙ³ € €™,À»L]ú† € +C½uº/¯žLI•ˆr[%6øY”&&ànËÙL?Ï×ký¢jq°SI@] }Å&ÂÌilîI9s³÷æVæyýöÒaÿôdKœ°$O ~[GÇM‹èí3}Mlêö?ï©n‹Ä\w›¿7ó\ìÇÆ=QçHž$gF@¶ ྽Ï@@¨UÕÓM;ÃWÇá®zÞæÊõô¬I§lÐ|Àsž–Œ3ê&K½4ˆ  o ªÇìf“`ÖD9yûD˜ñ5öY×zõ°¨ùe…™/`Ÿø_3/õµ×0W” JÞXsf@¨=îµgÍ™@@ØN`áý¾æü6ˆ•lÉ;#53¾ÇQçŸÅ?»O’&`¿à9øÏLZ+ý<㙉Uãw-.ùO µsBôQíÕŠO&'F@Œw.@@jYÀßê½Ë}­~;Ô±¦¬GÓh×òpºº]í©aG[·ß×A÷HÏÙý ûÆ/B“=ïkàËf“MÏ‚ €dƒ÷leúˆ € 2¿4õÚO󕻇tÂûÕiB 2e'ËÒþWÇLrôÆÉQýðy¨î7Õ<+= CM?ßW×+ݤNœåCJ÷@@ »Ÿ¶„FsJ@@ÒQà›©¦VöÁQµ=ÑÑÑ/zÛÓq3¼ÍÍû8:~FD_<˜€yTþ–°F=žÿ×@Ñ|©û|ä¬ ;!€ €@Ú ðî'm‡Ž†#€ €@¶ ,{<Ðw3‚lgH›þÏ¿ËMŽzè?<õ¼Å“­Î‚@* 4ØËÑqïDTø­4å8_›×V/è¾îãPßèðñžÜ®óTcÚ„ €‰ àž8[ŽŒ €$L `e¨÷¯ô5u¨¯Ù×úò «KXÃ8ðNÑM¡Þ>;ªÅÿ tüôˆÚŸÌ[ðX‘r9̯0^òÔ¸›£×úE•oJÌTe±ñï ªç(WM̾, € €@¶ ðn?ÛFœþ"€ €@F؉;žçê¤9­ÿ4Ô+½£d»§àÈæ/ cÁÊ`‹©×>3¢Æ] @¦à0Ѥ ܈£CÇzêr±«×jõô]ÿ¢fîMr[9êús>jVÀÊj@ÈpÞeøÓ=@È<•“­šªç\ÕoçhàËíWœíþk²ÝSeÄ¿~-Ðk‡FÕá,WžŽ(§!ÁöTÚQ=ýåéû=½a~Q³ì‰Šƒî«Þb¿äè÷0%“ª'ÌÖ € IÜ3i4é  €d¼€¿¹¸”Lß»<Ù’%Kç ¶f»B¶{‰I²îÃÐÔ¯¾Í×ôᾎxÔÓ¿ñ’Õ΋@Üö>ÍÕÀW=ÍéëãÑþNÇ-Ê5ý<_ÿÍ‹}¸Ó¬@@²D€€{– 4ÝD@Ìøäö@ ::ÊûÉÎoãÈvOþÛ ã[?öµüÉ@'¼Q›ãv§ä·’ P3–‡¸:þ݈–ŽôîEQEÛêº`ñ-ub¿è¨ÙÑÙ @È >dÆ8Ò @ÈüÅ¡Üè{+Ϙ&Û=9ÆÏB½jJÈDê)69jCóÅ ™&аƒ»¾7.—¦ ñµe}¨¯^´òµPßWùÿ›2Í‚þ € €å p/O…u € €@ ¼w¥¯n׸jÔe×\²Ýkw¿œ`êµ›I%÷áš22EêïzŒj·…œ ø ÔiâhÐDO ò»îgŽðÕoœ§ºÍ¸îã§Ì‘@@ ]¸§ëÈÑn@È*[¢dãÒÐÔ¯ÞÛ7²Ý{™„A¨97ùzïR_žõÔm$¾‰çè©"àæ8ê÷¯ˆ:žã*ï§®Ú[½ÿ7¥J?h € oH¼Èñ@@â+`ë‚ϺÆd>ìÉ«[ý Ò’l÷Ï4u¨¯Î? Õs”+/·úÇŠoÏÒÿhÓÏ÷µá3iÈÕogú(=¨®À7ð%SuÍØ@2[€4„Ì_z‡ € 0çÆ@­û;»AJ¶{|/†ü%¡V¼jðd`{|i9 € €i+@À=m‡Ž†#€ €@6¬ù(ÔÒÿê{W|²HK²Ý÷¿Î‹e»Ïþµ/¿0Ìʸ÷qÑ}:w•ÓˆÌö¸ãr@@@ÒT€’2i:p4@2_ C½w™¯î7»ª×&¾A]›íÞæXGv²ÃWzGc¶<¬â\ Û–èF©hƒÍ·÷aì±}^TÎsShÚí©a^|Û*£n¿¤°%zŽ}“·Ó©2&´@@TàB*Œm@@ÊXü` `K¨®WÆ'»}ÇS”d»—Ôvßãè ¶Iq}[P=`7Au»DJ9KnŽÉî.yl7ì müÒѤQ žQ£Î™t_ößPMtÔô€Ìë[l ù € €ÔH€€{ØØ @H¬@áêPý6ÐÀW<¹^bƒº%Ùî_>(§¡ š—ÔM€Ý”K)yi 9NÕÛbŠê˜×#jÒ­êû%V6>G_hÊÉìmÅ¿ˆÏY8  € €¤›÷t1Ú‹ €Y!0ûW¾òÎpÕòÚ êÚl÷}ãœI¿ß/åø¨Ž~ÉSËCk'k?£¼ym¨/ž uò§éÿeH"|8& € €Ù.@À=Û¯ú €)%0ÿ/r[;êtnú¥ËíxŽ º×•¦žèë¨ç¥ÖýÓ³Ÿ?¨ÍqŽê·ÏŒ/CÊ+Ö!€ € €@͸×ÜŽ=@@¸ ü°<Ô'w:~zf¾EÛûtS†ÅÝß<ÕWÿ'¥=I¯ {†Z46СÝ× Ÿƒ!€ € Aéõ)'ƒàé  € °£Àÿç«ë定엹ÙÓíOvuÄcž¦ákÅÄ`G‚”~nëê;&Ö¾ç ÞB§ô@Ñ8@@’(À§…$âsj@@ DàË ÖÍ uàï2ÿíYÛã]õÆÓôá¾l¿ÓeYx_ ®Wdþø¤ËxÐN@@RQ€O ©8*´ @²J º)ÔWù:èož"õ37»½ì î9ÐÕQ/xšq‘¯åO¦~Ð}㡾}#T§óyû\vyŒ € €Û dfÐíûÈ3@@ ¥æÝ¨yGí‡fW0·õ®M,žHÕ߬”ž(váý:œåªN“ìøB$¥ÿÁÐ8@@RX€€{ MC@ÌX÷‰™ˆóÁ@'ÍÍηe-6A÷IަU`‚î].N½/ü-¡>(РײsŒ2ÿ_!=D@@ ~|jˆŸ%GB@ª%†¡Þ»Ü×7¸j°WöfN7ïåhð”ˆ&•_jߟ›™IShùâ©Pº8²ídA@@* à^™¯!€ € XòïP[Ö†êvMj˜Øå ÝôGǾÑëÇØ »´ÿ¯RÇ$6Yê•©—y_!&/ € € €@Ò¸'ž#€ €@6 l^êÃë| xÆ“!sÚ^ »::î-tTtïþ»äÝ×Î •¿(ÔÞ§3FÙü#€ € PURuª*Åv € €@>ú¯v'9j}$oÇʲ6ìh2ÝMÐ}É¿}ô;¿ìKIy¼ð^?VWÞ«CÀ=)ÀI@@H32ÜÓlÀh. €¤¿Àw3}ù\¨¡óy+VÞhÚzö±LwS^&0åeúü99™î[Ö‡ZöDh&´MÎù˳a € €¤¶)U©=>´@2L ðCͼÌW¯Ñžr[’5]ÑðÖkS\Ó}å¤@ïÿÜ—`¶¶›e¿ÇÑŽæ1NµmÏù@@HWîé:r´@ÒNÀ?ýS HG/"ˆ»«ÌmíhðÔˆ¾›aêÝ_ìj󸿛,õ Þ.Ç–"€ € ÁüŽ9ƒ—®!€ €@j¬™mJ“ü7Ðò'9¦:ÉQÏGä8Ü«2:u›;øŠ§WúFÕü`G~Z;ðo& £R›ã§ªŒÛ € € €@±w®@@ ë?µõ¿MÝÚ£?H{ÿÄUÿ'=µ<´vÆ èRÒi3Ý<åiêI¾šuwÔdÿÄÁmvû>—»|1’´QçÄ € €¤§÷ô7Z €)(¿$Œe±Û {Á×Ò^?vuèžZp三§ IÜšÔò0W=o õæiQ y/¢œÆ‰óÜ´"ÔÊI¡ý“¥Æm9 € €Y"@À=Kšn"€ €@blpvù“6“=Ô†ÏBµ?ÕQï;<í9Ø‘I\P81½Ií£v½Ü‹ÕsŸ~¯£žMÜÛØEÚûtG¶œ  € € PÄ}R©N+Ø@H#ÂÕ¡¾xº8Ènë³·;ÉÑ×»j;Ä‘W— m"‡ò±ž^ëÕ'wø:àºøg E¡ÿ3ÐÑ/Äÿ؉táØ € € ÜSch €¤¸À–u¡¾|®xòÓÕï„jc2Ømïö';Š4 È^[égê¹›ìöת…™DuÏAñ­‰oǸ~{G-Šïqkˇó € € €@r¸'ן³#€ €@Š Ølöûúfr¨ÖG:êp–üÔQ&Ù“5t:9ê÷°§wÎö5ä' W[ìd©û^I°=^ž@@l àžm#N@@ ZŸþ)0µØ¥S—F”ÛŠ {µð¸q»“\u¹4Ô[§û:ö-O^Ý›uŸ„Z÷q¨¼Ÿîþ±Øu € €),@úN MC@ä ®2õ¼ÿ¨÷Ÿ<‚íÉŠrÏÞã÷®ê4“f]”ûzuWÚìöκòr ¸W׎í@@@ X€€;W € P€ÍnßëÇŽu&[QRW;®£#õôõ«–ü{÷‚îE?˜úüÚç2Þ'uP99 € €i.@I™4@𠀉(ø6Ô"“Ý~⇼]JŒp|ŽZ·¹™Dõ™ˆ&ŽªiOGÍ{ÕìË‘¥ju8_®ÄgT8  € €Ù+@ OöŽ==G@Jlv{Þ&k&èdImæ}õù‹§·N‹jóÚ°Fµådö¹‚·Æ5Âc'@@(àSE)@@b‚oLíö:ð·$i"`k¯·9ÖÕôs|…Aõ‚îß¾(š/µ;‘/WÒd¸i& € €)+@À=e‡††!€ €@²>¹Ãd·ÿÄQÃŽ`“559ïA÷¸*üNš7ªzõÜÙìvS»ÝÖ„gA@@vG€€ûîè±/ €dœ€Ínÿü!²ÛÓq`½º¶ž»§…÷ZñJÕ‚îv¼W¼ªóE¼-NÇ1§Í € €¤šŸ,RmDh €$Uà“Ûu8ÓUÃd;'u jxò{9:âQOïžï+É®KË,6ã¶?ÕQn+Æ»†äì† € €e¸—Áà! €d·@ÁJ“Ý>.Ð7ð)¯„6ƒ]uû…«i?Ž*ZPqÐ=ðC-z0PW&KMçá¦í € €¤”Ÿ&Sj8h  €$SàãÑ&»ý,“ÝžG¶s2Ç!ç>à7®˜_)¼w¹_ááV¼*·¥Ôªo‰+Dâ@@¨–Ÿ.ªÅÅÆ € ©›¾µäߦv;Ùí1ÄŽãèð{únzhjº—t_h&Kíz¥—ý¥ € € ÜSch €$Yà“ÝÞñl“½7ÙíIЏ>§±™DõÙˆæü6Ðw3·ŸDuÃÂPkf…êp6ã7p„ € €"àÎE€ €Y/°i…ÉnÿµÛ3ñBhz £ƒïõôÖé¾ Wo«çn³Û;žç*RŸ€{&Ž;}B@@ YÜ“%Ïy@@ ebÙíÃMvû^_SfPâØ[—ï»zûL_v¢Ôè¦PKÍ,]/ç­p™9 € €>ep € €@V lúÊd·?bj·_ÏÛ¢L¾úÜé*Ø"͹!вÇB5ïë¨ñ¾|Á’ÉcNß@@H†@$'åœ € €@ª||[ N纪ߞàkªŒI"Úáæ8êÿ¤§WúFš9TËd©‰pæ˜ € €d»©\Ù~Ð@²X`ã—¦´È£¦v;ÙíYqÔkc‚îOxŠ4ÚÂ,Y1èt@@Z ý–Á9 €¤ŽÀ'6»ý|“ÝÞŽàkêŒJb[Òº¿«cßtäzŒyb¥9: € €Ù)@À=;Ç^#€ õ¿0Ùí:y>o‡²íb`rÜlqú‹ € €@í PR¦ö¬9 €¤€­ÝÞù“ÝÞ–Lçš‚ € €¤µ)]i=|4@j"ðÃòPËtÊÞ ÕÄ}@@@Ê ý|Ö"€ €@ |òG_/te'ÑdA@@@ ^¤uÅK’ã € €@Zü°Ìd·?ê”ϼ´h/D@@H2ÜÓg¬h) €ÄAàc“ÝÞå"“ݾ'Ùíqàä € € €eÈp/ƒÁC@Èl–†Zþ$Ùí™=Êô@@HžîɳçÌ € PËón5Ùí“Ý^Ëìœ@@È2ܳf¨é( €Ù-¿$ÔO›ìö…ÔnÏî+Þ#€ € €‰ Ã=q¶@RHàc“ݾÏ%&»}j·§Ð°Ð@@@ £ÈpϨá¤3 € Pž@þ硾|–ìöòlX‡ € € ?2ÜãgÉ‘@@ Elv{—®r[“Ýž¢CD³@@@Œ Ã=#†‘N € €@Eù‹Mvûs&»}µÛ+2b= € € €@|Èp#GA@˜÷S»ýR“ÝÞŠìö"š… € €dŒî3”t@vذ(ÔWLvûb²Ûw´á9 € € €@üÈp¿)GD@øØf·_n²Û[’Ýž"CB3@@@Œ Ã=£‡—Î!€ ½šìöB ûœìöì½ è9 € € P»d¸×®7gC@Z°µÛ»^áªn ²Ûk‰œÓ € € €Y/@†{Ö_ € y> µâ%“ÝNíöÌ\z„ € €¤°î)<84 @ª/ÝjÆE¾ö½Šìöêë± € € €Àîpß=öE@”ð7‡zs˜¯zm¥î7ñ6'¥‡Æ € € €Y À'Ñ,dºˆ €@6E¡¦îËË•ŽxÔ“ëQ»=Æ>"€ € €©$@ ÷T Ú‚ €5üPïœãË/”Ž~ÉÛs¶×’@@@vK€€ûnñ±3 €$[ MÍöŸù*X) zÍ“W—`{²Ç„ó#€ € €Ù*@À=[Gž~#€ !ï_hý|iðëž"õ ¶gÈ°Ò @@@ -¸§å°Ñh@°³~ákõô@ƒßˆ(§1Áv® @@@ä pO®?gG@ ̹Ñ××ûfDu›l¯!#»!€ € €ÄQ€€{19 €ÔŽÀÇ£}-{ÌÛ§E”Ûš`{í¨s@@@] pß•PU_*¿ (¶uN½FÊE¶ªrl‡ €@µÜãkÑý&ØþVDõÛl¯#€ € €$TÀMèѳàà˧=­kÎ$'§ž7n»ÕËqtî5hÞêhÐE@jO`Ñ?}r{ c&GÔ°ÁöÚ“çL € € €U à^¥ ¶™yϹê0à Ý=~êN[Œ¿û2õh£f®Þé5V € €@õ–>hÎï|3)¢Æûl¯¾ { € € €$Z€€{ …óç=¬Ã®_º÷ÀwhÂäÉš0î ,]+]vØ/4;¿Ì "€ €@µ¾x6ÐWû41¢¦l¯6 ; € € €ÔŠ÷1GõÎCw•î9òѹšòÀ¯uÊ A:å‚_kJÁb*º×Û‹Ö–nË@¨žÀŠWͼÄ×Ñ/zjÞ‡`{õôØ@@@ 6¸×H»@Ë—Îݺç0yr÷í’ÛYçYºnÊûKKó@ª.ðÍ”@Ó‡ûðŒ§VýxÛRu9¶D@@ ;¶DC½·0ÐÝ/øzåƒ ;èuR"I={ÚžÜL†º¡¤ñ´¥œ¹Q Öl*Ù@‡ï¿Wéc € €@ÕVO4í _G<æi£ ¶WM­@@È> L}Q¨w„šµ8Tû–R¿n®zvä²Ùw5$¿ÇÜk4Í´ÏÀÒT›å>U®z@Ëþq©òr‹¶zöcúé…–¹ÓÞJó@v-ðý¬Poœâë°zj{Áö]‹± € €Ù%°z}¨Ÿ…šn‚ìó¿ µß^ŽïæhÄñ®Z5!О]WCjõ–€{ ÇcÐÏÔð›SlÚÔñ—©ƒ¹ 1Rõ¿¢'””›‘†Ý1Y§–Dâkx.vC@ ›ÖÎ 5uHTÿÍÓ^?"ØžMcO_@@¨L`ùªâû» ­ø^êÛÙÑq½ýö W ëd¯ÌŽ×jO€€{M­›ª;&×ø!&än’Ýebìã¼{§£ýò’Ay'V € P®À†…¡¦U¯Ñž:œE°½\$V"€ € %AêÓ/eJűr1…EÒaû:nJNöêä¨N„ {–\ iÕMbÁ5®¯§üIíL°½‡ ¶Ï%´÷0îƒL†û“á>5vT‡м§&,›©SÈr¯¡4»!€d‹ÀKC½~LTþÖU—‹¶g˸ÓO@@Ê l) õá’âzì3LBNCS¹Ÿ)síižºµ—‡ {Y/§ž÷šŒIá<]wÌu±=m°}Ø5î'¨ÙVÍ1_ÏÔ¨á‡it,î>WÃî~CEwP£L÷0 õÕW_iúôéUné~ûí§fÍšUy{6D@ ÙMÍElß÷ÿ\íûs/ÙÍáü € € PËkòC=öf )sCíݪxÒÓ;/pµW+ìµ<µvº3f(‚Z;_mÈ1ݰ¶N–)çÉŸý€÷½¬¸;ÃÆjÃó—j§iQ×NÓ©ÍhBl«‘š_t—ºÕàë¦M›ªN:jÛ¶m•ùþþ÷¿ëÈ#¬òölˆ €@26}jÒÑQu:ßU÷ ¶'s,87 € €µ-°±0ÔÓÓ½ø^¨ÝýäH&=­í1HÖùúõë§‚‚‚*Ÿ~Μ9Z¶l™òòòª¼O26¬A8ÍL±sælkϰ!‡ïl·/7;X§“&Ä"îKµÞ^;;Eå·§¢Gžç颋.ÒèÑ£+Ú„õ €¤­À¦¯M°}`T‡lOÛA¤á € €Ô@ (ê¥÷C=1-PŽŽî¹ÄSÛd³×€2mwy÷Ýw«Õöt)'DÀ½ZúóÆ6›ÙÊ]*Z_îÆ¬D@ ë Vš22&ØÞáLW=n&³=ë.:Œ € •v"Ô©óBýgj ¶Í:ÇS×vÚ³òbÈÐNp¯ÉÀ–‰¥O½ú.;ðõÙ!{½pÁ‹º°¸žŒÔcºîðzMNË> €dŠ@Á7&Ø>(ª½OwÕóÛ3e\é € €• ¼¿(и×¹&¾~ÕPW}»¸•mÎk¤¥÷ [£ƒu½Ù¯¸ÈËxõm,=5ãfß7O9kõéÔÇuá°«K<âºãĦ¥<@Èr‚o‹ƒí퇹êõG‚íY~9Ð}@@,X`æmzÈÚW¯uÞ@WG›ZíéR$ †‡.ÆY€€{M@#uýÜqÝã­{ׇ/ÿHÇèÖ³»•ÿk@È2ÂÕ¡&U»“\õ¾`{– ?ÝE@È2¯¾ õðä@ꬮN:ÈUÄ£|L–]Y×]~·QÃ!oÔý,{K£†õ¨ðÃ5S®R« ·à@²G Ð¼Ù¶edÚïªÏÛ³gäé) € °½Àœ¥li‘E_‡±Œç-fòL–Ìø~C¨{^ô5òŸ¾:´–ºÊÓ°C ¶gÖ(Ó›ŠÈp¯H¦ ësóúëÆççhäן룋´ö‡-Ò–-ªÓ|/í×»§òšåVá(l‚ €@æ lþ¾8³}ÏcLÆ¿lÏü§‡ € €ÀÎ_˜_;ŽhÅšP­LyÞu¥õæöC¡T¿®Ô¤Ô4vsb÷ÅÏ‹—¬·ëד\[œ%å6†zòí@/½jPGÿø¹§f «”(”PîqàmÔ¶³ú›  €ì,°Ù| š<8ªÖG¹:èn‚í; ±@ÌX¾*Ô‡KB-^êBóe{‹ÆÛ2k„«ß„}ô@ÿû(Ô釻ºùlWu"Û®‹¨jæâüºa,_Œµä›’ça,8o×E¥Fõ·ç÷j)õîä¨gGG r··ú-Ýý=ŠL¶¾-Ÿ2kq¨ÙŸ‡±/"¦¾Dļ .¹yæyŽyî™Ò*±ûÒç[·Ùaûâýó%ƒR†2d±Ç¹7OcKÖÅž—YWòºÝÖîÛÇtÕ~ÉÑÐäŠ64f Í—ÅÍ}=ó<¶^ÆSÊ­³kSû+…ß+¶÷2ãð·K=µm¾ëýv_œ# zÜSoLh €#°y­ ¶UKóÁêà{¶gÌÀÒ@ʬÉ/°Û »½Ù€ž ~æÖQ¬œÄ-g{ê´'·2dYóІ'™ û83Y¦ †ß¹§VMv¾lMïæ»I;¿¾#Xá–mÁw _òôüŒ@w<#s­I½Ìõ×§“«ýö²ì]oÇãW÷ù ókN`ÿÀÜæ. M YêÛÅÑSJ±y#GQ_±›oþm™Ç¾‰ŒÇîÍó’×b÷å>cÛlÚlþm™€¹Mì·÷ؽylƒø®c‚ñe×›×Í*Ù®—lkŸÛÇ%ël7m.þuýBdõz)ßüÒ`£¹ýP”>¶Ïí9lÞßÅóö‹âÇö>ÇôµµkáèÖážöikNÆ‚@ pÏâÁ§ë €$R`˺PSŽóÕòlÿ»ywÏ‚ €!`ƒó–›àºÉÞµö•k¥ól€ÓÑÍ—ì÷ØlûŸ Â]÷o_×þÈÕ!]y?@;ñÙW¡î›èDzÑo8ÃS÷Û®‹*¢ÂÍlƵýBgfvG‡î+e~Mi¯Mð¶×åß_öµÊ‘»›kÓ~Ô§³£¼ÖñiC ~ÏYZ`ŸeþØ’8öúï¿¿£‘§Ù+l|ì…ø´£òsÄçÕÀDù7šÀ|q ÞåM ¶>7ýÎ/°¿@cýîÓ™ãñQç(é.@À=ÝGö#€ ‚[Ö›ÌvloÞ[:ø>×dؤχŠä¤I €$UÀÜ}-Í6ALÈ\`©Í$ˆ½Mó²!®ößË”Å(S¤lcëíªuiôÓ†-l¾ˆOö2ó³@Ÿ£ØDŽLvO´¥xüFeíÅí3†fÌ]x#Ϧ_×Âbñ‡tµ·â“•üú–vyê“>n–’໽·ÙçUYl¦¾Í¢·Áu›Ån¿L°™ôuquÝ]um›¹×ý·a³ÚíM[¿à¨ŠÛ ÍŽùŸ†ùA Kª ´hÑB#FŒÐèÑ£Sµ‰´ @íŠ6Û›(ú`ûv:[Q|¿x¥Ô¤LÞ‰eÀÛû.m¤:ì_S³êì÷Ç_ ´Ð´ñbóË…£»WÝ·:ç©mí—#sͯ9ƾ˜Ù1ã½6ÚÀ9@ rî•ûðj¸WŠÍ@’*5™aS†øj`~Ùwø¿ ¶'u089 €Õxêí@ÏLtý®ÉjO|ÀÔV¶}ØÁ§Ì 5êo»IV«ÙôJ7_¼2ÔÏú±Àö5ê2‘e¥‡‹½hëÙÛIbËâW™‰â›™Ìó›¹/ToÖ0~ea|sîe& »$oïW®±åoLÞdîïk³áÍ}»ñ;gE"vrÒ'Íu3Á”9ùGgöw·+ÇRÑ~¬GvG ]îLšº;£Ì¾ €  è&“Ù~’¯úíMfûÃÛ¹$@H›ý}Ï‹™5Ô_/öÔ6ecªÒw0¹p°§6Íýúa_׿ê }âè·é'ßõ¬ùáÂÁvÒÎøÛN iÚíZ8:b¿ªô6~ÛØ‰G;›ŒöÎmÓ§âãn, µÐŒßg¦4ÊÛóC=ôz -Q[ÅàM¾)ƒÒД¬i˜kîM~{«on»3‰é[úÇÿu6¥Wþvií]7ñ“äH €@b¸'Ö—£#€ ÑQóÓÛ7†úª·§ÉlÄ“ë•ÿ“èŒF s €¤¡ÀZS n”©§nk™ÿõ"ÏLŠZûÃOèãj“ >úéÀL°)tðîÆ¿ú.Ô_L­vÓט™ ¶ãf'üìÝiÛEø­É¸·%^l9šI…²¥R~05ùm]~{_dò¶,Ž ¾ÛÉpšk äq£Øº’ }É6ůl‘Æ™_&¬1sö\}r|¿$ÙÖz!€é/@À=ýÇ € X°ýd_u[š`ûx‚íINŠ €@ l©•[÷5àGëÊfm'kéÝÙÕ:ºé1__¯ kÜ[¦æ¥÷M½ö)Î8Â57'©ýJ–§=ïfòU{ë@ù­°uômà=v+°÷eò[Ÿ¯2õèK^ßX(k þ´~®N=ÌU„$‹òqY‹î\ € P#Y#EêKGÎÓOû»úµÉtŸýyPòRéý{ ]vŸo&û”`{) @RB€ ÷” €@z,}4КY¡Nšã¥Gƒi% €Y,ðÙW¡F=áë¸ÞŽÎèšr-é“~âA®™øSýt Ÿ –†ôuU°9Ôƒ¯š¹0Ô5Ã\¼_þgñåM×@” àž²CCÃ@H-M+BÍéë¨ ž" Òç{j)Ò@Ê>7åAêÕ•š6ê×åoMeV»zmŠ©m~ÿ+®<ÉÕÑÝÓ30Ý·‹«;/ptÓc¾>3ïCæ, µO[G\á©Q}®]]¼Ž îÉqç¬ €¤•@†z÷g¾º\âªÕáéù¡=­Ài, eEÑP÷šàðôù¡"æGTë7Jž¹·÷fæÖÄ|ÑkÇnfrÍÒÇ[×7©o·¯yv‹9ÿæ-Ra‘¹mw–>oÓÌ1u•òYâöoöÓMžêçzêÚ®æ.©pÚîw_ìéÏÏ:Pú~y –´@ v¸×Ž3gA@ ­Þ¨ðÛPÝo¦”LZ$GRP`M~¨?˜²'6£ý_W™ÌåzŽlÐxÃ&i ¼¯ßÆîךÇëÌc;ñçÇË‹¯û¡x›$odêy— ÈÛ ¼oÊoÞ.ˆnèæ¹ÝÞÖK^ B)Çü‰«[GÊÍ1·íîØóÅ+ÙÐõà^®÷tRrâQ[råOÏšòoÆÔNŽÚ¢qzÛK.׿ÝvïAJ<¸GHmî©=>´@¤ l0uRçÞhð›yu2ãƒ{ÒQi €@L`©1~« ¶ÝÝ1uº]¹nñß[k¼I,³Ýn¶ë¿=[ŠŠƒò6@oƒòöÞì]ó£¬íè&xžS@/Y_wk€ÝÛzÆ~ 0o¹4é£@—ߨ«)m2¸—£#ö³ÇÛu+:n¼Ö»6ÔÍûÊkíèÎ =Õ1ýdA@Ú à^ûæœ@´üPÓÏóuÀõ®š™`  €ñ˜ôa›35Æmp¹µ™`ÓÞª ¯Iì—=:ÈÜ<]yb¨iŸ„zmv û^‘úàèX“ù~ÀÞÉù[ùñrS>æI_§êꬔ~«Éø² €ñ à/IŽƒ €@ |2:k2ÿöû%Þ3pxé ß|™ûàkf|jôùžº´INzw:o3Úímo®V® õúœÀ”rñ1.màýSr¦U“Äökca¨å«¤¹ËB=3=ÐÈa®É¶çïõîŒ+û"€ îñPä €d ÀšÙ¡ü5Ð DäìâgöØ}º„ [ýO™Âêf¹g„› 5§©ÕC¶iîèÜž†jÎÒДœ u©™ûd¿½lÖ»£Ã»9»UÞe³)—óåjiÙª0v³AvûØ–ÍiÛ\êh&½ãOöLl€¿VQ9 €i,@À=¦#€ (ßdͽsnT½î0“×uâ|¢œ9. MŸ¯ 5꿾Û×шã]y^fý}±%gz™¿™½:I›Ì䥶äÌKïúûËÒ€­%gl¾¢Åfþõ½LÖúöõoÖI{4Q¬6{‡ÖŠeÏwhíª}K)’a†Ù°@t àžN£E[@¨%~¨aGGû\ÂOÓk‰œÓ €-ðƼ@÷¾èh?ΔaÉô¥~]GÇ÷±7W_o²ÞMə۞òe'hµ%gÞÇѪu6°^œ­nƒì6ØÞ¤þ¶Àºýbâ§ý]íÝÊLüš“²fú˜Ñ?@â%@À=^’@ øöÍ@K tÒ\Þ&dÈÒ @ i~êáɦΠõ‡ážºµ¯8Ã;iLð‰Û¶ptþ Oç–)9óÂ{Ú™r0y­uÏs4ô`W6{½a½ìóI0?‡G@ Öø$]ëäœ@Ô(Êõîù¾¹ÏS=jÁ¦î@Ñ2@ ò BÝþt ‚-a¬^{óFÙLvÍ|(½;Û[ MD@ p¯1;"€ y\í«Õ‘Žö>=óîŸy£G@Ô°%Rn1õÚ{vptʼnžr"ÙlO‘¡% € hî‰æø €¤‰À—­œjè<Þ¤ÉÑLHa3i¦™C3+ko¿3?ÐÝ/¦ŒŠ+•’ÂÃDÓ@@¸ Äõu´°PÑ¢"™fæäÔSnn\÷Îs@@((\ê½K}þˆ§:MÉBäº@j*°¥(ÔK„zrZ M[«YÞ»“£>æ¶O[É–ÉÔ% C#ÐÄY¡~¦§Mmr@@ Ûv#"^¨åóÞ×;SßЛS¦jÆ„©š»“^ ~˜N8ò(uÔÑêÙ­­rwÚ† € l™#|í}†«6ÇRJ&ÙcÁù@ =|?Ô¤B=j&žnßÒÑ-çxjk&ÅühI¨ÍíögýP õìh‚ï¶Ž· À·iž9éM&£ÿOÏZcæs‰§VM2§oéyEÒj@H–@õîÑÕšòäXÝzÎMšºËVÏÕÔñööàÖ-‡iÌS×ëÂÓU£]îË € PŸ?hý§¡ŽxÔ«Óq@ £lV÷´OBýgj †&»è—§ºêÕiÛ——ýpÔÿ€â.¯\S|Ÿýy¨q¯j`¶/ ¾÷2øFõÓ3HýÕw¡F™zíû´utÃéæ—R9éÙŒº0é  €$M Z÷ϧ< K޹¬ü@{Ö£ö¨_?Ö™M›¾ÕйK5unÙ¼÷ ºú sÓ@xŸ.:¡›ªÕ€¤1qb@2S`ã¡fÿÒ×À‰ž"ièÉÌ‘¡W , ôðä@E¾ô³Á®ßo[ ½¼öÛŒv{;ñ )B-Z)}h‚ï/¾êÏÏêÐZ&X_œ¿ÿ^NZL4:ûó@·?èÌ®NëWyÿË3a € iUŠw®ž­{~ÑW×/Óý#4æâià¡=Ô¡]k5ª ^{´0_«V,ÓÜ™Sõè?¯ÖøXZüT]6d?]6ðzÍw½Í#ß½Œ,@¨›•ù^éªå!Ij“ €@F|b¾¬|x²¯Õë¥sºØÝ©vmv[Ë}ßv27Ç«¥Â-¡æ-/΀;ÑLb½V±è¶ö» ÂwÚ3õ²Æ§}èž—ýæÇ®úváïHF\Üt@v[À1¶ÃJR8[§Öë« [7~ý8]sé0õÉkVén½¸úóizüïÑÕwo=b1Z3ç*Õìh%sÖ·hÑB#FŒÐèÑ£3§Sô@ %æßåkéø@'̈Èåçÿ)1&4R[`É76ÐhñÊPg™Œî!}E¼ÄÂm-t[û½äV7G±‰HóZ'æ|Õ•mv ‡LYœ›Ïò´ŸÉÆgA@-à8Ž–-[¦¼¼¼DŸj·Ž¿ë ÷HíoO1êQýåç?Qçf»Þ¥²µêÜ_WÝÕ_#n˜§ÿÞuµ.œQ—²2•ñ € X?ßdRŽ tü;ÛÀË!@ þþ¾¸Fû,SþåôÃ]Ý`&™Î­“Ø sóFŽŽéioŘ/¿èÚq¾®Klòg§zÚÜn?ßSÇ=ëa—ÝA@,Øuô<ÒY·í" ¾&N¹­ºë‚ۦ肚ìÌ> € Pc jú¹¾ºßäªÉþJj ÉŽ ñßoõè›Þü8ÔЃ»ÊSÃzÉùÿæI»ÚÓü,øŽg7H¦=É)áòÈT_¯Ï15çæ©­©GÏ‚ € °½À®îÛo_ågÑüµZ[U$’«fͨÑ^e86D@ Áóþ(bþ4w™œ`M‚»Çá@ÝÈßꉷMœjPGÿø¹'›qžìÅÖI¿óBG¿Ì× “uÉqnµkÇ×´¶©­-oKÜüÅÛ[6N¾GMûÂ~ € €@"vó“v¾f¿ú°n¸ôR=½ k;£šýØ5ÊiÜ\­[·Vóæåô¼T¯.0³þ° € €@­ Ø Itc¨ÂU¡VN ´ðïú=ìÉÖ¿cAØ&P°9Ôc&£ýg÷øZûƒtïež®<)5‚í%­´5Üï¾ÄÓ‚¯BÝòß@¶Í‰^üÀÙŸôé—¡ ølO´7ÇG@ô¨y†{t¹þt\]7µ`Ì¥·Ç¬žöWõ=çîíUæ>¨!û=¨qs7è‚îd»oÃ3@*üP«Þ2Áòod‚æöfƒç[›`ÐvÏKÖ—l{]ò ŠïÕ—" ¤¾w™’yÛ+VçÈFe߆úÝx_û´ubAå)\›¼iGw˜úéè—ùºålO­š$æÿë[L²ÛŸôCA¨;.ðT¿nbΓ×}F@̨qÀ}ö}W—Û-MñÔ§…zùÁëJ¥ޏC§¶˜®«GOˆ­»ðêÇ4lÊ¥2¥Y@@ 5…ZúH eªÛBjØÙ‰ËmÀwÏ’Çe_+ªÇ¶iXòXòꉌöJ¼y ²[`Ñסn4Áö »:¡Ïnþ¸–(ëä8± TÇ¿hä?}ýþLO]ÛÅ7n³çG™,úó©ñÖážì9Y@@*¨YÀ=º@\]D—FhÆŠ1:´m®”?SÏßzÂwè‰~­Væiï=OÕ»ýÔ‰Zšoî$¹W>*¼ŠOJÿã@IDAT •›LÀÇØ—þ'0å_¤g»øJDÍ{àÈÊ ‚N#€@­|ò…)Íò¸¯+Ntut÷ô¶—ÀØÒ`çôÔ®E ß>âkä)®ŽØ?>}°uìo|Ô7µ:ºöG®<¿E%îÜ#€ €• Ô,à^°Ißn=êõ“_l7ÏóÍTiþâSbÁv»ÙÁÇjþk_Yª%« Õ§‘ γ € €@¬$̗χZb‚ìßMÕn¨£^wxjsœ#—àW P—ºí©@ט@õáûÅ'PÐWpðA=\íÑÔÑžðõõéŒ#w¯/kòCÝ`øìíèJóE„ël¯€žÕ € €ÀN5{'–#•$©ç5-y$-z{Jé Ž:´CéãÜ}5<öl®–|·µlé«<@@ úßL 4ùب ¾IüdqÕo]å{„fò¹o&š~~TÏ´‰jñ?uø©«ÓVDtäãµb‚Û+GäU@`7Þ[h‚íOúÍÓ;Ø^Â`ƒãw]äiÒGîšà+jæ©ÉòÍÚP¿2uáíêèÿ†zÛk‚È> € Õ5 ¸²ü6|/^ÖêõçKòÛGªOÞ¶,öÂe³T\i¦‡ºíiŠÈ² € PCüÅ¡ÞüQTÓ‡ûòÌŸšw̽ `§Ã²þÓPþÆ×syQ½w¥¯Æû:úqDÇN¨óÏ\å4&ƒ0Æ‘6"€@ú Lû$ÐϺÑÔ=ïۥƉR¢MsG5A÷UëeJÌÊ7VgY¾ª8Ø~B_Wöª³+Û"€ €l¨á»ËœÒ ÷Ëþô˜¾ŽJŸ¿pç¶ITG¡.¥ÅjòõÒ]wm=]GíÑ|[ žQ@@ ª[Ö‡š}­¯‰EÕô@G§,ŒhÀ³žŠ6HŸŒªz˜Zß®Ð/ŒñõJß"M:*jJÈHžñtÊ‚xƒ§&#‘@ ö^7à9ÐÎñÔ£Cæý?¸a=G·žãšºîÒ5f2Õ¯¿¯ZÐ}áŠP×=ìëì£\ýd7KÒÔÞhr&@@ õjpÏí®£÷füejgf«ï2ltiïFýô(EռХƒëŒç¿6p:m«@Sº=@¨H 0?‰_8Ö× ]£ÚôU¨“æFÔóž" Lsó÷çÈÿzšÿ×@«ÞI »mórS¦`êШžïÕªi¡züÞÓi_Gtðß<µ<¤f~+2b= €@Õ^~?п&™R2çzêÖ>ó‚í% v‚Ó«Nö4Ädªÿâ_¾>^^yÐ}îR3éêx_—™’f'ÄߨGî@@𔿡Wwçþ×Þ§ëŸÞO£·ÆÒK÷8F— ježækúÝ—éÁ©¥¯hܘ K'Rݶ–G €”/°òõ@³aJǘl½£ž÷ÔªßÎA€Fr¿§wÎòuâGŽêšŸÓ'{™52Ð7Su»ÊÔ~ÄSÝfÉoS²M8? lg§zæÝ@w\àiïVÙñÿåîªmsé–Ç}]z‚«Á½vþ;:ã³@1åu®=ÍÕ!]w~=ÙãÆù@@t¨RÀ=ZX(åæš¬õ2Kn7Ý6k•«qÏÏŠÕtߣïOôûëÏÞ)¨Þcø(ýýÖkÕ¿L]÷2Gâ! €Û lXhÊÇüÊך١zöÔq¸#Ç©88’÷×LBêÝ }=a»¿VÛ·6ž|ö7óóýW?3¢Ü–·¹6ÚÂ9@Š{3Ðk³MÝö =€Î®ÿ7÷ëæjôùŽn~Ì× S^æ¼AnéßÔ©sÝ?1ÐM¦–}÷ ,¯Ãõ €$CÀ Ͳ«ϾçTõ½Z5v¸N|¸ztn»}ð½‚D ó•_”£f¨Û^Ñ.W·hÑB#FŒÐèÑÛJöìr'6@ÒT`˺PóFúü!“>ÒÕþ¿v©_µÀHÔL ÷ê!Qu¹ØU·«“3ÑÛ h÷|_ÇN‹¨I·ªµ;M‡Šf#€i#ð¯I¾¦Ïuûùæ—RM²÷ÿÍßmcA÷¶-ýêTWÿû(Ôø7ŠkÙïÓ6{]ÒæB¦¡ € KX¶l™òòòRZ£Š¿43Òi‚nºì õíÒN9Î ]ó§‡5mÞrå› S+Z"¹¶W„Ãz@RXöûŠë´ÛIF‡~Q›Mö*Ûí"¦ìLÿ'"šwKËŒ/=x-=X;7Ôôs}ù„G°½–Ì9  P™€Í+º÷e_ï™_MÙÌöl¶[§–ýùgf²qóùmĽ¾ž˜f2þMy‚í•]E¼† €T_ J÷Ž'Ý¢1×PÒãOÕÝ×]¨=:¨qNO]zÃ=zuæ­5•gX@¨ŽÀׯz¥gTK uô‹žŽQýNd×dG}þìiÚO£*Êß帪ÓÌJ·-Xê 3AjŸ;=íi~ªÏ‚ \ uׄ@óÍdÛ6ØÞ¼ÜvDrë8ºñ§®ŽïãÆ‚ï{eI-ûä^œ@²M J%e¶¡jù‚÷5õ…‰úÏu£Uf>ÔÒM†¼CÃO¢£zí§V’[G·´Qiü€’2iÇ«è¡É |g¸¯¦|\¯ÛÈl¯È‰õ €@m l‰†ºõÉ@ë6J·K°½¶Ü9 € €À6݈DÔªs~éz~N¨5+ækâ£c4bà¶èûÔñ£uÎÃÔ¡y=õ<õR=ð õæ|õ{ØS›Á ùÓS®c·«<5ìähÖH“îÇeåë>ºÞ×Ñ/ETo‚:q¤åP €@µòÍ—ª×ÿÇWë&Ž®?ÃUÄãÿËÕFd@@¸ ìælrùšýê3zú¹wÕçš?ëônLâšýصê{ÎÝÛÙc„&>ñŒnëÖlÛ:!€d…À†…¡¦‰ªï]žÚŸR{ÁöÜÿgïNࣨïÿ¿g6äT 9DUðåÁƒ Å*‡­T ÔZÁ_UŠ¿ŸØBkŠÿVÁª¬¢h­Ö/¬ Qñ” r‹"w„ $;óÿÎnÂ%ËæÚã5}¤;;;Ç÷ûün–öï~æ‚>½Ñ¥Hÿe)å'忾W¢æƒÌLýY>Ú‘P§Ä™G@ ²üæ~yùRÞ~iOàÑÕn³îmÛcn\½Ðü;sN K·_i˶ù\®¬q༠€ €¡ „¸mÔƒý[j\vðBSGý1°²}þC‡‡íÞÖœéxötÍÈÙ£›:y¡<  €@<ìÿÆÕÜËŠtν¶ZßXþ°;³š ¬@›÷ùÕàG–’ÍŒ÷p—‚mæW©ó$[MTOÂm;Ç!€á 8&ð^²ÖÕÞÉg>ú¼LÛ2?vñº·-ð<°Í ¼îíSòzéc™mͼ™é{Šƒó@€nÂs/P÷¶yAz0\Wàº5¥dóUÙºµÍ¹÷GàѬ{Û†\hë²sùLw|9@@ bÂÜ—<>¦4l÷šTSÞ© ôúôq¥-ì1Yƒ~¤1™Ym#ÇÌVú¼Qbž{)+ €@Ì ì†í©?·å•v©Î¥ÉE¶Îþupfúåúd‡QÛ×_`Êâ öëÌÁ¶Úþ¢zûS–\âG Èo>Ç—ºzáC'´Ÿ^ß’kn‰áÝ”Ôdðu/Œ÷Ö?ÅÛË®—Ýß1¯{Ͻ×ÍÇhòṤ7mèê^°î…êæ¤Å!{Í0>·ãg¤è) € €@$ „¸­Ô´1Á]ÊЂo§ª{Ó$3Me¡^žYܽޓõü´{ÔØ<=÷ôÁêåíŸ=GëóLàÎ$÷HzÐ@ Â óÌLð~ÑßVÚý‘NŸó[[æùõÙouûóɵÉ5 ÑÇ7ùU³‘ÔõOÌ¢¬ð7 'Dˆ(8èêÍ%®þý‘£Æõ¤[Így÷v|öEÔ Ñ@@ˆ/pÏ߯­Å]?÷þ`Ønžç­^¨Òþ–A°ÝÛí¼þƒÍ{¯¬×ºmêšlÂy@˜ðf‚¿{µ_õ:HݦDN@c™úÍ4õÜÏ-Òé},53µ~C]–ÞçÈ«Eß~‚¼ó° €±(à•xyõWY µijéžk}êԒϼXkú„ € Pyáî^ Åâ6¥œZ²&­þ`^iK/éÞ²t=©e70Ïf*Gëv˜ÂŒ©î¥8¬ €1$๚ÿ¿ÍŒÈOûLMßÈ jjnéÂg}úp„_W|f©v³·oÝß­{ÆÑ€… J¨sâých8é ĉÀ.ó­¤—>v4g±«ngYzàFŸRÏàó.N†Ÿn"€ €T°@x»iD^ICLø\rõÎË%óÛǪkÊ¡P½`Ãb¶{KšÚŸn 1² €Äœ@ ìÊH¿ Í?}æ˜:é ‘ÖxenRovõá0¿úÎ3íô¿[ßs´x¬ÙonBHá|Ì *B˜ؼËÕ‹¦>û»Ë\õêhé‘ Ÿš5<þgbLcÐ9@@*H ôïÓvÁÄÒ­ÍEÒÚWþß¡›¨f\¤³J£ü<½öðÃÅG·Òi ñ‡’' €Q-ðéSve¥té+>ù’";°é<É–cþíZ6ÑÜÁï8ËžÕf¶þu~]`fÄ787²ûsœ.°8¦Àº-®þø¢_¿šæW’™<3ývŸÆ"l?&@@8Ið÷¤NʘØ;x©™£Õ,ÑÒY陥—žxý%JP‘–½2M£úÔÕuÓs‚¯õî£Ö‡*ДîÏ  €@t ,½ß¯-o;êmf¶'&G~8í;¿ø>­~ÜÑÖwݘYŸï^Y¤Ž÷Új~uxÿTF÷ˆÒzˆE/¿v5a–_¿yÖ¯æ ¥gÆø”1À§Fu#ÿs;ǃ>!€ €Ħ@Ø)BÏ»×ø´c ôžªÑ}›òõєњž}hŸSG–ÞHõÐVÖ@¢Y`åT¿Ö?ë¨ïÛ Jj=¡M–º?iê¹÷«`»[:þƒ®Þ¿Æ¯ÓûÙj?ÖWº@àX^9­H_­vt×ÓEÊ|Á¯.­,ýýNŸFôö)¹vô|fGº1íC@@ D ´ðKɆ“ÚëÅÛÔoæšñòâ@M÷ÓºýD÷vT¨ž6b¢ýýÝêY¦®{È×aG@ˆðn(úå]ö¾©qÞ<ú‚›3ÛÚ2×ÕÇ?óëÒ׃7y]x‹_>s»‘ý%ì¿IGìxÑ0¨¿ßÕçë]½÷…¹Ä W…¦DUS5ñóÙqŠ÷hÊjZ÷¶›çí%û?7û×®©°o0íµ£Ð/ùÍuf½Èû1ϽÇõ[]½`j´”®»ÈVßΖ#ôþ32œ@@ê°Ì¬œJ›–ST§¼ÂDÕO¦n{¸CݰaCedd(3óPÉžpÏÅq €@E lÊr´àfsCÑwÔ Kô…í%þ®þÛ£H-‡ÛòçKÿåèò”H‰…"@Àxÿ“ù‹2!»£–»:õé’Ž¶.9'®ï-ö™Ÿ½ù®¼õ<óyx^à–Y7¯›ç{ÍkÞ>Þ÷¿Äa}q ï3ë+ ÌáùzIÀî½V²xÇ$˜/ä~Š×}æyCSÊqpw[w°dÛÑû9]ÒO@@â[À²,mذA))) qâîEkuoÿ[uêØ?郺–Þ,5”^%$%«þñ²ö‚íš÷ìzdcoýóA:Þn¡\‡}@ªV`K¶ ÛGúu‰¹Aj4‡ížš¯¦©çþ|‚Þì^dnö* XHØ^µï&®†@d ¬úÆ›Éîèý/]Õ07½¤£¥É7ù”Òäð»ní’~¾½dëñóÍýJÂw/ˆ÷;® έ£ô#õÒçf_@@ˆîù;´ ;[ÙÙÝ4N½5yÖï4âÚžjfB^”»Qoükšî©à­TÏP>{ä¼#h  pŸ:š?į gúÔäâØ(»R·­¥óÿêÓ)­ÍLSSÛâ[À+Åâ…ì^Éo&¹²ß?Ô§6M+þó¡–ù£_-SV¦q½óŠ¿FÉ™yD@@Ê8qàžÜMOÎ}B·ö-»kÜpócÚ5bü9¤ŸÎm“bJÆüði r7kõŸjÎKOkÜ”¬C½JËМçoUýC[XCˆ`ݦVqö•~÷¨OÍ®ˆ°½„»å ±ÕŸ’~ñˆ¡ |»3X“Ý Ú÷ìW  ˯ûtN‹ðk¬‡veöB@@Xøá¤<ÐÓ¥ö¥yùWëÅGÆéºq3[gfŽÖÌâ²âi½ÓÕ£s+5?ã ÕKò¦çPÁî-úî›MZº`¦²ƒSÙs?kÆë~R%j;O@ªT`ïFWsû)í·¶Z%œ®R|.†•"°í{7P*æ]²oÍ•.:ÛÒè¶ÒZYòQó¼RÌ9) € €±.Bà^LÔTCîyNù#îѳާљ‡fªçdg)';4ªŒÉ³tç­?Qûú¡_:´3³ €@e ls5ï²"µý…m~ÌøX@((,r5g±+/dß°UêÑÎÒ—Úêv–W7r.Q:¬4@@ˆ8éÔ;©i'zàeýìîZ4?[s^Y¯O7ûñº”Ö[#ú PúÕuÉ…Ô8ÌÚïÇ;=Û@*Wààn¶_^¤æƒlu¼—°½rµ9;T¦@î^W¿Þ/Û|Içš¶Î7÷o¨™HÈ^™æœ@@x8éÀ½(©~Šzº)ðóÀ´"ååæ)/ ½=U»v-%%ÕRr2 {‰ €@´ l}ßѧ·ûÕà»Ç¯í¹êü{ŸRG24Ç‘6#€@PÀ»꣯9Ê0õÙ/ëÂ=(x_ € € €@å TPà^y äÌ €U'à•ùâ÷ŽÖ<é¨íí¶.xÖ§ÄSÛ«n¸T¤€ã¸ú{¶£·?w5i„Oí›óyV‘¾œ @@Ž p?Ú„- €@Ü 8~Wk¦;ʹßÑéý,]™“ :-¦âî@‡ˆ!ý\=øoG^ÝöGnõ©a]>Óbhxé  € €+@à±CCÃ@ªØü¦£Å¿ö«F=K—¾êS£î”[¨y®‚•%°yW°^ûYgXº÷:ŸjpcÔÊ¢æ¼ € € p„û [ëèffûuÙb~X@@@ª p¯Jm®…D€@Á7P:fã?}·­Kþã“/‰R 044Ê)ðòG³ßst÷µ¶ÎkCØ^NNG@@0ÜÃ@ã@ ü]­zÄÑ—™ŽÎ¼ÖÒU+Të4‚öhKÚŒ‡ ¹úËkŽ–orõÐÍ>5oÄgÛáB¯ŽÌvVÀpp ˆCÕ›]Mü§_—t´ôó~¶l›°=ßt@@ˆ;yÙ¹|ŠÆ\×KÍ$ªÏ¨Izqþ2åDTßh  Pi«ókïzWgô³ôñM~½Ñ­PLMtÇ”5ˆ„e¿ ¡>º©Hó./Ò™?6åc–%¶GÂÀШ0ìG÷þݯ›úÚº¥¿°½Âd9 € €”G ìÀýÀúC—Íž>A×õJSƒZ–n¼÷Í[¶Qdï‡|XCØؽÂÕÒÿstÑìµëÓ µ êp·O+v”•Zdý*4%ªz)Êwµñ_ŽÞM/Ò«íŠT£¾¥«¿2m¼ÃQ‰Ìú¬êñàz P9Žãêé·ýzêmG¿¿Ñ§¾ÃþŸ³•Ó@Ί € €q-æÿCIÖÐçß׌‰c•vßÌÌ1ê›ÖRµ¬>º÷‘ÙZ²1÷ˆ=xŠD¯€wãч)í~»´ºí³Ôò[?IÐ…÷ik¶«ÿ´(ÒS3}ÿ7•¼;~Wß½åf³ÿûô"­zÔQ³+, Þ˜ ™25Mè΂œHà@¡+oÆøô7ýzë3GkÌ·dšm‘¶ì+põ[óm¢œ ®Éð©]3>ã"mŒh € €ñ.`™›þ•óÿMhãÊEÊ~å%=ÿõýà S÷¬rµâ!'Pf¦yº¥³íSƒ. í\ähý,3£ýŸŽ’šH-‡ÙŸ:-*îU§Ê•@ ºVlrûû_ºjušÔ)ÅÒ×;¤õ[\mÛ-5k(³Ý ü´>]jmÖÖ­žÏ™owza»_íMÈþ+s?Š ÕÓŽê+®‹ € €@¼ X–¥ 6(%%%¢)* p/Û¿m^¹To½òOýÝ„ïÙe_*^O;U¿5T=Û7>Æ«l:R€ÀýHž#P}[æ:ú`¨_W.MP­3B z ¶»úê1G_=îèÔ4+pƒÕ3.·~0¬?^÷¬vµa– ñg;ò›º]}¸™iß)´¶ï¼lGøؾÛÕ<ó‡Ã·?wTX$S’ÅR¿.¶š68ü³$ÿ€ùÌÙ&­3áû:sãeïÑ{^#!¼{}«Ó­@ßÂü케 À½Yõ{ò¥=û¥ùÏßøaz‰ € €@ì Ägà^«e‹ækÎKOkÜ”¬À(§¥¥)'瘅f¯gÌZ¡iÃÚÇþ;"̸‡ ÇaT°ÀûCŠT³¡¥îÓ|å:³V}óŠ ¼þì(ÏÌXo÷+[mFÛªYff©wÃÕM/™0ËÌfßñ±«¦Mx3“Ý{s_ @@@àHh ÜÍ—‚Ë·l׊Eïéå™35az0d/{Æ@ØÞ;COŒ¡«{vQ­=«•õ÷‡5rÂÌÀnÓ‡ÿA·_ûœ:™ÙL, €@$ ¬yÊÑ÷Ë\]±¤|a»×7ï‡3MM÷3Ómí0å¼àýåVEjýS;0kýë;Úü†«F=‚!{¯-%VS½äH Ú„'ع'X2æ-´ –Œ™z«ÏÔc¯¼ »N’¥Ž¦ŒbGSž@@ˆg°÷µó_ÔS&dÏ%Ô©Ø ©Ñù¶z>okï7PjfåG-®³ô£)¾kÄG  Aj8Xäj¡¹Yó[Ÿ¹úâk7P~åmu1%cl»b?»ªµ£\@@ˆp0÷\½~ûuÊ<ªRLšÆN¾S7 ê¯ní›ê‡NnJ/{JVxD"JÀ1Ö‡Ãýêp­†?ª¼ºÁ§´4!ûÔòÏž(<ƒU"°ê[Wìïš’1ÍKÆüÆÜëÁ›q΂ € € Põ?”‰ÿ`kjšÿSW²¤¬Ñ7üXuKUrˆglÒm¨^˜ÑV{uºÎ4õ:Y@HÈù­#Ÿù|òw@ Rv—Œñ‚öý‚%c¾Ù§æÙ#eŒh € €į@ˆñø‘@õuÉ=3L]ö³umÿnjœtò§IhÜICnêtä‰yŽD„À¶­~ÂÑŸ%È¢CDŒ @ ž ºúh¥7›ÝÜtÙÜõ‚v–F °unkJÆÄóû‚¾#€ € €@ä „9m3O f=¬Ñé=ô?Ï®8a¯¶/œ¦>æFÖϘŠí, €@d Üm‚­~÷˜OuÎdÆhd­C v\×U޹ÇÃC/û5üÏ~½¹ØÑ%-ÍúµO÷üاngÙÔgÝá§g € € ¥'?5=ÐQS=/XÀ=”}YÖhe{Çå|¥]E ¹ìL”šÒlˆrE¿ô«É%–Z^æß$£¼ÿ4ªW`óN3“}©£¹9®|æc¨_g[¶uZ}þX½#ÃÕ@@@ „¸¯œ}¯®ÿÛrµª<éú¬àcÖãc4xNñÆc^o²Š÷ÕQ7Y=ælDªM`ý,GÛ?ruåÒ?«­­\bG`o¾«÷¿ í_o—zciܵ>uhAÈ;£LO@@@ BN”öïX®œì¬£3óœle…¤§wÔi!_1Úø‹”——/©H J®Ÿlþ›¢I`ïFWŸÞá×¥¯ú”˜LÈMcG[ˆF¿ßÕâµ^ÈîjÑjWR, în«‡©Ï^#‘Ï hSÚŒ € €„œ Ÿyî…F+Kiiiæ1G9eBöà¶ÆlÕçfMº÷'JúáÝ¢ðÕ\Í{æQý~ä„`ÙœÒôÖ䬩úŸAÞKMXA r\'X·½Ý¯l5¾R2‘;R´ èð겯ùNÊ^æ(Û”Œ©J°dÌ/Úf=ºG—Ö#€ € € = nÜó¹î=Åf¹z¤s1¡{ï©‹5ñiY°R÷v?[™eþøp"[ãÒÓ4k|–>0(ÿÐp¨§¬! _<àÈ1÷˜èxa{,Œ'}@ ’6mwõùzWKÍwÔ¤ÒÅ,ýáFŸZŸNÈIcE[@@@ò „<Ãýð Õו?¡õÏ/Q«–õ)nžé͉ח ÛÓ4ù…‡5°ã©Zf‡O˜ÈÉL×ô!»tG×úq#CGˆ6Ÿ8Zù£Ÿ&Èö~EÛøÑ^"M`ë÷ÁpÝ Ø½ ÝïH[Zêšjéçýl5mÈçL¤íA@@*J ¤À=wí}¶yŸ ¥¦ç^ T/;>µƒ®ÑÁ¬lÖüù›CkO¦º {jèÓêC;kµìU´ñ ,ÚÞ[s6¼¡)Á‚9î{N]Ïn¤³¯›hÛS/.Ôm]ÄD¿«›‹"P‰…{]}8ܯnû”Üš¬©951+k>GJÂuïÑ»¥‹W½K+K×]d«åi|¶ÄìàÓ1@@@à÷õ¯ß¥¾c²‡N^°G÷t—^Ù+PRæˆóýðÓ´©ÚµôÅÂ\ïÅÏ?]Ú×ñsf–†í%Û¥š"ož{Îë_)ï1Ñï’þñˆ@¬|:Ư]-µþ¥dbeLé•-—ïj™) S²oý^:§E0`¿¢›­³Îl›½²Çó#€ € €‘(Rà^¶áI‰Þ³DÕlXvk¼­o×Â7³Š;¡Ÿökz4@B{=W˜¯'MMh¯T~ìÝ,öè.³høú%G[ÞvuÅÒ“þ(Œ¶®Ò^CÀ»Áé^3[ýû}Ò–2eb¾Þ.µmfÊÄ´²õ««lµonþ¥§U‚ € €Äž@H)S‡!kA÷ݦ÷µÕ6-9 0lFŽºlÙo¢÷D™J3!,…JlÔ:6fylÒ¼à„¥¿F-µ]óf¿¤w-ÑÎý†¢vCu½¨Ÿ®¾ªš’´‡ðÞ`ª^`ÿ·®>åWÏ|ªYŸ™¨U?\ê8Pèt/Dß½ïÐú÷¦,Œ·-ø\ßmþM÷™/¿Ô«-51·¬éhÊÄŒ45ؽÙì5ùܨžäª € € €@d „¸'5m¯îGLâNNé¤î)‘ݹÊj]Á†•*™ßž“ù ®ÈÌVqþ~è’S25Zizbî+Õ'N¡i°†@D x³V?ú™_©7Û:íRJÉDÔàÐÊ)°ÿ€«Õ›]­üFú.·88/¬0³êÖ2!zs;š:–ùñƒëÍ•¬ÛmÞ>u’ÖË9$Ž € €Ä•@H{\‰„ÐÙ¼À^iæ¿sLÔž\QZïêÑ&OÓ§—ÆñÝ·¥ÙiFu ~3 „Ó³ T²ÀЇ4A\çI¾J¾§GÊð;®6n“V™o¬¬üÆ ê«Wæ°pn@@@ ®B ÜsW.ÔÂÍûT£¼T‰MÕ«g{SÑ<6–Ó@Öž3BsV<¤í:öØ—)óÇišP<í}ô˜Ù6o”ˆÜccÜéEt ìúÜÕ—ptùÇ ²) ݃IëãN`Ǫ›`}¥ ؽǯ6›Ùê&@÷ÂõvÍ-]ÖÅVó<ʽÄÝ[ƒ#€ € €#Rö½þ­ñ8樢)'߉´©Úµ´}lÔq/î}މÜ_X3CRQ&Ôï¤û²hqÝÁÒ3Ùs´Í>¶ÇÞ—#"p\hF`ë{Ž™Íîè»w\µj«ÿüÕë@hÇ›êؼ3¬{{àÇ”‰©en ã…ëmÌÏÐ^V LÌ©æÆ¦, € € €D»@H{îÚ%úÌÜ45ѤÆMϽ@©&|_»äc™M'·Ôhª º§FÿMS“:hD†™¼>Ýë~¦˜ýSMÖþ0‹Ü…ÿи’¼½÷…j}t"ØþKw÷$n/a Ø6ßÑJ¯lÌMÙ˜,õËNPýN„z@Ë)8¡@‘¹ÁéË]½¶ÈÑ7æÆ¦—˜ß½¾-h«iɲø]ÏV¯Ž–j$ð;goº‹ € € ð!îIMÛ«»ùzxÙ%9¥“º§”ÝŸë©}Fi^á0­ÍY®ß›¢öJuš©S—NjLÝöø|SÐë 8°ËÕŠ?ËÆÔ;ÛRÇÿ3ec[²}„| ÍÉ8ŽÀ² ®^5³Ù?]íê"ó;øÛ¡¾ÀMN³;›@@@ˆk÷ åm׊ÏkÙ&3í´F Õ0™s§©íÙíuVJãØŸá¬Ô®Ý•z"(^G“ðn†š}…_µ›K}ß6ecLÙ ¨|‚ƒ®æå˜ ýGûÍ¿éWýÈÖíWÚª[›ßÁÊ×ç  € € €Ñ,P¾À½h³^yèwJ7ýøi#4ëÑßjXOâèã#ñ )à:®>áW­3¤žÿòɲ úŽ4â9-ðÍŽ`möw–ºj×ÌÒÏúÚ:¿ùF ¿MÍù@@@bT üÀ½h­îM6%éT˜ÀªGýú&ËÑ€ J¨EèWa°œ2»÷¹úïg®^7õÙë$™› žoë¾ëm%Õàw® « € € €œ”€åšå¤Žðv.X¦k¥ifàÀ4ÍZüކum|ÌÓl_2[ýº W0v«5…+5ì˜ÿ˜—ˆé 6TFF†23Oø]‚˜v sñ#ðÍ+ŽÜìWÿT·Á_üŒ<=­*u[\ýçcG®pu~[KWg›?–ó»VUþ\@@@ <˲´aÃ¥¤¤„w‚*:*¼è»°PyÅ 1cæqÃvo—Æ]‡é¥¾ÐY×yñzíÈ—R©+S¬Ç”Øù©£oò«×Ë>Âö²0¬#PÞPÿžíèÏ]¥w·õ·_ÙjLÐ^´œ@@@Rð÷D•Öb¿¸[›Ò“o¥niñ™dSn†8Z`ïWï^í×õé´^öÑ;°ÂX²ÖÑ#¯:J=ÃÒ·ùÚÖä@@@@~X ¼À½P¥3Ü—,Þ uúáºì…§Œ7­ðf¸çÉÊ‚&pð{WÙW©™qÛjaûa8js¹OÆ @ Zò¿s•}e‘Îý£OM/¯šŸhµ¢ÝO ÿ€«¿Îñë·ÿðkÈ…¶2JØ~<+¶#€ € € PÕ!Íp?~£ ´lþ»Z•kÊÅg§¦M΃ïf¤MyfÆ|òqvf3Ĭ@áÞ`ØÞj¸­³n!lÙ¦c•*°hµ£¿¼æèìæ–¦ÝæÓ©§0«½RÁ99 € € €')PŽÀ}³¦ n¦ÑY¡]1-MÊÉ‘CÛŸ½@ v¿)#s½_uÛ[êüÂöØYzRU»÷¹zâMG_ltõË+mõhÇïQUÙs@@@NF ìÀ}Ù3ãBÛ½yaûøY“Ô5édšÇ¾  ŸÞî¨Ð|»¥×K¾@y©Xè}@ *6ïtõê"Goîªw'3«ý—>ծɬöª°ç € € €„#æ¹Ízùá™Å×ë­ï¯Ñ¶5s4¢xKÚÄ9úvÛ6­x–ÒK[5QwëTúŒˆ/ôkK¶£K^öÉGPƒN/Ë%ຮ–¬utÿl¿îxÒ/ó4pSÔ_^IØ^.XF@@@   Üó¶h±™±î-c³f覞©jœ:@·OÆë ME÷¦«}ÏazñÛ9êØs‚n}da`ÿBøØø‚£•9êýF‚j6`Vn|Œ:½ W à «×ÌlöQùõøŽº¥ZzîNŸF47æ÷'\VŽC@@@ J ÜMö’ûž¶oÕ ´ÁµëW³³WËT, MèÉÆÖ³Ædicñv@ ¶¶}èè“Q~]’åSrkÂöØmzWïv¹šþ_¿n|ȯ«\e\nëÉÛ}ÔÝV-¾RZŽE@@@ Ê®á~¬–6ïÒÇl6wQÍ^©mE&”/>{“Ö­Šw_®-&‰O)Iëu¶!€@Ô ìYíêýkýêñ”OLhÈ‚G |¶ÎQÖBWË6¸êÛÙÒ÷øÔ¼œ:ZŠ- € € €D@x{¡Jg°Ï™³\£:uô8¡vÍâžÏÓêmRjÓ£!Ìäxˆa¼5®æõ/RÇñ¶Î¼†°=†‡š®…!à•™—ãš ÝÜHØ/ :ßÖÝæ÷¤NA{œ‚ € € €@Ä „—†%·Ñàâ;¤fë¡'ÍÖ²ÍJns^ñMRs4ðw³•èîvý{ÚS¥7Y= Ĩ@î2Woõ*R»;lµë‹Ñ^Ò-N^`k®«¿½eÊÆ<ì×Ë]ý¼Ÿ­¿™²1ƒ{¶Ÿ¼&G € € € ¹áÍp7ÜÓï|Bš9:㙆+§æb-½§ƒ›û¦f™ª2š>\ ¦OVšrÌJ–jT«dGˆ% ½{µ_ç>èSêÈðþ–KôO g}°lÌçë]õîdéÏ?÷©Ecf³óî@@@@ V ܥú]GiÃÜjÙwLÀ¦a’÷¤ô &ˆÏ ñ&j(¶K“ß¿S©a_1V‡€~!ýß½ãèƒëýê>Ý„‰?&lþ¿äå»úä+WÛ¾—ü®äº®Gr̺ß<š§õ’mÞöÒõâýÛf^ÿf‡«æk]W›²1w¦Û:¥A{ü½³è1 € € €@¼ ”+þNés‡Üü¡Z¹|‹vè°ó‚ø=kÚ(ó×w*s}+e¤íÑ‚oÛhÒÔßkP§ÆñæKˆyMÿq´à¿.þ‡Ogô'lù¡æîuõñJW®põå×®Îia)Åü3e›·±m²qËüx뉦:’m6ž›m¾#^÷öõ¶•¼^rü©u,ÛÚ Clt@@@~@ \{à¼IÕ¾ëáAzrj=ðòR=ðæ%ˆ~uÏ:Zr—_—¾æSã LâÈ‚@„ lß Ø?\áhõf©‹ ĽR/¿b+™è>z4@@@È(àù}¤… P +ñëËLG}ç&¨~š™âË‚@„ |»³8d_îhÓé¼6–®>Ï<ÖªÉ{7B‡f!€ € € •!î¹+jáæ}ªQÞ.&6U¯žíÒEË{-ŽGJX6ѯµO;ºìýÕ5á% ‘&°~ë¡}Ç©G;KC{Ùêšj©F"ïÙH/Úƒ € € €@¬„”}¯k¼ŽÉ.ŸÓ¦j×Òöª_þ3q¨ïF’‹ÿÇÑwo:êÿA‚j7'¸¬†aà’ÇXõ­ ÙÍ,v¯&ûþÒí-Ýz¹­Î--ù|¼WÃÆf@@@¨@÷ ¼§B(pü®š›£ææ¸ºl~‚’`FéPÆT³WlrõÞÁÝ»iéEg[º3ݧgotS¥3 € € € ñ!înœ¡œÞùJL,O •X·9³ÛËCȱT“€ÿ ™9<Ô¯¦þõeÙ æw™°½š†‚Ë ìÍw5Í|ÓbÉ:Wý:[ú¿ë}j׌÷%o@@@¨^÷¤ú)êD˜ê)®Ž@5 í33ˆ¯ñË6pëý¦O µ5«i(¸l±Àâ5ަ¼â¨s+KÓéS$Þ“¼9@@@@ 2ì*iÆÆÙ²Ìwý­>js•\‹ €@EÈu5÷2¿j6”.y™°½"L9Gøù\=òª_~ÙÑ/¯°u×5„íákr$ € € €T†@H3Üá-›ÿ®VåTãìT£F å<8<øjöGÚ”'5M>ÎÎlFˆÈßâjÞåEjt­ó·eÙÌ"Ž˜Á‰Ã†ä¬wôç,'P6æ‰Û|ª[›÷c¾ è2 € € €/PŽÀ}³¦ n¦ÑY¡õ1-MÊÉQ9ëÀ‡v-öBò ìÝàÍl/R‹Û:÷¾òŒ£(‡ÀBW3Þqôî2W·™Yí½:VͳÊÑdE@@@8;p_ö̸ÃvÏ× ÛÇÏš¤®Iq¬M׈Ý+LØÞ¿Hín·uÎ8Âö(²˜mâŠM®)ã×™,ýÕÌj¯ ³Úcv°é € € €1"æTÁÍzùá™Å½5ãý5Ú¶fŽFoI›8GßnÛ¦ïÏRz)ÔDÝ9¬Sé3V@ òv.võö¥Eêô„í‘7:ñÓ¢ƒE®ž~Û¯ûgûuCO[÷]©Ÿ@IDAT%lŸÑ§§ € € €D·@x{Þ-63Ö½elÖ ÝÔ3USèöÉÁx½¡©èÞ´qcµï9L/~;G½{NЭ, ¬ñ_ y[ßw5Û4Õ§6£˜Ùy#-Z³ÙÕ¯¦ùµv‹ôØhŸúu øÐ¢— € € € iá%‰RÉ}OÛ·jPÚ§Úõ‚«ÙÙ«eîXšГ/Œ ¬gÉÒÆâí< €@ää.uõþ5~]øwŸZÞÞÇBäô†–D£@‘ßÕÌl¿Æÿݯôî¶þp£OëQB&Ç’6#€ € € Ïa×p?Zó.}ÌfsÕì•ÚVdBùâ³7iݪx÷åÚb’ø”’´þX'aT©À\¶_[¤®ò©™¹)% U-°a««?ýǯÚI–5ß®8­>A{U×C@@@Š/]+Té ö9s–—¶$¡vÍâõyZ½­tóa+fr< Dˆ€ë¸úh¸_gô·•:2¼ƒé ͈B¿yÿ=?ßÑ]3üÒ1“f¶Gá8Òd@@@8$^–ÜFƒ‹ïš5®‡nœ4[Ë6(¹ÍyÅ7IÍÑÀßÍVnà:ÛõïiO•^Ñdõ, !9¿ut`—ÔmjxÒ š…ßìpu×Ó~-XåhÊ-> îa˲˜Ù…CI“@@@@ Œ@˜)[²Òï|¢ô43' ׈™f¦{R Þ7Uš>\ ¬Îêl5ÑÈéÅwXU5ªUz+ Pß¼êhÍ“ŽzýÛ'_ ‚ÎjЏº´7«ý?;û7¿.hoëO?÷©y#Þqõ& ³ € € €İ@Ø5Üëw¥ s¨eß1ž†IÞC’Ò'˜ >kt1YŽJ¢voÃä÷ïTjØW,>% Pn=«]}<ÒÛk7#ì,7('8®ÀBW«¾•¾Üèꋯ]­ØäêÌÆÒŸMО҄÷Þqáx@@@¢R \ñwJŸ;äæÕÊå[Ô°C§€ÄïYÓF™¿¾S™ë[)#m|ÛF“¦þ^ƒ:™”…ªU h_ð&©ÿ×Ô˾$Ì/¹Tk¸x$ äíwµÜ„ê^¸þ… Ù×n‘š5Îiaé².–ƲոA{$!mC@@@ðʸ.›`¦¶n×{¯ÍÓ…ƒû¨©9crjM|r¦z|¼]­:Ÿ«i)õÃo!G"€@… ,¸Ù¯S;Z:ûN_…ž—“ŧÀöÝÁ`Ý Ø¿4?›Í=Úœ ؇ö²ÕáLK§Ô"`Ïw½F@@@ þʸo_8[×÷®ì€[o-Øc÷ä bþ¦l¥§ËͤeLÕKºC©Å¯Å3=F 2V<ä×÷_º° \¿ú‘ÑZQå®ëêëí¦‹p4,Ä8;hÃVW¯|âè½/\uieéâ–F´uz}Þ?qöV » € € € páîyë4/XGFÊxAùÓ†ÈTr?|Ij¬îFéåÂ~šÔí,MÈ‘r&ÌÑF¸§¾'Ï@ üÍMR‡øÕf”­æWq“ÔJ¤ŽúSûW VzA»« ÛLé¡®–þú ŸšœJÈõƒK@@@@ J Üë©Uq󦎺üè°½lÓRuûô©š(?³\[ò¤”23áËîÊ:T¼À§¿rT³¡Ôia{ÅëÆÆwïsõæW¯-rT¯Ž4è|[—v´U#‘ =6F˜^ € € € €@U „¸«PûK[XTºv¼•Zõê–¾”XºÆ T¶ÀÚ§myÇÑ€OdQg»²¹£îü«7›Ùì }¸ÂÕùm-âSS›@@@@ <ð÷ÂBm-¾ÞSÏÍUF×c””)Óž¥o½\ú¬°t¨LŸ:Zr·_ý²T“ºÛ•IUç.,2õü—ë³oý^º¢›¥¿ýʧÉíQ54@@@"R ¼À=¹•¦KYæn¨9S®Óš¡''Ü ÔúGTr/ÊÕü™ÕkLð¶©J룶”“‰È7Š-‚¦nûýúÑ#>ÕO#H­Ñ ¯7»ò\½nþ3g±«ÓN•Ò»Û¡&øx„'ÊQ € € € €ÀÑáŸýùκ.pÆì)#u–ùIë=BWöî¤ÓëI[Ö/Sæ”™‡]qòô¡æH¨LÇof0ßàירj5œºí•i çþòë`Ù˜E«]]ÔÁÒÄa>Õ”=ÆŽ6"€ € € €@ô „¸KI©C´aîTµì;¦´×9Ù3•“]úô°•Œ‹uO÷Ƈmã T¼ÀÒ{9¥®"l¯xÝè8ã÷{]}¼ÊÌh77AÝ“/]ù#[·]a›¢´GÇÒJ@@@ˆV°w¯Ã)}î»çJ½ø×G5iÜåC¡wÆdýîž_¨g*µdŽÁÃ&*Tàë;Z?ËÑ@s“T;pµBq#üdë·ºZhBö…_™÷€¹ÉFZKKC/±Õ£%7ÌðÑ£y € € € +å ÜÉ©rÏÃò?™Ú¾m«všÙ”§5©­=Ûö«n“fªŸ\þKÄ 6ý@ 2v¯0ak†_—¾êS­Ó Û+Ó:ÎíÝütÙÆ`Ⱦà+W…EÒùm,ýäb[ç¶¶”Tƒ÷@$Œm@@@@ø¨¸4k”ZúÜ[YýÞÜÒçiç‡íÞ¦dõ¹ã!M~j¦Æ™²î9™¯jåÄ>jÂUKOÈ %°ýcGï ö+m¢­3ús“Ô£€"pÃw»\yáº7“}éúà O»¥ZºÕŒß9¦.{Bö6š„ € € €œ”À‰£ï‚å2%؃Kúºûˆ°Ý›Å¾øƒà vo§ÛŸW¼sÉCcýx\†Æ ÷N²^»óÍCñÌø’=xDÐ6ýÇÑ‚[üêñ7ŸÎ¼†°=t¹ªÝ³à`0X÷v/hÏÛ/kj°_ÐÎÒíWÚjT—€½jG„«!€ € € €•/pâÀÝ´!¯¸é/Tý#ÛTô­>.ÍÛ3ta›£Óô&íKfÄgiáê\uïzÔYŽ<+Ï@à«õkÙ$G—¾êScsM–ÈX¿5X&Æ«ÃiušÔÍ”‰¹ûŸÚšZì>j±GÖ€Ñ@@@@ ‚B ÜK#ô…G]¾`ã•L€WújyŒ{¢¬;T’樰N(ຮ>çhÓ¿õŸŸ ºm™}B´*Øa_Aq™˜âR1f˜û€n–î½ÎVrmÆ© †K € € € €#Rà^2Ã]5jø· ß+Ý–>0í˜ÕbΜjöدQí.YzNVˆwÿWßäWÞéò”Ô„·ºßÞ@þ»ÄÕŒ¹Ž™ÅnÉ«Å>¸‡­Ö§36Õ=6\@@@¨NÒïÄÒ=ëù”;ªS™²2yšÿ¯Òùíês^«cöeaÖSÅÛÓÕ¾Yé|ùcîËF8$pð{7psÔ„S¤ËÞõ)¡î!êY[·ÅÕ_^óËûÂÏo‡útö™ŒIõŒWE@@@"OàÄE “ÎVzFqóGë7Ï,QQñÓíóghdVI§Fèâ6G×fÏ[2M3sŠwj¥zµJöç~H`ß×fõEE¦|ŒtIaûYUÅkùæ›Óÿë׸güêyŽ­¿Œ"l¯ w® € € €D“À‰w%èªÛg”öiúÈnJì3J÷Þ{£šô –‰ ¼˜‘®´’ÉëEÊݾVo>s¯êv]zìˆY£”œúÒXA Nv}nÂö ŠÔr¨­îÓdû˜E]o…–;ºÕܰvûn鯷ùtí67@­ÎáÚ € € € €@„ „'uºI‹ŸøXÝF—Éž®Ìì²=JSÖ½W™h>¸,{ê¥.úܘ6Q¿Ö¾ìA¬#€À1¾{ÛÑ7øÕíaŸZÿ4„¿‰ãlªïv¹zì G›wºº3Ý67De<*F–³ € € € €±)rzÔuÔ4}»`–F¤ 1BY+>Р”¤#_8ô|ÄT­YxŸRma Ž!°îY¶õëⶃ§Ê6,r5û=G·Oó«]3é 3«°½Êø¹ € € € µ%“ÒCê@ÓîÃôÜÒazD¥@þVWï^éWr©×|òÕ ä­ê\õ­«¿¼æ—ÏLfϼѧ³š2U=\@@@ˆ%÷XMú5{V¹š7°H-~lëÜmYAoUÞÞ|WÏÌuôþ—®~ÖÇÖÀn–l›1¨Ê1àZ € € € €@, ¸Çâ¨Ò§ˆØö¡ z¯ñ«Ó[íLù–ª(8hJø,wõôÛŽº¦ZšþKŸN=… ½êF€+!€ € € €±-@àÛãKï"Là›W}|“_=žòéÌk¸)gU ÏÆm®¯qõ©ùùòkW­O—Ʊ•Ö ÿªðç € € € €@< ¸ÇÓhÓ×j(ÜëjÁ-~õ|ѧÓM–ÊðÊÅ|¶.²/^ëÊï(0›½ÿ¹–Æ™>õê0£½rä9+ € € € €;ïªH`Õ_5ºÀ"l¯`oÇqµz³ä…럮q´ö;©]sK?:ËÒÕçÛíÔȯ`tN‡ € € € pL÷c²°Š(ÜãjÅŸõ}‡_¹ŠÝ•gf°›€Ý+³Ä<ÖI’º™šì?¹ÈVçV–jÕd{E8s@@@@“ ý;9/öF ,;:íRK º‡XXäjù¦CµØ7ï’ÒZg±ßØÛV³†¸†ãÊ1 € € € €+@à^±žœ £äºZ5ÕÑeóùu; ç–mp5g±¹Ñì*W§Ÿjf±›21·^n뜖j$²Ÿ€—@@@@ªX€°ŠÁ¹\ü x¥dÎ`éÔsˆCýÝû\Í]êê ´{7<ÐÕÖÏ/³Õ¨.~¡ø± € € € €@õ ¸WŸ=WŽ‚®¾zÌÑ€üªh¸sÖ;&dwµð+7pÃÓÛ®°unkKÜðôDr¼Ž € € € )¤€‘2´#&–?è¨yº¥ºí˜}¬þÞÌfçó`Ù×ì0ÐÌf=ÀÖ©§àu,/¶!€ € € €D¶{d­‹bü­®ÖLw4p ¿fe‡Ñu]}¾Þ Ù]-Zíêü6–~u•­Î­˜Í^Ö‰u@@@@è Œ¾1£ÅQ"ðe¦£×YJ6eQX¤Ü½®Þ6³Ùß4µÙm;X›ý—¦lL½:øðþ@@@@ˆ ÷ØGzaû¿uµv†£«–Å÷¯˜7›}ÉZ²/qõéW=Li±é>¥µ$d°·,ÍA@@@¨øN+S p,/pÔj„­:-â3XÞ•çê­Ï¼ ÝQ ó)3 ›(S·v|zë=Â6@@@@Ø p½1¥GÕ,°ïkWëg:ºzyüýz,tõ‡®þ³ÀQ÷¶–îºÆ§Ž)„ìÕü–äò € € € €U$‰`Ár™øX6ɯԟ۪Ý,¾‚æW8šþ_G)-M½Õ§f ã«ÿñûާç € € € €%î%<"Pyë\}ý‚««Wù*àlÑqŠÛ\=ñ¦£­ß»òn‚z~[sGT@@@@âP€À=.WžÀ²ßùuV†­Z§Åþìî}®f½ëèíÏ] ¹ÈÖµØJLˆý~WÞ»‡3#€ € € €D»{´ í=«\}óŠ«A«c{v»ëº}Æ;Žº´¶ôÄm>5¬KÐ1oD‚ € € € PmîÕFÏ…cM ÇÌnoûK[Ib7|^õ«Ççøå÷Kÿw½O紈ݾÆÚû“þ € € € €T¾{e(/¿PJ¬¥ä$ˆ+ƒ8ÒÎùý—®¾{ÓÌn_›³Ûs÷ºòf´ò•«{ÛØÍ’m¶GÚûö € € € €T¯w7¬hÿ‚ee‚öºuëªn÷Ç•[Ñçç|)s¿_íÆØªY?¶Bè"¿«—>r”ñ˜_5¥'åÓ•çÙ„íù.¤Q € € € €Õ-Àôë Í“¦é%çlUS—`Äîã.sÓЭﺺàéØšÝ¾d­£'æ8:µŽ4ùg>µ>=¶þ˜»ïHz† € € € P]äÁ(¿öÅñ^š¶›ï©À“sªˆðf·Ÿýk[‰1rãÐ-¹®žü¯£¯6»º¥¿­K:òE˜ˆ}óÑ0@@@@ˆ p¯ á(ÚøŠ®½nJÓD‹ÀÎEŽv|ìê¢YÑ?»½à «}àè•O\]}ž¥»¯õ)©³Ú£å½H;@@@@ª_€À½BÆ`£2¥+§BÎÅI¢I`éGÆ™Ùí§Dw0½n‹«ßýÓ¯Ö§YúK†Og4ˆîþDÓ{ˆ¶"€ € € €Ä޵"*`,çO© Åiûä¬4¶ÎÉ)"_`»¹™h®©ßÞö¶èþ5Z¸ÊѸgýq©­û‡¶Gþ;"€ € € €Dª3ÜË92Ûç?¨^²gIÿ¾îÔX7–óœKïstÎx[ µ¢w6øË ýó}G®÷©SËèíGt¼ch% € € € €@¬ ¸—g„sêÖ^ãŠÏ0^/Mì),Q^yÎɱQ!°õ=G{¾rÕfTtÖn÷;®þú†£Ï×»zèfŸš6$lŠ7D@@@ˆh÷°‡'Oό졬âãg­˜ TO³HJûœ-ÞìöŽÿkËW3ú‚ê}®xÁQ¡_zøŸ’£x†~´¼_h' € € € €@|¸‡9ÎËž¹K#‹ÓöOähXû¤à™ uØ w“¿³Ä˜Àwo;Ú¿ÉÕYffx´-[s]M˜íW»f–î¸Ú”ÃñEß ¢Íœö"€ € € €Ä{c·r¶ÒFN9b†žÕéÐYjÕ>4ýnMÕ:ôJXkŽãhÑ¢Eš2eJÈÇG!€ € € €T”ÀŠ+tðàÁŠ:]ÄœÇrÍ1­‰’†,›6Xi£Kª·‡ÖèÉ‹wéž®õCÛ¹Ì^ 6TFF†233ËleµºÞèV¨öc}j}cô„Öÿ07x}u‘£û‡ú¥dªËŽë"€ € € € ®€eYÚ°aƒRRRÂ=E•Ç ÷0˜kŸÑGc[©a­cŒÉׂÌ)Êœ··ÆŽï!íÌWûzP‡AQ‡lzÙ‘¿ÔjxtÌn/,r5åGë·ºšz«OëEG»#jÐi  € € € €'!@ |X%»¦ºCÓ•<;ò±HÏ,7»7>ý§Ê|à&ßNõÈyEÞArî÷«Óo}²ìÈ®wï Ök¯]ÓÒŸ~î“÷È‚ € € € €•+@à^á¾ù‡Î¸ç€¼gî‡H¢uíë\¹Ž”ò“È®¿ÙájÂ,¿Îkk)ãr[¾(øA´¾/h7 € € € €eÜËjTÂ:À•€Zŧt3»ý·~uþ½™ÝnjEEòòù:G™/:q©­«Ïž:ó‘lJÛ@@@@U€<8T©pö«ÎAif»ò™¯)œyMd‡ío.vôô;Žþ?{÷çDyïü—d¯\Eï""Þ…ªõV¥T¼T‹­Õ^ÄVk…¶§µöß‹ÕÓË9´çxë9{óÒzªô‚U±*Z¬÷¶b-( ‚ "(+ì²›ÌüŸß“™d6›ÝÍfg³“ä“}å•Éd2yæý<™d¿óä™o},.ïCصvDy@@@@*_€À=ô:,ßãÊÅ¡¯—ö‡€cN<ºdzJŽúßèönwL| ÚÑ•ë/NÈ~»EûÀ@Ô#¯‰ € € € €@)ÜK¡Ìk”­ÀªY®Ô ÉÞgG³ÇxK«+7ÜåȦ&Wn¼,!ö—mc£à € € € €e/@à^öUÈô•@jGºwû ³}õ½Zïú-®ü×S²ÇÎ1Û³½®–°½W <@@@@^ ¸÷§W®ÀË?wdÈA1Ù}b´z·§R®üéiWþø„#ç—O~0ù“¹Vn+aË@@@@È ¸g-˜B #Ðf†hyñG&Ü­ÞíË^wå¦?§dP£È/MÈ>»Ò«=SiL € € € € ÐÏîý\¼|4–ÿØ‘]OŠÉðc¢Ñ»ý½fWfÎw䉥®|îÔ¸L:’^íÑl9” @@@@ šÜ«¹öÙö¼;6¹²üFG&=·Ç£K¹õ!GŽ“[ÿ-!CÒ«=oÅ1@@@@~ˆF¢ØÏ¼<A¯ud¯sb2ôÐþ ¶ßÜìÊOïwä­w\¹ò¼¸ŒÞöA+¦@@@@@ +@àžµ` پΕ·9rÖ?ûï­‘Ô“¢>åÊœ'9÷¸˜|ÿS ©«éß🦠€ € € €Ý ô_ªØ}ÙX’ ,™îȨ)q4ªî_KŸU‡¹ñó Ù{—þ)GÉáyA@@@@*@€À½*‘MG i¥+k~ïÈ9ËKÿ¶h2'EýõÃŽ<½Ü•K'Åå´÷1|L8µÊZ@@@@(@é“ÅÒm¯„@/%c¾—ÆÝKÛ«|ÁbGn3'E}ÿsRÔ/'dÈ€Ò¾~X@@@@: pªI`ËbWÖ=èÊGV$J¶Ùë6¹òsRÔ··ºrÕù »A{Éðy!@@@@ú@€À½PYeù üë;)9äëq©Ö÷¡w[Ò•;Ÿ4'F}Ú‘— NŠK-'E-¿FC‰@@@@È pÏánõ l4Á÷¦¿»rÒïú¾wû²×]ùñÜ”ì<8&3.KÈ^Ãû>௾e‹@@@@è÷þqçU#$ðüÕŽþïq©Ø·á÷ªõ®|ovJ¦žÎIQ#Tý@@@@Ðâ¡­‰!P†oþÅ‘m¯ºrÀ´¾}+lnråû&l¿la{6ŠŒ € € € €@A}›2TB ÿžÿwGŽø„$êú®w{Kk:l?e\L&É[®ÿj›WF@@@@ oHÿúÖ—µGXàµ?9’ÜæÊ¨‹ú.lwW®¿Ë‘=ÌÉX?;‘·[„›EC@@@@ ×$€½&då(à¤\ù×wS2î ‰'ú.pÿÕÃŽèp2_ÿh\b±¾{r¬ÊŒ € € € €@¥ pÒÔJ«Q¶§ WëJÍ€˜ì{^ßszàYGžXêÊ—%¤¾–°½ Ša!@@@@ÊX€À½Œ+¢'2cª/ù”wk¢¸ð¬çV:2k¾#7\’aƒÛ c@@@@Ê^ ïº÷–= P©+nqdਘì1©ošÿš ®\{§#WšÞó#G¶Wj;b»@@@@È ‡{®÷+Z@O’úÂ9òÁ»û¦wû;ï¹ò½Ù){‚Ô£è›@¿¢+ˆC@@@@ ŒH˸ò(zÏ–Ïpdø±1Ùõ„ð›~k›+ÿùû”œxHL>|LøëïùÖò @@@@(¥=ÜK©Íkõ«ÀŽ-®,ûGN]~³w]W~t#CÆäó§¶÷kEóâ € € € €ô“É`?Áó²¥Xz½#{ž“acÃWý7 Y·Ù•o›qÛãñð×_z-^@@@@z*~Wßž–€å(@ózW^ù…#g>~“øyGæÿË•?Ÿ†:ÂöT'/ € € € €@$ÂO#¹™ªÚ^ø¡##?—Á„ˆ/^íÊ­9ríg2|H¸ë®ö:cû@@@@(7÷r«1ÊÛc÷L(¾ê·Žœ³4ÜæþÆÛ®ü×Sòsã2zÂöW O@@@@@ ÂýÂ*”Íé(°øû)35.ö /ߺݕïÍNɧ>—ãâmÔQ9 € € € €TŸ@¸]~«Ï-ޏÀ»K]YûgW>òJ"´’¶%]™þû”=:&çOØ,+B@@@@ ÌH ˼)~×Ï'%_—úááõn¿ñ^GÍÉQ¿p&oŸ®õy@@@@ê 1¬®ú®ª­ÝôG6>áÊÁ_ ¯™Ïþ«#«Ö»rÕùqIÄà ñ«ªbØX@@@@*T€!e*´bÙ,‘ç¯vä°«âR;8œ`üÑ%ŽÜgBü?ŸõᬓzB@@@@ʯëo嘰% °~¡#ï.wåÀ/†ÓÄ—¾æÊÏîwäûŸJȈÛ+ ‰°  € € € €„.Nz±X!½ÐÞíc¿ŸDCïÃñ77»òƒ?¤äŠÄå ½z¿¾ÞmÏF@@@@¨ ¸Gµf(WÑo˜“š¶nreÿ‹{ŽoßáÊ÷f§äc'ÄåÄCy»])<@@@@* A¬‚J®¶M\òCGŽ0½Ûã5½Üñ€#£wÉù'ñV©¶vÄö"€ € € € ÐSRÄžŠ±|¤ÖÏwdÇFWF~¢÷aûã/:²xµ+_9›·I¤+Â!€ € € € ’ĈTÅGà…k9ô[ñ^÷nßø®+?5'IýæÇ20„qàÃÙ:Ö‚ € € € €Q¨‰rá(=Øô¬#ï¾àÊèû=yZ‡eÇ•ÝíÈYGÇäð‘½ï)ßᘠ€ € € €)@÷ЬÖêܨþÛ‘ƒ¯ˆK¢—=Òÿô”+-­®L9™·Gu¶$¶@@@@âH‹sãYxw¹+o-teÌ{פW¬såO8ò­ó’Hл=bÕLq@@@@ˆ´@ïÒÉHo…«&¥×¥ä@¶× ->$×^í×Ý•’K'Åe¯áů§šÜÙV@@@@È 0†{Ö‚©2Øöº+¯ÝåÊG^îÝØí·>äȾ»Ä䌣8U¦Mb#€ € € € Я$‹ýÊÏ‹‡!°ìGŽŒš—ÆÝŠï•þÌKŽüíeW¾úÞaÔ ë@@@@@ èá^µ^AÛÜò¶++g9òáç‹oÊ››\¹ñ^G®üX\† (>´¯ V6@@@@Š ;oh<%:/ÍpdïÄdШâ‚r×uåç:rÊØ˜9š·Ctj–’ € € € € P~$ŒåWg”Øh{Ï•—îÈaW?vû½sE{¸öÞ 4,@@@@è)cïüxv? ¼r³#»ž“/®wûê·\¹ýQ3”Ìy ©«)ný¸ù¼4 € € € €DL ø¯#¶!§ºR;\YþcGÆßY\ïöÖ¤+×ý)%Ÿ™—‘#Û««õ°µ € € € €ô=ÜûÆ•µö±Àªß¸2xLLv=¡¸&<óÓ;~hLÎ9¶¸ç÷ñæ±z@@@@(CÒÆ2¬´j/²“reé )9ìªâšï¢Ž<ºÄ•¯M.îùÕîÏö#€ € € € €@~Çü.̰Àks\©,²çé=o¾ïnsåîqlØ>lCÉD¸š) € € € €e'ÐóIJì6‘WšÀÒë´w{qc·ßx¯#'“c¤éWZ»`{@@@@èoRÇþ®^¿Gkç9’Ü&²ïy=ïþÀ³Ž¬ÝäÊç'Ñì{„Π€ € € € PÉcAL,¯qäÐo%$ïYàþÆÛ®è‰R¯WÎ]•èQ™~rŸ#GŽÉI‡r\©Gp,Œ € € € €E DÅÆ“J)°ôzGF..õà ï¥þÈó޼ò¦+_8ƒ&^ʺâµ@@@@¨fz¸Wsí—Á¶7¯wåÕÙŽœóbáMuýWnyÈ‘^˜ÆúÂCú2à ˆ € € € € aºÿF¸r(šÈòÙ÷ã1°wáÁù/æ92ùؘÔƒç` € € € €ôV€À½·‚<¿ÏZßuå•[9ì[…ݾøUGVš¡d>~"M»Ï*†#€ € € € €@^Rɼ,ÌŒ‚ÀË?sd÷Sb2ä Âz·»®+·ýÅ‘ÏNŒKC]aωÂvR@@@@¨ ÂÆ®Œíe+ÊD ÙìÊòŽLx ð&º`±+)Gä”q„íeRÍ@@@@Š ‡{EUgålÌÊ_92ÌçÃ.,7&õúï­ÞÔìÊïwäó“hºý^q@@@@Ú Z¶ãàN©\ו¿rdÌÔšâïþꘞí19`îÃùRo ¯‡ € € € €Õ-PXÊYÝFl} ¬Ø•D½ÈˆñÝ7Å77»òÐ?]ùìÄî—íÃ"³j@@@@@ ¯Ée^f–Jà•[9à²ÂšáLs¢Ô³‰É®CéÝ^ªúáu@@@@@ pÂ’ÎÂ×Ç’,вÁœ,õ!WF}¦ûf¸ü W¯vå‚“º_¶à°  € € € € ¢éeˆ˜¬ªg+g:²×Ù1iØ¥ûë·=”’ ?— Ý/Û³R°4 € € € € Ž{8ެ¥‡öd©¿,l8™'—:òîv‘³Ž&lï!3‹#€ € € € €@ ÜKˆÍKeÞZèÚ;»Mè:DO¦\ùõ#Ž\zZ\‰®—Í®)@@@@@ ôî¥7çÀŠÛLïöÏÇ%ë:D¿ÿYW† 9á`š* @@@@¢-@Šíú©ÈÒíØäÊÚû\Ùÿ⮛߶W~÷WG.;=Q‘l € € € €T–@׉gem+[U¿qdÓcÒ¸[×½Ûÿ¸#ïÛ?&íÕõrÙ,Š € € € €U.@à^å  ?6_‡“3µë¦·áW0ÃÉ\rJ×ËõGùyM@@@@@ Ÿif>æõ™ÀÓk=Õ"²û©]÷ZŸ5ß‘3ŽÉnú^®Ï ÊŠ@@@@@ ¸÷ŒÅ{'ðÊ­ÞÉRã鯬seÑJW>9žæÙ;mž € € € €¥¨)å‹ñZÕ-°c‹+oÜãÊ‘/u}ÔÛþâØ°}Pcç¡|uK²õ € € € € EºG±V*´L¯þÖ‘ÝO‰É€=;ÒŸyÉ‘·ßuåìc:_¦ByØ,@@@@(s÷2¯Àr*¾ž,õ€Ë:or©”+¿zØ‘KNKm {9Õ-eE@@@@‘ÎÓOtQ`ãÓŽ´½+²ÇéóžsePƒÈøÃh–!Ò³*@@@@(‘Éf‰ «ýe´wûèÏÅ%žÈ¸oßáÊ:rÙ¤®Çw¯vG¶@@@@¢+ÀIS£[7S²¶­®¼v§—ýÅÎÃô9O8rؾ19Ô\¹ € € € € €å(@÷r¬µ2+ó«w82b|Lî“?L_·É•{ÿîÊçN£9–YÕR\@@@@p0z5™l‘––¤$[šdKSK¯VUiO¶'KÚySûÙŽ|ô„¸ì¹sþ@¾Ò<Ø@@@@¨LÎSÐÊÜÞзjã’åê‹&J¬¶Q–IÇ ‘‡4JlâE2ëñ•¡¿^¹­pÓ³Ž4¯ÙëÃùÃôÇ^päÍ-®\pRþÇËm{)/ € € € €T¯{/ê~ùì¯Éˆ±gÊ5·/ôÖ²X.ö&Þ.—|ð™xõ½RÍýÝWÜê,µ¦c ®'J½õ!Gþí¬¸Ôåy¼UÃS@@@@@’ ¸Iž\y§ráÙgO¸BæÌL›w‡\19;{á5“eúƒë²3ªhªí=WVÿÁ•.ÍßÌþoAúD©Gÿñ*¢bS@@@@@ H:‹¬Ä§gÿ<ûÌ©3eó‚ËÇ'Ž—ñg|Z~|O›û-ÉD’UMí¨Š;z²Ô1—ulb®ëÊOïOÉ”“ã2|HÇ0¾*pØH@@@@¨8ŽihÅmblPÓËrŸ·O8IÆ4äy†1rJ`h™Ú<‹Tò¬-¦÷ú¶5®ì=¹c >o‘+mI‘³íøX%›°m € € € € PÙ5•½y}´uƒÇÉwnž.ã–o–ÆQc$o˜Þô/¹gnöõÛ²“U1õŠž,õâ¸ÄkÛ‡êïlseÖ|G¦_˜D¼ýcUÃF"€ € € € €@Å ¸Uµ 2qÚweb§ÏÝ(³¾1U2yûäsåÐÁ.\q$·›“¥ÎväÌtl^¿ü‹#ã‹ÉÁ{¶W\ųA € € € €T¹CÊ„ÜZÖýM®ž8B.¹uqfÍ3¯=Oª(o—5teç#c2ø€ö¡ú’Õ®,ZáÊŧÐì2ƒ @@@@¨’ϰª²eÜ{ý4iÜëx¹Æßݬ{ÆüÕrñÁÕ·‹¬0ÃÉ0µ}ÓJ¦Ò'Jýü¤¸ nlćU¬@@@@èOŽc~ôgiÊòµ›ä¹;!—œ¥dû´› ™p•Ÿ¯½ÛG}&.‰úlàþÖ;®ÌyÒ‘ÿ½4Ñç¯Ï € € € € €@ôÆ/Éd²à‚Ξ=»àeûsÁ˜k.ýY€ò}í-2ë¢å’Û³[pÕÌÇä›—aÙY½žÒð|êÔ©rÍ5×ôz]}½‚T‹+wí•”IOÖÈЃ³ûü.%#w¹äT÷¾®Ö € € € €@% Äb1Y½zµíœåí £v”·¯ÏʶdÖå°}ª<¶z†ŒÙ»ácú¬°%Zñkwšac‹µ ÛŸYîÈ«o¹òíóÛKT ¼  € € € €ô“{1ðÉ•òëL×öÉòØæ[d|˜ÝÚ‹)Sž³â6s²Ô˲c´·´ºò‹yŽ|ñ¬¸4Ôe{¼G ¨@@@@]€À½Òä†WdAàyþö&yº¥%0§ýäŽ#äÓß¼XFWpø­/¹òÎWFžŸ ÖgÿÕ‘Ñ{Ääøƒ²!|{î!€ € € € €•#@à^D]6¯Ygž7W¾÷Õ¹™{ù'&Ȥ+*;p×ÞíûM1'KmHîk6¸òÀ"W~þ†’Éß&˜‹ € € € €•&@à^D&Ûzú¤½¤¶§O)­I@IDAT£åSfè˜U¿qäÔ…ÙæôÓûSòÉñq±S¶Ç{mEE@@@@z,MH{üÔê}°ã.×½¼zr¶üõ»]t@Lv:<®?ü¼#[·‹|ôxÂö*î"€ € € € €@ 0¸vWn©6mÅ­ŽŒ™šnJMÍ®üêaG¾rvB ÷RÕ¯ƒ € € € €ý/@àÞÿuPÖ%hZéÊf3VûÈO¤Ãõ™8r옘>’°½¬+–Â#€ € € € €@Ü{LÆ‚öd©ŸŽKÍ€˜,Õ'—¹réi4« Ó € € € € P$£ÕQÏ}²•N›9Yê,G¸,.)Ç•ŸÜ—’KN‰ËÐônïpVŠ € € € €‘ ptõD»poÜëÊ€}b²ó‘1¹÷o®Ô™Sðž~a{´kÒ!€ € € € €@_ ¸÷•l¬W‡“ÑÞí›¶º2û¯é¥ÆbîUPõl" € € € €ä pσ¬îšV¸òö3®ì÷©˜Üò #§™^îûïNØÞ½K € € € € €@¥ ¸WjÍöñv½ô3GF}&.‹ßre™9YêE'Ó”ú˜œÕ#€ € € € €@ÄHI#^AQ,^r[úd©ûO‹ÉÏpdÚqi¬§w{ëŠ2!€ € € € €@éÜKg]1¯´ê7Žìr|Læmpe¯crÒ¡4£Š©\6@@@@Š )-š®zŸøÒOÙóÒ˜ÜmÆpÿÒY4¡êm l9 € € € €HKƒLw+ðæ#Ž8m" råC‡ÇdÓà  € € € € €€;­ G/ýÄ‘‘—Å塊|ü4Ÿá±0 € € € €T´‰iEWo¸÷Þ«®¼õ¨+/&rô1Ùs8½ÛÃfm € € € € PÎîå\{%.ûË?sdßOÅäÏ/ºrÁ‰4óór € € € € qRÓˆWPTŠ—ÜîÊÊ™Ž¬?9&£÷ˆÉ{Ò»=*uC9@@@@@ îѨ‡È—âÕÛ]vdLîyÓ•OœDØù £€ € € € € Pr÷’“—ç ¾üÓ”´œ“aƒDÆŽ¢Ù”g-Rj@@@@èK’Ó¾Ô­u¿õ¨#mM"N8rÁI4™ ©V6@@@@B¨ y}¬®–ßäHÃ1qÍH2'Ìp2XÅl € € € €„ @wå+yÛ^seý#®ÌßË•óMïöXŒÀ½’ë›mC@@@@âèá^¼]U<óåŸ;2Čݾ>)2áÂöª¨t6@@@@Š ‡{QlÕñ¤T‹++~éȳGˆœ÷¸Ô$Ü«£æÙJ@@@@(F€À½µ*yÎêÙ®4“"gEØ^%ÕÎf"€ € € € €@‘îEÂUÃÓ^úIJV(rαqi¨#p¯†:g@@@@@ x÷âí*ú™wdûF‘Çvreò±„í]Ùl € € € €„"ÀISCa¬¼•¼ôG¶œ“ÓŽÉàî•WÃl € € € €„-@÷°E+`}Û׺²vž+ öqå£'ÐD* JÙ@@@@(ij Ëí%^þ…#­fìöcŽŽË®CéÝ^nõGy@@@@@ ÜûÇ=²¯šÚáÊ+·8òØ"çŸHóˆlEQ0@@@@ˆœ‰j䪤 ´æ÷®´î)2Ò„íûìJïöþ­ ^@@@@ÊI€À½œj«e]~SJž+r½ÛK ÍK € € € € €@% ¸WRmör[6>íÈ;¯‹ÔNˆÉA{Ó»½—œ<@@@@ªL€À½Ê*¼«Í]~“#¯cz·ˆfÑ•!€ € € € €ùjòÍd^õ 4¿éÊë÷º²å?EŽMà^}-€-F@@ÂpGœwÞ‘ø°a‹ñ êðdËoMn2)É5k¤uÅ ió®ÉU«$6hÔì½·ÔìµW»ÛÄî»K,‘(¿ õJ¬m?õöÛ’zóMI®_/ucÆHíþû—íöPpè¹{ÏÍ*ò/ßìÈ[Gˆœwfù~¨UdŰQ € €e)à¶¶ŠÔÔH,Ng–²¬@ Ý­€³m›$_]ÚLª·¨Ú«?ï7Ä$í68­=Zj8@j5xÔ[ïªa+ï‘n©Ëb·­MÚ^}5¨Û`ý•WÒ÷MÛH˜/¶Þµ-˜vÐðþ÷‹óÞ{’4ídÇóÏ˶ûï·Ó©µkí| Ýsƒxÿ~Bzs76–ÔF÷ë Û Ý„é)3Ô[ Öƒ·6H¬®N{ì!5#FHë²e’ØsOxÎ9öÚp ýÖîS[¶Hó#ȶ”–Ç—X}½$vÙEâÇÛÛ„wkï§u™¡C9xVÒÇ‹•³{9×^HeOµº²ì玬¹X䫇Ðó $VVƒ € PA®ëŠc‚Š” RRo½eo“:{õsÞ}Wâ;ï,N9EO;MœzªÔŽUA"lJ% h{×vž|í5{µ¡zδö^×@±vß}¥F¯#GJÃñÇKÍØi—0]jãFiõƒWÓ»¹ùÑGeë/iƒXgûvÛó×öñÌêó£ÚË9×'µi“èA…ºC±Ap¥¶ wÇi3=Óý^ê™ë¦~õ Kb×]3S´N:ÉÞ¯3Óñ!C f±sL¯a|ÒðzÕ6ØòÔS™yºïï´S¦g¼ͽ˜žñöVv¦ýÇÄÌ÷§ó-§Ïmÿºoé&\w6o¶ûõs0À†é¦ýë­Ö{ãĉRãÝ×ǃ۫=ü›M¸½íÏ– _,)óÞxÖY6|púé<¸`›ž.¨½íwüã²ý¡‡d» ÙõàFÃqÇÉ€3ΡӦ‰ho|Ó~íÕôÊwÌtëòåíîÛÞúfÛ%• äƒá|p:ÖбíÎ>XÁi{Në­¶VìútæÀŠNÇuZ¯æ`¢.3nÔ YÍånvfS§N•k®¹¦Ï^½Ã‘‡¿Ÿ’}ÿ3ަNŸA³b@@È h˜ÓüØc’Z·N’^hÞ.L7¡aÌôXO˜ÞŠ]]µ7£}ÜOm& l~øaÙn®Í Úb€†ïæªáL„E\ŠÐe­[ÅÑ¡40Ò[ ŒL0doM¨UcrÔg¯VÒÅÙ&ÀN®\i{kï[íel]áÝz_—ïù¤·™ðT/ ½m nÂôÌ´†ëzÕÞéæ=Ñ›KÊÔU°'t&À5Û¥u[»ß~Ù^ñ&ÐNì¶›í)­A«^µ×´Þö¶¹Û`ƒeïƒöÚ×÷²ðÁÞÏñÑasÚL=hP© `Û]=Ô¶Å(÷æ÷{›Û€ÛºÍ­ö8÷ƒoms6`Îù¥‚ÿ‹…øÀ¹”}v_Û¬ö*×ò¦´œæ€¨®¹ê­Éþ´†Îvž>îMÛÇ‚ÓÁç˜_fèþÂèÚÓ>¤‡öj;Ñð]¯;ž}VÆO÷~?ûlÛæ{‹¦.~À¾ÝôfמéìkÈ>À|öÄÍP>Å\œ¦¦ô~ÖÛßj8o÷»zk®nKK§u¬à´_¶î‚õ¡û0³>Ç\Ýæf;í¯ßô~ø®·&Ï„ñÞýLXoîúøÇeÐäÉÅl2ω €Q¶zõji>—¢|!pr혲•"p¿ûÈ6yò0‘kfÕHm =Ü#Þ$( € €@l7!¸ ÄÿòÛ›±ñƒ”ðåê~ˆÞ›^ˆîh°¢á»^wüýïRg‚`íù®¼b ä^{úšÚU‡3h3W½m]ºTÚLoTí}©a´öº×kpZ‡>è1·µ×§=Èa‚¢ûAº_Což zÌ}²$a~I;$‚íuiB& Awüë_Òú 6tÒð]ÝííØ±RwðÁ¡‡µ!4O» Û‹ÚÒmð{ë­ ¥Í<1½fíP-&ˆÖú´A ö 5íÈöÕö”s_çKàñ|÷5œ«ÙgëÖ¶³ž”ù•H0ŒW{ Å«zP@V½uM/ù˜ z5ôöxÿÖó:_z/œ÷³ãŠûAz0T7Ó6X6á¾=Èàl°ô„w_Û]¾‹Àþ{ÍÞzï?{áÀ¥Î„ï~_«Á¼™Fˆ›¯,þ<ÝžÜ =÷¾k†²½¶sÆS÷‡qÑ[ÊEƒM.á hP½}Þ<¾kH®íÌz¦þØc zF²5?ñD&d×÷JãÉ'gBvýI¥\ô}ëð6ŒÏ ämHèõ~ýQGIÃ1ÇT AÕo{Õ7pú:pßôGî›”’÷Äåü1~{8µÆZ@@Ò h/Ñ‹K«¹ÚpÑŒúóþ¸sÕ‹sCäv÷MÀVéxëÏêýÀÛL×}tº·¹Þæ'övxAhoÒæ¿þ5ÝûÝô@ÔöøÛÞï&„¯?üð‚K¢½q[_~¹C°®ótH øl°çõº­=è Û{8©ã-{×à´®OCÅÜ ÞåuHB.†´û•@îð;æ~pX]§ö*Õð¼Ý8Â]Ý/p˜ íE©t8ÿ}¢ï "ÕÇï_gBx.t qèj-—öœÎêÁp]Cuëp~âÌXè:äŠ90ÂÅŒþazÂúá{0ˆ×! ì}Êç›Ö^²êÚ{?ä`ºŸöx{àË;–4Uô½¦!¼ÿ>Õžâí‚Ã@€è¦ýàQo󅺬ýÚ³ÞÎíøç¨T‡aáÒoÚ–õ—V~ïw×|N øð‡ÓCÏLš$Á_h¨®ã°kH¯¿ Ò6ä÷bo4CùèØì\¨D÷J¬Õ~ئ¾Üÿr~R{Ç•«ï«‘õônï‡*æ%@¨HÕþäW{WörÈ(i¨cO’f{kÆtÕ^Ï:´‚í¬×cÛa{,›®~¨noMÈ®¡e&4Ô^»&0ÔÀÔ³93ᦠí8äzk®¶—° ¥Óp^‡â0=‰ƒÃNøÃWøÃPØûÞ¢?ïbx ý9{n˜k{U‡öh˜¼Ýô^·CºÌŸoƒÜFZØa]ôgõ†µaÔ]wëÐÐMúoËjnÕ[{¿ûã¿ëÚ+_‡"ð{ÏÚ^ëÚcÝü´ZôL`èA[L{´Ã|»`Ÿ™6¯¥A¤ÖŸ_‡ƒu¿iXd{ûÃìx·¶3Ó¹Ô—ÌÁ*¾ûï§Ö_´Ãÿø½àý0^ØT{TЫÒCó¡&µcag݇du¤kÀ^£ã›ÛJ§Ôõ[¯§ãØëûÚ?ë´ô ‰¡' Þïnàòú‹íÕÏ¥üv˜}Ñvès°Ðþ Ë|¶ëg…e?Ët˜󹦟\¨÷j¨ålc_î-\™32)ÎocòÙ÷nì½Pð € ÐÚûÒž(R‡r0×ÌXÉ:­óò ù`æûã§Ú"›àÐkÚ 3¤7¯Ëat™l8ª©†SöV§;¹ß“ž]bkèÜîähfüÓvÁºwâ4=‘ZædizÒ4sÕÔŽoëyÛ®'¡Ä›„ý@^oµwywcùêp ~OÜV? ìƒa1ì8ØþPp^T?8µ¡¼©L˜ ÿ6SÞ¹÷mÑœá+tžn[&Àõ‚]{òDªÁ rý0×vµ×sw]oó‚é^ì&h×@BÇJ×0B¯:t¹\v,Y’ ߵǣ¾´·níþû§‡£ðBuÛ#Ö ‹ìùØ—Ûh‡91ï=˜áסÖ]ÞÝÔåxÀÍØzé%Àû!¼Þê¾0zæžÄ/'Íž:ßô4Í=éŸî»l[×P½ ~aÒ—m’u#P ú9¼íì/b4h¯7C¤”òWYÕ`Ì6–‡{yÔSäKÙ—ûÓW§äÑùâ“5²Ó@z·G¾1P@@ D Qµ÷i¦j=Q»ZF„ZÔ\‹=Sˆ›Uµ«Òžp¶eÎÏÌ3½*óôÆì°¼YÆž ËÒ5L×i ˜L@jÇC6ÃHè0 vÚâAï¦í8Êf\[{;¯G´öŠn×Þ½ŸÛõŽîd9mƒÚcޞфÛZNvÍ53/0­ãùjð› åszøš\õ¤b²ë?±:þo¾“£Ùñl'K+d˜ ]_fl\ áƒWïäsZg:„ÿ›P^U?\×òéøÒ¶—­7æ´êB{›WàEÇïöÜ`˜k§M¯jI$l`žÈë ¤u,öÏ='õï&`×éJ$ôý£CÎè;ævÖ?›„ €t'@àÞ$ÐW»ÓæÊ»'eû¿ÇdÚÿ£w{A•ÁB €@ h˜×jƪm3=ôZÍÕÞš±|õÖ1=@Åîöb†ú謧ªí™葬÷sçi¯F]§bú³÷:3.p­91“ެ!¼ÞjïÔrìá…êÖáK:„µf\î”Úêc8k¯kÛCÜœÈ,Ó«ÒLÛž˜…öÂÔåMèlÇMÖ`Ý„è~È^ªž³a™kïÔvA|0 7Ó:„¿ÜôN·!» Ôã¦÷p)/¶‡·ÄëSdNèhÆó%\M׊íUýÖ[ízUû¡¼¾O?ð±CÅL˜`Qʺäµ@@J#P.;IkiÚCä^eùlGÞi¹àsœ(µ«Ê±?£7½­Šû²«õò –€ö¢Íê~°nnõd‰ÚsÖß&ô®?öX|ÑEö¾Žã™ Îu¨.n2™‹VOÚç•cÛ½÷J›¹¯CŽè¶'¼ð^x-›ÍÑ›‹í¥­=ŸÍÕͽÕ^Ý^ÏýB{QûËçöÆÖFkðœ{›™gÛÜÇÚÝ7¶±á¡ö‚öW¿t H×Ç48¶= Ñhçs-¿g´ŽlƒõǾöËZŽ·Ú£YÛy”ǬÕ!$ôZØaåH\ò2ë?Wº¿°ûŒN(ùëó‚ € €*@à^¨T…-÷Üõ&88/&»íNÐÒ[l˜Žûã'¿i)¿—T»ióÓ]í5¨½Þü3Æëɨô¤dz[£?ë%àèmõó|èF@Ãdb{=Ôý@»ÕÜדRÚ^å&¼ÖÛÆOL÷*7½Ìµ§s©.Úƒ]{´ëuàÙg·{Y{’?¿ìæVÇWÞzóÍbËoB´LOxÊë>7oxî…é¹Ù \{pk¼ux ¡sÇϽo{÷›çk¯bÛƒ¿“ñÄõä…Ú›?7ÔOšÏL™gæyôÄyö¢ZNóz:t†¾vpLon8þøvót¨ ¹ € € €”‡{yÔS¨¥\÷Œ#;^9ëñP×ÛÓ•µ®X!Ûï¿_¶™«Ž»©½µ—^Þ±a½Ÿ¶g Ü·½4»xqç½÷:êÁñAõ¤n5æ]™s™éIHüñAµwœö2l]ºTZ—-³×m÷Ýgïkðb{jz¼Æ×šutW®.ŠÌC P¥)sr??Ó¦ûÝï˜krÝ:;n¯ß[½ñä“eè´i6XïmñRPëøÊ Gm¯¹¯§Û–9˜°j•=ðj‡21ûåv½Ã=Ëm˜nÂu¿gy9øÔí:®¸ âÍ­Žož0W. € € €•%3ÿšA?¹DU /Æpÿý‡“²¡Î•Ëï®-éfë Ó4X×€]ƒvíY>àôÓe ùYü€3Î=ñž=9›™¯·vZo»¸¯'K‹™^Œv¼ÙÀX³¢û=ÕõäcÚk0¨›±„ƒÓ óóäb{jÙüpÌä5$K®_o‡Oðx½µ=ä͉ÏÊmÜ’6^ *Ð!Ú}‡w Ï׵׳í%îý’&óËÓkØÿH"ÞY_éˆÃP¼^ hqíÁœ â_~ÙöêÎ ÍaBs–ڣí÷x)ÇVïõFWÈ 4 o30m&€×0>sÕû&¤×“kXn{ø›°]{Ãg‚t ÐM˜nƒtoZ‡Í‰ÒCRMl € € €„(@à"f5¯*ìÀ]-ÛR;ä–¾"õ‰ò¹Co t¯æƶWœ€ž¨S‡ÑÑ¡`tí­æð3Æ!€ € € €@Y”KàîÙ3Ë¢j(dm¢^¦~“´$·ÉÌ¥WJÊI‚‚" cÏkÈÞ8~¼=Ÿa{…T,› € € €e!@à^Õ~!ë 2툛d{ò]ùͲoº‡OÌ@@@@@ ÊÜ«¬Âƒ›[—h”/ñSijÝ$ÿ·ì*qÜTða¦@@@@@z @àÞ¬J\Ô†îc&ï¶n4¡û¿ºWb%³M € € € € P÷’0GûEôä©_<âç²¥eܾü;&tw¢]`J‡ € € € €DP€À=‚•ÒEª¯1¡ûØ_ÈÆæ×åŽåß%tïJà5@@@@@ ¬Ü˺úÂ-|CÍ@ùÒØ›å­í«eöKß×uÃ}Ö† € € € €T°{Wn1›ÖX3HþmÜͲ~ÛJùÝKÿAè^ "ÏA@@@@ª p¯Êjïz£kÛžîol{I~ÿòtB÷®¹x@@@@°î4„¼j‡È—ÇÞ*¯5-•?¼òCB÷¼JÌD@@@@²îY ¦rlè>îVY½u±Ìyå¿så. € € € € €@P€À=¨ÁtµCå+ãn“UïþÓ„î×txœ € € € € €iwZB·kw’/›Ðý•wž•?­¸¾ÛåY@@@@¨F÷j¬õ"¶yPÝ0ÛÓ}ùæ§å®7±ž‚ € € € €T¶{e×o¨[7¸ng¹ü}¿”e›Ÿ”{Vþo¨ëfe € € € € €@¹ ¸—{ –¸üƒë†ËWÞ÷+yaÓ£r÷ŠÉæ–7ÅuÝ—‚—C@@@@¢'P½"Q¢¨ 1¡ûåã~-¿Yv•\ûìù’rÛd÷û§¯G›ÛQæ:Z†7î-ñÇt¢^Ÿ”@@@@ pDZêÖ2¤~ÓÓý6»Ý[w¼-on_)ë·­’õævéæ'ìtKê=Ù­q?ÙÝ„ð»™@~Ê–]÷‘D¼¶êÌØ`@@@@¨l÷ʮߒl†ïz=hØqí^o[Û;^¿JÞܶRž\w§ äWÉÖÖM6t×ð}w§{Çëp5 5¥>1 Ýz¸ƒ € € € €”ƒ{9ÔR™–q`íN2z§£ì5¸ -Ém6x_oBx àŸÝð€¼ezÇ¿gú©mvÑúÄ@¾7$y·z ãu^£ æõ¶ÞÞ¦k0A}zùARczÐ;®c®)qõÏÜïÛùú¸˜ÇÍôz_ï¥çë3²Ë‹¹ÕH"Vkzæ×HÞê}óÁ[;ß¶©e­·ŒY>³¬yŽy<é´IÌüÅc ;޼Þú÷cf\ù¸˜û1ïqs/¦ë}3_CòÜåSf}I3V}ÊMŠNoí|ÇÌ<®‘½^ô53Á|A½â›eõ ýzkƒýÀóýùº~[}mS†ž”QŸ§NÁçûåÎW/=§Ž*ê×Az:m}Ì{ÜÖ>–®û¸îdyoÝvy­cïùéõ¦ë0¸.ÿõ´žuZ=3¾ž« $3¿»©óœ¸W/Á-z@¦pût=i[ɵ׺Ӄ?™ún÷úÁ=íêøÛ¢·~»°å3eÕúìê “„ÒƒK®=8e9yÒÓÙUŽ©1Êú>ñë©»ºõêAkÇ>']OÚ¢zÑ}€¾kµ¼þ¶Úé—¹¿,µ­÷éý`p’žÎmçþ~23?g”2?Æ;»ßÌÜ̼72ïYï½`Þ+½?µm·9;Ìû­Õܶ˜«Þîðæémú~îãI³LkJŸ—^Fouíþ,gÓþ³ÄkïÞgIp?”žö÷iÚμ÷µw ¶ãöé¾_? ºßNý,ð§ßÏz°Y"›÷¸¾¿½ƒÈö=­{†.B›÷zÎû<[öNÞ÷“à{§«Ï€°Û®nº]ùûYïs¹“ÏF5i÷¹”Ù†ô¾Ên³:غ4Âúù‘YÆßGh=ê÷‹pÏW£uÖ犺Dõ¢´3EƒédѾ…vªHw¦Ð÷E)/úO÷ Z¯éÏzþUÊço÷79ûû×ì×tÿ­û.¥Èîû’Þ>*»¿²û'ûݦ4e©ÖWÉüoh¿Ãèg¶¾ØwTk{`»@_€O_‚ÛÈè2z*»F¦L=-ˆ†Ù/_éþý0\ƒTe‚¦lˆ¯a£¡~'¬>æU-É÷46±Œ~©«­i´_ð2¡M§mg=óuw c8—lØ£¿è.àIà ¥ƒ Ý²ì¯ ü`8i”Šý×±÷ͳ2ÿfÖeê¸ésýǬ£1Ö@#}í|/¨ql}øá$šyŽy\“h Ú…Ýž½oêÆþúÁû'T¿„§ë(XéiýUÛ‰®×o/~;ʶ ¿ xåðÚŒß.ürë­þóëdðƒ¥ô?_"¥ƒA½ ‘Òá’ª›Ç¼àM[EÚ\ÅÓu£u•õ÷êÄ<š®'­w/ìó? þÒá_ú€T8--ܵØ2šrç^Ò–*å¦í 5œËgš»žÞÜ·uáôÐi 6ýúéi¹t;sÛX¦­™¶ÓÝ{CÛ‚Iÿcé…Ùvlß~›÷ƒcï6ó^ÐL½åͼtŸÝ/ê}¿ýç¶sû~ñÊ›o{´^jâõR›¹ÖÙûuæ~z¾w?‘sß<>¸n }^M¼Nêâ ö=ž>@åígíÛß_¥Û·ßîý÷€¾_ô9ú¾ößé@5ÿþ'ýÞÖú°Û”ÙO¥ë%¸vûÍãºÇôßÛÁÀ»c»ðÚŒ¶dûÞn_סûË/ó>·ÛcßçÞ6Ûòëû>{_÷þ/ÅÌÜû Ýî|—àþ)]fóòÂëô¶è;*]¾ôü˜yUIï³½ÏOûõÖ¿è²¶Mf̤ÛVîg£.ÜN¿îüÏ ÝûÓŸAé}›ÝfÓ½\Ú)̽šÖMpr?CôýÒaž=8“óYd?›J3}ðÒ¯‘Îoõà—v¨°)Ìwí0a¯^' ý¾¤Û™þ…£ðÄ~ùè…òÎ×%í~"},}P-}@­ÅÌÏhËp3óRÂiÛÖ–§õï_‚û8öÛRösßßߥ?ï³óÓû6mëÙv•Þ¤~µ¿øí-øþJ/gæ˜÷¡ßýr…q[h»÷Ë«Ëkùr/j¦üÇt›³ûuã“ç»ÿ¸mË™Ï=Șnǹ¯Ñ›ûvçí÷ÒûÝ;zßu̾ ;­ŸåÞ~Ñ~Îê¾2ÝÙÀ_FËá»ùu¦{‚ô´úxue¬ìŸîC½éÌòÖ1]ÿ…|Æ%ýÏ.ö}é:ÐZȶ]ßLË~_Èn_z~ûNGÁ¬þó£v›Ý­;ÓÚ´µ¾´®Ì_¶Î¼mËÔ±.g[gfym³™ï?þwê¾ùEƒŸqZ® pß¡ÒmÞß_ä|6å|fù}qíJÛ£i‡íÚ¥~Ohÿ]5X×jæ·ñ´cÇ6ãûªw˜—Ü:iW‡:M—ß«C¯¼ÙºN¿Ÿõ¹a]ô³LëÔ:µóQÇt›ó ­Ÿç›Y>à­fa–-¬mì‹õ´«?mUê`·?=´ò˶=Ò÷­çj}¦ë¬/¶™u"Й{g2ÌG úá7N­Ô÷b-<úKÀÓÿ¬x¢÷Ot:p3ÿ¢yˆ?¨¤ÿ¹6¡„ Zúè?q™GÞ?Qé×iÿϽ_®vË{ÿÜûÿì§¿ìfƒ£`ðÏŒø“?´–ÿ‹ÿ°¶‘õT®@æýaƒ§l›M·Sï~ Ûè.2jÛ×£s‹Üà¹Ð°·r¥+gË4ÐJðïÙP¾Yy/˜ßaCùôýíÉ­òÎŽ·LP[—9HÖX3ÄL§ïר՚ƒg:_¸e¼é·ô5½õ÷kÁ.} °ãÁH;ß AýÞÁƒbú¸¶ål˜ µò‡6~€“7´1k íbÂ$- 6rne/$òïûÇlÀ©[¥›õø}Ÿúnyø['?Hœé¬æs×ü…uÑuÙÏjÝÿhîÝOÄÐý™ã”úxÒ1ó¼ƒiéåýÏßt˜m¿çg´t8äÛ¤½”˜º m´d>sýÏTÿ`CûÏÜÎÅ¥û?ÿ3;·ÒÛãmWÎvûßr¿ëXÿ€ú‡ø&¬ºÔõèw³L}šiÝVÿª­SÝ^o~ºŽuyï9Á¶`–Ñp0Œ§šé>À¯“Ì÷£ÀA¡à㙺2ëEË‘»¿Èí,<ØÞÕ>D×§m$ý>³S™i}÷¦Û¡üšû™}FfZŸ“nŸ¶lÁm·ïß%÷@Qö3:Ÿ£¶}…uñßéõúejÿ½Àê2é÷çc^Ö?È¥u¬‡œÂºh¹Ú¿†Þ×}ƒ¾n¶Í¥—ÉÙ¯xËùÏ×ý‰yrXE‹ôzlë°m$]‡Ù÷ ß®Ú[¥÷µímûbÏù9kÔ—úbÕ¬NÜ;¥á@jÐ\í?`Õ Àv#²@:° ·W\ÈEduÐPk`|¨ ¬Ú/%³A›é:¡½ç¹&@‡“œúz)­1Wö¸}-ÝqýúýQ„˜ß›#Äg&àT+léî— û—Ý¿"K æ³€  € € € € ÐÏÚQCôÊ2ñw‰e¬@Ñ@@@@@è¥{/y: € € € € €*@àN;@@@@@@ ÷Y € € € € €î´@@@@@B p‘U € € € € € @àN@@@@@@ ÷Y € € € € €î´@@@@@B p‘U € € € € € @àN@@@@@@ ÷Y € € € € €î´@@@@@B p‘U € € € € € @àN@@@@@@ ÷Y € € € € €î´@@@@@B p‘U € € € € € @àN@@@@@@ ÷ûrÛ¶m“Õ«W÷åK°n"-pçwÊ•W^é2R8úZଳΒ—^z©¯_†õ#Y3fˆ^¹ P­Ë—/ý,à‚@5 ð}¨škŸmW Èe—]U/ÐÔÔyƒšÈ—°l ˜”––¤ÔÔÔØkXÅN¥RÒÚÚÖêXe'°eËyã7Ê®Ü0V¬X!ÍÍÍa®’u!PV6l(«òRXÂhiiý,à‚@5 ð}¨škŸmW­[·Êš5kÀ@ êlj¼=Ü{YE-—È-W_$±X­466Jmm­ÄÆ+?˜õ ¬Körå<@@@@@ lÜ{QU[ž›%#ÆÊ®¹½ýZÏ•ï]r¦ìUû5Yý_9´/;÷@@@@@Š p/ŠÍ<)¹\¾}ô%Ùg*wÌ›/sfN— ™¹7ÊØ/Í2÷  € € € € €@Å ¸YµËÿøc¹ÕîØé²bÑ-òé3&ÊÇ/þ®,غH¦úÝ~¡ü‰nî¾· € € € € €@Å ¸UµåÞë2q»Ì¹ë*<ýìà£äê¹WdÖüó–f¦™@@@@@¨L÷bêuËryp±÷ı×ɇڥíéù#O8GÆz‹,|ðyÙRÌëð@@@@@² p/¢ªš^]* ½çM¸ðÙ5ß:†”ûó>!¯2»¯Á- € € € € P‘îETkmmöICfï§jFÈ“ýMÒæOr‹ € € € € P‘îETëæ2ÏÚm—™é®&}W‹ñ € € € € €@™ ¸QqƒGŸ,Wx´uÄ^E¬§ € € € € €Tš@M¥mP)¶'¹þi¹Ñ;iêsKÖŠqp·/[ì2‰DBîºë.‰Åbݾ†¿€>'çXŠïÁmy 8Žc7`Μ9å½!”^¤R)9æ˜czôYЋ—ã©DNÀÿ,¸á†"W6 „@)\×}ÔÕÕ•âåx ")À÷¡HV …*¡Ÿ%Äæ¥J&ÐÖÖóÄ´68ÖwÉJÚ³"pï™—]ºfÀÐ̳ÞjÚž™ÎØ‘™1XŠm wß}·,^ì¥û™õu=1bÄ0 °¡nº^"€ € € € €á ¬Y³Fô`R¡—!C†ÈèÑ£ ]¼ß–#pï%ýÜçVIRŽ’M¯È¼¹ÞÊ'Ÿ$cŠ{¡3Ï'r@¸[¶[w÷Ǽ&ßìnÈÙBÞ9 Ü­(æew´ûl˜±hsžíãûPf•©À3×Mh׿óÿ/<Ù}&ç`> Ê´Â)v^s¯êæ}0Ö»¢ÃüoœW“™å$°uÑŒnÚ~Çüçºg²ß¢öY@÷¨GJ.—o}I¶tc§ÊóæËœ™ÓÅ„‘ÞåFû¥ÙÒäßå2hZ·Dnºük²°€íX>ûÛrÉíÙ§\w‡ÌŸ7G¦O;Cn½p¬ÌZÂ;$«ÄT’+ï”C.¼1[´ WÈœùÉcóî+&gg/¼f²Lp]vŸY ¦Ê[À´åoŒ |ç‘É2cÎ<³O¿C®š26»ms¿ ß™½<{Ÿ÷@Ö‚©ÊH®”«¹°ÛíâûP·D,P6MòüSþceìØüW‘ݤ6¸M|5˜.säºåc“¯ÉlÅØ)×ÉüE‹eÑü;dJfîb™|Ùo$ø›'> 28L”³@m}·¥üg`—:Àf)ŠŸåt´£šÊºìŽ©Ù#;c§»+Ú[¿u‘;5Ðó}&ÝÜ8L–›@óêùîUS§º“Çv“‘Øà^ç´KÛÓ…\=7;üÀ„랉LÉ)=èêgCî».ûOèÔ9™löµW¾ŒLvkŸ`fc ~ØìΘàlšâ.Ê mñÌ—kÓ£ÅkóþϨùœè÷ª£¡ ,¾yrfŸ>gu¾oÙ«Ý«ü÷€V&}•÷@hÀŠ"'°v^à ”ßöÍmnàÎ÷¡ÈUê@ó"×ü°Ï~LŸ¿¶À5ñYP ‹•ƒÀæÇ2C«ŠLwWç)ó²;²qü¡4ø,ÈŬŠh^‚ÒtÂÉ5Íφ”éö ý°À–åòàbïuÇ^'ÝñLÔ#O8GüŸR,|ðùv?'ê‡ó’-P;üH™qÝ ™1Ã\o¾Y®»*0†F'k]õôS™G¦Oùt|‡Œ–s¦ûCËÌ•¾üÁ]æ©L ÐÿM/Ë= ½bL8IÆ4ä)RÃ9%ð¶°?£æs"³ÊUàw·zEŸ ûìÜqnN¡$›ü3‹ÚS…ñðE¸­4 dÊ™ßKoÕ”2÷fó»ÖN.|ê†Ùe)вv•ÌõJ¾Ïž# Û> sb©²ØòòÓ™¡U§Ì<_Fæ)õÁŸþ­477Ûëÿ;n˜]‚Ï‚Ç@†ïCŠwkÓƒúGÇöÈ:uøþáÿä˜o+\ͧò¬˜Ð¯þ#ÒzÑÛÛº/(Ð{H»[[õ¡^M÷(ú4ƒ>=úíWCÏóà\u;šÏ#n©nntƒ?:™¡®£[ã3çthÿ~?7#ï1wtmÏ6u1Ï)ã\5a,'¦/½¢Ç­¾%]Úš¤«àL=pÏÀ¤ÿêo´7P<;xå¦JìÓ—¼(y@µÖ$=¿ÑÅ`ä…œðéìËíZU\!×ëªÂTÌÙ¢þ+Sj¬^f×’ó„MÁH ”¬|JççÔ{. ©ñuwÃ,á #ïžZýdÈ'ŽÜñy[%Ÿ^nrØÏ)èòþX«czX*Šö …EÁ'D®‡, ÞsB L[»G4<|AFÆõ\MU\­J*«õƒá#Ñy~®asÀ¹ JÂX ˜Íu5Ö¨Ìî“¢P+·´j Ãº–ŽŸyË´@àÞ8‡öM?¯78&¬Ï ²X z1âÑïÆ’7q¿øë_Ù5\»v¹=Ι'0¡ƒÛâƒí-]ýWC’`ûìòsž˜-ÂtV lª.PAAªwžH~Íc*´vÓæ9«Å10' ²B ¾QÀá={´÷À^sƒ|ÅDâM]úÌC#ƒó¼<:V¸ÊŠL!oRÀï÷+øš{(ViéÜK9ÌmÃ’l(ÑÚêhëõP,=I±K>¹Â~à\ïÁTî yºdµG«ëܬò›¨Z& ¸ßÄKw’’ŸS•éÿÖ…$ñĉó¿Šü®iz¨þlè!zÖ*¼#Û%úÜfû‘çÔH’êš~ _²Z„¹´nEÌÿf'IÍ,î¦ÀàÁFm³>®¦‡Òþ‘)í~jü­¼8OÜÍ=FÞwT`êª~¹’îûùˆ"ÌKÈbêýèåƒM¹8ˆ˜‘­ÅŸÔWÜÍjnnVKKK«¹.ZqÖÓ˜´O.7m¹ÊÖ]N¹‚ .** ½ž=q91ApÎôEýÆjp¦ûµØô°Ä¹ 9s³S ¶ ±Ë¿OZ‰‰ßý¯€ 'à\Š™9 `žkö‚u“ìÐã5ÏY§Œ=2P`&p¬^ói ½êº.Ì*ã•@›3º¼Ó;9k9“d¯À¤·Óþì»:’Vdfø˜Fªx§â“]éi‹.wu8Bâ}˜Ê ™á@sä»Þü»R üfËÆyâf¥H—áæh±:’#·#zÝÓq:˜†c Ã÷,Å»C3ºìkšÎY<\Ý!d6s×b¯ÿåìŒ%)Ñé—},¨ÙcÎÁsA*fe©ÀÔ îqñ@§+z=dÅ8dé§Øó \é˜Ç‡¿÷mIÏ Ñ dæ¹@Ñ2–IqæCÖr¤?pel,062h‹ù’•³Ó|í2 ;±Ÿý¹îBïŠ;ZýÃWcæð¸£ãæØéH¼É/j’Ý3±&àîîè´µµÍùr»»Ñ˜b•à´œ'²û³Ï¥¿ÐU÷½ÝæŒOÍf¦Æç=ú˜`»ÔGYùü©ÉŸºÇ~ίi¸ÊŸOBŽ×4®‚ °ÔµN›kû©™™€yxvà˜;&Øn®yŽ\ˆ¶¶‰=F¸ÊñÏIÎWoÖwº£>Ðí “cÞ@G#æzɸb{ÌZÏɽ±MÃHÖ \én±?ïNwÿ 둉çî7Ümw+ÁL Çí´?`Vk÷øwGÀ3¹ë¼[Å$_î°@ìåÜw“镞€ù'ëyGKw¤õË.$›Cà LtÌûŽÿÎ~ÞÓö¿lpž¸C»ÍÜm`+÷¸ úÜßí]q?¢r Üí]Gþ©ˆ½.J ¸›ü¹JýN ‡´Œ¾¹k¢ºÎÓ³Êù`“Ù,0Ö0§ÞàþÀ8vÁ¾!×–sA6ïuÊžD 6êî‰þ¼”$idVæ èÃÝD32s(Tu«GÝmõɋ稓çÂ/µiYaòåÌE ¢\O¬Myµ<ÃÝ2-“umýrwMÒ§»']™ÜÿÌ­fZó %ηªGú (¬Ôî+:Òó°°YEu¸Ü:mžoðÔ겘%1Œæ@ÒË"®‡ò`ÏçG—¬kÔø…n5G[0«â.uõèPúYó9Ìa2›–lС©auÖÏq ¸ZtúÊ€¶TÍzFç‚lÞë”=A`ZWßy/2שµUKR$ÎȼsAAð§€Ä‚2'“ü¾Qy;¤±®›b-ÐÒåUrT•H̤DY_£C^ Œ)t„ܳTU8T^ÆQwq§uš8O¤œìR&àÒo½oiâú-X`¾Õ”iyÕ#ª* ´'fÏ1hœ|àz(ßöx.×wœ ÞºtM×gfôÁõë*«X¡Ï¬¬4 žà\0¿K³KÀ7zIç/]Ö¦Ž9 ´tÅJ­®\rƒJp.¸‹ó@ SÎÜóàÃF@@@@@R/@—2©7&@@@@@< àž;™*"€ € € € €¤^€€{êÉ@@@@@ ¸çÁN¦Š € € € € €© àžzcr@@@@@Èîy°“©" € € € € €@긧ޘ@@@@@ò@€€{ìdªˆ € € € € zî©7&@@@@@< àž;™*"€ € € € €¤^€€{êÉ@@@@@ ¸çÁN¦Š € € € € €© àžzcr@@@@@Èîy°“©" € € € € €@긧ޘ@@@@@ò@€€{ìdªˆ € € € € zî©7&@@@@@< àž;™*"€ € € € €¤^€€{êÉ@@@@@ ¸çÁN¦Š € € € € €© àžzcr@@@@@Èîy°“©" € € € € €@긧ޘ@@@@@ò@ 0êH@@ÈÿÄ^íySZ°à–ÊsýúuÝ÷ÈT]µDC½òüÏô‘þL5_ߢe‹niSY”دÁ“?Õ¯/ûôñÏþ¶¬+Ï¢²ST@@|(˜!_+O½@@H§€ïì>•®iº½,šìmÐÅ}ÕZÓÔg¶áÔéÉ^­+¹½ÍeüZ¾³ª.]£PMÛÔûÜêŒ/2D@@€.eø € € .¢…·ŸÓ{ÉoÖ.ZXÙF©Šnk™¿¦©œ]ÓœmÅŸù»"€ €Üš]ÊÜš©@@¸m’•Ok|ìK¡À¹½‘ÂEš|ãGzðÑ¡YNw~ÖüòOÃë±Ã"•™Éwbg1Ž € €%@À=£v…A@ÈmB•-Y’PÅ’%‹íy¥‹ïUY‰ ­ßDW13öZ¹9âËÍjQ+@@ K™Þ¹T @@ ;n/p~¿>¦ 9Ú®ÍÕ«TPP`^«T½¹AûOœÕt\Õ¯éÄþv=ÿüó:xjTþ‰³joجUÁu¶T\`ÛM½ÛÕ°y³ªW­Ò*ó nsßÑ^]‹ßh|C§´ogChpY ´ªz³vî;ªÁѸâÖó]>¥ög·šõªU]m^&¯ö£g41S¤ûãRÆL˜2ž<ø¼6¯ Ö9úÚüì>§1›`@@TðÐÔT¨²M@@nAÀ7¸_¥Ží¡5\:Þ8÷B÷o•cûánÝÙÖo4º!œÎwÆ<€t}è¤r8åðöÉkmÁ<ŒuÜ<Œ5Ø]ô”¶UlÔÜ[w©{ø'ª©ŒïTý̾­Zß4÷ZÁ¬ÜÝ#j­Yfåz¿Üۮ呮tâÌšˆ3™8£­÷­Ÿ§ŒRGÿˆ7Äç5k“L"€ € Z¸§„•"€ € >g½[]G:ÕìŠæÙ·ã[:9龨È~©‚ÁvG4J#ãÓƒ³‚í.µu“çH‡¢›õ¨öÁoêlLƒuÿ¥£qÁvWK§ºûûÕ}¬SõÎh>»j¿­Á˜Æç¾ÁƒñÁvGÚ:;åŽ])ººUHøçh°ÝájÑOzºÉ]­TÓÆ&‰)cÂf˜ € €@ŠèÃ=E°l@@Ô 8uìÂÏ´¥*Ø>Ý O|]Î_”kOŸ™ðêõ¡1Õ”—‡Y‚ai¯·NÝþ]5UÑþäÏìkµ[;šèß{BK"w ›¾âÒ¾-ËÕä nå°ÜGŸÓñ†•¡MŸê½ÿ´x†µ{Sedzƒj¶<¡/4|^O¶§÷éÃ`ß9¡Æñ>mÝI'9[<òìÞé¶¾AO×íWÅÆp‹;Qpdú¼ŽˆÌq´é—ÇŸ µÌΩ®Ù¢ÇÖZ-í=:sqBëVG\"«ð† € €@ªhážja¶ € €@Šêü8lå±H}íkvn}o^µÇ­¯ò\éŠ ¶Ë?¤ÿÜЦ›dõz)&ØZ¯p™¶[º{^ê3½Ç‡‡W®5[ õúêcV°=¼,øä×Õmy^™í¿Ü§ZÙ™ÀùKv°=œ |Cƒ¼ÑvõÖÖdövÃuïõNL‹ù`šu_ý–Ü--jiqë¡ÅÅöjŒ € € .Z¸§Kš|@@¸£NÕÕÎpK33Ù¹”Úc1#õ­z¬<þ6`zø¬¬†ãr­V©ß§ _¤;šÈªÅ…ŸÐgÌx(NÞ׫·|ZW"-ÙШsÆp*¿_¾‰ ù&ßÓÕ«×4vé µo;“yxtâCvòõ­_V´}4éÊ/5ʹÝîwÞš]¼8æAª{å(>§–Îo¨ösëôÈòe*[²N­»×Y©yG@@ íñWÚiÏž @@@àöJuÏm\Í»V:Ü«KL¦3þ_tʳ]ÅIºs‰¦Y­Õƒ¾K§ô£öÓŽV³õY‰gM¾ýÆI{ÎêO/µÇãFJîö;o-(¬ÔÎn·ÔîŠÌéÓžíæ™r8ëõô3uúêßnÐ’P×5ÖŠ¼#€ € º”I3¹ € € ;RŠ?õˆÝ]Lü’¹¦&ƒ½»„†ÑÞv•>¸1i°ÝYWén&~;8¿aÏÿh&¾%}|ÊÄ©e5­îW[ìb#ɼ}ÔôøF--Þ¬Þk·¶ÝÄœ˜ƒ € €À­ p¿u3Ö@@@ §¦Þ~3ÜUŒ©•«­_“S“OxMNMi*ôzUkLw2ò_Ò¿<ºÃ¶p6w¨ß;¬±ñIMÍÔ{è^9Ro/·F~ß÷S»Kk^²w»¿öY Ë*7蹎+`Êyex@ž#jvEûŠv|óè·_!÷YpL"€ €¤\à6þ 5åe"@@H£@Ñâr;7ÏàÛ*Z´A% ]²øtrß÷ôúû&éâµú§Æiì¢.ZkÖuÉóÂSæ1©ñÃè;v {ÁëªÍx¸û™ã?S«7ØË¬‘‰×aÿ`ÍóžÒž»5¥{Uû­Іò•W®Ö¦àë‰F¹/ëAW¸ß÷‹ =`µÌZ™w@@Ò @ ÷4 “ € €™,°¨r­š­~R¯ M[SöûÄ™.Õ6íÒ®]æõúxx~É ý}½34î|¨2!Øî=©ïìè‹lÄâ#¿—|ê!»K™¾]ßQï¨MddT?þN´å¼µtêêÚµgöìÙ¡W¼cÖlû½Ä´|¯±ºGk'`@@ pO10›G@@ ó–©!¦ë—'þ¢ž¹¤iÓ'‹ßïÓÙíºo}“]ŽgkC^-ôê‡Âõ`àüà©KòMOkÚwMgNìÓcµáÖæ¡5ëõó×Bc…å­çퟭتƒ£¡.`¦¯ jßÖ Ùqz;W©ä“Ñ@ýÞÚZíë’õÓÀ´ï²^~~›vxÃ+8Ö?"Z·Çà1Š € îia&@@î®À\ý¡[¥ªzâ_ÕYgMõiÛúU\T ¢¢R­qE[›;Ý=zfu$”]¶V­vífª´¸XÅ¥KµÞÕlowûš¥ÚztÈLjÓ®Ù«ê°\Ž ¨x©CM‡­rÌz/¯Ñ‹îp‹z™^à›}XÅ«´j•Y¯t¹ßî¦Frê…gƒÝÖ0 € € ^îéõ&7@@æX8ÿbÙËg÷–žd=;m‘î,.Yé×%!ù5šTOG4 >;IË‘½ÖZmÂåÖ°H[~0¢Îz»kAè½¾£GãSÃrÇ,ö¾ó~8MÙjíŸôÊíŠ[%2áTç±#²7k×CÚÐú3uÇ•Ñ+o¤U{heg³z†=ª^’l»ÌC@@ µ3¤6 ¶Ž € €Ù$àŸ•÷Í!}p] Ü£{ËËõÀòJ•%q½G!BÉüº»¹¿>ñ–ˆ7w®XŒ)Ãènæé8’§ŠPñÆL%¸ÿß~€å©ña)µ:†ßýù\{íµAÃ]úðCàú[pûgç!uJ¨´‚³Ôôàô‘•Và‚*ÔÇĶ,‡–R8¿ âŒŽ‹îfùõ |(ê$D­àÃvѧRfc᳑xÕÛ¨5G~·ÚO.úÒ¦DÖ3ûT™îFþõ« —.]‹ÏüýR¤„jŽ}J˜Ch©«Ä+oŠJºÐÝ\‡ªoâÒ–1ßá=œÞþ¥Ò%ènAåÿ¼µwZÇV¢N*ŘKx„¸¥{‹uIüóÍÓ‘rëLLIŒ’¾:úàÏὋÀ§ø æ_‰ûÀ VJßÇ‚¨ÜïÄ÷ELúôHŸ?°ñî õêeÕ-Æ:ÿ#Æ:ª×_Xšt\ïi;…C¿ù3®½B×ߌ%Ë"1˜ÔÆ8A„»t=îüÂRôÞ ©Ç‚¡ä5 ¡O`Œ"Ž¡/&%$ áI »¹ë§-Áž^Ä·eæãùüuH‰Ò3U/ÙY½Ý5Xœ°Uâª-¯'7ηú÷é¬s&b½KM,í'×pû§J†×ë cîzUb;ª;+1ßgÔó¸[Ðp®S\ÅÔ)ˆ¿êFNkA=-G0wê2¨xô#¿¶ëÒ‚>–ø‚¸Ó©)̯=»Ïäf:C°<8²y.–í¤²‹º«Të.œ_!†•—m x¯G´š„©H ùÂÂZ(w]æ®·^ yfGií¬L»Š/Ö¤úÏ«nÇÆùáÚ\È‚„õhÜÿf¬*1Âd–5 (=Å8§#4þé.Y7Xuaèœß'”¾|I†JŽýÓ9ᥑ¦Ôï~/}­ä{„…½T'Ö¡Ïì™…(ÎÏBòLj²Lybì±1ìØ#´'Üä€,¶çc÷þ¶¤§Z¼=Í8ZqB¼Aÿ$.½ÝŠiŸ]$&\„j Ý8¼a>»](¬íDVZäoÂ=͇;ÍáË;ô}¦q–¸ÿ›O;Îs=Xd6LÛ±m˜|÷V_z98§lG¯¯=¤z³ô%1FíÏøÍ’'$@$p 1SÄ,)“& Á&Ð} _ÆvÓü$ÌٰϨ÷Å,£{ ëkÏzÌ83N9³"3PG³,±Â8íKoz\ìSŽAÂt‘„j»4N{ ècŠ“„±Ü8ú(›«8Ãgˆ· CüIÃo¤w• ¿ý…QçâìöéHˆíýVl0@þªÝk1cw9*š~ŠÅ!žÎ-Œ= ø…dl·Ùí˜>ç&­îÂùE ˰âvá¡sûþÂ)v\ŠW…Us'ãÝêV¬›•ŒîR_p7Zò6ü>!õ©Ä>!*zpæÐnˆW#?ìóðMap÷¾òîjÑ=%ÞñG¸ì·[¤GvbƲMÒÍ™]\'WÏ{wŸþ©×Ø.fÕà>ÛÕTc’?‹\°Õ;'£ jrcþlƒ}7jÊMc»¯ê•f,òÂýÍßתÞÞÞ»¬wc»Ø÷kÑcè=¿è<% A%0[ö  ÊÌH€H`¸¨Ù³Å4¶ÛsP[²Õ²ŒÃ–ÜGåÓßÂ’õ¾AjÕZç¿ñˆ÷Ëí|$ýßÝølò•Ó(WÕ³8Öü8–ÈBd¤6¢¦Qzhê® °  r¨4Céý€xáª_“5931ÑÓ%æêZOçÛøÝxp“ïEfÕ&™Ö— Á8~‚a`w,Y`¸½‚†óó•dØÿÄIŸKµ}*WÜubF™øg«ââ⟸»ÊËQ©/#TU‰7Üë†Ü—}*kˆÀ'öÿg~ât‰¶™Ä—dC]wɲÒ=@ÑÐ9þ"„L3„Þ÷Ïó«C a&Æ‹{…õޮɒ˜ˆôûPþþ9±ä›fì¬zí­(ÜÍûÕÕ)üÀs½úcÁ8¬,:‰•?¯KÄä롾B×Üux$a®oŽ%ã,w[«/Š{ŽŠ`làÆÏ·¬ÕâØ²QýÒÌO&í§ÿ ;™…Mâ±cǦxbéFðÞvì¬UGÄ„Š5ý\J.uÑR‘€ÖK*Ná™Õ³--ÖýúqoùÔWÞW ªcÏop&?³…xÆá> ±}ïpàŽÛ#}yB…Ô{zü% «K`ìÕÍž¹“ ÀH%ϬÈÐ g_!6¦ ]NÛR}mDÀyâ4ºý‚v‹ Bwf­À˜1cŒ¿9‹ÁÎýÇÐáÖ{êi³ %6£Ç™3+²6cå)±=iߎ¶ÓÇP°9 ‹Eº s¯Àæ‚ý8Õ&µ©ñ脉¸†BžY;q¬Ñ?žº‘UŠŠ pðXs¯vœ®a‹PPt͘z^°s'¾¿«ÄWúvìĶm{ñç·êP´m'vnÛ†¢#ÁÓö4c¯ðß)ÒPã4úWBðXð´‰´7à§ÉTt¸Nê_œ:¼Û6ß,ùODí¤2D;Ñ3ëËï”ùxLL yô¹¿¶ápÚNE?j%UÛà6­šŒŠP'7À™ë‚—ÐÛDûWË¿­àˆÄIæ×#6Þª?EçÀU_&LÒçzÑGÃDU7L®ñ¶S¿3lPõDP ‡>ëDQµ=<²XÎc ?²‡ëZ¥ú`¿à êŒý5AüEŒæcûEˆ0E•«¾×M8Ý© , ÷³Ÿˆò«}Hû{dsNùð6ׯfqÑý¼ý÷`T.-‡ÆÊƒ^½÷ èGbCÈÛ¥û‚¸Çl(@MŸõ™µý\„öµQ7ÇZÐ-ÚÐÁºìê½±èÈiM`±ÙŸ*㠣܋ñˆÐ!eì£.Ó_ ù}·7=¨÷­í¥o}£ïe–r|ìÝ&ô½µªí¦oúJO³o²›m'šºS—¥Ÿ¿½Ç[ôðCF Ã´Ôh:h[ÁáàcAÑþ÷{Ç4;QD™$ĺÑX©Þ'ͱݘ9+¼cKùN¬Ýc¢5†êÀ‘"õ>#îaBnÿ;yc¥¸'ûÆkºWÄ÷>ï=Jè]UƾŒýÄ'ÄÂÝr ÛTÝgŒ•Õ1†¸¼HìœÆv5„j€wcÿ㺱ȯ~‹¥uÍß;ã[^Å6H5È…XÜ2W{fÈÉû¦flWC‰IÿoŽoìçzoØ‚Â'6yÓ)ýÿ¿búƒ$öRÒíwˆ“|GÉïÐä7 }ý¥J¯§KÜù33…|^«û¼rÆÄëïn:!¾¿ôöŸ=Qs÷>.ô×c½é==ñÛG½îu]%ÉC' Àè" nšÊƒH€H Ú:±œ¸"î(Þ¿üêÖ0t) õ.¥^ü¹êÏ)=RȆò<# =-ëoŽÒÐ%Eh=ª3ø8ö<¥IΤ«Öˆãȯ•S”êüŒði‰¼rË›¤8¢ÜŽ^ò÷É—SVoÆë¬VÄ`Þ›—ØÈʼB¶Ú|»O.»RÝ)ä̳…Ó®Tþ¾Ðô³å)Áj¢½:ß ã(Ud¤¦0VWS…'(s»RV/„GgmèzXZ8³2›¬„°^hRr$yòk5”ÆíJ¾-D]Ùv(;Búå+º=çzko¥ÜÒ@Ŭ;(v‡µÞ̲õ(G ÷={n¹¥žÌtíJf†5]¹ÏØr+´>&ñýU·Ø”ËŠ4ÈY§ËlWþýƼý¨Ñ¶L¥^î{ý鯒ܶÌLE¶Í¶kqÛ•ŠsRfR_29k’ú÷ó°úÊR:ïIëQ³}ÛsUvíŠXóÕ«ÐåkƒþQ»”<»οÔógƒ%VŸubO“’ß‹N²ç8‹„µŠ0xå·m J¾.·Ýìr‹´nÂé.U·…?dÝàPô®®Æ1ûC8¾%77t?³‹¾baô…¥ÝAË^™Ñ„Ëeôe«ŒŠè‰}íç2ã`íE¿æÈÉU2¤6¨_×~Eßh•ú†q`º,º:Ç¿?Ze×êÓ¸ïJúÀ?œWIþ–{«ZCýèf»Š°Ìj>êÑ^mŒ3üåÔÏóZÛ1Äÿý]n;‘öϹGt9ä=BÒŰZuO”;kͱ†]£Õæ;|:VùG•ãé:_–Içô×–£ø†/Š%΀ÇP­JžÑ/mJ¹e@&tŒ®WU’í´Œ‡•Ö ó~çó“ÛcocA¯>•Ùûé-+‡rÔ"›?ÝÈΛœÙÆ}О{Ô/R—R–é«8Š­eõ ižŠ8ÙZœœòsæeáê¬ÖïÃï¸Xõl*Óò·e—G˜¾%Ié¤ÕR7e–qT§¢}Ô78zò‰µõ ²ŸY!Æ…þzL:·Ö›uüÖ½u]%Q¤“H`ôÀè+2KL$@ƒA@6„hÈŽì<¥¼º^iíŒÄœ«iMƒž: ´9r”b§S)Í7ðêuÓ ¤ÞeãŠCÉ/+WŽV”+…¹™Æ Wã(t™¤yÜÓPj“S¨”=ª”—*™òC2—Q¤Àr«ùeæ*ej<ãAK“³X¢ !ƒ⺿§ÕU¦äää(vÓК‘£dgç+õ]ç$ãŸMqZÞ6hÊsÌx¹¤_¹f èrùPJ^q™â,Í7Œ•jÝ‹ï˜-†@­îLÞZ­=èe“ʼíUô2ÑöóstƒÞQh¾œ1Û„æ§Æ³gä(…Å…J¶ŸÁÕÛ„±7_ÔIŽ(¿a´ö•?ßÏÈHXôÏ^ î=J{Sµ’+õ[žüÀ=ðþj²³+9¹¹¢,Ö~ù![ª³h™ÊQËK5›RêÒ_§+u°k]J©ôr±´^Sr}ØrdížF»Rh©›’“_¬8ÅJ¶ÄLl5ííCj¬¾ëDÑw$ÙÄFÅJ^i¹R[[­”æYY™zTd$±’u¢.¹Ä|±(̤x‘ÖMxÝeæÜ%É«1[æ¯Ë’‘“§æYïºDüܼ<ÑW¬}³¬IWîr^zÓꬴ8?À¸-dLYüd”Œ/ªê=²·~.×!»-CÉ+ ì线#;WÉËÍ6û¹ª—2%cÞ€t™ÎBû¨Îéó}·7=&µIk[î_ß0ëÒ,wØ2{n—"–)7î™êX¦ÔY¡T”—)¹–—£¦¡0x{ׯöOö mGè—^u§žmCÞ#¤:0´†Xõ¤q?²˜uaíWº˜rþºÎ—¯éýöL¥°´,`œˆ }òAtÇP¦ÜbÂF…d4FTýE§&[Ž"¿‚i­È5Ú>N3ÓÒôªOeöÞñ‰Ú.íJna©[çé«ùÛrÊu”ýû/™Ìòd+ Öw|"ÍNó(ÆeÅâ%¡Ã¡ØívñçP2sò•£õþV©/‰—"µú‹CUè÷:[®â¥ÚS¯dz˨¾`ì_äXÕyæøKn‡Jk¹¡[m9êçœ9éC¼6³¶Ž ¥7ÄZ=Zï=zûô¶]©Þ¼z¬7½§ Þ/½.ñUÛÀ€u•Ln ÑH€÷ÑXë,3 À èj(³ ÞõÁ£w /ÓÙ¹ùг¢Zih ö¸%²$£“#ß:ã¶KÌ Ñg„b–»:——b n™€"¼;ëMºåÁÛ ë£S/Cüg™ª ¥úÌa¨1gbúelÙJµþ@àM·U)6â‰Ì2m–rädYfÿ‡,ŸÈŠ)³x =ܘá¡d»ôàÚ¯ñP¢>xeJ/¬ÁÌ3é!I ÈùGýf³Ì¨µKFÖPò™isY™êÎÁBê×j Í#ƒ[(Æ=¦áÜò"FM,ŒŸüðeË.U,Õì7ûPNW® µ/dä—[㊇T³mÛ”Âjé\ˆÔT¡ÏâRëKó}ö@kº6¥Ø2K»U)” ;–™aaʨó ö`¸ÉbÓ3óÏû «Êèû†óÁS¤…þêM;Óšn{µô¢NðV Õ¿öÕƒ0¶KЪ1ºT¬À¡®‰Y‡F}I³{šdýدäÙ—j=Zßs‰‡Þý+ñÒÈ©š]ú®­z5I)ˆÏ5gŽÊ†}™•Ñ,å—úd8ƒ{¤u#Ò¸n°ݬýÁay±×.^/™Dû´å”_­¨/a*rMö¦¾‘ÊìmÓ™Šõc›Nc楷]J³SMY$ûÙÏåºQó±çÊ_'´K÷%µß‰¯Œ¤H=çÊͶ*Õ[ttYttŽÙ¿î}ß (”“ú½Ü–ûÛ7̺TùFXfIáÿJOžÑo¶7K‡³œôWvÿ¶ƒ>ôO‹žÈ÷™½U1FjhRüþê•êòb¿É â )ýý—Á¬ ©_I²Éùë\åkjÿÉ.®¶Œ_Úk­“ J}I3¯¡ºêÍ<Ô/ÎôÃzOÐÚ—Ïp‡rôô¦dnZn-áãgb‰þІ³x7ˆÍJ–Ï7 ']D!•ÐIt7ÔINiHð¸ÑÑÑaùëÆM¸MO¢ªo˜Øô«ØôØ"í9„!¸\ý,[0Il¼kM·Ã-R¶)£²æ¬_|íT¿k€ü*!!Àw`ÄgÇK× °PúËÏýÝhb±¸{Ú|jÇÀû«=ÿkHµÚEÒrIƒ÷¯5³&cÁz§QèÜj'Òûal÷nB˜§×— «îŸm¤ Ñ3–U7f[ÅFk¦­—ŒöàÀýwÑpSîƒØÛõâ%Æó݆¾ëD9L0þ]Û±eË.T*¨È7•©kë”Æ­©Ë· §½Î2”––¢´¬®s(ÊÒ^ T>õï‹ðÌÒCšjØV7ÐÝüÆÄŽÇøñâ/vŒØäº§û°.U˜ßø[±ÌÒT¡^­7O^Ð_,8–/B’n_d¼4xá×Úë€sÿû²‘xÆŠ¹!ë0p\hD‹ØÑo½U]±¸ H$0‚ ÜfFpYY4 ¸j“gc©ú·2 Û‹ŠÑÑvoœzÎâ<ì(Ñç¦kçæâžž]¸ðJ¹!ëm·Þb¸eG\R fØ<Ü8¶ÿÇøaÞ&8Ídåh}r»áÇ;ˆM{Lã\Ä $Œ ú0quêÕà® xo‹î´‰§ÚÏ€‰¸çq1§ªj·7ß²ª,_-Œ²bÌ}Ör°Ôûd>‹&©nÒfûtô¸±˜8]/c´ hz¡Ï¿QkxÆ'„zÜ4‚ôÙÑsá]3Žs-¦Ž_kž‡pJ‘Ô©~–>‹1X% Ãý9óêO*‘Ç™¾ìad‰—\ÁŽí?8ŽYØä©è²ïBWQº˜Ã­ë¯ Q2ÍV½ø2ræ/ Ñ_ƒ•J»Ö}úl2ôŒ(Û=‹…¡æ=ÍsÒ$¸Ä¬ãØó4Nü{:&Š+ÝMÂPàó±ß‰[ü›×+)©&ÓS¿ì£Nì>eæáHÃÔ#Þ˜„I^ã’Q Cà9¢U7“B€ëB”Ý›v§d¡’YЗS°2=D}êñ’E̸ôêöv¡Ûãƒe.MûßÏâÂ÷ô‹=^S]Ri—ÔØÑÑeÑÕñºï†,­ä!÷¿ôðô¥übR°¹<{–mõ]¬Âñ ßߙ͞‰ÇÏÀÃ_Xˆ¤ íJJ+J²FÿŒ…ÏZ-‰à´ç¢ö™•¸¡§GzU‹ØØ¼{¦?†ÛÝ>5ºÕñ-Üßui½1 Ȥobnžnèijͭ¾ÈÑC©cÀ¹ˆÐ^Cmþ(¾î\œxå¾{‚ý‹+ñ¹‰Ubv¿øjl÷Q´îZ ü±Ú˜ÅíøÜ´¾(Dè„É×…ðØeOó‹xP-&žÿ5ãÓÍäÉñ‘•ÀÓŒ‹p÷ª Æv›˜åè[n&²ÄÄ„¢ÊH˜qwPc»=#øL}KÚ–3ë‰a㙄ëc-OÖpQc΀>òêY¸\¾ÙÞ6Ì»]L&™·À'ì pµ ÎÕúüöÌKŽÒCWù²ŠÒÏïŸ3MÛ9ååºü2ˆKD²¨ûÔÙþÆv=\ þþ s)¼wÞ½ {„ùíÆÏ¶k},·â ï@•O>dÛ3óh8'^xçøÒ(Á‚Ü#ÚWaRÕ½¦Ý¹Dw¢öõ×qªæwƹՈ.Œó ã¼÷¨ÆùÓøãIíźœÓ‚¡êP´o³ùi÷Õ1½5]ÕW¡žH`D Á}DV+ E$pµ œ9ðÌ‹¹ æâ¹×Ädù’ÒV#/G ­N¼z¶çªË|@(£®ÇÝ!–ŒiÞ¥m÷Í¢UÓ±#¿ì¨X·¢³« ÊÉJìÛwÀ0«!žF|wÉ&#ˆ=;G] hmïDW‚Ê}ûð|i/†Q1Ã=Ôqáý¡17†w‡ŠÜßë‰óðOúø_,+óªxòú ‡ŒÔþéKs w8GÓ±RiižP¥¼~Ä7-M$…ç‡p"YýZjð´‘uæ…Z(Ó«Og]o½f´OGÞQÑÆ:ÑÞÞð§¶½.ï߯07¢÷F8þœ>5ÌŠsíè ’n{§h‡¾´kÖÍí“ìW%püTÓà.¦ «­&ªýµÏ…ÊDmgêKõ¬_kì5Qrby‰wÚ†œ|±œN~>òå?±ÄŽl`ÛóôKÚZþ±±æö¿CðU›=âK U¿µ‰e'ºû®å<‚NÓÖJémYï.aìòV$ÝgqÜ|§eõ g¶”ßV\¸‰n:ýüÊé²~4„hÜw#ÉöJö0ù'¦,ÄÆ]‡ ˆûʆZ8Kó‘íÐÇ>jD'–|ûWáWIö`År»Š1KçÍ]€ŒÆõ÷þª­®Æ ù¥YoJ'&_17Ã@g/_mÈr68.Ÿ¸Ç…šìÐõ7ßúÜâû˜Lƒ;¢4†ò ¢Î€Öì¨rVýî÷>ùÒa³­“æÞí»gºpâwUxùÍXkË]ÑĈ€ÂÖq_ÜcÜ3¾hJ˜œ=ðxÔ¿ÐAbcC£ƒÅrŸú/¬R‡Pö|¬]¬æÝ3U;G^5ŠÖ-GÊ”d,^½ ¥ÙZ»s½·`É×âÅþú¨ÁYþSüägÕ>¿l,ô3¢Ïü¼nœ/SŠžƒ1$μÓB œæ¨^Š®X›H`„ Á}„T$‹A$0´|üŽU†@U¿ÓpwxpÉ;åUóMASçÞe}öÅW ·ìxiëDLž ÝDŒo}OæŠtÅßoÏIÇHgh9ל„[nö·²zPùÔ¯õ!Ê/mõTlúùo×*û­)溌¾ ž–#øŽ¶(µ8èÃÄcGîk|1ÌŸÆÃEÆç­¶œ5Wh=ÒüÍÌÒp%ݹB3þ‰'„ÝkWA_¾=#Ôæ§FLÓ1~R²oæ•XŸrÓ bÈ«Ûÿ”1Üžlc.3½¾º&„x€ìnÁÞ ‹`îekƒ3ûú¼.w$òÄ¥Ì3?s/Y…çONê¨)Ʋõ[±u«ø;ÑI²"LæÝ¿Ø»æûÏKmê—;ð_ÿ² [wˆtÅßùž –=h_-Æ…È#Ç'„~v7WâŸZe$f³ß.6P‹r5RÔ!Œ^Þ#Ù®B#RÕ¦»±7¢]Ôºñ›b}=f /ãóFŽ˜YxPß O¼ úÉÕrÛæúvÅZé{ņþšS®ûSoé‡NäÛ¼¦‘Ÿ?ܨ‹à®Á.Ã@lǦhâ ãƒnOv–¿¢ÍÊ7 æÁáÜ'L]j\–#¸îŠVêÑIljÅ<›…nß¡gàX‚Ð×\å~®Ë(~¯œ.“2 ç”uNTî»"39Í y oM/üÅ®ó¯ ]½;vlÂó®Ö€ÀñbæûR½«öºXÓàÊ lˆ κ?û½TvãÏÆ˜,ô—Š!’ y9ø¬ôœxÝ:ñ4›º‡ÿ §dmnàøE|eQ´E\Ú°öYY¢1†Òœ¹p™î4~ï¿'Õçž‚Eéú=B÷ÎÀ=·‰éï}:SŸzP[~Ð.÷‹s#íÀcþƒ|‘Œçkö"BMôÞÏÍ0Òæh«| ëUãzF)Õ÷#ò»|½ð'K´·ÿòžï|:noñ s‡´eªÝ÷ÄçÊùûÏ–5fîÏÛ êM÷ÞyÉaÒ€—¤÷ú«×£««PF%1hp1UÉ‚ %q©_„SZqeí܉È*8ˆºÆtˆ™æê2 -u8X°ãg8LãMfnSmåI‹ñí\ý T|f=9 GN·y??m9}Y‹î6 ºùêÚ㉘·ÂáC X¹{ÑØáFww7ÚkPuŸØDÉ|ør¯Eá½0ÆÓ‚§÷hÓbª¶~{5Â-Òêv·¡æp̔YÖO¼$5›0øŠ— Y‡Ñè]¢u7c†Ã0É`ÓcwyFÛñü¯kÐ"Öþ´q³°J]¾Çò`Çš{õ‡½T{6¨Úz7VlÞ‹ºÓ§ppç#°ùŒù¶œêWÍá N›ÿy?o;î™kÖ›éƒÏþãýæ©×¥®Á߇Ìüb; ®÷ú§×£««‚IËk$@£Ž€ÂƒH€HàÊèr)Â.«ˆK„ÙŠ«S¥«^Ûõ7GièÑât5”õÖ?­L¥¾KÄíªUÄpÜב_ë K)Ëôþ<£´^ÄíT áÃé<2 õ¼BÉúº«0ÃWV‡R+1s:üµŒÒÑY[h “Qªø‘B‡pvÖ*âQÉšŽÍ¦ˆÇB˵ìR—%Pr[œDÎÔ`›Tñ5 3µ õ,¼ÅõŒ€ú÷E ç§´*…ÖòêùË¿öÜ ‹,‘0h¯ö«#?®Zúv¥âœYÊÞÒít™iší\+¿Þþu¹í…Öz3!š.9==^øß ¥¼ÉliÑí¯¦\j,6ú Ô?¤úϯm—#ˆ(¦PËàû¦5¤÷ÌU¬÷?(6Q¿½BêmLM¿Ð§èÊr,ý%¿ì²3ù>êD5¢«83 ñ.ÐîñŽæÚýÂøÇçj:öBAÜwHŒ-mL÷U7Â?Ýe$c8dÝ Õµ7=½Ž¬×½Q¥~m‘ß—®Ü¶ÍrÈí* ¹f–Ytj¨¾ÙŸ~ü~eõrC hç!ù_]œ£Uj'z›×tNï»aÒ”ò2ëRãÕŸ¾aò Ò®D²¡ÊØŸÄý2  ÞªÉÖÛÿý‘]æîÏBËOnãÁËç/W`¹ûF€>•õ­¬?ü÷·×曺ÈQ(î¼¾£µB“—M¿0n½/Èõ£·½à¿JµßmBÏ6*c(_bâe¯)¿-W9§g¢þ¶µ”/S¾øÂ…j!õi˜þ %Ù÷6àEQäúð/‹Hv´*b¾ŒYþõ—².ôÔʲ½éØrÊõKæoOƒ"æï„È'ðÞgF áê©WÄêïfzö|³MúGi-·Œ‹mÙå–ñ Ëßbµ¥û–yQ=û¨Õ(³W¡¡<ߢEW5{v1šºüt¯ð]¸åç(³´ò+jQž'üÔtäô1#¸^Ú…Ht—UrúÖèÝ>O£yZó‘¢jN‹ü¾’®•üìªn&— ‡zoè,J·èÔP}¾_ý<=æ“Ë@DNïRhÆõþé²P÷!#YÙ! Rçôÿ¾Z…n“ýêF9ziWjÙ°Z*·Ü+ÄýRê‡c” ±–ûâp“‚%žý’½mÇÚ>¤Œýœªž(Ï >ÎQƒªýá§–±Ž¸áƯzVã'ܤ;ÅêXkñßuÚ¹øêçç®Rs–½ ¶ÌBÔÖ: ?½*äM8sĦÖþã%oâþêj߇ù!&åGe å“uî2óë'{ú"mýv½bcUãÃMq—øÇ;“uóW/˜Ÿþ ­OC÷3QÝA׃Šßî÷Î_~Úɒ_pgÖjGy]ªÆÑîOE!ë›®XíëªË‰/辩àõÑþ‹IÁ–“­"Ÿé>hCf^ι÷I1ƒ;ÅR1v©á8VÜ¥­,tÒ\‡óˆb‘0i’#d‰åKN¿Ž¿´‰ñ™Ðq×MIAš¨‹ðGtÇPáóˆïPÖ§~åíøô™7Ðöþ%ôôüMô‹DÌœ=)4 OÛ)¼ôû³¸öcs°8-ÈK ¿¬Fâioz¯?z=êºj$‚g™H€z%@ƒ{¯ˆ€H€H`$p× Á·¾¸ø¬‡Ö¥¤â±,$@$pHw±wB{eV/km_˜$ ÀU'À1ÔU¯ @$@$0LôgÊ0)Å$  €˜ÅÕø&Œ?í™ë}íø—Ghl× ñ—H€"%ÀˆHI1 ŒC„ZdH€H€—Ç˃˛¹‘ \ݧþ Ólk-9Û󾋅Ñ_™Ä’OH€H`ÄèmÝ÷W`ˆF7Ž¡Fwý³ô$@$@ý#ÀMSûDZH€]'Áý@IDATH€†žž‹ViyxFl,ʃH€H 2g}áÎ^„'²( E$0p 5*‘E  t\Ã}Б3C  A'àÝêm±ñ¡ØlÂ$±A[rØ ]>fH$@Cœ€»­n¡B)IWtçë!N‚â‘À(#À1Ô(«p—H€H hpE¦A$@$@$@$@$@$@$@$@$@$0ê pI™Q߀H€H€H€H€H€H€H€H€H€H hpE¦A$@$@$@$@$@$@$@$@$@$0ê Ðà>ê› Dƒ îÑ È4H€H€H€H€H€H€H€H€H€H€F=ÜG}           h Á=™ À¨'@ƒû¨o@$@$@$@$@$@$@$@$@$@$ 4¸Gƒ"Ó          õhpõM€H€H€H€H€H€H€H€H€H€H€¢A€÷hPd$@$@$@$@$@$@$@$@$@$@£ž   @4Ðà ŠLƒH€H€H€H€H€H€H€H€H€H`Ô Á}Ô7          ˆÜ£A‘i Œz4¸ú&@$@$@$@$@$@$@$@$@$@$@Ñ @ƒ{4(2           QO€÷Q߀H€H€H€H€H€H€H€H€H€H hpE¦A$@$@$@$@$@$@$@$@$@$0ê ÄŒz}àéî†Ç>&.„×x J$@$@$@$@$@$@$@$@$@#œmƽV°5‹ñÔÓÏ¢¤Ê%…¶!3w6¬ý2R“ú€±û4v®ÿ>'Ü„ Rj²óÂ…wñ±{ÿ [ÒSåËt“ acq aù®²hØûÈD¬) /F~u+ÖÍO H÷í8†ÅïF•~âמ_‹Êui!|y™H€H€H€H€H€H€H€H€H€H`¨èÃÔì¡&ú•—§ñà·,ÆvGv>Ö>p;Ú_{ yëw@Ÿï¾~Á·q_WRãz—Éýö놱Ýf³àraê¸Øà~¼J$@$@$@$@$@$@$@$@$@$0$ p†{ÈjiÁ¶9S±ÕgUÏ-oÀ–¥)fèŽ:lX4»}þùµíX—–hú‡pµTnÃÔ%[…¯Õ‡0?>D@^&         VÆ+iSX÷[¨Õ§°g:‘#ÛU9Ó½%»Ï½w¦V‹c›‹ÓØÞg~Œ@$@$@$@$@$@$@$@$@$@C• î!kfnó­øbKù‚­½ãÁ…±ƒ{tãÏug5¯éÇäàx•H€H€H€H€H€H€H€H€H€H`fG†Å¸"ÇÏFîñVdµ_@lÂ͈%ežÚ¶Ç¸~Ó ã whGÞ{Ç7m>¾‡önƒóP-ÎuvŠ( ˜¹`12¾ú0¦F¸kèŒèC$@$@$@$@$@$@$@$@$@$0ȸ†{€·ÔÁ‹§ÛÑÙxÏnÝmlšjÏ)ǯ¶/E¯{¦vŸÂ#ãm(é%OG®û¶,Wœé½I€H€H€H€H€H€H€H€H€H` Á=âÊp£`NÖëëºKñÊÎõ }J ¸k°"aœ"®ºZšTFvnØ…*aÀ¯’Ò´åVàä–ÅÒ:I€H€H€H€H€H€H€H€H€H€†2®áÞ‡ÚI°Ù`³ûv÷Å—ðàÔ¹8ÜÜÝkJî3¿óÛÕ€.Gê;ìÛµ[¶ìB¥Ò‰ŠüL# ×Ö%8Øì1Îé          Ú8ý?õãéFsýo±=cöè3Þ3Jѵoeøeeº;Ð|®]zpó¬T$LŠ÷à`Ö\<èK4³´E+Sû#!¦L™‚óçÏ÷)î¸qãúžI€FË—/cìX¾µÉRÀ•%@}qeù2uI¨/FRm²,$pe P_\Y¾L†2‹/öI<Õvñæ›oâŸøDŸâ v`ÜB¼­‹'/ñ-ã@uç!ÌàÂëîSEH°­õJåȯšuiý’p̘1xôÑG1yòäˆãOŸ>F·ˆi1 Œ .\À¿þë¿âé§Ÿb)H€®(ììl|ç;ßAbbâ͇‰“ o}ôþùŸÿ?úÑpÍ5× ïÂPz +N`Ó¦MøÆ7¾›o¾ùŠçÅ H€†Õx®(JÄB=ùä“8yò$lê’#Cø Á=Då4Ù†i˶ _;œM¿Âòä`[¢vcïŠñX£.Êj…Á=-¬ÁÝw•˜ÄÌn×é>½ãg­ñž Ôà> VjþO$pµ¼ÿþûÞs—.]ºZ"0_ aDàÆoÄ믿îý’n‰MQI€™@OO®½öZ¨ã‹ØØØAÎÙ‘ 7S§NÅoû[Ìœ9s¸‰NyI€™€:Áx8Ø;¹†@ˆ†ñÞµ>Ÿ*œ>ß"”­!¼.»…q>Ö;àŒÝŒæíBSõï Ÿ›oš`¸é          ÑFà£K Þ«|&üÕæCƒ{ˆ˜4mºá³é)':Œ3ÓÑ|¤›ª|çöŘ®Ïnïv£¥¹Íâ¯#è^ª;pàX›™îê8†o­Ù£ŸáÞÏÍ0Üt ÀH'pé}}é2þ´ù#TÜëÁÏnðàø—=#þ ‡ƒ÷µ”|ßסû•¬ÁÄ;Q×Ü!–„ñ £­‡ ²|KÎh²¿új¦§ö80uÚ4LÏœÔMõñX˜‘©§ˆMwOÆÎƒ5hsw‹4Å&¬u±bâÝð®N£†›°~!9ĺ3F*t Àð%Ðu^Á_^Ƴ?Bùg=øù-¼ºé#xþÌÈ‹|+ŽÆX(âßp8hÑ UKq³ñ=gJ;´ÎM˜+þ‚ÅØšžbz›j¸ã¤% SÒ¿‡|Ǭ÷YÕ7=¸ÁSÌDuÁJ[5ÞH˜         F”Ë :ÿ ´WÐvü2ÎW*𸉟ƒÉwÁ§wŒÅä…cpMÜð˜Í = îÁ¨ø®%/ߎsÕ·âñkÌ™ç–ð6ä–îÁ7WηÇcÇ™k¯³„OºCí¸µ ËÖï¶øè'öìbïX {´êøK$@$@$@$@$@$@$@$@$@Cœ€§KAÇŸTãºâ5²¿ó[1ã$a\W ìŸúÿÆbâ\±XŒØu¤4¸÷R“Sæ¯Æ!åK8]÷'¼ñf®½þZ\º$~ln·¥"1ÁÔÕEPÄ_ð#K×í‚’¹§Ï¼¶÷/¡§ço¸$¤™9{R’8¯=87^%        ʺߜþÁ4°«îë§köO|q,æ=5×}|ä׃ÕEsq°`£ýZø_uýõËÞ%bÞ©RpÙÜôÆx—ˆùìS× éŽ1;º ìHâ„w"<'         QN çCíµæò0­ÇŒ›è[]llúw9× Ñ6ºëÁš îÁ¨ð Œ"êúëÚÒ0Ú21êf§ ŸR ìcñɯŽÅÅc0þØ{k4¸÷Fhû_ýõÃXzŠN$0âããñÊ+¯ FṼH`¨¬¬DRRÒ( ‹@$p% ÄÄÄàøÔ_$@$Ð_ýêWøÄ'>Ñ[0ú“ D™€¢(ÞõÖÛ^ÖÖ^?_©àb01M[föwÄúëwAÌuCËÀ>ìc\%ÊõÅä†1cÆ ©© ÉÉÉC@Š@$@$@$@$@$@$@$@$@$pµ|tIÁû'Í Nßù­0 [úä»4»ú;qžXýš¡e`—y {'§ȵF7 s—ÞWðÞ„Ý;ƒ]ÌbEÁ„‰åa>7S–ÅgvŽA|ÊÐ5®gü4¸çÚ"²wœ>†Š×ÞÒ\y_XŠä¸ð‚5×Á‰·>Á?…/,^‚‡OlDùv r¿gÜ1éÓ }þ”aZ:7êŽTáÍ/áúOÞ‰¥iC¯ž¶SøÙó¯ÀIXúhºÑfõ¶yíµ×eéÃqéÚë1{ÞBÌNN f0/ºkðëWßb_LèÌ‹H€H€H€H€H€H€† -ææ¦mÇ/ãƒ×gk³×o}|,þl ÆM¢}0ªŽKÊ å«Ç`~bQW°s×WyK™WÛŽia ‘ÝuX1~.œjh[>ÚO®C˜ÐWÜUÌÒ]ƒÅ  ’´çÕ¢rcÚUfYKå°åUãäÆùHìÊD5Û¬Õ•˜¯æãFÁœ¬wE–§=§¶¯ÄÕ\ÉØ(ûRd•ÆP$@$@$@$@$@$@$0(—|P±Áée¨k°Ÿ¯Ràs['‰%aÔìÞebÄï5q#ËÀ>˜öÎ4Îp=Æõˆ7Õ Élu¯mS1iØ t@l,t’ ‘€”¢Uç$ÄIÑÌ6›`‘0aº7Bƒ{ÕŽU˜\íFkeÖU3ºå`_’íŒB‘ @4xº´×i3ØÛŽ+xç¨"635×_O;‰ŸK²‹=y\}´w^ý: $0²Äߊâ«bI™‰³n¦esàhëOq‡x;ä1JÐw{+jù–­Ý­]­Z‹âš/cã|~§a`¢ƒH€H€H€H€H€H€H`@ºÛ¼[ã3°‹ìïPp}Šj`‹O<8óžƒë>Nãú€ _ÁÈ4¸_A¸LšF'D,L_‰…üð×ÅÅ!F|i`*É8ÄM‰ÇÒ¬]¨h>‰%;´e”ŽÔœ¥Á}˜×5Å'      «IàÃ&ëúë¾ 1c][æ¶c1ùî1¸öدfõ%oÓ–Ô—X KQ'ІÃÅ8ù°è±oàŽXž-,ƒÕxÏ›×$,¸ÿ!d=ñ(Ò¦®·Òvê Ÿ*ÄÖ=NS2›ùÛ¶"syšocVê>‹Þ™\œŒ•ß\”À¤Ð\¹Ͻ܊q¸ˆ>÷Ud-ž0 Ùº›kP°}6I²ÙìXõO™øúÊ…A×°Oˆ…»åv÷‡8(âyW9±Ù‘©2Ø $É‚ vE‚]ëE||Ñcȸý<þã[¹(Uãe£sßjèËøxÚêðìö]X»»DâdGÎãÙxâÑåðGÛVwÅ/œ„HßX}\‡ŸEÑO ú¬¯V¦/ÀC_Ë£c5Yuóןi›¿Þæ@úÂdo^Ý-5Øóì‹è7ÎÌ;ˆëb°ºñ´¡²¤½‚3gÏzÛÄ$‘÷Š/?„‡¿¸FšnÛÿcìùÏ#^~“Äõ™s–"#ûëHŠŸ`„êc^ú ÀgpO’@›ØHø¿Ÿ+Á¡ªQåÒÖ¨±Ù¸Å—ñpú˜- ÷òÑ?Îr nO[ ž.Ôx_|ÿ"æ=–¥)Ö|cñ À•$pÙ£àýSÚúë­êò0¿U€Ëbååùš}úªkpÓ‚1Kû•¬‡+š¶ÂcDFijj”²¹ 3„f€÷/¿¶=|ž]µJ†/,ì…J§º³Z±û®Û23›&à×®TœëÑcyk¥üu9,¿…J“7J§Rh×äTýs¶ZÒÑNÚ•|)Lq½p²5”çl,2åÊQº|bÈl S^3¾C±ˆ.É›ÝÊN0Ök¤©"¿YìJ™Z^é¨Í·ûâØ•Ì [Èø¶Ü ŨI±ù«‘š™V°2É×ìJµ$FϹ£f› ÊÅ¡”}Ùõ4)yR=šìä|T·C©5òêTŠº¿Ã"ƒQŸãhžÎJfi½Å»:ßì¡òÍ-·öM“M8‹\¾'÷%UšV?fÅJ«QAj$@$@$@$@$@$@$@ƒAàRçe寕)®\òÒ}=ÊO¸¤ü"ù’r|Uòç{”ŽS—CŒ‘‡jg,{ç@€‚ò «O@Ú0ÔµgoßJ1ó:79Ù™’|UXòäKƺڞ惘»VŸ­mCN~)*ŽV ¬0Âh¯%k±æé:áŽÇßÎÕ¯bëó¿7Ò1.ŠYØÏVùÎly¸?UÌî§lîº"ÌX¶ÉHÚæÈA±Ó‰Òül㚘&¯ÔHçþN;r KEœÉÉ'v1Ï%ùંË(¸’ sŸÚ‹iKÖqly(¯®EuE)2ðUxp–Ç:Œ`06åDö”h3µí9(,.D¶Ã çÚº¿jö­v.É#oþ:á¦9/`·[ÿâU‹å62í>…5Sï†^ÃÂ@޼â28Kó…K?œX6ãë¨sëçnì]3 ›ôz—3ròP˜Ÿ ÿœô‘þzº;ÄWÛp·‘¸ËRèžÆýX°^’6§åG¢¼¬™Ræ[—}§ºhýãlF÷ºŒµæÛŽaÅd‰Yf)Ú÷­FRŒ_ž’ D@w«‚¿<µßøåÿǃƒIbÅáînR¾6Ž7c°¢)Ÿ+‰Á­k¯Á·‰º Lð*ˆµžq‡.Ѭí1ËVäÙïîþ³»3ÅŒ\ o{u¡9»Ú–«œóùÉyg”Ë1D1ËWeµxö|m¦·%Ÿ Å¥Ï.÷¥×Pšiä“Q웹l‰#Ò‹H¶vËlzG~µTEéjp3ú1Ë]}ì—=ÇiÌNW#wÖ—™³×%rlÙ¥ÖYÚb»,·£ÐågMÏ®8åYû=ç„Ìú,võ7Ô w-ŒÝfSlÒŸÚ¯ä¿ÂZ™‡¢Ô›³ÛårhêTJ3õ¯¬3èûÅY$jÄÓg¸Ÿ«0Û¼Õ–]f~EbP¥ƒH€H€H€H€H€H€H ._¾¬|ðçËJó)¯¬éQ~1ý’òÓë/)/.êQþômrîÈGJχœÁ ÖjƒiïˆÌœá.jŠÇP#‰ú‰¹’X‰ó…XîC;\µxË7›¹Æ´fLh×Ö7¢%Ýœâ<1K>¹+nÅxÕ#ΆUÙú”h3‚«k¿ôŸ{|ç"Ü}3$?Ý™lݧX[å‹cÏÃÓëæë xãR–c£1Ñý´tY¼ÅI6žÉ]nYß=>õ Ø„Ó%æõ;ÏciªI¯ûô/±V_Ú^ÌÚfÝBi#P5ö¬ÛW ±Ô÷¨Úô<éÒ¾‹â'³ôVÏ7Ó…¨¡G7>n¨~ã¼áŽÔái9ÇܵFpaìÇöåbÛmõðœÆO6é‚gâÀ“+­³´c’…ÜÕÆLwç*Qƒ¼¼ïi-¾ø?·â–«_)èGÌd=SkÄÑ/‡úU×_wIþáš]§!MTǤ”y¾/+2ñð}¾r‘â‘v‡ÞöćÆu«£_œ§Æ£[Ù>u tb¶'ŽïJ7Öï·æÂ3       ¾øè¢‚wk.ãõ~„ßý£˜½~“¿YäÁÛÿsÙ;Sý®Ÿ^ƒßÁ½U1˜³íLùû±ˆ¹Ž3ØûÊy¸‡ç"ýG üöü¯!5 eöXJª+o˜t³q}ϪY8SžƒZµ óm·#yJ"æ¯Þ«©;Ÿ{ä1`÷zo¼Òçkñ…K5´ºÉ¤n$wlÀç¦Heëé¹hÈåXq0i‹67Àõ5µ\±˜¦¾ ŒÜöÜ/"% ûà ,)gnÁ}~r÷ô˜/%27-·¼È0âÆÏÄaÌ/ñZkÏâ]ñÀº¿¦_{À\:E'K” _Œô·û4¾9u™X¬Æwˆ ^êgèn¨ƒþúŽ4$xÜèpKDÈñ17á6ñ뻪o¸ÓáªÔ–¾_ો徤ãÒð/¹v8·9yšuy¢Ç‘ì·¿ë­Íxåà8}YìXs7^x£µÛµ6”´pN*ë´d<¸;:àî|çÏ·¡µñUì\SbfÔÕOÎ%«0Ù’tŽo_Nc{PƼH$@$@$@$@$@$@‘¸Ø¡à½?(h››ªœ¾[­àº‹)ˆwÁÇ‹ÏäA­4¨GFsô„ 0鞢³¤C•€´‚w¯"¦¬ØŒ\Ûlõ@«Jv@ýÓ2sCÆWÆBiÆw¼í~1|=v‹@®Ý¿@ýŽ¥˜4þæ¾µãÅüò¯Ùƒ+#•­é•rCöÛn½ÅpËŽ¸¤Ì–íÁ’-9aòurЈݎ´OAÅrȲ¤Ížjñ3Ob1qº:ûZ©¿Ð0ýCÏÈ–ÃDîî@ÑWfyë@‹“ƒ†âÕæ=Þ5“s®ÅÔñæLxÓÃêŠýð<^ÑííŽdL´zg×ÝÐÛë~< ³ƒiÈ-ÛÑxd§±>¿kÇ2z¬ é)ywã1üxç±i>×ÜÈ6"G0öE´:‚—[¾¥~/_,A"<ù°¬ <óL„¡G~°)¿ü%ÆŒó{3ò‹Í’ À¨ pámͰ®Ø/£óÏ@¢mŒ×Àžºn,&ÿ| ÆM¤}T4†2˜9iÉ1êh'0.¶·&%™{³yFS,+²¥¶‹~ö ~˜·É˜y¬EuaÏŽõÞ?‡Xªä>{:&_ɳc·wãË=(?ùÙ{¸ªÊtïû·a£h¡¡‚†yа†œØŽ£6ḱi`jܞƦ)q&ë<^¡žsdð“Π瑦Q|;…t:øŽàähÛžÂ:Áî€ÍiЛ´”‚T2HH¶†õÞk¯½Ö^6ÿAþýÖù,×½Öýﺾ÷Ò9ýÖµ¯û7ˆXbÔ¥“±àgQ¡½™½Ë6s¿ÿˆH[buF^‡ëRštÙ£C…;@¾CE·Wô1çJÛ¹w%Št1VçÆ£WZuª¾ÇPþ¼~ºÇ“¡¼)Úúwš±•iáù´Ný“æÜêLýÒ{Ùº­âõë íÚ¢žFµ£UDùw5XXÌF¦ÆJW”|Í%¹±?jŠ21{eŠWtæ¸8\ÌËÓ>êxm4hmˆ{õE i‰ú3ü„ÛoÇÔÇÝ©ƒú3Ƙêcìé߸1å-!     1K@j—ðÕߺ÷Úì_¼+Áñ50ý»‹öEÛ}´Ì_ ìcö%"Ǩ Øq5¬.ØóèGbËåˆn$ÏúónÁ±Ñ#‹Jÿ‘õÐFçio¨ÁéþŠ#ïÚðò–Ú\Ö”å8ð€ˆBU¢®ú'À)¸ùÖð”ÈK¢¥“‰ÃÂÀþ›#÷<_º_Is"Ê]‰Ü{še܈€ ÀN‘éò8ƒqT•ä;Åve¬®þÊ7àÃÃî+eûÁ°D£òÀ“šP-?É.Ñ^"±›Î~ 1”?˜ìÙpM?'MÒò¡[?tgõïæýš½:Nä¡ÉS-ån^ΕxF'¶›“³ðÌ#÷ ü†`À_ ¯ŒŒùkµD9š¿cçøìrìzÔëüLÊzÛñËwa×šŽ¹ä;öìþ~ÂüùO$@$@$@$@$@$@$0š 8¾‘P_®‹`/‘à'‚Aeq]NsË¿ø"p!`0P`Íë<l禩#aF¹ sÝ©yó«ÐoCªU¸ §ÞÎ×Dp³yÁ£o›Q²;›6mBæî2g ô€ÀDF­Â†ÍÛE.íFXSÍš 5å(dåð_!RÑ(åŠ7^Ã÷¾¦Ù•÷ý‹ß³uL^~û˜:­Çõ-Ó,ÎxßfÝ£Í`Üè×çà;zÒþ1 4ýxf8w˜õÞt Oí'vcþýr2åHÞ ‘Þ¿nøMug¾·ž8 ?ÿv8x/çY<û¬8sÞ…#`¢Õ%·íÃ1¯/c ~ß³ØÞýG‡f\žézdWDcGíiœvù9ýö ˆŠCP "¶ËU5ç´jËÁ¹š³ñÛ„Hñí&bõȹÿ1”xe ¶à•H€H€H€H€H€H€Æ&æZ çµãXJÞúžû§9ð—ÇÛðu50÷AüøC#î;ç‡;_1â[OøbÚmŠícóU¸ê^Qp¿êÈÇÞ„7,IA\‡-Oï>ªÞy\í§àݦ‘1+Â=êû~Ó„c¿OAzz:RÖ[q¾ÓˆŠq?õPPC°úIå,;°6QˆÀNý4÷/Ó'VWšôõÏ€Y7iL*¶ìDQGѳ¡Ùšî|þ¡›ôuîŽí'MU\¶”t”4tlÝû¼MnÎð¶akç>}~RW‹i½Ö-.«Û×týø‡-¹ö]‡ØôµSÍêvm(ËElÒlÙ"Î÷ëÅó@ܼTÂmøuv‘ÖV-Ôåª?nPy¹`r—ì(Ú™„ûs*\ý̸uŽX@±ñìñÊßóÍa²Ñ8jãW®_U8sÕè²+y1 o¦¸›‡Ä¤"Wl€«6,j/:“Sëy%      ±AÀþ‰„O~ߎ²x^_ЊƒóøðÙv@¨Ÿ·nòÁšZ#î=á‡%Ù¾˜çƒÉ7ƆãôbÄ à>â–d…ô MáCÎúEˆ~r'JNT¢¦¦•'ʰ73Sn¹_‹"‡)qQ¶p«&®¦cUÂ.œjP¥ÅfT=€õËÕ|Ú&Ü,‹¢º#âí|,ôSsZÂEêAÑxZ ¡RöÊà>U‡ÃšS‡‘°b¹[àβ``ã»·Ör2’UÚŠåÓ[”^Í(Ûý$%º#¾“ã–u?`¿j«±õ®•ЂèÅsf|öbïÞçî½(«‘×1 ùñÚlkoùv—UBÎÂãpØqôP&¦-MÒ곞Œ¿L0⮄­Ú3Û–•XyuÎÔ=Í8%6; Ö¥}Ñv*ä!îŸ3±sg&23ås'2Å/)6mÝ„u §`e’;-Œ9#Ý™Çè¨Á 9Ї¶-¿Âî’JØ››Ñl¯CÙ¡¸{v¬Îÿ<¼ÿaǯ0Œèý‘>Ç} î«ûÝ+Ò׸«Y"      QN Ý!á¢Hs*« %?uàÀÌV¼µÔÏ´ãÚ0–¼ä‹Ÿ~eÄÝ%FÜžî‹Ù÷øˆô1ØGù²óCZ5ÎÒС#°dã È8lÕ"‡m;’ ŸÞ3 ž‚;aˆÒªïYUŒBØßSúJ§_‘“ˆ[Äi2™PQ¡F+c›ÓžGLÇ<á!Kð¸øN¨Û?óç÷/öjrßm¢ÿuR·Ü‚tçˆ9ˆ½Å-Òº'IÅK/Ñnû3ܹû~FĤå"~Ç"(¸lœL‚“žTr~Vuä¤Y×ûB'{ìQ®ŸH •¾Öý‘¦ãÈ¥õXâð‡~ì‚(ßlX¿t>Ü1òî^æ´B<îJMc ]…òÜx,Z¯xkMÛתß]Ü]¼–ô{ÕV䤠«7Xí—Qˆ—6ºÖ/p16‹ï÷;§¶.÷n«Ú7qQ0ŽäŸÄž‡ºŽòWÛöõj Y…Ül‹ø¢¼Üé±)°ÔïÁïÙ{ú:<Û“ ÀU%Ðjû_Üù×ëþ,Á¦’}Ö]>0ý›SPP¿ª‹Âɺ$À÷.Ѱ¢oB°ñíó°fhI@¼v7Çg ôü›Åo±í¥0¥§\jK1…ˆ$?r²ñj·xÔQlOÎ.„us”{§³WDÝßîï¥]?móǶÖ*ä&›½Œ X’³q¦q´Ï^ýœG°ÿã<&vÁ. »Ï Ë”Nl7#»¸ ÛŠð´UÛWÇܳ…ûNkëÅ?·î]—¦jn!aO# ³Ü‘î{¥æ—ãíÍÑ"¶Ý}D>¼ '­i95ù®tBÚ[§4˜Ø 7å––ø4ž¬ÅžÑº|ÿþXóïUÈÖ3ÖÍŸUˆú¦3ÚÞrUŹKJ ]/ ÐÚŠ®jY—RFˆ|ô9¤j/òð¼õ”ZÅ+ ŒhM$g´ú_“ÛP°XD°9ptcZêùùÀò‰«?ñÿ7â¦xŠí#z5ÇŸqIãÏí±ï±¼£rUUBC‡2YIEºê3§ñYM-¾n‘ÛL@`pn¼i>‚ô²hýûõØêå8þÑY´L˜€ --˜0óF˜n3!¤›9«=‰¹%™z|þìz(¬_³÷ÔÉ^W‰ÓŸ| áÙoòTÌš9[l¦éMÜïi¤×7TŸÀ±“ŸBBËå\;gn_À¡Zš›ìÁÑPƒŠN¡V¼T&\ƒëBB0onºÅh¯ÁÑ¿¹ú\ˆÐ° é…¨=@›eÆTÖ¡U¬÷5×áæ›ÂÝv:PY-þ?ã$L›,žpðdÁî$@$@$@$@$@$@$ÐYšlü¨;"G°·£ö¿%\¹L_l@Ћ3è{'3‚½;Žã¡nXõÎ>¦àÞX£©éhy‡—ivFOC’3í¶å9ôZìðºÌÙI€H€H€H€H€H€H€H` ´]‘PTr ìâZ"Áw0c™[\Œ4ÀÇ—û0.Óˆœz´è ­‘¯JÍuÕø¢u2.¾»Ý%¶‹ÍR3R)¶%tŽM$@$@$@$@$@$@$0. \©—ðe™"°ËQì_Š\ì׈„ räúœôÁ¢ç ˜Oq}\¾cÔi îctaéVWìxå¹XïŒjWÛ˜ñÌc®/ÕG¼’ ô™Àןé67)bO·)ÑëáOù 8Ê€‰Ó(°÷,;ŒÜGÍRÑÐÁ"Ð(ò€éŒ‚—¨Â2 @OÚÛ$\ú»œ]ä^—s°‹üëmM"ÿúE`ÿÎÿë‹K ðH½'–¬;(¸µ¤'½"€u‡NÂ|ñ´ŠöÓç™:Òw í•_lD$@$@$@$@$@$@$@CKÀñ„‹ïëò¯¿'aÂuÐ67ýö/}q] çÚæAã•÷ñºòãØïÀÐpŠ\aÊŒæ {uöþþØŠð©­®iLf ¢cVc]ÜO04“ÖQíÕ8üÖû¸,ì¿öÆ;2¢<±W–á­câ·o×~ ÷ÆDÀ¿ÖU—Æûg/c„ ^[·\¾Œ– ×"bq"B½¶¹šûããÕ´s‘ oj”ÜëJ{;.ýbCS‘F¤…¹ùùàÎ?àL}øVˆ3UIcÕ¹ñì—¼tUUBC¹;h÷ïE;Çʤ¼î›‰Úøìbd%DõJ¸íq°1ÐÀ~t'¦,JrzbÊ(ÅñKF”WGwFcQ’ 0e¡þøô,Û±sá$©_[zðÆœš}ÛBP톲ºï>¥5›H€H€H€H€H€H`¸Èò^ãI8SÃÔù×Ez˜+õÀŒ%Jþõà; SÅ'S`®5â¼'0ZôNF¸|­9¨%Ѐ½ Ó°6ÇÓ¸øTD„]‡¯*ÿŒô«V™“¸¥µ…(ß þÅXü&jlæùûiå‘Rð›8[1eúÄ^¯×”y¢K/w[úZ—ÚQ[”0l¢{|)ëC;H€H€H€H€H€H€úO ­YÂÅr]{‰ã5"=ÌJû·’|xàãK½ÿ”Ù“úG€ºaÿ¸±× P¶s½‡ØnNÝÜÔ5ÕeŽÙ–UƒC;S`IQ"à+¶¬Ä w×cÃ’žã¥Ç¢qì‚ŵ¯`™x…VØëkQþúóˆMÜ¡<µ%"·ì§ØÈ÷A£Ä Àà¸R/r®ÿ;ÿúÅ¿J¸VÉ‘ëÿ°Æ‹vp#ÅõÁ'ÏI ï(¸÷{Œ EHMrG¯Çç–c×Ñ=óÁª{PŒóXž"Ò“ˆ#)ÝŠõ†N—ïÜOF=küýa‰ßÝÿHúÃ_äñIØŽÂêãX™®¼‡Ë>¥à>êW› ÀÈ"p¹J‰^¯="®ïµÃ~˜ip ì þÕAQL ¤À>²VÖ€BÀ‡ H`<({i'¹TxoÉÅo½‰í:0Q=“zoý=NÛÕåê¨;Š]O®ƒœKJ;FcÓ®C¨iöl«¿«;U‚›½p¡ÖoaôjlÚ¹'j:L":6œ8„Ì­[±5s/jÍ8z «}b÷ wûº‡±5aµ6¦Ó¦…«±óÐQtiŽ£E»3‘°zµÓž…bÜèÕ Ø¹·u]vÒ{Ó—²°ýÐ.¬‹Öñì¢×m¡£5Ý dG™Óg}¿…X÷d&J*ºéçYå¨+ÃNÁ133[7mÅáJ7;Ï–Þï¯Y­ULÑJîB_׵®™»KDD½ÃÉ&au4ä5P×aWwkçžZ+ ÔGm H€H€H€H€H€H€†”@{›„ú¿Iøèù6ù™¯ÍnEA¤UhÇ5¡Àw_ðÅO¿2â‡ïq{†/nXåC±}HW„ƒ“À È›¦ò{Äk!‰MSÇžcƒâQ½”e†$3’ÏŒâÚ^ŒÚ*)-” ÅYP*Õ¶º»Tfic©cz^ÍÒþ“î®RiV\ý ¥x®ay–Yëc¶˜´²<_Vy½säòìÆË–ªtöËZÏKq.ž¶«œ,RÁ™&—åÊ¥±"[›ß’UîQ×íMk•”eQÇõ~5§Z¥NÄšÎHºuófgªõŒ6u…ÊÁœí9–Ø9ÆÃ׸\×z6J¹š]©´“ÚÐRq†{âóOº+Di`ëj–âã<×Uï§)­PÒ/]ß}ô0•7$@$@$@$@$@$@Ã@ õr»ôyQ›T‘æÞ¹»Uz% EúSh‹tdm«ôÑ‹©¾¢]jooË8% Œl²F2ôNF¸‹•â1ÎØ?E‘MõÙ‚»n Roº¹¶$1ÑâŒY‚ Wžû‰Ý˜»2IëgŠË@Ai9J ó¯…ÄÛpÿ-”è°•{±4IÉ /w¶¤f£ ¸û³oֆÖاqB]®l’© l³vÞÝÓQ}‹ÕqMHÍÊGaq!ög§º#ôó±þ…£îIšO`ýìåP{ k‘»Öü,QR+bç?†£} W;ë®vì^?îl>&dä ¼¼ùñZ;[º–Ì2í^Äöc×ÏæÃ•ÕG<—}Ë…Õš‹d¯tËcœÕ´<ìu%X¬ó5>õ{ÖÖSmßÕÕÑÜ ~U°UK/˜®5غÊÃØ“§¬«9.Ù¹ÙHv/ä=Þ¬Ö¼Ñæ• ÚÓúè1(oH€H€H€H€H€H€L é gÿÔŽòÿ݆ÃKØ?Ýò'ÛÐü¶Þ?>iÄê*?|/ψ›Åf§ʯº<1 #û»­ë/ñ6Š/>ýõo@ýË%¡a*ÑÙ¦4É3†¼/#7JÙZD4$KV±Gô±$÷ˆä6gkƒŸÌuG¡ë£²•R~¼åìi­E4»ìË*ðˆ¶××ÇtˆÜ‘Ýšßæ,I‰‡Ù-RÝ”œï1žÔ!Ý’]¡ùП÷ÆrwT<'ë* F>_¬ÿµ€Y*vÙX®.÷ÓÌ…&ÉšêŽ8O¶*+ª±P#ÜϺýüLÉû=#ßÅ;Â]y?Ì&“dÒòß+ý™]îaˆ48ëj’rKõãÖJÙº¨÷Ô‚óšó}÷QëÊ À¸ôQ»tæå6éÏë[%ëM-Ò&·Ho¯h•þö´C:¸Mjidôú¡ç°cœÀhÑ;á.VŠÇ8#0i:©QÑó‚1­Ÿî7Ÿz‰ê¾«¦ ¼´!J·Á¦ä1Œ¡Â‡R-ÒݺÏ&bÍû{4ãõí‰Zç´âß!Jý©€ëiHÔˆ”8®;ò +EYî—äîW˜!úi·¢àUO$kŠŽ_ÐÊÎÂì4ËQß³WBõÔ”jÅ‘íkzÜøÖVQ Ýé90P]qJXç>c]ãó÷áá%zƒð‹k“”~ÜÁ?¹f>j³@$@$@$@$@$@$Ðgí­¾üK;Nþ® ÿ}Ÿ‚Zñv”ç^oÇÔopÇ‘ý’?°±p«/B~è¿nvÚgÐì@£ˆ€+1Æ(²˜¦’À@ 8.âc-¥ÌÄ~ÖÚê·ãSVA/‘jƒÜ„•"¬<Ï©ô~Š/›ÄÏÅ v߀ãÒ¥™Ã{CìqáBj+!s½;Á‹6V‡BÊ£+:<¦NŸ©=ËY{ N¤âŸÖÆb‰éV„†bÉñDk!¤ì3G‘£Þ["1ÅaGƒ]KN⬙dœ¢ätÁV„í°DøÐ÷£-²xÜ¿Ì+1,¸ãN1´âÿ5—D9X×Ï‚{îééë—ãEJœm1Î-_W ù±;EêˆpK;¦h%]¡_>êú³H$@$@$@$@$@$Ð+-—„À^*¡îˆ„Zq^ü‹„ɳÅçßiÀ ÷úàöß0åf 꽂ÉF$0F Pp£ K·º! ÔKM÷µÇy¡/‡÷âo‚£Ù{“"FQõçm’Èñ¿®^?L›'G«+y¹õÑêöʼ˜ùRrÔ¸k¯tñ0á³ý;Õ…­Þ„4S¶(ÓÁ–—î<•†&ħ>ЏŸ?ˆ¨pEìnýæK÷ÖDÌž”è¾ï¢¤÷¡‹&Þ7W¡PuUˆû³»`nœ2ÝýïrA|Ðõ3ßYÝóù#,<Âû¼žÆ{5O!&¤ œíMxðñDxk²y*gb~lгeEz,>Ú„5aŠa[WñÁ “½ýyÐ{7îG e8ñ廽k<Z­{ FŸÁY¥q€‹.’ À¨'ðÍ9!¬¿§ìuGÚqé$pÉ€`!°ëÿñAp”þAØGýBÓDÞä¤AžC‘À$ RÊ \‰R.BU­áÝŠ¯²ÍÈûÙ¬w ÆÙxè®D‘.ÆêŒÅ¾ÒêîöÚ×OwߺJ5E™˜½Rl;Všãâp1/Ï%Ñw¬UïÅ'9ì¹£ø,RÀl.¯ÇŠ?¾„ç2R´Hl¥WrÒ“œ§%£7FaÒœ[ébT\½ëk£sڮ뻩áçÚ‡ŽÆ®Û'Oƒ1}?›œbf ‡ ±q/£¾(]eGk“¨ì"’?,f# Ócåå§5—äÆþøºviP+zãcà〠Óz×x´âÿ=™.’ Œ["ý5.ý"r½]‰`/‘Ðò0c©"°GþÎ3–`œÌÿ2·/ '^ àÞ Hl2ÖÌÆÂ¥Â'gu²_?‰˜„¢£íÇqPS¥ã°ø¦T½’ïJ|"óéê¯R><¬å¯QÄjG%žÑ‰íæä,<óÈ=¿!ðCUÆNÆüµZ²—¾-€1Qmtžö†œþà¯8ò® /oÙ¡‰øÖ”å8ð@~xñ-¯¹,ÂïÙp®(~ý¤ÆI“´ÈkcG‘_ß°»²Ÿfªõ^ó¢(•ö³@%æÔåõýÌßVrÏ«ãhWê ö0ú 0ÀÓÈøìrìzÔëüLÊšÙñËwaךŽùóµ{,´”«Vºšõºö`ÑPø(O9oêBçÙÃô¬&     QG ­Y¤„y_D¯‹v9=Œ|5^#ÒÃ|OØoùß¾\|(°ºÅ¥Á$0Œ¸iê0ÂçÔÃEÀˆeqiÚäÖÄÍ(éa'в\‘·[íaY‰›„ž;wÑê|çC­ìQ°ŒM—‡b§RGíiœVÅåº}¢"¨ˆírUÍ9­…Ú²×f”ìÎĦM›¹»Ì)>† 2j6lÞ.rÆ7šjÖÆ©¹Ø¿©î|èÖgá'‹ÕN#ÞËyÏ>+Μwãjƒô¥à?‘"Ÿ½ó°ào]0?}¤HuáÜ©"p\×ÏvÇê´jw¡æL F°8W¼xÜý\.™³ñÛ„H¡ÄG Cä´WœûC‰·±\ ät}4ãòL9Uë‡n]ÕIº¹öÓÇnFd Œ9W.JÎÍL¥´á­ï9ðÇ@þò¿Úp¹Jü7þÏ|ð£cFÜwÎQûŒ"]Œ/¦Ýn Ø>æÞ:DCO€‚ûÐ3æ #@PÔ£ÐIîX>-%5ÞÓœØû$–&ir;²¶Xœ™F&Muæ—ݳ¥¤{íî}^êÍ÷!L„©>¯ßæ›Ã:e-qÔƯRT•^ä4éuºè&û} ÒÓÓ‘"rßœïÄ=Q±1î§B$ö[Œdõ‰ØxóµSÍêvm(ËElÒlÙ"Î÷ëµç…‰½1rB¨"µÏí)óÂyc/Ãvµ÷EÉèX°HýP`ïsK:õ+ËËÖžÝ>K+; ºhú˜T䪢¿ˆ£_þÔ^‘,ÈÛ€Éâãˆ÷ÃŽ¢I¸?Çù ÑÄŒ[çˆu²uõn…ÇÓ~ùè1oH€H€H€H€H€H`̰"á“ß·£,¡ ¯»šãÀ‡™í"døvªî«1âÞü°$Ûóâ|pí\QÁƒH€H «<–ÝI`¤ÁåÙØ²(Ñeh–ÏÎAr¶Ä,„¬_:š>ÃÛ…¤Uü“­x<2ÐÙÇr2’MˆÝ! ¯V§h_pò׈qnHÚŒ²Ý©Xš˜çl+ÿ‘·ÌY6:jð‚kLÛ–_a÷Š—ð“ųá×jÇqÛjIÒRª@$@yÿÃß!2RÙäTÌk!·.‚¶M¶'«B±ï7¿@x œ^¥ÕGÿ/’–«yãM¸Y‰Eó„üxìp¥¯Y{ËÐRú~¶(L$ɱ£âͱȢö²žŒí”6^6źODÖ×ÎäTæÞަ&Ì2? Ol¦)Š·5i)Ö¡¿‹A0±¹¦ ©±KÝiz’7b™‚Q‰OÃ$ò¥ËžÙD:œuþr¿»ØZ‹wrŸAlŠúAÄKT¨§úÛĽ`Åv«EI¯#>2¤­]m1îH¥uâþ9~[ØåTä…_]ÀWB„?{ y²!®Ãœ‘Žhy‘¾ghÖU©›k¿|ìf.£PjÒf#<ç@IDATfºuÕ³¶¸8ÊÓöÝGÍXH€H€H€H€H€H`Th½Ü.}þN›tüßÒ;?h•^¹¶EúÓ¼é½u­ÒÇÙ©áƒv©½½}TûHãI€< ÈÚÏhÐ;™RF¬ñK ,f#ZkË‘åJñℹÅgP´mˆïpDbWãÑ_HìêQQ¡mN*§É.®Âö‡ô›²úcÍ¿W![ßGí+®ñY…¨o:ƒ4ýç.9[øMœìj)G§{9‚¢qädôCW{ôGrv!¬›£t‚°§…YâÓAGj~9ÞÞí±5¬ŸßÄ.Z{<ÅÕ<âá]8S¥¥ã‘[ëM4'碪i;":¸¶fÎç ¢Þygý&¨ªyS:·|ô9¤j|óð¼õ”³ÑÄsvî©<±Ä§¡ðd-ölŒÖEü÷]¡ÚÚ)Á ´¶¢N-÷ÁG/#ò ŒxM$|öj;þúd ;°ºGÿµ W.óÿÉ?þȈ՟øáŽßqS‚/®û¶È¿n`4ûˆ_XHc€AþN0ý÷.Éÿ£"¾ø 44tܳè-€f‘äôÇ•8ßðµ«Ëߎa!:QµëѪOàØÉOÑ‚ h¹Ü‚kçÌÃí‹"ØMâ&¹Ï•uhõóÃ5×áf1Ÿ3Œ<£•Õõb³ÏI˜63X<ïf Nf9P}¢Ç?:‹– 0¡EX5óF˜n3!$ ëq‚AŧPûµh?á\‚ysÃÜ6ušgšpâø1|ú…kxNâ°£òäi|ùHo/RÇOž: óÅuí•g÷«q7tëz5¬ç$@$@$@$@$@$0ü.’P'ÒÂÔiGÝ{š>f,QÒÃÏ€Ë ð   >ü+E Hàê-z'÷«÷N\Õ™FË xU¡p2       G ­EBÃQY\WDvY`7øŠüëBX—ó¯‹3ðv|ŒØGÜâÑ ¸ŠF‹Þ9’‚B¯âòp*        á"ðÍ9 5oI¨úC;¾ü³„Éÿ§°~ÃjDþÖ€€ùׇkm8/ ÀÀPp?ö&       èÆ%œ=ØŽê}í° Ì\a@Ø#>¸óøQ`ïB6!(¸‚E¢‰$@$@$@$@$@$@$@$0Ú´·I¨_Ù%§ÈÞÖ \·Oû"äGøN¤È>ÚÖ”ö’ ôL€‚{ό؂H€H€H€H€H€H€H€H _Køâ¿%œ‘쟽*Áo*pƒÅËvû"x¹rf$@$0– PpË«KßH€H€H€H€H€H€H€H`ˆ 4×Jøüm%]LM„©·„ÈnÀK}1å& ìCŒŸÃ“ Œ0ÜG؂Р      é.W‹(vk»ˆd—ðe™„ ï0gµß}ÁþÁÙGúúÑ> ¡#@Á}èØrd       $IBÃß mzzåK‘ý.æÇû`Åÿ5À8™"û˜Xh:A$0`ÜŒ ÀØ#ÐvEBÝeÓÓÏö·Ãà«äc_¼Ó3WàãK‘}ì­:="( î%Èþ$Ð/v=lÃ'— z1@K Z®ý?Ô¾-¸öÆ;Ò‹† ‰½‡ßzÂ…áµ£ ×ì•exëØYaœÊ­‹†ºÇÕe‡ñþÙËbM¼/JËåËh™p-"G!"4P×sxŠýñqx,å¬$@$@$@$@$@£…À• ÞQ6==wHÂ5s‘=ú¿ŒŒ À>ZÖ‘v’  îÃÇž3göñ/±ØúÂÀ”…zYp×õ5e”›àn?mEìýIN†ÓŽ®ž~#÷' Â*·®jÏí°ÆÇ"©B{ÐmÁœš}ÛBP·­†¶²ï>­=H€H€H€H€H`tó±~¸]¤‹‘Pûߦ/V6=½=Óo È>:W•V“  îÃEžóŽo~~˜=¦ÃoFéç~µŽóü‡ÑÍ Ï‚ßDáéÑÛè¦ÌcôRp·¥¯Ep©µE Ã&º÷ÇGOJ¼#    ¯.}(RŸ6=½tJ¬hæþÌQû ð›B‘}¼¾ô›H`àz«C |&Ž@$à€9 ybJk«÷zõ©ß8“˜ÜŒgöçãç—[0í–Yj-¯ƒJÀ‚âÚW°,phã¶Â^_‹òןGlâå©-¹e?ÅÆ%ß^F3“     ðB Ý!áËR9UŒ„j‘]j›žþЀ[ŸöAHŒÈÇîG‘Ý 6>" > àÞgdì@ƒL`J0憄@h»½<µæ!Dõ²5›õÀ5þþ0úCïÿÄ$lGaõq¬LW.û”‚{ÿ³ Àh½,á‹"yÓS‘.æOüENÌ,>øÞ^_Ïgˆgçð$@$0> PpŸëN¯GƾÓ€¢½ÄiûL_`Áš¨PçuG!÷ãÀœxêáe¨8ô2výç>”~zÑY?}ÞR<ðH~±*Rl¼êåpÔ¡(/ûþ§?ýr/¹ÏêŸ>€ï‹F×N^ÆéÕ£f=ôÿaûŽDä)ºµ³—9.ÉO>U]nkGÙ‘¾5V-õ‹ qÉkÿÄcˆ ë]¤¹£® /d¿æ‰qå«+Xüh2bÂze¸³Ñâ5«—à>ÅK·ºS%øÃïópðRØ*CMf îYýS<¸æÇˆ½þðÚés•½ûè9¯—n|D$@$@$@$@$0Ê 4}.¡æ-eÓÓÏß–pIÉÇ[î‹€Å>Ê——æ“ ŒÜGÁ"ÑıOÀ¶¤¾Ú?Ư×&:7\5gÜ© îgì@ÊY½6£²ð"rò4EZT¿6k^H+Dùæh]ä¶H›RS‚õ³—#¯ãô®>I° àÌ+B”ÕÝQkæ"ÉÚq2À–—î<Í©VX·­òŒúo®Dææ#E'лCÞŽ q¦ ÕzÛVõ œ× _ƒu¾Æå¢6T¢íu—àçoïÔÚΜ1Y+Ë…²ë°4©ITجÎ3]ì3›VP…Í1¡Z¿¬6ˆ¾Ð¥úF,“ ŒöJ!°‹|ìò¦§õG%Ì\®ˆìK_öÅÄéÙÇÊ:Ó ÑA€¿ëD+Ç2"ݧ/_º W§èôomM!Å«b»1ž›d‹`Å–•x³Z'ñ7Ÿè ¶[‘»Öü,!³«‡±óÃQOMZ­ìÃÕŽÝëõb» ù(//E~F¼6Ž-ÝKf™v4`×Ïôb» ©Y¹°Zs‘lv7K·<†’÷½ZÒ¼Bôj½ØŸú=#¨— àhnÀÑ[±\Sý͈‹ W§£r¯‡ØnIÍFAq1 ög#^gç–Ø§q¢Yë†~¯{w®ùú¨’E     J@j—pñývüíé6XojÅ[ËN¡=|ƒÖÔa~Óˆ›(¶Ðå£Y$@cœ@/e¦1Nî‘Àp°¾ËêxKM"›Õ(Ò»Üôdv=Ñ+MÈ-}/ úäãáû¾î.$º¢ÞKOÖbUhˆ³ªlçf-²Ý”œwž}H WýÔ¢‹FÏCÚÞ8˜Ð;œShØîÅz-ø;NlLš‹(—Ú¹+–}³—‹pqØRRQòX¢D–ûÑ=HÔ"âå~{D?eØU«~ó¦ÁâLñbÃk%ÕˆZ厗[9ÿ¡«)ÂêÙ+¡cJÞ#Û×xFÑ+CŠ?­X:ųÉäL­£>®p¥‡Qï³Ë÷9íSïÏ”¨ÅÑöQˆy÷¿Ÿp'ÖæÈ¿<°ã9„^÷ÁDëˆÞ¯»O|Ô÷f™H€H€H€H€H`¤p4I¨-V6=ýìÕvøNRò±/Ùå‹™+ 0ø0’}¤¯!í#(¸u¦—#š€œê¥Cú—Žö6v—à¤cc >Ÿ[lwVá‚{¢ó®ôã @ŒÜ§ðŸ)ª}:±ÝÙЊ {JQ4e©S¨¶î³¡AîBïÇь׷+óËÓŠ§‰íê`!QPžý>%ʪ¼ y…•bƒØÙ¢Ÿ"Â;ûfhb»ÒÏ«žHÖrª¾é÷ÙhQßëôb»HYs¤cÊÕÝUÍ¿®{äQ¬®8…æÈ M7Ÿ¶XÈåy¨@<¼»cj›D.3NÁðóÉ}Óëµswà£~–I€H€H€H€H€F+%ÈyØåMOÏ¿!aÊMŠÈþƒw˜º€ûÈZ-ZC$@  î|H`Ø ˜`±!¶CqͬÆF̛ѕ<«µÒ,xäÇáº{¥¨—ìÕhúæ3G‘£¶´DbŠÃŽ»–€ÅY3É8 DÉ)ËÛŠð±}–ôkïÍV´h)iâqÿ2Wˆº:¿ëºàŽ;EIÜ/j.‰?ƒuýÄÆ£w(‘ùÎê!wãÌÉ ´ 'ý¦ÏUŸ*×¼µV†s=Ïè…Ø.§¬y¡=‡ºT[?H×6lM_¿o|,Râl‹qFщǥ J'‡ö†Ø/âÂ…:ÔVC¦;¼ßs`í®÷k§u‘ ýòÑcÞ Œßœ»ÈÇ~Näc¯{OÂŒeJ>öïìðŤë)²e¢$@$Ð% î]¢a \%–ÇñÊÁ-Jz0fí­<ßúÍ—î鬉˜=Éî®ð,õvlÏ^⮹ …j0½÷gwñ¯qÊt%%î:ôýÌw`–¿Z¡¿ú#,¼·©n㽚§D€8‡5áÁÇá­Éæm¨<œ‰ù±)Ζé±8øhÖ¸6”µW–àÅÌç’£:«·³çr¿ùz Ý=:tyóÉ —º¬owßf€¯/ÿ#g¼­;ý%   ¡&ÐP¡lzZýÇv|s˜u—7þÂË_3À/€ÿÿçPóçø$@$0˜¼ÉIƒ9>Ç"è‰@#Ð$ÚxÕ‘{ê;ÀúIsnunŒÚ{i¸úHù>M/ÂϵwásW‡qò4L×WêûÙ*õ5ý,Û÷2ꋺIcG«¼(]Dò‡ÅlDaÚa¬ÜbsÚPsIYÁš¢LÌ^©ñ3ÇÅábžœnæj½ñ±wv|Ù(¡¢Š‚»Jë®…BpWox%    ~hoU¢×ÏZ%|¶¿]ä_Bb}p{¦/®ÿ>FŠìýDËn$@$0ì(¸ûÐpmx9 šÎ~ m"jÉ(Æž ·ÁÑä™RF6Ë8i’–sÜØß/~~˜©ú¨æ´QïuW»°I‘±Å†±òs}?ó·!öòr8ÐP×Ùr£<ŒÏ.Ç®Gý°ÎOΰ.["~yà.ìZÓ1Ϻ—¡»xÔR®Zéjà¨Ä3:±Ýœœ…g¹á7# þâ_ÛÊØÉ˜¿VKâÓÅÈý{<>Ê–|÷fqöÏ&ö"    phÁ,Ÿ¿#ozÚ.RÆH˜<[ÉǾüU_ÌX"w$@$@c‚ÿEËH'H ü¦ºó¡[Oœ…Ÿ,Vv8x/çY<û¬8sÞuŠÚýšÍ."-®žÖü­Áû(§i çN¡ÿº~¶ƒ8V§U» 5ï`Zp0‚ŹâÅãîçrÉœß&D %>©Z]Îý¡ÄÛX®ÝGò7ãòL9ñ»±£ö4N«÷q¹°n߀¨ˆ0*b»\UsNk¡¶œk?}œÉ9 @W¾éÏüG;l÷:ðê,Ný®×EpÏq#~ü¡nO§ØÞ;>' ÑJ€‚ûh]9ÚMƒ@À?l1’ÕqÄÆ›¯jVï´kCY.b“¶`Ëq¾_¯=÷(LìMæñI] ŠÔV<·§Ìcç½ Û“Ô7fÜ%G `Á"³«­ ¿Î-éÔ¯,/[{vOø,­ì,è¢éCbR‘«Šþ"Ž~ùS{ÑÙc¹W&{¥uvíLÂý9jr3n#rÏÜ„â;Í7‡uÊFã¨9Œ_¥¨Qñ¢}o9èÅýò±ã² @Ÿ 4~$áï™mxë^wàÜ¡vÌùGüãy#î>bÄ‚õŵs™2¦Ï`ÙH€F ¦”% E3I`h„"!?;\iNÖÞò#´”¾„Ÿ- ƒQËo¾ˆEwNò¬'c½æš·îËĦÚ9J2zo†65a–ù lxb+®(ÞÖ¤¥X‡ü.>A"LsMRc—*)_ä1’7bY 2XTâÓ0‰|é²ÄmKYŽuþr¿»ØZ‹wrŸAlŠ*Ò[`‰ U:©:óÒ¨7ˆ{ÁŠíV‹’K]|dH[»ÛbÜ‘þJË<Äýsý¶°Ë©È ¿º€¯„ö@:òT­]46g¤#ZÞ€µ¡/ä(‚ºm˯°{ÅKøÉâÙðkµã¸íHµ$i©r ¼|ÿÃß!22H5l`×~ù8°)Ù›H€H€H€H€H@!ÐÞ&áâ_äMO•|쎯ëc BX÷AÈÄ@)®ó]! ñD€‚û°®¶Cˆyj¾l#üå$Ï<Æ mÑ~x<¾§ è×È.ÈAbž\cÃú¥ó±¾c#qoN+Äã‘.¼c½-éjðvÇ:×½yÞ:lXµ ¹ñ0­Wò˜ç%Å"/ 0‰À÷ ˆ-ÔvT¤ÅÑßuEãµý©˜ºóÚO­V¯ÉûŸÃ’.LTÛCV!7Û‚E‰ŠHŸ›Kýg¿+j#q­ÈI0­Û#.£/m\¢´ \ŒÍñ‘ïò­à¸Ü;GuÀÄEÁ8’{ W Úµ;mD$@$@$@$@㘀ã _Ød‘½Ÿ½&aÂT%ûÒ\_G`0Pdǯ]'ç˜Rf^{uvnZ‡…?L›Q*§®NÀî¢SýÏ‘= ¾pÊþèÝ¢ÞG÷ÓÒ•LÑå%™¨¶éJz:´¶rà $ìiDa–P‹»8RóËñöæh·.Úùùy ÒEO÷ã)®æ,¨Éeäz±Ýœœ‹ª¦íˆèàFØšm8_œ ³{H]É‚Üâ*l×o‚ªš§K·¢vˆ|ô9¤jäáyë)gÕÄsªí;^-ñi( ô–€“ØpLìÝ$§ŠÙߎæ/D>ö» ¸Áâƒ~l€ñŠì½eÉv$@$0ØF‹ÞÉÐÊÁ^ùnÆ«)ÞïÛÍi8óæf„¹"‡£cƒ±O´v‡s„œÿx¿‚{±¾ÝÌÆ*       ž´]‘P[âÚôôÕv±É)Äf§>øÎ‘"f¥>¾Ù{bÈz  7 înC^ºxº\›cnª&¶«#JFªÜÓå"á5G%Ã+ –¯$|þ¶’.æÜ뮫lzºâu#¦/¢À>x¤9 Œ?Ôt¯âšu©Ñ5›s¦yCïÀEÕÑÔ¡–y%      ¯?“pþÍvœùØk‹%Lÿ®œ*Æ€Û~ã‹kæPd\v& ÐxS}µJ—@ÔSVœ ­ðÃÌ€ÎcŸØû¼;åÌMÓ1©s>!      è%¯þîÞô´ñ# ³DŠ˜¹úàÎ}L˜J‘½—ÙŒH€H (¸÷Ö€›ªSÚ›kpøµwQßò%Þ?ø2vX+\S˜aÝt/\éÝ<-       ñ@ Ý!áËÿqåc?ÐŽöV‘=Ö€ˆÍ>¸þ‡øN È>ÞúH$@ÃI€‚û0Ò·x±k“t˜DYˆî–d¬ ¥Ü®Ã" x%ÐzYÂ…BW>v‘.fb’ýŽ|_Ýa€Á@‘Ý+8>$ ܇k/õ›“ø¿é¦ ØœÁíòBt·Z°pSʶÅ0ʽ—(ÙŒH€H€H€H€H€H`ühº ¡¦@Ù?ÿ/ ×™ ˜#ò±ÇüÅó)°Ÿ7ž’ ÀÈ#`Ä1òÌ57TãÝ=Û›”£9Ÿ{²‡ëRÐh5=ä/ø¥¥¥˜3gNÏ]-®¿þz~ùï5-6$     ¸šìg$œµ*›žÖ“0óûò¦§>˜óøQd¿škÁ¹H€H`0|þùçè‹4={ölTUU!44t0¦²1(¸Úþ \’¹ËS¬ÎΖ¬rÜÙ¯dÁ= >>>½î_SSƒÉ“'÷ºýp4t4œÂ›…&ôiú––L»õûˆ¿-ä1(ìÕexëý³b¬i¸cu4BFÑïeìÕGa{ÿˆ·ÂÃöê²Ãxÿìeñzy¿Z._FË„k±8 ¡ƒÂq ƒØ+Åkpí·poL3˜ìK$@$@$@$0âHí.þÕ½¥¸>FŽd÷AÈ='Qdq‹FƒH€H BBBðÍ7ßôºÇ¥K—F…à>Š$²^³™ Õȼ{.Rl€9ÕŠ··­‚7ø‹W­\‚û@9qâĈÿâÓW›>}–ûõyïû0‚9E èßoú0Ϙjê@]å\ ùM™°7½ÓÖTÜŸ$^h˜QÚ(wwÕˆ'pÚú/°t²Ýk|,’œézvÁœš}ÛÂp~Â9ý†k LY¨§àÞó¢± Àˆ'ÐÖ,á‹w]"ûkíBTWò±÷E_Ì\!ò±ûPdñ‹HI€H —äàß¾£eOŽÞ‡?÷Å{¶íL éþ,k“â°½Q»RìôgÓ¥Z÷³‰î"K.~€rñ Ù7ö <0ÿÜrË-¸/ïþõÁ­ý&ÎvY7~:;§ÌÓÝôP´¥¯Epô.ÔõÐn(«5?¦Oôúo(çæØ$@$@$@$@$0X®\”ðéÞv”<àÀ þ¶© þ³€»ŠŒX]å‡ïdùbV´ÅöÁÎqH€H€†”€· ë!pÜ>içÉb*’ðÇ£ëÙ1%E5žOÑEßÖõOë5¶ ¢¾ö>OáÜèÆc/bþJ…9­¯&ßGsGy݉mZƒàP£Uizž¿^šæÝó r§ü\L2 ³<«aâá‚âÚW°LDí»ß¢VØëkQþúóˆMÜ¡hKDnÙO±q ߬á^1ÎO$@$@$@$0º\þTÂù7D>v«„º÷$̸CÙôtÑv_LaûèZMZK$@$ '@Á]Oc(ËÆ0ü<7éëóœ³$.š†KÖr¥à>V_úE$@$@$@$0¨ŽË©bÚqö`;."ò±ßmÀû`ù«‘Â’"û Âæ`$@$@ÃF€)e®"úð¸CªÉ=aŠe¦Mòƒß¤i˜¿T/¶¹å[ÆÏ!nX=”DŠñ^ '!sëVlÍÜ‹G3ŽÈÄê… a0,Äîîd?u§J°sS¢u"W ØˆvaôjlÚ¹'jÜíÔ‰ëŽ*ãfî.QÑ=´ b3Ñ…¢¿|F¯NÀ®CGѬvÐ_u8¼{«°C™GžK>W?¹Gk¼ö¡×u(9°S™ÃÕÞ æY° {‹Nt™¶¢¦Ìé³~®…X÷d&J*\V9pâÐnlÝô |">-øOdfnÅ®¢Jg›†SEصkvî:€êN& ®ÂÿuÑú9 ˆ^· ‡ŽvÎÏ5 v𾮕}ʋ׈½\ǵ »öÕžú¯›Z+:êʰS¼ç™™™b·âpeçwVkÌ öV líøkr^›Ó Û½|#þs`áÿñÅš:#¢þhļµ>Û‡€=‡$ F«K õ¼”Ÿj‘Ä’{=M–4©´ªiÀ6ÉãWUU xœÑ2@cE¶ÆÓ’UÞ­ÙåYf­­ÙbÒÊ2³¬òzgßÒ¬8çÞÖ+­À“¯{\³ç9®¾¿)­PjÕ[X_*Åuñ>¨ý²Š=ç’j‹{ìs†Tå1‘˜´éŒ”aöþî©s¥ZÏHRc©dîÂ&SF©Óz½¿¥:‡Z«¤,K÷sˆƒ%}ýX}b'¦íÏZUd«ëk‘Ê5C¥\Ín‹äá“Î=¹Xœá~‡âóOzÔöÇžþú¯ùaÎöàÙéýˆË•j;¾ Vó†H€H€H€H€‡@Ë¥v©ú@›ôÞºVißÔéЂéXªCª+mœ 8 À¸% kW£Aïd„»X©«zCðжƒh<ÅVX­(ׂÂbœ<_ã7cI¨ÈcÁcÈ(M*?5°Yµ>Ú|ŽÊ½Xš¤Æu–Ôl£`6â… ­[bŸÆ ]d·¶%lÈÉSÆ5Ç¥";7ɵP±e%Þ¬V3ƒ7ãÐ/—jQä&K*ò­…(,Ø´8÷Ï!’–'¡L PnƧ—k}„…ÈÚ_€âÂd§Å»'²¥ éåî{4`×Ïæ#Ŧ>2!5+W¼ƒ¹HÖù•ny %—g`ur2R“ã YaŽCjj2 ŸáÀí¯~ãQ;v¯Ÿ‹$«{ŽŒü”——"?Ãm›-ÝKf™Úî±úÂNù÷s­´‰ûXp47ˆ_DlÅr ¢q±áÚ(ýµ§¿þk‹‚úF¡®«ƒuïG|>ê÷<Œ þbF‹e    A$ðÍy §_jwF°¿:ËS;ÚqÉ€3âÇ÷ÃmÛ|1c å‡ADΡH€H€F2qûIdŒ;.Þ¹QñÅg°–¡/îZT°+‚;.«À#ú÷d®ý Éííad£”¯F¯{FA{Žk’rKku=k¥l]Ô{jÁy¥®©Ü©nÊ”øzw7}´´}/5Uèú¤Jg:ü ¢ñd¾¯öo,ÏÒžqR±Þ<©I²¦º£¶“­®ˆúV÷\–ì ·a¢äö×%ÞXîþ¥2‡gXõùb½ f©Øå°{,92¾—ì„ _+·í"¬_á®Dè›M&ɤ;å¿Wú3»Üâ ØÓ7ÿ5nj„ûùBI|ÛÑl4%ï÷Œ|÷XAÞ @ÿ |u²]úà7éð²Vé•k[$ÛªVéÌËmRóÅöþÊž$@$@$РѢwò³X)ã—€)µ{6ÄxDÿN[ìŠêŽÇƒw‡u€€ÈeZÌ7<·u7Ï߇‡—è7w Â/6>®5(ýø‚RÉçµÀõŠÏqN1/7XòàHKM‘åi¸yê$¥ÿtÜéŠ~òA„uøADÀüˆ5Žf¼¾=I{–V˜(½yðǪ'’µú¢ã.ûºìøWte­¥¾ Ï‘¨=H+þ˜Ã3¬:$jʳUëlÈ+TòÁkD¡×ìDÛÁX+ýÜË¶Š TèÎŽõÕ§×ûÕ}H€H€Æ6Y#âAã”@Âgww‘°W–àÅÌç’£Æ ÷ QW‘ïF1†aSArb·¸ªlHO§ëÎdŽÇ£ÇáÁ{£äaª%{_Äs)šøÛilýƒæ*ª®˜ïÀ,±Ô†þ Poú~ÕÏa‰Äì.þu1N™îüAçìùÊ”½fç²p kåÝQ|<Þ|ؼ •‡31?6ÅÙµ"=mÂ×O jO_ý÷nÿa¼WóbB¼9à½GWO¿©‘ðu•œ¥†‡L`ÆRþ‡%ß   ±M é Ÿ¿¥ˆì5âz]„7ÜkÀJ|15œûØ^}zG$@$0®Æ †ƒ†…€ù–ÃÎ;ˆÏ5E™˜½RS;šeŽ‹Ãżů¨…µ-§hqT#óÍOu³˜Ä&ž¦‹ÈsmÚªÕˆ°u-ÀÝÖ9‹Ön ý]dœ< Ó»®îSÍЭ•­MÂ”ïæ„ÅlDaÚa¬Übs6¨¹$7öÇÐÙãÝŽ®ŸÚ÷2ê‹Øu£^Õ\ø/ '··õªíxhSj„o‡3ƃßô‘H€H€H`lhüXBÍ›í8k•pñ/f®0`¶Ùÿ»/&Í¢È>¶WŸÞ‘ 6 îƒM”ãnŽJ<£ÛÍÉYxæ‘{~C0à/þÆTÆNÆüµ9ƒêg`X6ngº5çOã¯eG`ûãËØ¡æ.™¹W>ý&Zw­BõÁm:±ÝŒ¬ýψ1កY <%2¶Üâ™VÆÏϺÆüm¸²ÁwðÁ†º8ÄS£ú¨*êçÐræt˜BÜÚÏ~E¦ºÑå;wìød˜ÖJ5£¥\õÂõd˜í‰Ï.Ç®Gý°ÎϤ¬½-¿{µÍŸ×ÇpS¢V¼n€ßµÙÇÎjÓ  «M€*ÊÕ&ÎùF4GíiœV-ŒË…uûDE„!(PÛ媚sZ µe¿¯ŽšlÝ´ ›6e¢¤FHÝBè ‹Äª‡6`ûÁãhî@,^­ª©B8OÛÊ;š…u•eØ™p·È+® Ú€õH9T £ŸÖæ²¥,Ǻ‡Q×ì€Ã^ƒÃ;°4Eíg%*T[85÷»õˆ G+«a—sÎx=Œˆyb«VcMZêšCyÔ\S†'ï\êNu“¼Ëµæ}. íZå!îŸ3±sg&23ås'2å_"lÝ„u §`e’;¥9#ÑbsÒ¡µ§<úúĽ`ÕÖyk‘v¸F߀e    1Làë³>~± E1¼âÀéìvÌø®÷ž0âžã~X˜æ‹é‹(°áW€®‘ 3æpæàô#Œ@àblއˆ^–í²aýòùX߉‰‹‚q$ÿ$ö<ÞM«nªBbð|šË›oV iå-bƒTL¦ T¨ÔÎîfl2ÚYZpOàŠ·íXùâìòÈ[à¼ÿÁɦ]ŠÆkûS1ÿþtgó¼¤Xä%uÿ9,ñ&„‹Æ‹Äiή@QBDçŽò“U¨È‡i½"H«s˜Dà»§?ɨH‹Á€þ‚µ’C 9)b-º?â2 ñÒÆ%J£!°§ûÙ»®5ŠuÈͶ`Q¢ò%=6–ú=Þ×µëaXC$@$@$@$0J|õäÌÇ.ozÚxJQëÌ}Èw¾bÀ„ë(®’e¤™$@$@c„#ÜÇÈBÒ ‰º²—¢ßÄÉ®§" H§Ãkþ½ ÙñjjÏñY…¨o:ƒ4]uŹKJ#m^oãzŽ­-µùUd •_;:ˆíædŠ\îÑAJÿ°58_œíŽ`Öú‰‚h[p¦Uiº§§qÉ•½ØnNÎEUÓvDè»u1–çÄ®;­mÿת«w`¢Þ&¯“+-ñi(FßÂÑòŽQüt‹H€H€H€H€H€L é 5oH8kmÇ…w$.48ö9÷ù`ÊMØ ˜ Œ*£EïxXî¨ZK$@$@$@$@$@$@#—@ãiW»ÈÇ^LÂ̲È/àL‘}ä®-#  …w¾ $@$@$@$@$@$@$0Lä,¯ÿ"‹ì>{­W¾fÿÈ€ðd„Ä`œL‘}˜–†Ó’ @¿Ppï6v"      þhûÿÙ»ø¨ê;ÿÿïs΄$@€ w"ˆ(AAEEÔ€µ^Vðgm×µl+½ ÿþúóÒmeñ·ÚJ­(½(lÛU¶J·R»VÛZµµ ­ô×êZì¼ ˆ r¿äBfÎùÏœ™L ¹Ëœ™×<iΜ9s.Ïï©dÞùäó­ö´su²o}ÆU¤‡ Ù¯±uÞ¿9*¾Ø’í²·M–w!€ Ðõî]?œ € € €@† Ôì7ýØŸÚÅøß Æ“žNûm$Þ›=Ã/ŸËC@ kܳf¨¹P@@@Î8¼ÅÓ¶_¹fÒSO{ÿä©hJ0éé¤uB{gŽÇB@ ³Ü;Kšã € € €d¼ÀþÿINzêêðûÒ [õ9[—üÒRN/BöŒ¿¸@@¬ pÏú[@@@¶ ¸µžv¯ ú±ô_®@Â(@àÆQãœ@@@ºL ¶ÂÓŽßz¦UŒ«m¿öL{²Ï´5õiGýεdY„ì]68@. pïâàð € € €é/P¹Ýôc7áúV²ïú½§¾“‚~ì¥÷8*8…€=ýG3D@ sÜ;Ç™£ € € €„LààÛAÀîOzzð /Þ"føõ¶.ü‰¥Ü~„ì!NN@N pïf‚ € € îžëiÏŸSýØkIC®¶tÆ?Ût¹¥H>!{º!ç‡ €@W ¸wõp|@@@.ˆVyÚùbPɾu¥§n}L?ö¶.xÌQÑÓÝ&dï²ÁáÀ €„P€À=„ƒÆ)#€ € €´] z¯§íÏ“žîxÁSŸ3‚~ì—­vâËmß3ïD@l pÏö;€ëG@@²@ b“©b_éšIO=í{ÍSñÅAÈ~Þ墊= n.@N pïf‚ € € ЙžçiÿÚ ûÖ®Ž|dú±_eiÌ—l ¾ÒRN!{gŽÇB@ [ܳe¤¹N@@@ ÃbG=íþ½ß*&èÉn9A?ö‰ßs4àRKv„=Ão.@. pïò!à@@@Ú*pô éÇþ|°o{ÎSÏ‘&dŸiëÒ•õHÀÞVWÞ‡ €m po›ïB@@è"Ê­A?v¿’}ÏOýÏú±Ÿu¿£ž%„ì]4,@Œ;· € € €@Ú ”¯ªØýIO½ãiÐå–FβuÑZÊ-$dOûä@È÷,h.@@“€3ÕëôCvÓ“ýW±*Ó*æK¥ß°5ð2KN.!{˜Æ“sE@ [ܳe¤¹N@@@ Í¢G<íxÁŸôÔÕ¶_{Êí/ »ÖÖ”Ÿ:ñ¶1–EÈžæCÈé!€ õîY € € €t@õnSÅþ« ]ÌÎUž 'ýØÏ¼ÓQ¯1ì]72@Ú"@àÞ5Þƒ € € ÐfCï¦ú±ïÿ«§ÓüÝÖä·”?€½Í°¼@º\€À½Ë‡€@@@2[Àó<í{ÕoíÕ»¤!giìWl þ¸¥HBö̾¸:@²G€À={Æš+E@@:M VãiçK~Àn¾Vºròͤ§¦Šý¼:*šjÉvÙ;m08 €tš{§Qs @@@ ³jÊ=íþƒ§-?sµýyO£ƒIO§ý6¢ÂRöÌ}®@|wî@@@6 Ü`ZÅüÒ•?áéÞ?yê{Ž¥á×[šøG=†²·–7"€ €@(ÜC9lœ4 € € Ð5µ¦Š}§íÏyúÐí–# œniô[—® {׌ GE@t pO—‘à<@@@4¨xߨM›²ïú½§>¦=Ì«,]ºÒQ¿sì4=kN @è|÷Î7çˆ € € €@Z D+=í1íaü€Ýo«–L³4âF[S~f©[oZŤõrr € Ðeî]FÏ@@@ô¨Üêi› ØýJö/xê5V|• ØŸpÔÿK–EÈž>£Å™ € €@º ¸§ëÈp^ € € €@ ÄjÌ$§¯¦ªØkö™*ö2KCgØ:ÿQK¹ýØ;Ÿ]#€ €@† ¸gèÀrY € € €À±Õ»SUì~5{ÏAû䥎Š/6Uì6!û±f„€½Œl‚ €d´{F/‡ € €'#P½ÛT±¯ ªØ·þÊSn?i°i3a­ÓM{!ûÉøò^@@ ÓÜ3mD¹@@h³€çy*ÿ›´ÝLvºý9SÑþW/>Éé«,•Þã¨çHö6ãòF@@ ܳ`¹D@@hZ ¦ÜÓ®Õ‰*ö•žœ¼ Š}ܶ]n™ç„ìMëñ  € €@}÷ú,#€ € €@V|ËÓ¶DûÞW<õ;Ï2­b,]¾ÆQ¯Óسâ&à"@@ pïTv‰ € €é%P[aªØÿLxºu…+ÙÒ Yó%[—¬´”Ó“=½FŒ³A@Â)@àÎqã¬@@@ Š÷RUì»_öTxVPÅ~é¯"ê;‘€½>^F@hƒ{Ðx  € €¤Ÿ@´ÊÓž5~ÈîɯbUI/³4ò3¶.zÒR·Þ„ìé7jœ € Yî™5ž\  € €Y%päÃTûΗ<õ>=¨b¿ègŽúM¶dY„ìYuCp± € €@ ¸wñpx@@h¹@쨧½JU±×ì5UìÓ- »ÎÖùYÊëOÀÞrM¶D@ho÷öe € € ЮG>ò´ówA%ûŽßzê9R|°Zm@IDAT•­Éÿî¨ø"SÅn²·+8;C@h³{›éx# € €t„€õ´ï¿ƒ*öíϹªØdªØËüV1¶ÎýWKùƒØ;Â}"€ €œ¼ûɲ@@8Iª¦ŠýÅT?ö¼Ò°Ÿ½ÈÑ€K-ÙBö“$æí € € @àÞ È@@ x®§ý¯{Úþ\PÉ~ðMOÅSƒ OϾßQáì Åx† € ÷0Œçˆ € €@Ôì3Uì/UìÛ~í)§WPÅ>þn;>ñ©“KÈžÃÌ% € €Y-@àžÕÃÏÅ#€ € ÐqžçéÀz™*vWÛL%ûþµžú_`™V1–Æÿ‹£‚S Ø;NŸ=#€ €t…{W¨sL@@2TàèAO»Vû­b\mý•''Wt¹¥Ó¿bÇ¿Gº²gèÐsY € €F€ÀÛ@@NJàà† `÷«Ø÷þÉSßs‚*öi¿uTXJÀ~R¸¼@@ Tî¡.N@@®ˆ1Uì&<ݺҕ ªØGϱuÉ/-Ó›½ëG‰3@@è ÷®Pç˜ € €„L âý Š}»©b÷Ãö>ãƒ*ö‹é¨ß9vÈ®†ÓE@@ cÜ;Æ•½"€ € jXµ§ÝLU±×”~ÌÒˆm]¸ÜRn_ªØC=Àœ< € €@‡¸w+;E@@ |‡·xÚñBPɾãEO½ÆHƒ¯2ûOõ?ß’e²‡oT9c@@Î pïLmŽ… € €@ ¸µžöü9¨bßþœ«#™*ö閆ΰ5y©¥¼bö4.N@@ î!$N@@ö¨Üžªbßþ[O=†Uìç,qT4Õ’í²·—5ûA@È>÷ÖŒy´ZÕш"ªREmŽ òZón¶E@@ Óܘ§ý¯yÚf&;õ'<=ô®§—Z¦UŒ¥IßsÔ}({§ D@ÈX÷ ížõ¿Ñƒ‹iáòÕfëR••®Óêuf±l––Ýó Ý4uT ö’ؤzƒÝú-mêÞ_Ý›xWeå^ ýØÿÕ]×mb V#€ € д@õSÅþ» »²çöªØÏºÏV± Ûn„ìMëñ  € €m°<óhûÛ3ÿž¸]§ú¡^hÙüzî¾jQ½{ùMë{±üèþD²Åkµê–‰'Ú䄯Y–¥-[¶¨¤¤ä„Ûñ" € €@øüéËÿ*SÅîÆ«ØË×y*¾(¨bz­ž# ØÃ?Ê\ € ÝaÉ;©p?Á}Ýôtð½ì6=õ/×iÀÑôˇ?­‡Vo^½p¦\¼M÷]1ø{ ^ªØúV]Ø^ZZÚøöëÖiHnN㯱@@#PSîi×K~«WÛžõ”ÓSôq[gÜiÇ'>ä²s£ € € ÐÙî'ÿó?L½:g™ö?r“ k¦^ñ)ÝðÈl?wy|ÍÂyËuûw¨(õŽF—*öìN¬Ÿ©¥|F“ ÝŒ• € €'pà `÷ÛÄì3}ÙûOªØÇ}ÕQïqìDZ@@N po¼\]lü2Kk§Âöà-Mþìše÷xä¾îOz¿B*j&@ß·qmðöÒIÖ̶Mž/ € €d…@m…©b_Lxºí×®d2õÁ·tÚ-¶]n™ªvBö¬¸¸H@@и75Tïê™dÞ^v‘F7Ö =o´¦Ï”–'ZË4ߦZï¼¾98âÈa*nêØ¬G@ÈZCï“n3Uì{þè©ïÄ ŠýÒ_GÔ÷,ö¬½1¸p@@P¸75Lô//Є û•?r´ Ó+þ¦ga»¿›Ú¦öU·¾Vûv­ žìÖ3?þ¦V<³VÛ2ëziôùÓ4ë3ÿ ©c›kLS·C@@B.­ò´û‰*ö_¹ŠU™^ì¦z}ÔçlMý¹¥n}ÙC>Äœ> € €@ XžydÑõ¶ã¥îÑo¾L³—&ô™Ëtè™›tÂ.1Õëõù¥A šœÉÌ+ôø]3N¼¯¼ß),³ö6s¼Œ €d¤Àá-©*v¿eLï3, ¹*¨dïw®ÿY.#/œ‹B@@ aÉ;©poÃWoU f¯…É–3fËîÿDóym¥L›÷ø£Ôü¯ÕϺm¾Æô­Òê»Rrw+îž©‹ô’þv×´`cþ@@ Ô±£A{²Ó­¦Š½f¯©bÿ˜¥’OÙºàÇ–òúSÅêæä@@HPáÞš[¡z»V.¹G3ç-mð®Å/mÑ-ÓJ¬kìIÅë‹ÔkҼख़èíÇïÐØº’ø ­ZòUM¿5µï§¶Ôêú’¶ýN$,¿ñỉu € €@&ùÈÓŽßú­b\íü§ž£dªØm 6•ìý/°d;„ì™0Î\ € €@ç„%ïl[šÛ9†it” ½þô¿iö'çÅ«ÒëN¬l¾^^~·¦nlFÕº­ê Æ}Q[Þû„ª*k5àô±*l _ i·ü@O½ùŠ>™hSó»ÿ÷ž ÜÇÖ½¿µ O<ñ„ú÷ïßâ·Íž=[‘Hƒ“jñ{Ù@Èv7êiï+~«˜ d?¼Y8Ýocë¼XÊDÀží÷× € X¶l™¢ÑhjE†,‘®67Ñ´èòš—ì÷ß~¦~é~}~ÚXµ 0¯P%£ OpĈ>þå/IKçÆ·Ùµ·òÛ6ÿÒ+¯¼¢ž={6¿ab‹Ï~ö³-Þ– @@¤ª¦Šý… ûößxÊT±Oúž£â©¦Š=‡û@@ÆÖ¬Y£šššÆ^ õºVåÅ¡¾Ò6|¹~<»aØ>ÙËúÚMSu¢Ø¼éCEÍomüW#¦’¼ñ­rrr¡ k—,Y¢’’æ[Ý´a×¼@ÈJÏõ´ï/É*vO‡ÞöT|I0áéY8êYBÀž•7 € ÐjÇ{¬Uïñ»y„áÑDì†Sïøs\ÿã[4{yò8sôò–ÅšZÒ²ö1Éw¥¾WèÇ×öÒìþšùÚâݧƢð-¯ü¹î-úw¯[f@@ kjö™*vÓƒ}»éžʹ‹éÖG¦»­ l (³ää²wÍÈpT@@ÒO€À½©1‰nÒcuiûL½¼ÿMmiY{u…¶ïÚ¯Z³ï^JTx\F¿PO®¹]wL-jxôò5úçÙ©IS?6åÔ†¯ó @@ Ã<ÏSùߨý~ìûÿê©hJPÅ~æ]Žz&`ïðAà € €„T€À½‰‹îÞ¨Uõ^ûýãKôçêêzk.ÖÔëÆ¯Ý¤Q&\_¿t¦Jo š¾?ðÊ~Ý1ÙOê 4uÖiE¨Ï»¸XzêÍþøæKÛÖýZ·Nú¤âðþ®gýTWÂð4Tæ € Ð1GzÚùR¢ŠýYOv7SÅ~¥­qwØx™¥HwBöŽ‘g¯ € €d–‰nãYµó]­«{m…î¾µ. ¯[Ûp¡L—ßîÊR÷R^NÝ¢F]¯Ï\ªä®æ}ò|ÍK½\oiŽ^Yr£Ž+Œ¯·‹ € €''pð-Ï´ˆqM%»§½¯xêwžeZÅXš~›£>g°Ÿœ.ïF@@ ;Ü›÷¨ß¦U!Jfë9¹©Þë §@-Ò-Ïìט% tå­5º÷²Û–iÙÂ›ÔæVñî•• € €Ñ#¦Š}ubÂÓg]¹æç½ÁWXó%[—ÄLzZx¶äÿÌÄ@@Ò_ ,y'î]u/åjìøÉÛUÇç¸ € €@ Ī=í~ÙÙÍ—©b¯= ú¸¥‘Ÿ±5å K¹} Ø3pع$@@ÒF€À=m†‚A@h‹ÀáL›˜çƒ^ì;Wyê=6¨bŸò¸ïËnÙ„ìmqå= € € Ðz÷Ö›ñ@@.pk=íùAûv3éiå6SÅþ1Kî³5ùß-å `ïÂááÐ € €dµ{V? €„C r»§¿ ú±ïø§žfššÁ¦û¹?tTt¡%;BÈŽ‘ä,@@Èl÷Ì_®@¥€ó´ïÕT{Å{ÒÀi~«[ç!{Ûuy' € €tµ{WÇG@2\ |_Åîj›©d÷+Úû_`™V1–ÎøgG½Ç°gøðsy € €d•{V 7‹ €t¼@íaO;_L…ì2™ú+-þ[/³”Ó“½ãG# € € €@W¸w…:ÇD@2Làà†TÀ¾÷ÏžúN ªØËžsTXJÀžaÃÍå € € €@îMÀ°@@ ih•§]«“žºŠ‘›*öÑsl]ü´¥n}Ù›Öã@@ÈT÷LY® @hgÛÍd§Ïº¦» Û_öÔçÌ Š}êÏxE»e²·39»C@@ ¸‡lÀ8]@@ ³Ê×{zû;1mûµ§A·4âF[ü‡¥¼"öÎ އ € €é-@àžÞãÃÙ!€ €]&°ÿ¯žÞZÓŽ<¾ÙÖÌM­bºl480 € €„A€À= £Ä9"€ €(°÷¿]½õ€«Ýk<ù’­ÉKåPÍÞ‰CÀ¡@@@ ¤î!8N@ho½¯ºZÿMWû×z:íÿغðqG‘îíííÌþ@@@ sÜ3wl¹2@@ E»×¸úÛ]®*6y{«­‹Ÿvää´·@@@zîõ0XD@²I`çKAÐ^µÓÓé·Û:õf´w#hϦ{€kE@@ö po_Oö† €¤µ€çyÚþ¼§uw»ª=d‚ö²5êóŽìA{Z'‡ € €¡ pÅ0q’ € €ÀÉ x®§­+MÐþõ˜Ü¨4Nù¬%Ë&h?9YÞ € €¤ÜS,!€ €'àÆ<}ô ´#&'×íw8q£ Ú-‚öŒl.@@º\€À½Ë‡€@@Ú_À­õôÁ“&h¿'¦n…–&,p4üz»ýÄ@@@êÜë(X@@Â/;êióãžÞøfL¹E–&}×ÑÐíáY®@@ @à†Qâ@@f¢UžÞÿ±«7¾åªG‰¥ ~ìhÀ¥íͰñ2 € € ЮîíÊÉÎ@@ΈñôÞ\½¹ÐU¯Ó-Mý¹£¢ Ú;w8 € € ¸s' € €!¨=äiã#®ÞZäªï$K—þÚQ¿sÚC8”œ2 € €d{ &—‚ €™/PSîéݸÚð «¢)–¦¿Qá+ó/œ+D@@B @à‚Aâ@@ê=žÞùW7þ5pº¥Ë×DÔ{A;w € € Nîé4œ  € pŒ@ÕO»Úø°«ÁWYºâ¿#ê5š ý&ž"€ € €i!@àžÃÀI € € Ž|d‚vÓ6æ½G] ¿ÎÒUÿQÏí •x† € €¤—{zgƒ €Y.px³§·¾ãjórW#n°uÍ›uJОå·— € €! pÉ@qš € Ù‡Þ5Aû·cúð)O#ÿÑÖŒw"ÊHО٣ÎÕ!€ € €@¦ ¸gÚˆr= € *oš }QL[Wzõ9´¿ç(¯?A{¨‘“E@@îÜ  € €@ìÿ´?ÓŽ<¾ÙÖÌ÷å´wÁPpH@@@ ÝÜÛ’!€ €Í ìýoWoÞïjÏ=ù’­ÉKå´7/Ç € € ÕG=8ž+'pÏXq¦ € b½¯ºZÿMWû×z:íÿØšò¸£H‚ö)§Ž € €mð«3Küeù2ëz›°Ý6oxò7Žî¡&N@Â&°ó¥ h¯Úîéô¯Ø:õf´w#hÛ8r¾ € €d«ÀÑÚ âܯ:OU¡¿ì‡éMØž×-Íý ½0–ûù˜ÁApÞ§‡mÖ!{ÏüÌýlDàž­ÿáº@@ C¶=çjÝ×]Õ4Aû?ÙõyGv$s˜ìDvŠ € €"PYcBôxå¹ Î'Z¸øzb¹~°^Y#õÌBôdµ¹_…î//J®·ãUè~ž›ÃçÐÜ;äÖe§ € M~­+<´Çäšþ‚ã¾êhäg,Ù?pfÓ}Àµ"€ € ÐÙ®iåRQåW7^y^žXŸ Ùc¦+‹ß¢Å¯<¯_…>°ÐÒØ¡ÁºÞ¦Kš Ëýö-ñÊsÓÚ%ÞÂ¥^°î¯?l*Ö»çúÕæ‰ ݯ87Ë~åùà¾~K½é‡oïâoKÁO£è]´’À½‹à9, €„O f~HÞü¸§7î)·¿¥Ißu4tA{øF’3F@@àä*ª•è‰àÜoë’¬<¯¿\n^?jZOö2ýÐý°¼ÐçÁÄ¢RßK§ L¶wIëR7æ:ùê¢=¸w<‡E@ðĪ=mZæêo¹êQbéüG œFОäL@@h^ fú¡ªôCs™–.U¡éA˜î·f *ÐãṠу0]ÚÏÒ™%É`=¢›V.¶M%zó£þ-ÜÃ?†\ €t@ÔüýÞ\½y¿«Þ§[ºèIGÅSÚ;ˆ›Ý"€ € ÐîGkMz"D÷Û·$Ãòx+—x°nv½Y>dZ¹äæ!ú±“ŠŽœèî·r‰·w‘ ò ÐÛ}À2`‡î0ˆ\ €´¯@í!OqõÖ"W}'Yºt¥£~ç´·¯2{C@@ m•5A@ËýåxUº Îëë•5ROÓÊ%Þï<ÞóÜTœûßMEúð¢`}ïDˆî‡ìyÝÑÛ6*¼+)@àž”à; €d½@M¹§wàjÃ®Š¦Xšö»ˆúžÅÜYc€ € Сž´rñ«Ï«=“Áºä8üLß¡Èθ7àà  €d£@õ^Oï,qõοº8ÝÒÇ^ލÏüPž÷׌ € Ð>ÑXbBÑ•ç©@=hí´x9h¶‰8‰V.¦]‹_}¯B7Ë#­\ M€î¯÷Cö^&l·üê<HC÷4N @:G j§§ ¹Úø°«!W[ºâÕˆzá÷ÎÑç( € €a¨>š ÑNL*êW¥7²|ØôCïž›¬BOT'ZºŒ– ×M?t³ÎŸt´G?‡‡í~à| poÜ…µ € Á•[=½ý=Wï=êjøu–®úkD=Gò~9—† € ЄÀ᪆‰Ö¯4Tâ € €@˜bn½~èTžÇÃs³ÞÓý/ÿï‡nòB¿eK<4—†ö³tfI²2Ý´x1ëýV.ŽÍÏÏÿ‹@ãî»°@2HàÐF´/Šéç<üG[3Þ‰( 2hˆ¹@@ £ŽF­\=ЃÊóÔò³¾ÜŸTÔè‡*ýÊòdµy˜•çÒèAApÞ§Gª ½ ŸŸ‹3úæáâ:]€À½ÓÉ9  €t–ÀÁ·<½ù@L[Wz:õó&hßè(¯ˆåÏq@@š¨¬1y<@O„å‰å&8/?&X¯¬‘zú­\L¯ó`2ÑÄD¢¦"}xQ°ÞÑ“Áz^7~æmZžWèX÷Žõeï € Ðå3Aûý1íxÁÓè›mÍ|ßQn!:º`(8$ € 5žç©ÂLZ?,¯_y~ìr4Lê‡è}Lpž Ëô±4fH²½K¬ûÛD~žÍ𛉠µ{¨‡“G@úû^sõÆBW{Öxó¿mM~ÄQN/>˜Ô7b@@ å±Xª×yªò,ÙÞ%Ñݬï‘ÇÏ Çzól p϶çz@È Ýk\­ûº«Cïz{»­©O™ IŸ2h„¹@@ e‡«R•èå‰ýØŠô ¥‹TS+õ2ýÐýÊóBS…´t‘úX:e ¿ÎÍôC÷ƒuóÕ-‡½e£ÀV à ¸s € €@èv¼h*Ú¿áªr«§ÓÿÉÖ©7;r˜*tãÈ #€ €M ¸®§C¦EKS•çLEz*X—Lûô 87ay¡©B‡èfyh?Kg OëÁz?hwlBô¦ìY''@à~r~¼@:Q`Ûs¦¢ÝíGË=ûª­QŸwdGø°Ô‰CÀ¡@@“ðÃô}ÒÖ}ž6ï”öòÁz¢º Óý°½›I­’‰&'õÃòSŒÖU¡›`½€¿r<éqa Ð>îíãÈ^@@ ƒ©jõóǘpýB[#Š¥ü\ #š2e=dŸÀI$âÕú`ýkú«¯?¬Z­WV¬ÖºãüJU6ë|]qÑ%ºä’K5aì`å· +@@ ›bÕž6-sõÆ}®z ·tþ œNОÍ÷׎ €+P~¸aµú6¿·º©\ß±ßôN7ýÓý*õ!¦b}x±¥ O÷û«[Ü—P½cG…½#€@¦Xf"2¯UÝ£U?X÷~ún­nÕýgjñSó5ûúÉ*hõ{yCkü?»ß²e‹JJJZó6¶E@ Ó¢G<½÷#WoÞ覆ù WºÀVñEí6@2Z ªÆÓÎÇW«`&,õ“ ¿§º¬§¾[*)’ºå¬gôÁÅ!b°ä­ Ü7­zD_œ>·ñ ½´L3K‡h@÷îña«¬Ü¥më6kõºãëÞ¥2=üüõù+Æê$JìC|{tü©‡åìx Ž€ nµžÞý7WoÇU߉AÐÞÿ<‚öt'Î@Ò_Àu=í«HöUoøÝŸÈ´¿©v úª§¾`©°'¡zú.gˆÇ „%ïlQÞ]½çu-ùÊ$Í[^ï2Ëæhñþ—Ê&—jÄb4ѯ=Z]¡ÝÛ¶hÝ««õÓݪåñ²øÕš{åéš[6_¯,›¯É%Իדe@Œ¨)7Aû\mxÐUÑKÓ~Qß³ù°—‘ƒÍE!€ €@» øÕêu“”Æ'- Âõ÷˜Št“ìÔ¯R?s¸ÿÜÖ0SÁqøY«]‚!€-h¾Â½úu]›?I+;›5™n¿y¦&–¶`÷Ço²gÓýìûßÕ­%öXºXûÿv‹Ú¶·ã÷Ïš@ ,¿ña¼@2_ z¯§w–¸zç_]Ó›ÝT´ßã¨Ï|øËü‘ç @@ 5ј§=V©oÝ+mÙí©²F*îªRªÖ- äósUkœÙÂ+–¼³ù ÷HoóÇaÁOõÝ/J£ ›ˉ†­hÔTÝòàT͹s½þóÁ[5û•\ÚÊœŒ×@©@ÕNOrµñaWC®¶tÅ«õÃÂ'§ €í$PQÙxµº_Á^—ªVbú«ŸsªyÞÏŽO`jÛüÕNCÀn@h¾Â½CÏÎ;J ,¿ñé¨ëg¿ €]'P¹ÕÓ[ßuµé1Wï³tæ]Ž Náb×GF@Î8Zëi—?ai½ö/[Í_ým1–Æ\i@ŸFªÕ‹¥ü\~fêì±âx °ä'W®~‚ñˆV”«¼:ªH$O……ôh?/!€ ‡·˜ ýÛ®6/w5â[÷FD=†ñ¡1#—‹@@Fö›ÉàýÊômñ`=U¹¾³\êÓÓ¯N·âýÕG[ºhœY6Ïõåç£F1Y‰dˆÀIîzý7¿ÐÓÿõgM¼ý;º~¬¬Gõú_Ó¤O?”"*£çŸ¼_WŒ¥S{ …%@2CàÐF´/Šéç<üG[36D”?ˆ’™1º\ €ø–î0zª'«Ö=}`&,õCû¥ªÕËÆû¡º­áEf2Ó~ „ø_@ »ÚÞR&ú]>BóV`‹×î×- µgÍ"_<¯QÅeëé¦ñT»7ŠÓÎ+Ãò'í|Ùì@ ¾åéÍbÚºÒÓ©Ÿ·5nž­¼">Xvâp(@h'×õ´¯Â„é¦í‹_±^ÿû^³¾¯TµzýªõžüìÓNCÀn@fÂ’w¶¹ÂýõÞZ¶ûÁÔ§Õzvi*l/›ó€®í÷'ݺpElö­Oh檛E{³÷ € ¶å3Aû˜v¼àiô\[379ÊåO£Óv¼81@H Tšjõ­{SUêÉpý#³.7§~µº™‡¦Ä¯\·5¬¿qÖSŠ,!€œH m{tƒ¹5Ñ¥9zeÛbMl¦Ò®xUÏ,O®ì=ùÈ2E¥³^«‹ýíW?¯Í&p§ÈýDcÂk €¤¥À¾¿¸zã>×ü5›§1ÿÛÖy8êÖ›Ÿi9Xœ €Y,yÚ}°a•º¬¸ÛÓ‘šÄ„¥‰ÞêÍÄî3γUb&,-Èççš,¾m¸t@ ÝÚ¸WUjWâæ¿ôõ l7Ï+6¾ªºþ 3âa»¿Ù¹—_kþ×e³Þß]­‰&œç €¡Øó§ hßÿO§ÝbëŸ8ÊáϧC1vœ$ €™,p¨2U­Þ ¿º × òÕêñ`ÝÒy£ƒjõÁ}%Û&XÏäû‚kCºZ m»ù3«d‘zIŸä’´ñ«ê®ç’É#ê–óFLÒ,ól¹Öéý½UÒ(÷:@HSÝk\­ÿ¦«ƒozû[SŸr¡ò+MG‹ÓB@ 3ŽÖzÚyàØju3aén)æJ ý`ÝLTjÚ¾\0ÖÿLXÚ=—P=3ï® H¶îæºÌœ!ÁÄïÁ£\/>“¬o¿MKR¡zõ–µ&l÷¥;Ðüš™ €¤­ÀŽMÐþ WG>ò4î«¶.ý•#‡­i;^œ €™ °¿¢þd¥©Êõ]åRaO¿:Ý„éý¤SZºø ?X·4 äO Ç@thcàžSWá>wѺfÙͪzîÛ©ITçLÑ©u{®Ð¯|0qÍ#5 o*ˆO'Î@lØöœ ÚïqU³Ïí_³5êsŽì>Äfû}Áõ#€ Ð^UfÂÒ&@ߺ·a¸þáɱ¥A¦ÝKP­niZ©¿T«wãç‘ööƒ Ð u±x«Ž•7^s”iùÝ«MŸ˜¹b¾ê?üý%Š(ªõ+Õ÷š«¥f³ø£lšNIu ©ÿ–@@  <Ï|à]á™ =¦Xµ4îG#?cÉvÚ»`88$ €¡p]O{™PÝüëÞ†ß÷™?•/ꕪV7ÜÒågÕêý{ñ³GèŸ @ˆ ´-p7oúµjþÓ§káºc$Ëkî´"³²Bª¶›5ËÏ®›Hõ˜wñ@:QÀ3†?|Úí b²LEÙ¸v4âË,óa·‡C!€ Z#Õ «Ô·™‰Jã•ë&dÏ5­gýžêCüÞêæ«tDP­î¯‹ðKýÐŽ9'Ž Ð2îÑjSò–—gªÖë=òÆê¾µ»uÙò‡µì™µñžî&}J_Ÿãq¡zé¬úþ½_ÓÔz}Ýëí‰E@è$7êiËÏ<½qoLÓµôކ}Âíô?í¤à0 €„G ó´ÛŸ°´Aµºù¥½is¤FñêÉÞêGYšqž­SWÐ_à‡g”9S@ö°ÌŸ’{Ííôõ%×jÒ­Ò‚‡géêË.Té¨Á Ã÷&v­®PEmŽ èÛÞ‘ªÍ/3"yU•W(§ Pf±]~p²eË•””´ËþØ  €@¸bG=m~Üíߊ)o€¥3çÛ:Ô¶ó@@¬8xÄS¼B=¬§*×·í7áy¾_žlã·ñŸ[ñ~ë—õ÷ €@g „%ïla¼k°iµîž»BwÇËtÛŸÑuW–é¬ÓKTÐÄ^"y*$k?þ¾‹n×o}T‹~x·Vû-yÊÊ oÐè~Ö‚eúÆm7i½îwc  €@«bæÏ½7-sõÆ}®z–X:_AÐÞjHÞ€ €@ÈŽÖ&&,=¦Zý#Ó&3–&CuiÊé~+[ÃLµz÷\ªÕC>ôœ> €@' ´¨Â½|Ó=þèr=ºp©ŽmÙnþ]sæ^ÿkæåšCŸ2{ª¦»õÇ ó;6ÿᙺÓ?÷ÜuËõ†œ9¡îi¯º%@h(PµËÓ†]m|ØÕ«-}üÏõ:Þ •x† €@zÄbžv8¶ZÝïµ.®–ú–&z«O:ÕÒLÓn¸ Ú ºóo{zŒ g €@ËÚ-p¯ȼÂ]P6Sc/¸ZwÞwXm\«§—ýPÏö¬üúfÙò¸¿ÿ-Ø1Aû˜ަT¡‘Ç[x©n­ùëA €4¨Üæé-ÓŸ}Óc®†_géʵŒâÃx$ž € ÐEÔŸ¬4Ôýjõ¦ßzù0\¿Zý|ó‹ò¡ý­xØîØü[ÞECÆa@hw“ Ü+ôúo~¡§ÿëÏšxûwtýX3å¹¢zý‰¯iÒ§ëMZ:GÏ?ù Ý76[kÛƒqË+™¦»œÖä –¿þcMš»¼îõ¿/]·Ì €@v þÀí‹\m^îjÄ ¶þn}D=†óá<»ï ®@ +ŽÖš½üøjõLµz4–˜°ÔT«1êóÛÀØf¦æêžË¿Û]1^@Îh{àý@‹.¡yAÇ-¾ùþø¹ïYó½†a»¿vÝR]yúR-[wH7÷Cy ªõê tþ§¦VÏú©nÄ*åÁ ¥ïyzó˜>ø¹§S>këš·#ê>˜ìYz;pÙ €(°ïPÐSÝoû’ì©îß}PêÛ3è¥î÷T?Õü»|éø ZÝŸÈÔï/Ë@²W Íûë?¼µ.l÷ùrãS¡VëÙ¥óê4Ëæ< kûýI·.\_7ûÖ'4sÕÍYÛý¦ÞÂö×WêžÙ3µt]½•3k˲ů&ê™°ˆd™ÀÁ·MÐ~L[Wx:õ ¶fnt”WÌø,» ¸\@¨ª1“”šv/[Í$äÛ’—še¿ZݱÕê¦í‹ß_ý²³ü>ëv¼-Lnÿ&wðа{@B+жÀ=ºAÜ„èÒ½²m±&Γ*^Õ3ÉŽ(eèÉGîùË9=ðZ]ìo¿úym®0;I²ª·¿®%÷ÌÖ¼I»tÛ²W´ð¦É2š'ýøâ¿¨îÝ»·x?O>ù¤rss[¼="€´¿@ù:´ßÓŽ<žk‚ö÷åöåC}ûK³G@lp]O{LUzý*õdÕúþÃÒS•î÷R÷«ÕÇ—˜ùQ&Õê} ø÷7[î®@ kn¸áUW›ÙÃ3ìѶÀ½ªR»ó_úz¶›ç_U] ÿ…ñ°ÝßìÜ˯5ÿ뿲Yïï®ÖÄ‚öˆ“ý=‡óñÁªE1=õ—þU̼m™î¿s–ƵmH“¸úê«UTäÿÊ£eH¤ýŽÝ²#² €@R`ß_\½qŸ«Ý/{:í˶Î{ÄQ·Þ|ÐOúð@æW5¬RßêW¬'*×s»ùÕéÉ`ÝÒY§ÕêƒûJ9þ½mΖ×@èë®»NÑh´Å»^±"™<·ø-]²aÛÖ3ÃzâtKú$—¤\Uw—LQ·œ7b’f™g˵Nïï­’Feoà^ñú# Ãö²ùzùß¿¦©£ ë¼ÚkáÚk¯UIII{íŽý €t€Àž?› ý[®ö½æiìm¶.ü‰£œž|ðïjv‰ ±XbÂRÓK=Y¥î‡ê~¸~ÄÈ 2«’Õê玶tíùfÂR3yi¯îüÛšÃÏ% €d˜À§>õ©V]ѧ?ýéVmßU·-p7g[‘Ü´‚¹plÐc}€ Û›`½ãG‡# € €À‰Ú¸çÔU¸Ï]ô„®Yv³ªžûvjÕ9StjÝž+ôëLœÃH è› âOtb™øÚ¦ß>’øÅƒTöÀ+zäæÉ™x™\ €À v¼èjý=®Ž|èiÜWm]ú+GN.áÀ Èx @ CŽF=m÷Û¾$ªÕ·ùßÍ—?ai4–˜°ÔLV:ÄT¨Oç÷U7–š¶0=òøw3Co . @Œ¨‹Å[u5yã5gA™–ß½Úô‰™«!æ«þcÁß_¢ˆ¢Z¿òQ}ÿ¡¹Zj6‹?ʦé”TšúoÉ‚å¨6¾¾1u;^Ð’%0¤V5Xª©Qñ”uÓ´Q Vó@ œÛž ‚öS7î[£>çÈÎ!0çhrÖ €­Ø{ȯVÚ¾Ôÿ¾çÔÏ|>jBõ¡&T=ØRYiP­^d&2µ,þl3Û"€ €@zXžy´éTª7èÎɧkáºcÞ]¶X»WÝb&L­Ð#Ózin2l7›-[wH7ÏÖÄýxcäŽ{Z¶x­VÝ2ñ¸õ-YáÿpºeËz¸·‹m@ðÿ‰ÝºÂÓú1E+¥3þÙÑÈY–l&gë qv‹ Ð1×Ó~Óst×™–/¦í‹ùëÁ$¦~——!þ„¥ñ`ÝÔƒ>ëþº\~ùÜCÆ1@¥@XòζU¸ûC’7V÷­Ý­Ë–?¬eϬ÷t0éSúúüMØÞðQ:k¾¯™´^_÷†[dójÕôjÝuöÊmÝöl ž >xÊÓß4oB†3æ;qƒ%‹¾²é1@œ €@«ü_ —õ]‚>êÛ÷{ò+Ôw™€}×A©{7i@óUhi ù^:ÂÒUç-`úP©Þ*p6F@P ´½Â½—­®PEmŽ ²·o{ ˜:d“°üƧC.ž"€]$àš^´[~f‚ö{cŠôμÓѰO˜ ?‰ï¢á° €-8Ti‚óD…ºÿ=¬ïLì'Ôö±L¨î/Áºÿ}p_)ŸùHZJÍv € Ð×ôáŽm߮莊™/ÿ{ß[nÑætôh¾Â=ºIw^þEõ¹í;úÿfL¬›,µ.Šä¨°©¬½zVýÇ}ZòA™þó¾jj³–‡m@èJØQO›7Aû·bÊ+¶4ñÛŽ†Î°»ò”86 € ŽTz2H÷ƒuS¡¾£<Ø´¿ù‹Ü‰ u?H/!÷±ãzA>Uê @y‚ €mpN…è~ þÑGŠíÙ¬KìÑ?”gw§_?9ƒ)b¾üïay4_á^ñª¦õ:_A+ö2=ðÓ{4뺩ÜÆ„ŒÑö¥‡]#€ ±ƒ«Hš=Yÿî鱘œþýƒ}ðàº0=ª'ž'—-»áçë°äÍîŠjÓªGõÅés¡{p‡Ìšÿ°f_™Î]bZÆœ¸P¾º|»6¾ñ=ÿËÇ4ï¡©[¬tŽžò~]1–¸=…Ò>Ka¹ÛçjÙ  йQóg÷ï-5Aû"W½ÇZÿu[.iøƒ@çžGCÈt£µžöšžéÉ/~…zý0‡ªLhÞÓ¯P7_~¨nú¨ûýÔ“­_Šz›iEhq–é· ×‡ €@» øó¸¸û÷7¨Ho '+Ò·nõÐP¤¸¸AEzÄèõ+Ôýç‘Û|ŽaÉ;[¸' ª·ëé%óôÉyËC)-›©ó'ŒÔPSÚß;Ïü$§UÜ©[?Òß^Y®ÕA){ƒ÷Íÿé+šãäVµ¨i°žœP ,7à /‚@4¨­ðôzû»®úžíE´§Ù0q: €@(b1¨W-^vÖ롞 Ö÷›×z›ùAü ÝoûÿÞ X—&çåØsÒ €t¶€_eÛ·¯ùŠt?HDâUèɪód{—úÏãËEE~aÉ;[¸'Ȫ·¯×|ÿ.Í]X¯R½œsø©nÿâ§4¶ðÄUñ­Ø%›6"–°‘Sg vGMá;ßwµá!WEúA»£~“èe›vÅ !€i,ພÊûêæË´}ÙíOLHê‡ê{J=LÛÎd…zñ1Áº¿>'¿=i<Äœ €].àÕÖ¦ú¡ûÛÒ%Q‘îW©[yyj¬½~EzÎðá² ºüº’'–¼³Õ{ò«M/ö×Ö¬ÖóÏ>£g—®HôcO¾Zï{i™fM»B3¯¹R—\8^Emìý^o,¶@ ,7` .…M@.¨ÙçiÃbWïš°}Àt´ßí¨pl˜ìîÝ»äZNæ aÉ;Û¸7ĉª¢¼BU‡d~‘b9êÞ=_yyù*( aohÕ9ÏÂrvŽGAZ'PµËíßsµñWC®ö'Cuâ½Ú[·¶FÈ4ÃU^¼B}WbbÒúê;M îÏëUl:lú}Ómý2¨¯_ÁN ži÷׃ €ÀÉăt?87_ñÞèMT¤»¦ý‹Ý§Oóé&H·rsOæ”Òú½aÉ;Û©¯KD……ñ¯´N@TnóôÖw\mzÌÕðë,]¹Öüû6Špäd¼„d”@õQ¨×«P÷ƒõd?õû¥¨+õJõP÷ƒõqÃüç¶™¨TêÓ“32ê†àb@h£€{äH¢Ÿ "=jú£{‡Ëî×︊ôÜI“T¨G† ‘•cþTŽG(Ú)pŵr’ €4*pø´/rµy¹«7غ®ºÉ@IDATz]D=KMÅb% bšÚ WºßC=ÞòÅoýbv¿åËvó½ªFêçêõ*Ô§ ò+ÖM nZ¾ô3-LýÊ* € ±ƒƒJôU¤ûAúÑ£rú÷?®"=ÊÕµwñÛ¾˜/–ãd'f_5{.—† pbŠMžÞ¼?¦~îé”Ïں歈º!H9±¯"€é+Põ´÷Pª‡zý u¿rýà©°g01i²íˤS-¦›/²÷ï-96ÿ¤ïsf €´¿€çyrËË­HOöL÷K7AºÌ¶NqñqéùcÇ6¨Hwä—ôí?T¡Ù#{h†ŠEh/ƒLÐ~_L[Wz:õ ¶f¼ë(K{ù²@ £b®§ý&POT¥Ç۽īՃÖ/ûLØ^`æÿòÛ»øº_•>ÞüÅÒe‚PÝï«qøï}GûE@ <×UlïÞæ+ÒMÛ+ ‚tSq^¿=w„Ï#&lç@sîÍ ñ: €@Æ”¯7Aû·bÚñ‚§ÑsmÍÜä(·ÁKÆ 0‚¡ð+ÌÊû-^‚6/ÇöSßuPêÞÍ„é&Hê&@=ØÒÔ3üIJƒ€=7‡ÿ®‡þFà@8€*¶gO³éþ$¤þ¢É=bZ¸8&P˜‰EsÏ;¯aEz_3»9ÚI€À½ Ù  €@ú ì[ëé ´ï~ÙÓi_¶uÞÃŽº™`† €@ç ª &&õû¦Çû¨ÓO=Ç|B)6­]â-_L°>¼ÈÒy£“šçÝsùïwçGD@ ãü¾çÑ]»š­HíÞ-«G ­K½ŠôœQ£”?uj*`:TvOÓKŽ,@àÞÉà@ óöüÙ5A»«}¯y{›­ ÿÃQNAMçGBl8Ré~ ~l…úÓ Æ±«8Ùò%ñ}ÂH?`·Í—Ô»ÿÎÆû†kFÈ\·ªJ1¤û}Г=ÑýêóúÏýe×´±ûô© Ìã•é&PïvÆÊ¿ì²TEú!²óó3Œ+ ½{è‡ @8V`×Ë&hÿ¦«oz:ýŸlMý¹£HwœcxŽ´E úh*P?¶BÝØkj¥¢^© u¿R}ì BÝÔûò‹Ï¶°ó@ÒNÀ­¬TÔô?¯ Ïý½‘çîÁƒ²MË¿¥K¤^EzîÙg+rõÕu{ÄéV7Ó;Ž!hcà^¡§ï¼[Û'^§ë§_ Á…mÜMÈñ8}@ôØñ¢«õ \ÙâiÜ×l]ú+GNA{zgƒé.p4êi镞¬P?¶õË¡J©_®"=̘êÎÀ²l»ù³Y&`yæÑúk®Ð’ ½tëºãß9kþbÍþ‡™ºp|‰ÈÞ÷é¬5–eiË–-*))é¬Cr@ Sü¾¶®ðLE{LÑ#ÒóœeÉŽuê@p0H;×õ´ÿ°¨7 Óýv/~µº_½ÞÓ´=ê¦BÝï§îëÍ÷äD¥ÝøoiÚ+'„ €@cþç"¿÷y¼êÜæMöH7•é2YQÄ„äñJtSuž¬H÷+ÐëÖù-_LÕºŸ+ñ@ ÝÂ’w¶1p—ölX£gŸú¥¼û!5’»›ñ(ÓüÅ_Ðõ3¯ÔÄ’ÂtŸŒ?Ÿ°Ü€?\ ´»€g‚¤žòôƽ13óž Úït4âËTVða»c³CH[‡ƒªô‰‰I“m_’ß»™¿c­_¡oýb~$÷õAæ{”¶cˉ!€ à x±˜b{ö4_‘nBv¿ï¹_m~lôd ^¦÷ë.¡KÞÙæÀ=5:Õú`ÃkZ½Ò„ïóšßËfiñ—fkæô‹UB¿÷].…åì@v&àšžÂ[~f‚öoÅ1•™gþ_GÃ>a‚v*/2l¤¹ð*ªm^L»—¦RÝÒ“ê~åºÿðõxEºù^¿B}  Ô{æóKÈ@‰ÿE@ ½¼ÚZÅvíj¶"Ý߯êÞ½a —Ĥ£ÇU¤÷6ýÞx aÉ;Û!p¯?šÕÚ¾áozaåê'&|_]ÿ¥ÄòÌÛëŸnþM[ÔÈ«¬j/°Ü€íu½ì2WÀ­õôþO<½y_L¹ý-´Û:ƒ>™;â\Ù!PYãi· Îý õ]‰V/õƒõÚ¨Td>;'{¨ûÁº¤Ç¿›€½OOõì¸S¸J@°x55ŠîÜÙlEº_µn›€¼®ê<1©h]ˆî·tIëv3© ¨KÞÙÎ{ÝõKÕÛµrÉ,Íœ×Xìn¶›9_Ïóv]1žà½žZ»-†ål· fG q1FmzÌÕ›÷»ê1ÜíÿbkðÇ Ú3n ¹ 2T Æü²Ðï•îOHš Òë뇫¥þ½L n‚ôú­_’Áz¿¿Í*¡z†Þ\ €@ˆÜÊJ5˜TÔôB÷û¥×­K¦y­ˆGii©Ö­k¼Ë»¿ÁœŸ¾­Gn›FC—§–03´¹ hOh¥§÷–ºzëÛ®zf‚ö»l ,#hoOcö…'/%õ&*Ԛɜ {úê Û¾$'*íoª×æž8ù` €´QÀ­¨Úº˜À¼.<7Azô˜çþvþ$¢ÍV¤›ªt+'§gÃÛ@ %aÉ;O:pVïÑÛ¯ýAÏ,_®»—!ûq@esôðm³tÍÔ³”h£VüäA;{yb³YZWõ¸Æó˽ãØNfEXnÀ“¹FÞ‹™%Pk&|÷‡®Þþ®«¾g[·­¢ Ú3k”¹Â#34ï¯ð+Ôm_Lû—]¦Z=ÞKÝ,ï;$t÷+Ôm^Ž Ö‹M ž¡B=<#Ι"€dŠ@ÌTš 7V‘î·€qŠ‹›¯H7“‘ZŽ“)<\¡KÞi«ò¦5OëQ²/l*d/©_úœ>yM™Æ6›|NÔMw=®²s‡iÄ• ÍÚ UÖšoîI!¾#€Y%pô §wþÕÕ†‡\M±Tö¬£~ç´gÕMÀÅ"Оç©ü°?iÐö%þݯVOë»JùÝL˜žÒý`}ÌKSÏð[ÀýÔssÔ»`è8$ €@ øÿn»ûöµ¨"Ýs]ELH~lEzî™gÖõF÷_ó«Ö-›ÏYx;qÉt¸@÷r=ûåOjáqbJu۷놗kÒØÁ:ÑÎSdcʃx €d@Í>O»z÷û®L·tÙªˆ K ¯²îFà‚è@C¦E•_¡îW¥7¬GÌgl¿Å‹ ûÁzI‘¥óFûm`ìøúyü7©‡‡]#€ ?HíÞ­Xý¾èõ—ý^éþs3©‰¤BtRQ?47_¹“&Õ-ûëì~ý˜…{ ºTàD™ø O,·_êå™·= ¹7|BS&RA ÷X<éôÔ²1:¬–ŸÚKÿ?{wE}÷ü33›Í@„#@„#á’S@A%ØbµH}´"U@mÁ£RE+ÅöiÕǶ‚ö¯Šö°¶Æ("ˆX J8îCÂä$äÞùÿ~³Ù% lv7ÉŸí+f³™yÏ‚ö“o>? P€nŠÓ†Ys`™ŽNSLú·ñ}j÷UçÙQ yJ+Òeõ‹\¨T ¸¡}M .'Ô;$(Ð]ìbm°ÇEñïžæ¹2Ü+(@ P@ü{¸¢Â–Âæü8~vç}ùY„éŠÕZ·Ö%%aÝ»#rÔ¨ºémÄ¿Ìy£(w¸ïýè-¬¯êƒoM‚¤7Sö –C ”N£`ñæyP€×(;a˜ ¡ú:º~K,†ú´†Øž »®-Ç-(ºU5/ M¨‹Éõò*¨‹®tç„z9©^¬ËÏrÑRùßD¼Q€ (à[Ù“n†èõtñµ3\×ÏŸ‡Ö®´N`q~tîìºo>.¾ÖâÅ¿Ìy£(à†@ ä&å%Øôί0{e¾x=o?”yU’3›—᮳±næ ¿}j5º_õyü&(@ ¾@éQ»–ê8¼RG·ïª˜²Ã‚˜n ÀÿÊò (à½@µÍ€ìJ?i.FZ·úEN¨—”mãµ/f˜.&Ô‡÷– •:&ÔÛŠÿ¨TUþ}âý•à(@ P€Ãfƒ]Ô·8Cs[­ÝœL¯ùÚìI—µ.µô°Þ½9a‚+P·ˆIu9½Î(@Pð0p ì%Ž÷7ÄòsDØ.·ËÛó6¸];ãÆ®¹ (@ ø©@É!´ÿÌŽ#6Ðã¿Tܾۂ(±à o @èØíΊåzNÖ›P—ê²[].Z]¨‹0]Ö¾ ì.¦ÔËû ’ÄÀ›Eãß¡óŽá™R€ @s è—.]ÒEKíݰ˰]‹3Cs纜N3Ƥ×쪘\ço‘5çÕâ¾)@@p;pßûîS¸ëÍÝè.¦ŒäípŽãsÎoæaÚªšÕûg1rj¶Å‹¬ÖÛ”_R€ @À \Ü+‚öí8þ¡ž¨˜º_Cd2³€¿°< 4 :;'¦/j/Lê ÓeÈ.Ãö˜ˆÚê@Ÿ. ÆeŠ@]ì²ÆÆ¿ åC (@·Ì…GÏœi0@wN¨Ëp]îZ‡—'ÐeÍK—.ˆ1ârí‹ÔÕ¨(·_›R€ À•nîegw#o]Ε™yÞ:两g÷G²Û¯xåÁò P€ð_¢|´ÿÔŽèõ´ÔÑŽAšÿ^1ÜÕ/N»8qþòB¥gDL˜øo;goºœPï!~À62ÃQû" çßîKsK P€ @]£²Ò\XÔ9^;@7“/µ•/ÎÎôðAƒ}ûí®€]†íЦÕ}~E P€>p;þî2h”xñdee‰ÏyÈ«²;»ú±uÿßxþ©ï@ 9ñF P€A$p~«üì8½Þ@ï¹*†½®Á*ª x£W ¬ÒÀÞãâÏvøAšX‡a_¡#Tï×UAgñƒ´!iâëÕ Úc#ùç=p¯4œ ZSÀ~á ÐÅ4º3`×σڶ­+4wv¦‡÷ïïÖk*^´6â§Ü¼Q€ €_(âWŒ¦I^ˆy"t÷J.ÖÎÜô]ðÍ*(«ö6+wN 4«ÀÙMºÚuœûÒ@Æ£*zÏQËà­Yѹs 4“À…K"XÓ뻎Ø)ö‚S@·d ¿Øû§:>â¢øç»™ø¹[ P€2Ãn¿¼ðh­EGeˆn¯õµ\ T.,*;ÒåGíÎtçcò3 ²7O‡ðX PòN·'ÜëJ$`ʯ^Çá?mE÷n¢|“7 P€SŸëØù¼Ž ; ôù¡Š1Ò`‰f2ožhPœ*rë;kvY ÓK,jÜ¿+pß}EÏz„•®ƒâbó$(@ PÀ§zi©kú¼¡EGåĺýÔ)¨11Wè‘×_焺 ×µ¤$.<êÓ«ÃQ€ð·÷¢C[±íD)ª”A#‘– ¾M_|kf_qç6l¥žîܬ)9< n½¨;ûã6 (Ðb߬qí%_è·@Å× E0k± À¢€‡ò—œ†9¹nì"d¯ÿM×WN¯‹IƒT¤§ž=$æÓ(@ P ä¿/õ³g]/ÎJ—ú•/zI ´äd×Tº3@6ÌñXMÅ‹*< P€ðDÀ­ìûð?ˆ óÖ™û_º© †ÿ¼¬Y)Ó¤ÍzçwÌ…Ìëy£(@À(ü—¨Ží§DÐþ„†÷)Ð8ùG’6»ƒßˆ€]N¯‹ÙÁadÿºü¸kŒŠníÁ‰º|wð¤)@ „¦€QUuyáÑšJs:]v¥;+^䣋+H¯³ðèm·]~¼cG.<šo#ž5(@·Ü Ükï-"L~†ð¶µå} P€&9ásüÇb¨¶Ô=¥¡ûLª…°Áty.Á!PQe`XàÔÑ¿s±ÓvqŽþõëû*˜=YE‡þÙ Ž«Í³ (@úæÂ£²ݹШ3@¯õµ¹ðhbb tÙÕ·/´š‰t³C=ãõ}ù5(@ 4]À­ES+NìÅŽc¢ÜQè5$ "¦/9’Ý'ËDôñ[ÉnܪÖ®§%¹±-7ñV Pðö<ù| PÀ·†.ª'ÞÁÝOíÐí"°{ZCê]"hgÕ„o¡¹7 x!p±ÔÀn±À©³ýðI «˜X¯½Ài®«à…0ŸJ P€þ `.<*ºÐ]èµtW¸.“Óëu­ › ʯŤJx¸?œ ¼”¼Ó­ÀÝ >µ•å ØJ<|Y P ž€.*( ÞAû‹vÑËîÚ»|[aåD='~IÖ8}áò§²æd‘\àôrÀÞG,pÎ öÖ¸6|M P€ðL@/+»¼ðhé²?Ý~ò$уîìH7Ãs1•îüÚYù¢µoÏÿfõì2ðY N PòÎ&WÊÜ•àS€ @£r¢ýë·D˜'‚vk¢‚A/iè|»Úèöü(м²ÎéØYGÿº ×óE{Y¥XàT„ê²}½ħa¬wjÞ Á½S€ €G®…GÓèòsézqñå…Gk&Òe€~Ýu®@]ìjLŒGÇÁ'Q€ ZSÀ­À½hïfl>Q ±Þ–w·°Œ“·^Ô»Wâ³)@ Pà'×êÈ}LL´G*úk )73h¿¿MŸ Øå§¢ÆÑ¿î¨‰±hŽéõ~© ¾5RE÷d@U9Áîs|î š$`.<úÍ7 èr"Ýü ªªÙ•îœ@—éáÀrë­®u­CsÒ&7¦(@ ˆ€[Ù÷áÕObò¼uÞŸRÖ+8¿#\†Ä{Jî €§¥¢ûyÇíøæc™ÏªHHå¯ázŠÉçQ ‰rÓ}…2XSìb‚}øó˜ëØGôVðÀD)m®7‘•›S€ €—ö‹¯ºè¨ìL·Ÿ= U,*ê¬tqV¼DMœW¸.¦Ò5±8)o (@Pp+pe ž;(@`°WØûŠŽ]Ktt¿WÅÔýÂâìËõåyø§@I™X¡fSYsHL³wiçØo¢àGw¨"pçŸCÿ¼z<* P€/`èºÙ…îš@¯©x©½è¨¬|1íØñòºÎÃÒÒ9vl€ þ{‚g@ P€Í/àVàÞ÷{+7®aaÞPµv:sºÝB>— €‡Çÿ®cËÿØ“¦à–/-ˆëÅ€ÏCJ>W8sQì"X—;Eÿú‰ó@ºè\—ýë3nPÍ.öèþù»*"¿I P€n ˜ Š ˜×л]TÀ˜ ŠÝ9‘.'Ô#F޼<•.¾æÂ£n‘s# P€ €[nî ©ÈdŒ[ Üˆ €? åØ2׎rQa!{Ú;MaO»?]Kà ?ëÖe=Œ ØKʌΠú‹þõ‡oUÑ»3`å§¡y ZX@Ö·8Cs碣òk3X¯Y„T502(wV¼8k]‡ ©®sáѾx|9 P€y·÷¢C[±M,šV ¤ ‰4¾Úúˆ‡šv³¦`äð4.šÚ45nM P É•çEø÷‚ŽC+tôy\LÕ.РY9UÛdH>µ캯E%Œ ÖeÀ.:UÄ+9½.öiÃUôèÀNk‘ñ.(@ Ô0ª«a“SéÎð¼¦âŮ˯Ň\xTKIqU¼ÈéôðÌLXn¹Å ØÍp]TÀ(·þ/}½£à— (@ 4§€[ÿv>üÏbBÍ¢©K7cÁpàŸ÷ż¼&š¹hê\ÖÊ4‘›S€pW@·‹@p…mOØÑq’‚Û÷XÙA»»~ÜŽµ*«å§0ƒu°ï]ìm¢ýëCÓÜ?AEçvüóUÛŒ÷)@ „²€^\ì˜J¯™@w…èµ*_ìgÎ8­Wñ9aB©t.<Êï$ž;(@ º€[{퓌0{ÜÃÞ¶ö£¼O P€­-pê3ÑÓ.êc´(ãþ¥¡Ý0ÖÇ´ö5áë–À¥rG¨îì_?ð Ð)Qìbz}Ò e«hË…†ë¢òh)@ ø@À\xôÔ©:/ u¦°È…Ge'zM Ö½;"ÇŒq…éòq5"ÂGÅ]P€ (à¯nî}§ÿ›†_ç…^Y±æ¹ÌX‘‡'Ë&þ'šfܸ‰ESÛõàt»RÜ„ @S.‰Z‹OÛqr­¬ç4ô|@5œºmŠ!· MsÅ5‹›Öô¯?¤‰J°g´jVÅÄDòÏRh¾;xÖ @¨èååuë]êU¼˜Áº\x42Òš;;Ó#†wë"`—•/æÂ£¢ †7 P€ B[@1Ä-´ ‚óìeØVPP€ÔÔÔà5@Η\^àTö¯= ôHvìÓG98⟽¼ägó¾ƯxÌù=¹mQl¢ÖÅUù"ˆ¨3.CôˆaàÝq‡kZ]KN†Â…GýøÁC£(@ PàZžM¸Wäã{‘YXiî= ïä®ÁŒÁI ¾Ö™­ïâ¦!÷À»ÏÇÁê_!Í㘿Á—àƒ ÊO|8t>D ÔœüTô´Ï³#LLé^÷ª†¶C&òÍ:ßœ¿<½.û×Ï•}:;ú× œFXùg"tÞÇù¹v€^û1ˆ\ ‡U|Èϵï7øX|¼9©^{B]‹kè4ø(@ P€pK PòNÏ¢ïêjˆÿßkÞf®XÙhØ.7H<}o'zÞ)Ëgãl9Æ^ÓŽÿ (ÐÀ¥Ã¶?iÇé <¯!íûìioȉ€.8=}¹=_ì6;ÐWVÈ[‡¨è)8Õ°ÏUç™P ¸ ›­Îô·3¼v~®=!ÞPÈ]g»FÂs£´æjÐ"wÞu>‹Ê•Ú¡xíûZBB£ßsîCÏwÞ—Ÿy£(@ P€pOÀ³À],âîÌÌGI¿æ+ŹÊgbEÝ o (Ѐ­TtRÿ¯Ž=¿ÔÑóS÷k°D3`lÈŠ¶@µ¨J’ëÎþu¹Ài¤ÕQ“ÕMÁŒTt¿8'§x£(àK³ENzË»^%Š[!·ó¹5Ïw>ÇùÙ ÏÅ9ì⧆KP»vxÝØ„¸Ö¾ýå»&0¯”;÷áz,:šWúò Â}Q€ (@x¸WÃ5á¾5·È¼z/{uÌ“âPå„{ ÄSy£(@zGßwÔÇ$d)˜¼Õ‚Ø ëñË(«¼¼À©ì_ßW$·qì7ôW0gŠŠömøžàKÌC§€×†a¸ªNê„×2Ø®r׺¯×浿µçÊ:ˆßÔ5ëQÜ©F©5!®Š‰p¹X§3ðv~vßµög~Oášæµ w@ P€ (xžî±}ñ™@ÎJ`ùýOà®IÁø”FvU’Ÿ/”a»¸eOF/çh¼ãþ“ @H œßj`Ë\;*‹ Œ\¡¡ãDÖÇ„ô"HNþÂ%±À©˜Z—Ậ‡9"êbº‹Nû¥*˜6±Ài<{#H®6O#䂙Π»Îçzâ ßÎíúžœ0¯ý}3‹jºBìZ·ë±úÝá11PjM…×Ù®^%Šù=¹}ç6Þ·Â’ìÙÈ©Ùê=Ř‘ÁĽ–d³Ý ”Eš €;¦€Ÿ TœAäs: þ £ß*2U¡Z8áë症׈À)ñ#g=Œü|æ"Ы“ì_wL±÷í¢€ œ6‚LJ)à…€[=áÞNˆ_«'¼~^óµn× Ìk‡á Nˆ‹íy£(@ P€ @c’wº¸—`Ùø8Ì^ר©6áñ™¯ãüÛ!¡ Oᦞ Êг³ã³(¸ºè®>¸\ÇŽgttžª`ÐÏ5D´cиW4ôŽ\Ö>ȉuWÀ.&Ø+ECƒsÓþbŠ==ETsÓÐ{sðŒ]†èï®?½íœäv~6'¾Ý˜oh2Ü܇ ÂeO¸˜Ön0¼–Áw½À»Ñí Íâì w][Þ¡(@ P€h=@É;éi&¸¼ÊfÚ1wK PÀÿN}¦ãˇío«` 1h÷ÿ«Æ#´Ù œî“ë;E¸.?‡‹6¬÷ëªà®1*ºµç§|§†€Ù^;ä®}¿V7x£!wýiñZ•(Î ]~†¨`èï–wSBn51–ÎÍJ•Úâ M†›ûeOx`¼ñx” (@ P€!%àFà‹Û—ä |Ï%X­^ØTUÁÚu§Û½ äS)@À(9d ÷1;d_ûÀ4ôø/ö´æ• £®¨ œwô¯ï< ì÷ÛÅ9öÑ}Ìž¬¢CX=ËF{Âë…ÜÎ`Û“ q9uEqòÛ9! -9¹Iá¹âÕ8·¬=_ (@ P€ð€•2¾{1î©ååW,ZN„¯D–¨ Gîþ¹Ž}¯èHHEæOTX¢T¶ü•à+^Màb©xŸŠNåôº¬‰9|è*&Öû‹éu9Å.?·‰áûöj†¡ô=[a!ìçÏÃ5Þ„ q×sjO’ך‡®C©Y0Ó5ÑÝÄ qù<×sÅ}µ&0¯ÿX(]3ž+(@ P€ ‚E PòN7&Ü}pI޼ ¥›X`uÜR®]QíÊ(@ 0;®ÿl`«˜jO¬àÖíÄtc`´<ÀNìô…Ë œÊz˜“ErSGÀ~ï8}ħQá|¿Øeõùáê"·>ŒÊíÛQ¹c‡ãóW_ªXà¹Mפ·³.Åù¹v°méÐáŠIòÚßw>ÇùÙìûç (@ P€ @ x¸W ÃgØW$êbQ°Š_§Í{I„íò¶n#Ž•)±Ž/ùO P€Á&pn‹Ž-suT—õ¶†ãÛ5¤ó‘?ü9zfïºs‚½LTK÷¡ºì_Ÿ0@E/ñSð0 ö@º®¾>V½¤¤N°^%vñ!+T @øÀˆàX_{ Öôt_¿<÷G P€ (@ P ¨¼ÜO`Ù´N˜ãžGV—'þO½Xh7 P€Á&P~Ê@þ³:޼§£ÿS*zÏÓ j 1ƒí:ûûùØÅ§E%Ì®šz²[4Gÿº¬†™~½cSUå{Ó߯esŸüŒíÈ3L¯ª™\¯SëúÙ³ëÕË Ö­"`1×]5N”÷óF P€ (@ P€Mð8pÏk¡Ûa»<"¶?ùÎóѤããÆ üZ@¯6pàuy?ÑÑå[ ¦î³ ¼-ÃL¿¾hAtprÓ}…²fÿúÑÅž(~‹L†ë#z+x`¢Š¾ƒèŠ»*raѪ½{á ÖÍj˜Ü\È…<åĺ Ö£³³‘¸h¬™™P4ñ“Þ(@ P€ (@ PÀk÷øàW+k^|V|þ¦¤Àc='C>šµxVÍ‚â½Ÿà‰±÷À1¿ÎÈôú€¹ P€þ"pòS_>bGd7}fABƒv¹6Áz%evÕ,p*û׉iö.íû­CüèUî|ëõoì¼ìgÎ\Q SµoÂRSÍ`]ì ?ü!‡ ƒEÔÄðF P€ (@ P€Í'àYà^r¹bb]Þæç¬À}cRŽ4ÌYš• sÐV4º§$%‰øKa"&ušŒuX„_„æ7ŸÇP€TârµãB¾/jè~{ÚõZúûqŸ¹(v¬;û×Oœ œŠÎuÙ¿>ãÕìbŽ`Àîï×ÑWÇgØl¨>xеˆ©ìZ—•0Fe%¬}ú˜“ë‘£F!þá‡>x0ÔþZ¡¯ì¹ P€ (@ P€î x¸‹v级Ý]¯︻nÝ”<3ÞÜÆ’r Þxo>zÞù2ræåàˆÜe<Ï(@@ ¡îZªcÿk:z=¢bÌ{,‘ ;í:úóñ?{9\—!{I9ÑYAfª‚9Sħ+8õçKè³c³_¸€ªÝ»ëVÂÈ…L]•0±ÿõ_h÷Ë_š‘á³×åŽ(@ P€ (@ PÀ;Ï÷F^³óÀñâ;¢@fÝ^œ¶‰P¾fïí{t¯yÆnœ,Ri}#ûáàüI@.4Xð[·£ÝpSò,ˆƼQÀ»nàkQ ãœ^— *âm%§×û‹€}ÚpÝ;8õ†9 ž[}ìX`]N®ËǬéé®J˜˜éÓ>t(´6mâœx (@ P€ BUÀ³À½¹¹y[µj7ÊtÔÄX¢Âk]‹§EÉŒøµ÷ú71Ï(@€8»YÇ–¹:ìFÿQC²¨ñàžT‰v÷2Xß)jbä§ñÑŽþõ¡é ¢s;þ ÇÛ@yŽ^Qj±i¥Ôå"¦f%Ì–-PTÕ¬Gßz+žz áYYP,žýgZ xð8)@ P€ (@ £€gÿO.6ÓfŠYö•âcá|¯ò,øïo!3}(²…Rò0ù¹wq~Ù $à Þ_ö;—Èêy£(à÷å' ìxÆŽãèÿcQå1Gƒª1 õû çGx©ÜÀîšNeÀ~ð s[Çû¤A ËVÑ6Žï)?ºd>=û¹su‚u3`ß³–ÎÍJ˜ð?o’ÅÔº%¥ Ÿ wF P€ (@ P€-% ˆªÓ+Úº ‰Cf»žšµ4;ôÅ[Ó"q¿h•qܲ%Â÷šõUÅCOâ`õ‹Hó,æwÝPD/AAARSÙ˜ï7¡€KÀ^e`ÿ¯uä/Ö‘ú¦"<¡¨ ˆw8W\³ÀiÍ"§Çωßô•0²Fv°÷í¢ †ÿúê7 »Õ_]§¦RL­ë—.™ ™ZE°>p dÀ>dÔ¨¨@=U7(@ P€ (@V”¼Óãè;aðC(ø´Ý&Ì3¡ÛFÈOÈ^ôºqwñµÃv`éç2loÕ·%_œ¸šÀ7«u|ùˆÝìgŸ´Á‚6ý´_Í+Ô¿Wxîò§²&¦¨è#8•ûì[ô÷ÃÃø ¦÷‰^R‚ª]»êN®oÛ5>ÞU ;cÚ½ôÂúôü¼þÁtýy. (@ P€ ÜðxÂݵóŠ3Ø»û$ÚöÍD’º‹~÷Ck±äñG±äpwÌÊ*ƦÂt<ÿÊ ˜š™äzï4¯@ üħy¸w ¸'P¼ÏÀ–ùvï50p‰†nw³§Ý=¹ÐÙJ— œžºÜ¿.:•¿&8í'öþâsZG.pLï[aaÝ`]t®W‹ß KKsM¬[ÅäzÄu×Ak+º‚x£(@ P€ (@f”¼ÓûÀ½Y¹sOå èéùñyð…@µ¨Ù¹DÇßêè=WEÿ§ThœHõ…m ï£Ê&ª…ä§¢&_„ërÓ˜Hǧr‚]ì]’ø^ ôë,ߨªBÕ¾}®ELe×zen.Äx:¬ýú™U02X7+aD-ŒbµÃió(@ P€ (@ œ@ äWÊÜáS€¨KW^i`ÛìH­à¶D‰úÞBW ´ÂªËÅMåôú@‡Gÿú„,ónW‘Ï÷H ¿Cì.Ô Öwì@ÕÎæ¢¥2P—ÁzüÛìa=zúéòø)@ P€ (@ P Ü Ü‹önÆæ¥ðz¦+,cÇdÀ­m ¾$(ügþ£cË\†˜`óž†öcXüWýÊ3,ºT·ýèY G²#`Ÿ>J5«bb£°_)ºÛáÃu*a*äB¦EEËÈpTˆp=î¾û>x0ÔØØÀ81%(@ P€ (@ ø½€[Ù÷áÕObò¼uÞŸLÖ+8¿#bh7 P€-*PvÂÀŽÛQø™?QÑë•j‹^„V|±ç È…MìçJ œÊþõ&)È¿áaåû¡/‘Ç/­—–¢j÷ëb!S%*ÊÕµsçH|á³"FQùC6±ùD P€ (@ P€¸¦€[û5÷ (@ ø©€½ÒÀ¾ÿÓ±ó§:º}WÅÔý¬m¬úéåòÉaÉN N;ú×e=Œì`·Ù œÊþõ[‡¨è)8Õø>ð x îÄvòdÝ`]TÂT<Yÿ⬄I¸õV„‹…L-íÛ·à‘ñ¥(@ P€ (@ P€·÷¾ß[¼qå ó†­aq~º½bﻈìs€˜‰Üâ·1¸©¿…^±/Íû)EµCT#œeegÑyâÓxfzF#[ða PÀ‰ú˜ÿ±#¦‡‚›ÿmA|_¬î¸Ú6Õ¢Hv®;§×w‹N#Eš ׳º)˜qƒŠ®Ir L^ÿ@¹¶Fu5ªöïG•ÔÍELåg±©|<\,d*»Ö#o¼mæÏ‡Ut¯«rjZ¾×*è×ïQ<ãÉþù P÷Ø2ÏŽK‡ ü™†Ô;Y!Lo‹2ñ[ {D¨.vY³¯HnãØoè¯à‘)ªøšáz \s»èU— —:ƒõªíÛQ™ŸML¨‡‹`]N®Ç?ø ¬¯½kzz œ“ (@ P€ BTÀ­ÀÝk›#ïBé&¦ÂÇ-EáÚHñz‡­°[ ò׬ÀØE׊ʯ~l%Çw»Âö¬¬¬†7ÎËC§p¯~ áýòQ ¹@ÕŠꘃoêȘ¯âÆ¿kмúe¿PZ·ýˆ¨‹é.8•ýëÓF88æuö÷ël¢ÚçÈ‘+*al'NÀ*2Áº ØcgÌ@ø!Ðâãýý”x| (@ P€ (@+¼ Ü+¿á3ì+ª‚øíýoV«y/É q[·ÇÄ`xJSkXÏn…V`í²ŸãO_äbùÊŸ¼~É‘™·l,ÿâ  Ÿœ>wBf0Dg÷׿7°m¡É7*¸m§QÀ6 v ìôTÑåÅMåû™‹@oq=û§ß¿IEŸ.\à´.ƒW/¡——› ™Ö©„ÙºŠøog×zô´iH|öYÇB¦/ÿsÄ«£å“)@ P€ (@ P€¾ðâÿážÀ²i0ÛÍZs‹Ám/{à}wâîí©;³ËÅqûêvî@®cWYCÐ…a»¯X¹Ÿ8ý…èiŸk‡¢*¸áo’F±>&ÞrêYN¬;û×w‰€½¢ èÛUìâcÒ éâ×¢,\àÔo/«íôé:]ë²Fö¯‡¥¦š]ë2`OøÑÌ©uKG±Z-o (@ P€ (@ ð8pÏk¡Ûa»ô“aû“ï<Áµ®Y-|KÏGxøE|ñ›…Xéq_}[;ÞNÝ» }¿±xjhn²ã¶?mlj d='BÙYªº7÷ërÿÞ ØìŽNe°¾Sô¯ï]ìáâßDrÓ~"`¿kŒŠnâ/G.pêss<Û°ÙP}ð`Ý®u1µ®—•™Sê2X¼þzÄ?ü°Y £F5¶4xs÷I P€ (@ P€ð÷øàW+kÎ`V|þ¦¤Àc='C>šµxVÍ‚â½Ÿà‰±÷À1¿ÎÈô³vû("0fÆ\ŒqmoCø*o÷jœ;U“ÖÇžÆo=œrQX\,^!é#Æcæ½ßŘŒ$×+ò(PWÀ^a`ï+:v-ÑÑý^S÷k°Æ³>¦®’ÿ|UQuyÓG 85Ð.ΰî«`ödxýüçŠ9ŽÄ~ñ¢¹iíJ˜*ñ“s51ñr×ú}÷¡ÝË/#¬W/þ€Äß. ‡ (@ P€ ZMÀ³À½ä$rkrãù9+pßQ¬‹4ÌYš• sÐV4º§$%‰øKa"&ušŒuX„_„æoµ“õþ…˽ÛEE¾pVð¬\ˆ;?³¨Ùëºu9X¾d²çàíg¦‚3ÞqóÙÁ'püïŽú˜˜47o² >ƒA­¿]åâ21µ^3½.kbŸºŠ‰õL1Á>u˜œbWÑ&†×ÍŸ®[õÑ£u*a*E%ŒíØ1XEn‹˜ÊÉõ˜ï|áƒC;o (@ P€ (@ 4.àYàWœÑýòÿùŽŠw¼ÐºuPòÌxsKÊ-xã½ùèyçËÈ™—ƒ#"p—ñ|HÞªË ÖŒ5o¢Òòg3ç?‰^‰åX·èeñC Ç-gQ6FãS솼Q€À…]†ÙÓ^*Üë^ÕÐùvö´ûËûâô…Ë œÊ ýdЫ“˜`õ0÷Žs,p΀Ý®—QY‰ª={êVÂlÛhâ·D23Í`=zÊ$<õÂÅ×J˜ø—=o (@ P€ (@ 4IÀ³À½‘—èH¨£‹ñs÷vmÂË}=Ÿüû Ü3êòk ½€¡8ôÿÄ¢¨OÚÑa¢‚Ûw[Ù‘!nK_x»Xàô ¨„‘‹›š œŠ v‹æè_—ìÓ¯w,pªª¼6-}mœ¯g躹ií®õJ¹©è`·öíkêáÆ!nÖ,ÇB¦11Χò3(@ P€ (@ P€Í P'òu{ÿ±é˜6S̲¯ Gà{•ï`Á ™éC‘-v’#ÊR&?÷.Î/›œÁûË~çÚµÈêC÷‘€Ô´„«œ¿7ÏyX>ÛÜæÔÙ²«l{ío¥¥¥AUݯ޸pᢢ¢®½cnAf8µ^ô´Ï³C“ì7þCC»á›ñ°Bb×rS¹¨©\ÜTö¯ï9f QüŽ ×G‰¾üoV‘’Èp½µÞ ú¥KæB¦²c½RL¬ËÏ2hWãâÌ0Ý*ºÖcï¹í^z aPšð÷k_— (@ P€ BW M›6(+ó.ÿôG=ÏwÑΞýèëÀJG0¼rÑ=È ÏÅŽ}1M$î9raÐå÷ qùRd‰ðÝ1¯-O¿/ÚEú#CK“ 6QµX`iD>,Ìù[ÞÓV1娵kW·wİÝm*nØ ²Ÿ}ûSvœüÔ@Öb =P ( w›ºÎ.¿9o࣭:ò Äoˆiö.íû­CüèUî¼uÀZè [aá•0ÕëÙÓU =m"äB¦b‘rÞ(@ P€ (@ P€&päÈÈúZwo Wdvw/Í¿]#±ïµ_8aðC(ø´Ý&Ì37n!?E {‘âsA¼\ôrØ,ýüQ¤yüŠ×>&ÿÞ¢oM‹Ãýò‡xÆ‹ .[°é?®ÓHnçÝ´y||<äOŠx£€? ØÊ ìý•ŽÝ/éèq¿Š©û5„1ämÖKvI˜¶ÓÀ'Ûuœ-Æe*˜qƒèÈï¢ :‚{³â×Û¹QU…ª½{͉õ*çäº\ÈTTÅXû÷7'×#'MB›  ™†ûõ…_R€ (@ P€ ZT@f—Áxó*þN?Fùw±w÷I´í›iúÈ ¾ø`:–<þ(–îŽYYÅØT˜Žç_yS3Cd ¯¢'N‡¬Ï‰KNE‚ùÈÚoŸ%øÓ†G±`L=¢ xâ~Ç¢©rë‰×÷¬ý$Þ§@Ð ûÀQ'êJnùÒ‚¸^ {›ë"ë¢×Q`µÙ7î108MÁ="dÒSÆöæb¯³_s!Óü|¸‚uY ³{7,;º*aâyÄœ`ëÑ£Îsù(@ P€ (@ P€!àUànž¢E¤ÉÕg°þk1jÚx¤ˆ=ƦÇâ7VbÄΠû€AX–ãþ¾ºdù˳‘5o¹»¥›ÎcÁpyþ±3s–˜þwê ǶÞÛ„ûo€Q³S˜÷Ìr§è¿¯¹Í|·¥zyœ»ãg ø“@Qžaö´—Ÿ00ì·:ÝÊžöæº>…ç ¬Óì«ruÄ‹_š™8HŬI*b£øÃæ2—¿gûúkW%Œ³kÝ~ú´¹©ìZ4q÷Ýg~–ì¼Q€ (@ P€ (^%ºg6¿‹»FÜG´<›ŠEà.Ø“·òcëí¨›Éšõ þú‹¹H«ùžc‹ þgx'×ÉE„¹î"mú x%{9æÕ¤ê ï…—¿]ëÞ,lzu†(èáÁ%P)úÂóŸÓqøm}¨èó¸5ŒÁ¯¯¯rY¥MûdeŒÃ§ ³2fñ=º'ÓÚ×ÖºXÜ¥jçÎ:‹˜ÊM•ÈHW×zìw¾ë‹/ÂÚ§Móõ!p (@ P€ (@ ø‘€Ç{ÑæWÑ~„#PwœÏ¹FO+où<ô\þ6æ°w£[Ò7ÿéAXøåîõºm»I˜ûÁyôzu1&Ï{¹Á“7V,¹©LÛôáƒ) ÛÅ‚œoêØþ´Ž”É nÛcA$Ã_Ÿ^L9U½÷8Ì^v9ÑžÙM8U0¼— ‹Æ Ýضo¾©Ûµ.*aª‚¬ 8rr=ú¶ÛÌ©uK‡¾xI(@ P€ (@PDHãþR°®“;ƒWÇ·GMk ½Ÿ>/Fe¦^žÊ®8ƒÍŸýK&ÏvÕ¤d-þ;žãÚKHß©(ÂÞûqæBª«KQ…¤g@Z’o’vEQPPP€ÔÔÔfæÉ·¾ÀÉu¢§}®–C_UÑv(ëc|yUN‰Ê˜]þ¹EG”¸i Š Y ÚoÞ<0l6TíÛW§k½R,djTVš —š•0"`»5+ ª˜fç (@ P€ (@攼ӳÀ½d3¦Åpé³ÞCù²é—ƒöú®¶Cx~HO,Ê“ßxÆ‹`\É÷_ÊÐ÷gÎ=ú‹À¥ÛŸ°ãÔç¾ ¡Çý äû’7ï*ª |uÀÀêmö¸¡¿‚‰"hïÕ‰¾MÕµ_¸€ª¼¼º•0µúá4@IDAT¢"ÆÒ¾½9±.'×Í`]|KKã{¸©ÀÜž (@ P€ (à#@É;=«” ‹G÷¨Wº¹ñ°]ncIÜå¯`‘Y?³'K€ÔÆÛX|ÄÏÝP€­%`+3°ç:öüRGÏTLݯ!ŒÓÖ>¹Ä"³«·éX—o £³ ÙMCß® Ùë»ÚNŸ®¬W‰`½jÿ~„uëæª„IX°ÀœZ·tî\ÿéüš (@ P€ (@ øTÀ³À=¶;&g99@ÞËwâV¬À‹îFZB½?mEذr1ÆÎÊ[ÖxôbŒÃ‚ÿ¤@Tœ5ÿ¬Ž‚?èè÷„ŠŒùÔ0†Âž^Ú¯OX³]Ç'; ¤upTÆ<1]E8MaØí¨AzJ±©~é¬ýû›zäèшŸ3ÇœbW££=½ |(@ P€ (@ P€ðXÀ³ESÅËUú "{ÞYç…³ÆÍÄ”q™èœ<œ%/¯¬óý¥›NcÁð¤:ñ‹æ”Ešçì¹×æÐÅöÁå:v<££óTƒ–jˆhÏ Ý÷¢K6ìrTÆT‰†® T³›=¹MèzêÅŨÌϯӵ^%2UE¯zíELeçzXz:•¿QáÉ{Ï¡(@ P€ (@ ’@ äîòbYû*ºM˜çÖu™µ"ËîìÖ¶ÜÈ{@yz¦ÜCK |³FÇ–yvXE <ôÿ4$Ý`ØS{›ÝÀÖCŽÊùyd†‚IbÔÌnŠèi-Ïê£Gëër‚Ýv쬽{»*ad°.ƒv­];OÉù< P€ (@ P€ \ PòN¯wó•Â_~ûž_ø2ò¸hãf-Ås ~€1iì’i€§Ù ”7`³pÇ>(ùÚÀ¶…vœý/jèq/§Š›Š|Ltܯ–•1Û tÙñMbÔú)ˆ þݨ¬DÕîÝu+a¶o‡\ Ö*2uN®ËÏÖ~ýÌN›êËí)@ P€ (@ P€^@É;½Ü×ÐV3§Oá\9Ü> ŧË×¾b=«‰wî–Ÿ=”7 ggÇgµ¤€­ÔÀ®—tì{EGúC*2©°D@ì+ãâ2_ìvTÆ—ÉÊ9Í®"¥mðÚÏž½"X¯Ú·rÑRg°nÁºY “šê+j(@ P€ (@ ”¼Ówi¸%I)© í%ˆì$&Ú}·÷ ~«ðÔ(à¿Ò±õq;)˜¼Õ‚ØÁûò*Øu;;*c¾Üo`hº‚ïߤbðSÕà14tÕ^Q £Ÿ?ïXÈTVÁ ޏY³Ìp]åo:ùò}Æ}Q€ (@ P€ (àMŽÄÏÚŒõ¶ã\eGÜþßS‘RkG6`ñ¼9X’s¹\&+{û(îŸágÏ#¢8—k`Ë\;ª.ˆ~ñ·4ta1o×8q^†ì:>Þj I,=QL²?r«Š˜ÈÀÙõÒRTæå¡Jt¬WŠ*Ùµ^%6•!ºœT—ë±3g¢Ý/~°^½ hÚµÁ¸(@ P€ (@ P€2&TÊœÁ»OÝ…{–¬«!‡MÅk1¼f`±$ÿ]ÄeÝÓ(ÏÌ×sñöC\4µQ #P~ÅÂǧÍÝy)PqZLf/Òqô=ýŸVÑ{® Õøa±—,W}ú¥r÷:*cÎ\Æg‰Ê˜A*º&®›íøñ+*aª –žîª„1»ÖEÈnißþª>ü&(@ P€ (@ P€ð…@ äµæÓ¯vÚExë{íqÿÊÚÛœ«õÅ ¼\/lÏ— ¬Ëq-¤ºrödßTŽéiµžÇ» €?èÕ¼®#ïY]îPpû> "Ún`Üܦº¨ŒÙybñSÝ ÛŠª˜cU\'ªc´«Œ±¡lÕ*Tææº&×êjsj]N®GÝ|3Ú,X`VĨüû»¹ß[Ü?(@ P€ (@ P€-àVà^´á:aû¸ùK±àî©è[3Ý^±w5ÕrxåóÌ#Â+ÁÚWÆ„yޤþùßmÄôÇ×Ú’w)@Ö8ù©Ž¯æØ.&²'|jAâ@í]“ç ¬Ë7ðÑVqQŽÊ˜oVÅýÀ2³âÒŸÿŒ²Õ«Q¾~="ÆŒAÄÈ‘ˆŸ3Çœ`·tëùScÞ(@ P€ (@ P€ š&àFà^OW.tíõÉœƒxqjšëkyçÀúO]_g-þ´&l—ÅbüÜ_béïVb¡¨uÏ[òwì]<n¼ªk‡¼C 4‹@ÉA¹ÙQ´ÝÀÀ%ºßÞö† Ë+•1k„ÓáSnÈTðÜ =:N m†Ù½^úá‡fÐ.÷Èñãs÷Ýè ‚w.fÚЕçc (@ P€ (@ P é׎¾+v#gyÍŽ³_Çê…írŠ=÷ Ç»ÜêáiCëE¾½pÞ#wrËŧšÉøzòK P ª/Øõ3û_ÓÑë£ÿ¨Á`ÚÍÍ$ê=ÇDeŒXõó]ú§*¸m¨‚á½UX´ÀÚõŠ T|ñJsrpé½÷UEôÔ©hûÒKˆš4 ŠåÚý7·3÷O P€ (@ P€ ‚MÀ­Ä¥¤æ¬³'BB}[!þãÊÛgaTú•izû çD|6(ÂðÁWì¥þ^ù5(àc"üÁÀÖÚÑn¸‚[·[Ó-0ÂcS4º»S |&*cVåêsTƼù?*bÃÉ~æ ÊÖ¬1CöÒüa=z :;)â±ðþý=o~ƒ (@ P€ (@ PÀ7n²úŠW­8²ÎxdD·ÖÔ«øúr%Í;à @³ œûJô´ÏÕa/5pý;:Œc}Œ½¢ÊÀ—û ¬•1û Œí§àÉézwŒ½º ²*FN²WlÚ„ˆ#̽ݯ~KÇŽÎÓäg P€ (@ P€ (@p+pwN¸›#Ÿõªpóz×#Ù“³l‹±tyEl3ÏÜ®]”[/éÚ'ïP€ž ”‹Îñ?¶ãØß d>£¢× j€T¢x~Öî=s¿×eeŒ\µw'Åb±‹îRa óï ÝÐuTææš!»\øÔ~þ<¢&L@Ü £ÞÕèh÷¸(@ P€ (@ P€ €ÏÜH¿Ã\!zΟ6¢è¡ÌZµ2%Øðg×|;ÆíÞànÎù]ÍãÙÈèäš—op[>H x/ W‹imÑѾóy]ïT1u¿†ðDÿ’½?ëkïál±õ;•1¢a7 TñÛ¨HŠ÷o½¬ åŸ}æÙßjT”ÙÇžôÚkˆa»"úÙy£(@ P€ (@ P€h}kî}= X)sõu³ñÄ[CñëûC>ñ̆¸?Çy31:ýÊnö’­Ë0yI^ÍFÝéÜžŸ)@æ8ñ±Ž-síˆLQpÓg$dùw˜Üµ÷Ye3ðÕ9Ín`çQ©ÓGÁü©š¹jííüí¾íäI”­^mVÅ”}ô¬}ú˜!{g±ªµwo;\(@ P€ (@ P€ €PÄBŠbÎóê·Šü·™uÿåÆÍ“#ʰdÉÊËÍzÕ˦›A«"}¶ Uó¿€¹¹èŠË l•1«ru\(&ˆÊ˜‰¢2¦s;ÿ3¨Ú½ÛQ““ƒª]»yãfÈó­oAKLl."î— (@ P€ (@ ¥@ äMšpÊ+Å“¢@ØÅ$û¾Wuìü©ŽnßUqû~ á~ÚKîkN».~È ªb>“ì_00¤§‚û&¨œ¦@Uý'h7ª«Q±q£#dï=ºŽ¨I“ðĈž<ŠÕêkî (@ P€ (@ PÀϸûÙááP ¾@á¿tl™gGtªXô ÚôóŸ¹þ±úòkY³.OÇÇ¢›½]ÌIöG¦¨ˆõ£aí.˜1²*æ’˜d·¤¤8úØÿøGDŽåKî‹ (@ P€ (@ P ¸ÀEâ!†¦ÀŽrçÛQ¼ßÀ ¥Rï þžöKåþ½GN³ë(<ŒËR°ä^qîíýç‡ ¶'P*Âu³}ýz„_w²w}á„uíšoVž5(@ P€ (@ P€ €)ÀÀo ø™@ÕE;_ÐqðMóUÜð-Âg_sé¢2f籪¨Œùø!Ã€î ¦R14]æýô†a */Ï Ù/ýå/°=ŠÈ s÷ÝH“ìZ|¼¯I¸? P€ (@ P€ (@`à އ|†ž¿þ½è+ÂŽö7(¸-ß‚¨ÎÁ´Ÿ8g`m¾·ê¢&ÆQóà$ñÑ­ÎFe%Ê7lpô±‹]ö¯GÝr Úþìgf/»bá_Á÷'gD P€ (@ P€ ¼`jä½!÷@¯Îl=ísu±Ð¦1ÑÐ~tpÖÇ”WØ(¦Øå¨‡O¸¡¿‚ŸÜ­¡gJë‡ìösçP¶zµ²—þãëÞݬŠé(êc"†õús (@ P€ (@ P€Á/ÀÀ=ø¯1ÏÐÊ ÅDûSvœøÈ@Ös*ÒgiPÔÖŸ}I&+YvƒÙ˾a—~]L¹NÁˆÞ*Â,­{®ÕGޏúØ+6nDÄÈ‘fÈÞîÿ×\Õ—Ü(@ P€ (@ P€ @ð 0pþkÌ3ôC»˜ôÞû²Ž]?ÓÑý{*¦îÓ`mӺᳯ™N]0𙨌Y•«Ã*þ¦™8PÅsT$ƶÞyºŽÊ­[]}ìöÓ§5q"â¾ÿ}tüà¨11¾fàþ(@ P€ (@ P€ BH€{]lžªÿ»ŽÜùvĤ)¸y£ñ}Z/€öµHE•ÍûÅ¨Û ìÓûcú)Xøm }º´Þ9êee(_¿Þ²ÿõ¯P#"¤W_EäøñP4Í× Ü(@ P€ (@ P€ @ˆ 0pÑ ÏÓny‹» l™gÇ¥ÃÿBC—;‚§§}Ÿ×?Ù¦ã³ÒEû¤²›]…5¬u‚vÛ©S(ûøc³½lÕ*X32̽³Þ­}ú´üÅç+R€ (@ P€ (@ „„÷¸Ì<ÉÖ¨Õ*ù‹uZ¡£Ïã*nü‡-¼u‚h_:œ-vTÆ|´U‡hj1+c~ûIñ­snU8<ýðCTææ"rôh³=é׿†%9Ù—§Î}Q€ (@ P€ (@ P Aî ²ðA x/`èý?Ç¢¨nRpÛ. ¢Äôw ߪl¾•1Ÿl?D8b`”¨Ã™w»†Ìn-^†ÝŽŠ/¿tõ±%%ˆœ4 mæÌAÔm·AŒ dj;(@ P€ (@ P€ @ 0pÀ‹ÆCöÓtl™k‡bQpCކ¤‘]sè²ëø4Ï@·ö•1*ž˜®"ÂÚ²A»~éÊÖ®5CöR¹Èi›6fULû7ßD䨱PÔÀvöÿw6 (@ P€ (@ Pàj ܯ¦ÃïQ ‰eÇ l[hÇÉO d=¯¡ç ¥eCé&r£›]2ð¹èdÿW®Žò*ঠ^}PCÇÄ–=[a!Ê>ú—rrP¾f ¬YYŽ>öM›`MOoôøù P€ (@ P€ (@ ´´÷–ç륀½ÂÀž_êØý’Ž÷«˜º_CX\ËÓ¾€µÙ ä4°ZTÆlÿÚÀ°^ fߢb`–ýÁAÕîÝ—ûØóóyãfÈž¼b´¶m}qªÜ(@ P€ (@ P€ |.ÀÀÝç¤Üa¨ û@Gî£vÄŠpú–ÍÄõ¼ ýÈiGeÌ´wLt,€úX¶Šèˆ–9£º7š!û¥÷߇ü:êæ›ÑfÁDOž %<<ÔÞV<_ P€ (@ P€ (@`à€‡ìDÝÊ–yv”3pÝÿiè|[`õ‡—‰Ê˜]>•1E¥À„,¿ø¾8v-²Û/^4+bJEULé‡BëØÑS§"ùw1jTÀVñøÇ»“GA P€ (@ P€ (Ð Ü[C¯Ð•ç ä?§ãðÛ:ú.P‘ñ˜­…õЮ;ªb>“ì_î70¤§‚{Ç«ægMmþ ½úÈ”­Ze.zZ¾~=‡ 1«b/FX·nžžŸG P€ (@ P€ (@¿`àî—ºè7?ô¦Ž?Ö‘2YÁm»-ˆìÐü!µ/lŽž1°6OÇêmcIUÏݨu,y?ÑQð®Ž~OªÈ˜¯A ó}xí ÷© Öåøh«.ºØ•1ËQÑ6Î÷Çi;}e}d†ìò³µwo³*&EÜ8ЛÓàs)@ P€ (@ P€ (Ô ܃úòòä®& Û \¦cÇ"o“â{,ˆLö}€}µc¸Ú÷*« È…O?•1û Œé«`Á·4ôíêûc¬:xÐìb—ì•[¶ rÌ3dOzí5X:t¸Úaò{ (@ P€ (@ P€ @w¾BRàäZݬ‘ ¡ŽÿHCÛëü§>fßqÙË®cýN=;*bT‹îVîé{ÃnGÅ—_:ªbd{Q¢n¹mæÌAÔ”)P£¢Bò}Á“¦(@ P€ (@ P€ €7 ܽÑãsNàR­?²ãìF—hèþ=Šâû‰ñ¦Âœ-6ðY¾£2Æ®7 PñëÙ*’ÛøîØôÒR”}ú©#dÿà¨ññŽ)öåË9v,Õ~èÐT?nO P€ (@ P€ (@`àîWÇÐì¶2±ØèRû^Ñ‘þŠ‘+4„Åø.Ìöäªl¾Ü/¦Ù·É…P ŒÊP0÷6™Ý|÷CÛ7ß ì_ÿrô±¯Ykf¦²wþ÷¿ÍnvOŽ›Ï¡(@ P€ (@ P€ `àÞ°  "‚?éØúC;E5Ëä\ bÓZ7h?øìe×±V,‚ššäXõÉé*"Ã}s\U{ö\îcÏÏGä7š!{û7ß„–$^7 P€ (@ P€ (@ P Y¸7 +wêçÅäø–¹vTž30òw:Nj½Ê” —DeŒèdÿh«ŽÒ Y£à•4¤´õ>d7l6TlÜh†ì—þö7å刚<m,0{ÙÕˆ¸< P€ (@ P€ (@ ½÷ ¿Ä¡w‚g ìxFÇÑ÷tôZEï¹T‹÷ÁvS%mvøÓì"øßöµa½<(BÿA=¨ªwÇ££ì“O}ì~-9ÑÙÙH~ûmDŒå½ôMõâö (@ P€ (@ P€tî~yü.]t¢ø­Ž¼gut¹CÁí{-ˆHò.Øví¼ wŽœ–½ì:>Ýa 9˜4PÅcÓTDGxw,ÕÇŽ¡ìŸÿ4CöòÏ>Cø!fULâO~‚°=šp„Ü” (@ P€ (@ P€hîÍ¡Ê}¶¸À7ŸèØ2ߎð>± q°wávSO X,ʺ^TÆ|,*cÎ_Æg)xé~ ]½ ü+óò\}ìUûö!ꦛóï ùw %ˆ4Ÿ7 P€ (@ P€ (@ PÀo¸ûÍ¥àx"P"ªZ䂨ç¾20ègºßÓr=ív]TÅÓìÛ |uÀÀ±ë÷Æ©¸.]æaeŒQU…ò \}ìÒ$úÖ[‘øì³ˆš8ŠÕê ŸC P€ (@ P€ (@ ´€÷@æKø^ÀVj`çû_ÓÑë׿­ÁÝ2SíGEGü§;t|"‚ö„GeÌœ)*â¢<{}{QÊ>þØ1Éþ¯!¬kW³½ãûï#bØ0ßãq (@ P€ (@ P€ @³0poVî´¹ Ã@ÁÄdùìh;LÁ­Û,ˆéîYÐÝ”c,­0°a—œf×qâpc¦‚fjèÑÁ³×®þúk”Öô±Wüû߈1 ÙÛ.]jîM96nK P€ (@ P€ (@ ø‡wÿ¸< 7ÎåØ2׎ê‹Fý^C‡ Í[£‹Ê˜¼ÜdÿÏ^YÝ|{¤Šá½X´¦íò•¹¹æ‚§¥~Û‘#ˆš4 q÷Ý9É®ÆÅ¹!ÀM(@ P€ (@ P€ (@`àîÏW‡Çf Tœ6°ýi;ŽýÍ@æ3ª¨Ñ Zšx7…òÄ9Q“§cõ6QáÀÄ*˜¤Šú˜¦½¦^QòÏ>sTÅ|ð”ˆDO™‚v/½„Èñã¡XøÇ¯)×…ÛR€ (@ P€ (@ PÀߘøùû áãÓ« ìí;Ÿ×ÑõN·ïÕÑ®i¡·»|啾Ø#¦Ù·é8| ¸¡¿‚ߥ¡w§¦½žýìY”®Ze†ì²—=,=1ÙÙHÝìჹ{8ÜŽ (@ P€ (@ P€@îxÑBáO|¤cË|;"“ܴ΂„M ¾Ý1’5/»ŽBL²ëø·Û3:‹NøëTŒÊP` sÿõªtTÅää rËDŒm†ìI¯¾ KJŠ;‡Âm(@ P€ (@ P€ (@ `à1˜N¡ä ÜÇì(Ún`ÐKºÝíûžöS ¬Í  Š ]¹º¬ŒyýaIñî…솮£bófGÈþ·¿ANµGÝr ÚÌ™ƒ¨É“¡ÆÄÓ%á¹P€ (@ P€ (@ P€n 0pwŠ›5¯@u‰/ê8ð[½çªýG –(÷pwެRÔÓÈ…Oe/û¾Bcú*øáúuuï5ô²2”­YãZôTEôÔ©Húío9v,Msç0¸ (@ P€ (@ P€ (Ä ܃øâ©ÉZ—Ã+ l[hGÒ(Qé²Ã‚˜T÷BpwÎoïqÇ$ûúzvTÄ4»‚Ebj>Âzí×°<‰2ѽ^*ªbdØnÍÌ4CöÎë×ÃÚ§;/Ïm(@ P€ (@ P€ (@`àBÛßNõì—¢§}®{™ÑïjH¾Ñ7õ1犕1‹Ê˜j»¨Œýï¿™-öŸpí½jÏžË}ìyyˆ¼ñFD‹EO“Þx–öíýÇC P€ (@ P€ (@ ø‘w?º¡r(å' lʎ¿È|VEºÃUíÚaøÕ|ªl6ï3ð‰è~ßyÄÀH±ðéÿܦ"«›Ei|߆͆ŠÍý’èc7JKÍö6  êæ›¡FF^íeù= P€ (@ P€ (@ P€.î. Þin{•èOUÇ.ÑÕžú]·ïÓžØxîÎñÙ{îñ¡#êã+ÓëcX7mu¶¶ÆÚûïÏ'Ùï¸#ÒõÙ‡žzjìþ­oå’íun®+û @€ @€ °]îÛÅçà :;;ã¥$E½´=FŸT§>ÕC÷éY¢½yMgÜûtr7{²dÌ[«#¦Mª‹kÎMq;ío¿kî¾;—d_ó‹_Dã>ûä–ŠÙë¶ÛbàÑGoö©Æî3 @€ @€¶G@Â}{ôÛEà­G:â± ;¢³µ3NøICìyâÖ/ÓÞÑ ^ìŒ_=ѽÐG&KÅÌ8¹>ŽÞ¿.º&Ú[/Žw“‡¦ËÅ´<ôP :æ˜\’}äUWEÓ¾ûv‰É @€ @€ô–€„{oI×p?k_KÖUÿz{,»«3&]Qœßu›XW}C†W–'Iößu$ËÆtÆnC#>œ,ó_O­]‡–“ìé]óë,È­Åž&ÙÛ’„û~4†Ÿ{n¤w²7ì–¬5ãE€ @€ @€>pïã Èr÷íë:cÑuñû¿íˆýΩÓþÐG”å›Û»-qÿïóKƼº"bêauqÅŒ†Øïò±ëÖÅšyóJ=­kL–¦9í´ØãÚkcðÔ©Q×Ô´©æ• @€ @€ @ O$Üû„=û.ý¿1ÿ+í1tߺøÈƒ±Û!ådyw£ëH–Œyrq~ɘßü¡3_~\}L>°.šóǶ¯Xï&ë°§w±¯ùÿˆ¦ý÷Ï-3æg?‹ïwÍ*#@€ @€ @€@ÕH¸WÍTd#wžíŒÇ/næç;ã¨hˆ}>µùuÚ—­ìŒ_'KÆüêw1x@~ɘÿò‘úØ}X>ɾþùçcUa=öu=ƒN8!—dõïDã¸qÙ@% @€ @€ w§ÁV ¬§3žúëŽxñ¦Ž8èÔÇÉs¢aP÷wµ¯M–šyð™dɘ$Ñþò'&w¿󬆘8®.:;:bÝo·æÌÉÝÉÞþúë1äã]¿ô¥š¼×¶Uñ¨D€ @€ @€jp¯¶©²x:“¥`^üßñ»o¶Ç^§ÔÅ'ŸnŒ!c7N´§6}zIä’ì'wÁ¿/©sêê㸉uÑØÖkýëxã[sbMr7{]’TO×cõ½ïÅàOŒº††*µp @€ @€ Ðs ÷ž›íà#ZâÖ &ÇŒY cú ó㎠ŽÜÁío{so>Ô_ØžkàÄŸ6Äèã7^>æ·;ãž'“µÙ“»Ùë’<ü‡¯¾T#ZÞŒ5?ÿy¬¸,Y=I¶8ä:}zŒ¹çžxè¡Û”#  @€ @€ P¥î}=1«ŽN’í¹×º¾&ßÿšW;㉯µÇk¿îŒÃÿ¦!öÿÏuQW_¾«}]kg¤w±ÿ2Y—ý¹¤îñÕÅÿ8£!\³(·L̻߸3–<ùd >ùäüzì7Ü{íUƒ @€ @€v’€„ûN‚Ýšf›—=7]ò•˜·5•{¡N{²öú³ÿÐÏü]G¼÷Üú8ý¹†°k9Ñþì+ù;Ùï{º3&$ùóñµ÷<í?û?ñîWçÄÒwÞ‰¡§ž»ýÅ_Ä~4ê‡ é…¨uA€ @€ @€êpïåyhY27®¸êÇñÌ#³bNáÆö^¡Ûî^¹£#æÿ÷öv@]|ôáÆØ5¹k=}­X,³0¹›ý‰Žhm‹˜vP[\»ï½±ËÝ?L’ì?Õ#Gæ–Š}ÓM1è¸ã’;á7^v¦Û @€ @€ @ Æ$Ü{yB[W<WÏšÕ˽nº»·ßó/n?½Ü¸®!Æ^ëÛ:ãßw$IöäA¨ìŒÉïi‰s;çÅ~¿ú_Ñò—÷ÅÀ÷¿?$ë±øæ7cÀnºq{ @€ @€ Ð$Ü{y²›F¾?®¿æúˆAIÇFË’»â’«çôrëVuÆSßꈗþ­#¹¤>&~¥!^Zñ?Þ÷&KÆŒ¼&Nxû¾8ç§æÇ}(†žuVìõoÿ {ìÑëñê @€ @€Õ. áÞË34hü”¸ðkSJ½¶-Ø« ÷ÎŽÎxáûñäe1æcuqâoâáåÿß?·ÅêwÖÇq«Šÿq×߯žËÅÐO~2†~ã/bp’l¯”^!ð"@€ @€ @€M H¸oJ¦—Ê×¶®ë¥ž"Þ¸?Y§ý¢öˆ†ˆ‘ß­_¶¶Æ“·F¶zAœzÏ?ÆaíÏǰӓ$û¬«cà?uuå¦öZ:"@€ @€ @€@F$Ü3:q= ûÝW:㉯¶Ç²{:cõ™ëâ—{vÆî/þæ†8{È˱ç©ÓbèO¯¦÷¾·'ͪK€ @€ @€îµ¶ÙÞñø_¶Ç¾ÓK'­'ÏYG<ÿ£øêŸ–ÄÄC¾ù­h1¢Ö†m< @€ @€è ÷>aßùÖE}üâõÑ2º5ÞþðÃ1qØCqÌbý‡‹·›ŠGÒ¼K §œrJÔ××w)ó @€ @€;Z`îܹÑÞž,]c/ ÷›ÐâpÒåן9ëWñîð—¶Æ¼åIÁKÉÞŸßY¬²Ñû”)Sb‡£n䢀 @€ @€+ðío;ZZ’%:jì%á^cZNGgG|ö+£bQç1úí߯÷:-N{vŒ²o±Šw @€ @€ô‰À=÷ÜÓ£~ëÒ;Œ3ð’pÏÀ$mkˆã‡MŠÇŸo­]÷.½%þ~ÁŒ˜°ë‘qò¸™ñ¾“·µYÇ @€ @€ @€@7îÝ ÔZуÇÅ™\ŸÜïËñ›×~?úÃ_GSà˜:îœøÀèO$ÛkmÈÆC€ @€ @€^pïuò¾ëpPãИºÏ9qÒ¸ñÔ[÷&w½ßs^úNLsVœ0æ3±ëÀQ}œž  @€ @€ q ÷ŒOà¶„__W‡š–ûYú§?ļWnŽ+{ZLÚcZn¹™÷ ;x[šu  @€ @€úµ@}¿}µ ¾Vv·Ëû✃þ&þjòÏcAãↅ_Šëž87ž\~Ott¶W›x @€ @€ PµuÉ«j£Ø6 ¤Oí]¼xqŒ?¾Gm´u´Æãoü<î}õ–XÓº:¹ã}F»÷§bpã°µ£2 @€ @€v”À¶æ;wTÿ[ÛŽ„ûÖJe¬ÞŽ8Ÿ[õÛ˜·tv¼ðöc1y¯éqâØ³côž%ð3Æ&\ @€ @€ªP`Gä;{cXÖpï åŒöqàˆFúóÖÚ¥ÉVgÇßÍ?;ößí1uÜÌ\yF‡%l @€ @€ìw¸ïÖ¾otg\ñii{7~íßãþWÇ´qçÄQ£?M }°ø|ß‹€ @€ @€^Øùκ„ûÎP­‚6wæ ØÑÙO½5/·ÜÌk^ŠÆœSÆ|&†Ü£ F. @€ @€jM`gæ;w¤•„ûŽÔ¬¢¶zë\Ú¼(I¼ßO¾uO¾Ç)¹‡¬î3ìà*’  @€ @€Yè­|çö:I¸o¯`•ßÛ'àêõ+âd©™—Ý{Ù/Yçýœ8l“¢¾®¡J…„E€ @€ @€@Vz;ß¹­.îÛ*WåÇõÕ ØÚ±>ãçqßÒ[bmûŸâä±3☽ψÁê\Lx @€ @€T«@_å;{ê!áÞS±ŒÔ¯†ð«{—ÎŽÞž“÷š'=;F yOF…I€ @€ @€@µTC¾sk,·¦’:¶Eà}#&Gú³|í+¹Äûµó?ìvt²ÜÌÌ8`ÄÑÛÒ¤c @€ @€ Pµîp¯Ú©Ù¾ÀªñŠÏÚ¶?Åo^ûiÜÿêc`ÃÜ:ïGíù‰hª°}ƒu4 @€ @€5-PùÎîÀ%Ü»S©²j>;:;bá[ssw½¿±fqLsVœü ¸G È @€ @€;Z šó•c•p¯Ô¨¡í¬œ€¯4?ó–ÞœKÀ¾Ç‡âäq3bŸaÕÐL  @€ @€Û+•|§„ûöÎt•Ÿ•°È·zÝ[ñÀ²ŃËn½†ìS÷9'yrÔ×Õ«x'@€ @€ @ Ÿ d%ß)á^£'hVNÀ ù[;ÖÇcoü,î[zK¬k_“»ã}ò^gÄàÆ]6¬ê3 @€ @€ýD +ùN ÷=!³rnŽÿ«I–›™/¾½ ŽÙûŒ8qìÙ1jð>›;Ä> @€ @€jP +ùÎÆ´7¤x߈c"ýY¾æq﫳ãÚÇ?Ž8:¹ëýœ8`·ÔÈ( ƒ @€ @€Zp‡{­ÌäãÈÊŸ ÂÞìǵmÍñðk?û_ýa nØ%·Îû‘£?Mõ6{œ @€ @€d[ +ùN ÷lŸg›Œ>+'à&°™í±ð­¹¹åfÞ\³$¦ŒýLœ0æ¬>`äf޲‹ @€ @€¬ d%ß)ážÕ3l qgåÜÂ0¶¸û•æg’ÄûÍI~^1êÃqòØ1nØÄ-§ @€ @€ÙÈJ¾SÂ=;çT"ÍÊ Ø£Am¦òêuoÅýË~-»-ö:!¦%ë¼2ò¤¨¯«ßÌQv @€ @€ ¬ä;%ܳp6mCŒY9·ah›=¤µ}]<öÆÏ’‡¬ÞëÛ×&X“÷šƒwÙìqv @€ @€ P½YÉwJ¸Wï9´]‘eåÜ®AnáàE+‰{“åf^|ç‰8vïOʼncÏŽ=ÛÂQv @€ @€ PmYÉw6Vœxì(‰»éOú`Õ{—Þ×<~V8âƒ1uÜÌØ·ì¨n´C€ @€ @€œ€;ÜkôDÈÊŸÞä_ÛÖ/û÷ÜZ%‰÷sâ¨ÑÆú¦Þ C_ @€ @€ôP +ùN ÷NlVªgåì ÏŽÎöxrù=É]ï³cùÚ?Æ”±ŸÆ|:† Ùáè“ @€ @€-d%ß)á¾…‰Ìê€}íûÇægbÞ+ÿO­¸7Žõáä!«3cÜ.ïëë°ôO€ @€ @€@…@Vòî“VK›Y9«ÅüuËãþW¿v{ì=tÿÜr3‡Œ<1êëê«%Dq @€ @€è·YÉwJ¸×è)š•°Úø[Û×Åoßø¿qß«·Fk{KîŽ÷É{MAC«-Tñ @€ @€è7YÉwJ¸×è)™•°šù­üMÌ[zs¼¼úÉ8f¯3âıgǃÇUsÈb#@€ @€ P“YÉw6Ö¤¾AØw?6ÒŸ7×,É=`õšÇ?ïqLî®÷ýw;jô   @€ @€jIÀîµ4›cÉÊŸŠ«~sMëêd÷Ï­õ>´i×Ü:ïGŽþX4Ö7U}ì$@€ @€ e¬ä;%ܳ|–m&ö¬œ€›BÕîêèl'—ß“[næ­–¥1eÌgã„1gư#«6f @€ @€Ȳ@VòîY>Ë6{VNÀÍ !»þ¸ú÷17Yçýé÷ÆûG}$·ÜÌØ]ÌDì‚$@€ @€ ¬ä;%ܳrFõ0άœ€=VÕVgÝ›¹¥fzíö;ôÀÜr3œõuõU³À @€ @€dE +ùN ÷¬œQ=Œ3+'`‡UõÕ×··Äcoü,yÈê-ÑÖ¹>N;3ŽÙkz lRõ±  @€ @€@µ d%ß)á^­gÐvÆ••p;‡YÕ‡?»òá$ñ>;^^ýd»×§âıgÇÈÁc«:fÁ @€ @€¨F¬ä;«OLjAà Ý‹ôçÍ5‹“¬ÎŽ¿}üÌx߈c“åffƄݎ¬…! @€ @€îp¯À¨¥Í¬\ñ©%ó-eMëêH×xàÕÅЦ¹uÞýÑh¬oÚÒ¡ö @€ @€è×YÉwJ¸×èiš•°Fù7;¬ŽÎöøÝò_'w½ß+Z^Ç|6Žóé6`÷Íg' @€ @€þ*•|§„{ž¡Y9k”«‡µdõÓ¹ÄûÓ+î‹#G}4N7#ÆìràV¯" @€ @€þ •|§„{žY9k”¿ÇÃz{Ýq²ÔÌCËnq»LŒ©ûœ‡ì>%Òyô"@€ @€ Ðß²’ï”p¯Ñ35+'`òoó°Ö··Äoßø¿qßÒ[¢½³-wÇûä=§ÇÀÆ!Ûܦ  @€ @€d] +ùN ÷¬Ÿi›ˆ?+'à&ÂWœ<»ò¡d¹™Ù±xõSqìÞŸŠ“Æž»Æ @€ @€@¿ÈJ¾³±ßÍŒȈÀA»éÏk^Î%Þ¯~ìÏcâîÇ%w½ÏŒ »¾?#£& @€ @€þ#à÷ë¬\ñ©Qþ2¬5­«ã¡×nOÖzÿa k™[çýÈQ‰†ú¦ÒŸF  @€ @€T‹@VòîÕrÆìà8²rîàa÷‹æÚ;Úâwoý:îM–›YÙ²,NûÙ8~ïOÇ.Fô‹ñ$ @€ @€@ÿÈJ¾S½FÏͬœ€5ÊßkÃJ×wŸ·ôæøýŠûãÈÑ‹“ÇΈ1»Ðkýëˆ @€ @€@od%ß)áÞgCô‘•°hj²Ë·×½‘[jæ¡eÿû ;(¦Ž;'Þý„HÏ/ @€ @€YÈJ¾SÂ=ëgÚ&âÏÊ ¸‰ðo£Àúö–øíëwƽ¯Þí¹¬NÞëôØ0d @€ @€¾ÈJ¾S½ïÏ•AVNÀ2xFggg<»ò¡d¹™Ù±¤ùé8nï?Ë­õ¾û 1t @€ @€dN +ùÎÆÌÉ ˜- ¤¿€yBîçõw_N°zs\ýØŸÇA»Ÿ»ëý½»±Å6T @€ @€ @ gîpï™WfjgåŠOf@k Ðw[߉‡–Ý,ûQ 02¦%뼿ÔG¢¡¾©Fg @€ @€µ,•|§„{ž…Y9k”¿ª‡ÕÞÑ¿[þ«Ür3«Ö½ž[jæø½ÏŒ]Œ¨ê¸G€ @€ в’ï”p¯Ñs4+'`ògfX‹W/Œy¯Ü¿_ù@5úãÉr33bï¡ûg&~ @€ @€ô¬ä;%Ükô|ÌÊ X£ü™Öª–×ãþW¿v{ì3ìà˜š,7sðî'Dzy @€ @€èk¬ä;%ÜûúLÙIýgåÜIÃ×ì6 ¬o_¾~gÜ÷ê-ÑÑÙ™$ÞgÆ÷:-6 ÙÆF€ @€ @`û²•Ú1"@IDAT’ï”pßþ¹®Ê²rV%ž ¢3I¶?³òÁ¸wéìXÒüû8~ï?)c?»Ú› @€ @€^ÈJ¾³±×etH€@Õ ¤¿À9%÷óú»/å°zÕcŸÊ-3“.7³ß®‡WýH€ @€ @ ·ÜáÞÛâ½Ô_V®øô‡nv€À»­ïÄCËnË­õ¾ëÀQ¹uÞß?êÃÑPß´Z× @€ @€M d%ß)á¾é9Ìôž¬œ€™Fî§Á·w´ÅË™,7sK¼½î81Yjæø1gÆÐ¦Ýú©ˆa @€ @€ìl¬ä;%Üwö™ÐGígåì#Ýî —ßy2YnææÜzïGþDœã‡Óö9'&Ž8.Ò_¤^ @€ @€²"à÷¬ÌTãÌÊŸKõX×¾&}}Nr×û­QŸ$ÛOwN|pÏOÆ€†Á5>rÃ#@€ @€Øœ@VòŠïËÊ ˜ab¡ïDÎÎÎøýÊrËͼÒüLn÷)c>#íµ{Õ4 @€ @€@µ d%ßiI™j=ƒÄE  ¤¿@ybîçµw_È=`õÛ‡$eSÇÍŒ}‡OêÇ:†N€ @€ P­îp¯Ö™Ùθ²rÅg;‡éð~$ðnëÛñಟ$k½ÿ8F Ü+¦&뼱LJ¢¡ÞuÃ~t* @€ ÐO²’ï”p¯Ñ4+'`òÖNhïhË™Üõ~s4¯_'Ž=;ŽÛûÏchÓ®;±WM @€ @€ô¥@Vòî}y–ìľ³rîDM÷ßy"·Îû¢•ÇQ{~"N;3öº_?¹! @€ @€ú—@VòÖbè_ç¥Ñ¨) »¾?ÒŸ•-Ëâ¾WÿøÄ9Éúî‡%뼟Gé/b/ @€ @€½%à÷Þ’îå~²rŧ—YtWãëÚ×Ä#¯ÍI’ï·F}]}.ñ~ôžŸŒ ƒj|ä†G€ @€¨m¬ä;%Ükô<ÌÊ X£ü†ÕÇñû÷'ë¼ÏŽ¥ZÇ93Yëý³±ÛÀ=û82Ý @€ @€l‹@Vò–”Ù–Ùu U-þ>t“r?Ëþô|n÷¿ùíô8täIqò¸™¹egªz‚#@€ @€Ȥ€;Ü39m[:+W|¶<5ì?­_.ûI<°ìDZû 1¹åfßã”h¨wÝqÇk… @€ °ó²’ï”pßyç@Ÿ¶œ•°O‘tÞ/Ú;Zcþ›ÿ‘»ë½¹uE²ÔÌÙqüÞgƦáýÒà  @€ @€YÈJ¾SÂ= gÓ6Ę•p†æ;LàÅ·äÖyÿêßÄö<5YnfFì9d¿Ö¾† @€ @€vŒ@VòÖRØ1ó­2(0a·##ýYÙ²,î[zküÂsb¿á“rËÍLÜýØ ŽHÈ @€ @€})à÷é·EKK[466æ~zth/WÎÊŸ^fÑÍ ¬k[¼~GÜ÷ê­ÑPט{ÀêÑ{~24 Úìqv @€ @€ì\¬ä;%Ü·â‡ߘsq©÷»ë™Òöæ6VÆú¦øà^§Å%øq|þ «cñê…ñW|4~òÜ·ãÍ5‹·¯qG @€ @€dZ@Â}SÓ·jQܽ°°sÒ5qRéÖöòã=-Š‹ÂÌ»ûw±ª¼k[-ñ‡/ç÷í·OŒÞD-ÅdC`ÿÝŽŠÿrèwâë¸=ëÄß/˜ÿká—bÑÊG²1Q @€ @€ìPâ);´ÑZh¬ùåòZëSg£ºÔˆñqjRžËËÏ{0^n¾ Flö®õÖXñF!‹?ì͸ãWÆœ;æÇ««W'­ Ž™3?vL™ØmoÝE Œ*9xlüÙþ_S÷ý¯ñ›×ÿOüøù+£±n@î«ØóÔÐ0¨ ¢ @€ @€ÀÎpß„pSÅ3K‡Ú}­ÆÑqàôdלtws´v_«\Ú²8ÌÕMŠf_Ÿž]Þ•nÍ›7'f]}QL¿bNÜ|Ùé[õÖ®-øD€@_ l'›‘[×ý÷+îË­ó~çË×Çñ{:)ûLì:Ð÷Zúr~ôM€ @€ØÙ–”Ù„ðÊåo–öì¹ÇÒöæ6*rôÝWk]“¤åó¯âR43/¾4®¸ââ˜ZqÄœË§Ç Wέ(±I€@–êëêã°=¦Æ…GüKü·Ãÿ9ÞYÿf\ùÛÓã_Ÿùzüqõï³4± @€ @€ô@@Â}XÃ&œ²âG6vµzVÜüü}ù›á“ÃN¿&ž]Ý7窸ì²ïÄÜÎÕqÏõç—\xù)qû’¶ÒgdS`ì.ÆÌ‰WÆ_MþyŒ²oÜðô—ã; >O¼ùËèèlÏæ DM€ @€ Э€%eºe‰h{ý7q]a¹õO½qØÄMÔ,oiI™a!¿ðç±vMkìyÐÄÑEXL»ðÆm¿$>=+ßñ¯z!οå~ËtÝúë¿þë>|x×ÂÍ|ºöÚkcÀ€›©aÛ*0lÀÈøø¾_Œ¿ç?Çü7ïŠ_þñŸãÿ¼øqÒØ³ãؽÿ,†4mýÿV·5Ç @€ @€ªEàk_ûZ¬_¿¾ZÂÙaqtIùî°Vk ¡Æ!»–FñFóšÒö†ëJârÝ÷Rq寠1~ˆʒ ¶ã£_þRĬ/æÊßxkÓýnp`·GŽ#Fl®¿®‡ÕÕÕu-ð‰.ÐXß“÷:=÷óÂÛçÖy¿{Éqôž§%ë¿.wüïTƒ @€ @€*5jT´¶néæ* z+‘pß ¤9 ^ж826Âj~>î*>uú qÀ -5Öm¹Ub£q£ÆòÇ65 ÜR#[½ÿË_þrŒ?~«ë«H€@ï ì¿Û"ýykíÒ¸ÿÕÆß/˜ï~DLÝçœx߈cz7½ @€ @€zQà«_ýjzûæ7¿Ù£ú}UÙî›vÀq1³¸oÖ¯âÙ–â‡òûªg,­É>uÚ1¬¼«›­æøÁMÉ]ðéÏ7bI75Ò¢Åü¦´gkÖZ:À™Øcð¸ø³ý¿Wó˘¸û±ñ£?\W=ögñðk?Ööò÷h298A @€ @€ú‘€„û¦&{ÐA1½ô ÓYqímPsY|ÿÒ‹JeŸ™zpi;ZšcÙ’%±$ùYÕM¢>âêøñËËõ‹[«ˆ¯Ÿ7«ø)>|üþ¥mÔ¾À Æ¡É²23ã²É?‹Oî÷åxìŸÅå|$~öò÷âuÝüΨ}#$@€ @€dJ@Â}“Ó•®§~CiïìóŠoÜú@,[¾<–/Yמ16.™WØ=õ†8ë°òýíOÍšc÷Ý7öM~¾ÿäªB¥a1ef)ƒ—œ8:®½ýÑXÞÜ’,3ÓKÜgì~béŽù˜yK|rü&Ö)EeƒZ¨¯«I{L‹‹Žøßñ_Ÿo¯{#®üíiñoÏ^l~¦‡lL @€ @€š¨ëL^51’2ˆ¶˜{åGâ”Ë‹™õî:™sÏÓ+’ãOÝxNLúâì\åë篌 ,>¸ty|÷ŒÑqQqÝ÷îšË•¬¼1&Ûd½MïH€ºxñbk¸ošÈ™h^¿"Xö“xðÕǨ!ãcjr'|𔝝kÈÔ8K€ @€Ø¬ä;Ýá¾ÙÙmŒi—͉»®)ߙޥú¤™1çÙ{»$ÛÓýM‡”ªu}꨸ðŽ•q×õ—öo¸1õâ›bñÚíK¶oئÏd_`Ø€‘ñ‰}ÿ߸âØ_Åq{ÿYܽdV|ë‘OÄ=¯ük¬mkÎþ€ @€ PîpßÊIlk^ ·(Þ|w}rÄ€½ïĘ4qLló¢/-«bÑóÏÅò·×Gkë»±>FćF Úʈ6_-+W|6? { ØœÀóo?÷.½9ž[õX|p¯OÆIcgÄèäîw/ @€ @€@­ d%ß)á^kg^aÃîѧqéœ @€ °­YÉwJ¸oë WùqY9«œQx2/°´yQÌ[:;ž|ë×1ii¹»Þ÷vpæÇe @€ @€@ÿÈJ¾S½FÏˬœ€5ÊoXªN`õúñà«?Ž–ý$ö²oœæ¿ñ‹d¹™Ù±¶ýOqÒØÏű{*7ËÌJ€ @€ô?¬ä;%ÜkôÜÌÊ X£ü†E ϯz,·ÜÌïW> uÉÝîõQõ¹÷tõeéï”ônøâþô½\V—l'ÇE²¿T¯X–Ö+·›¯·qYR»Ð~á=wL¹,w\©4ŽBû…²Êv‹ã¨,+µŸÆ—‹3©ØWn+7îtonœI½üv>öÊþËí&u“tä¹qÆŸ/K÷¥Ç&û mU¶Ñ%ÆnÆï£Ð~²ß‹ @€ôwôßÞ‹/ŽñãÇW5EcUG'8ØiŒ8:ÒŸumkb}GKt&[팎HºZ~ïLÊÛ“²ä=ÚsuÒ½iYgR–Ô.”¥ï]ËJmti/­—ìIëæú*¶[,KÛN[Í·UÙF±¯Ê²âvGg[´¥ýäú*¶UÙW±¬Ð~®ÿb_ùãŠãÎ÷¿A[¹˜6,KcO½Ò±ÚÏ9¥eIÝ¢Ma»»²¼a:Öò1›šðüò?I ¿pá£xq#rÒ´šø/\0HÊòIû|YéâAº¿P¯²,©½Ã.x”ûM[M/8¤ íç.>T^„¨Ü.ÇÖå‚D1ÞbOǘŸÛ_ì+_–ï/Á#1¤àPÑFÉ!WV<.)MãMŠ1çÞÓ²ü…žü…§´~¡n!¾b{éñ^ @€ Ð$ÜûïÜ9r‡ÄÀB£ŠrIü\’?½(¿øÐõ"Ä$r‰ÿârò¾2‘_Nø/>¤õÓË…ö»\„Ø ý\,´Ÿ»Pn+×~—²ÂÊ 饉¤N[GÒ~ñ‚Dñ=wl¾d¹zå iɆe¹½;è‚Gy•&iŒÅq*ËÒíî^i²¾|á!MÞW&ò‹‰ú´Î$rÇU^„H/(äÛªl¯˜Ü¯,Û¸4Šrûù¾òeå‹…o¥.T¶Qê#{>Ötúm˜ C¢±¾)ùÿ©KßËŸ›*>7Ô•Ësu’} õþüìî¼QF€ @€@møOmÌ£Q @€@ äîfO’±i›IM/ó¥„|îAò)wÁ¡¸ïRV¸ ÑíâÅ…Ê„ÿÆe¥ Êe…ö»¹àQ¾ø’^ÆÈ·Û]Y±­¶ŽtTërAÒñ´´¿›\4iM~Ö'ß,I~Ò÷ÂçöÎByn_ÅvásqFÓ%«6 ŽÆ. ù$q_‘¬Oúi¾)—ØO÷¹}…$šà¯øœ~³`@}Ò^ñ"@aCáB@åE€\Ò±ù ùo£óN€ @€mpßv;G @€rËñHØn݉~ƒ`]ûšŠd}ER>—¼O?'?¥D~!¡_™È/$ïÓ¥°Ö´­.´Ul§òØBY©­ ?¯öd9ªâ«©~P!a_™Ì/nçóådýV~îrA¡ØVñ¢Az¡¢ôbAÅgËgÆ; @€l H¸gk¾DK€Ȭ@ºœÍ Æ¡IüéOu¼Ò»ö×µ¯Í%îówè“÷ßÁ_¾PNÞ·VÜá¿>igMÇ;\ØÔEƒü7òÇçûjO.6lù"@š°Oîü/Ý¥Ÿÿ\yÇyùžBB?W·"¹Ÿ|.}s —èOÛ(´Sñ9÷ ªãD @€@f$Ü33U%@€ØÑé·7î²£›Ý®öÚ;Úr³Î/ד&ã+.lb¹ž´nš°O/ T^H¿QðnÇÛùoäŽ-\(^((} ½ã?í§µp|þ"@ú9}0uúJŸÿ&@×ä}åþ]–ªHÖ/”—ýIü]öoêsåEƒ/ ¤q¼ @€T“€„{5͆X @€ú½@ú`ÙÁõÕu µ}]ÅR?å;ü+×ðïra`3 ZÚþTh«âBB.ñŸOø—¿I^HÊ*. ?§ßLH_éÃ|›–Öô/ݹŸÜÅ_\ÿËE€Š;øK Jß(<3 ðyÃ;üóK U\lȵµñgúýÿ„ @€ý\@½ŸŸ†O€ @`KiR»)n©Z¯íOŸÐÚ‘\¨¸ã¿x‡׋Å;ú wîw“¼Oë¯MžP¼Ã?|ùÿâçÖÒEB›|N/œ¾’‡§Éùô¡¿é{åE€žÜáŸ?¾ëE€î.ä/¤wÿ’~»\ph zíÔÔ @ $Ü @€dJ M h”û©–À;:;ò*.“õ]îþÏí/ܽŸnwù\¾£?}&@ñŽþR;ÝÞñŸ~3 ½øP<6ýœowË]“ó…»ó+îðßhÿV-ûSLô'ï¹¶Šíæßóó“_ú§r t‰¢ò«°¿²¬¢r׺ÅËÇ—/(T”U¶Uè¨\/¿DÒÖ÷_¬Ù}ûåv»ß_:ºbLiÅWq|Å÷\yywR³ø¡ø¾Aü…vËõ*[O[ËW޳\–ßênºÇ‹Ø ÷mQs  @€*êëê«ð"@{!ù^HÂot‡zçþ›[ºÃ?]ÚgMáÕ ŠþÍ_¸ÔmmoéòàÎè¬ÐÊo¦ßT(¾Êû»+Kjê–÷¦G–?¯l³ëþrO¥­Šþ‹u‹íä[/·_ìªrñ˜.u+Ú¬¬[n©b«¢n±­ÊcŠqVó{º¬S9‘_yA uéB@ŇRY®Z!á_º°–›J6»Ù_QaKý+×KK*:(µ_Ž9TéC¹nweI[u‹•IK ñWÔëvñàÜ!ÝõÕ]YÚñÀÒF÷ã+W,Å”ëªpx—˜*ê–Ë7Ñ~¡¸\o¾m#Î÷Ÿ™üþlª/‹ªÜV¾ñÔ¸\–?ºô¹Ðnþs¡~ɼØSåñå6‹ýWÖÊmwi³k­ò|wí+7ê ÆXŒ1÷ÞM›ù– ½'û»ÔÏ’ÿo®«ûË¿Q»þûŠm§{óÇåÞ’ÿT¶[ÜW,+×)_Ñf~o¹î6Û¤ UŒ¿²×ü®´b?ù÷ÒçâÇœÞu6Š5=ªpÀûJå¹PŠV¶WØ.WŽ2cÚni_åqùz›³ÉŸ^Œ­ð^úœ´[Ú.t[ü\Ùn±¬g6…s=äãÞ–qäú.¿ÜfnléxJûŠ6ÔÉí/î+ÄQtH/lÇV<ºšß%Ü«yvÄF€ @€mH < apîg›pXÆÒ Åg“øéŠiþ. ýŠ„¹¼X3=¦¼]ܬ,«Ü.öÐõ‚G¯\·ÜfeÝn÷—OšÏW®W9ªr¬•mv9¼8€Ò{ÚdE,åÅãºôµÕýî>¾¢SnoEÿÅòrDå1åZÜbÿ…~+Ú¬Œ¿¼]î¡rü…£…ŠýÛ[öß–þ‹½¦cmÏ]üKKÊCÈÇ’©°]Þ™;8ÝWŠy#£âñi›ÅqËÊŸËûòñÛ+¾§•¶óUÊŸ+ö•ëú(vQc²¾Š}–I l0ŽRyÅqií\;¹÷ ÛÌíJk—ëlÐfy_²UØ—/K{Kþ/wh±Ý|OùÿV´™+È×ÏuTøOZ’ß•OÛ-–•ú-îªØWªSеØjÅñ¥}Ä‘Tí:Ž|¯ù’ãKÇ•ÛL·r}–ö•‚ÊU*Æ“?vÃþ Ÿ“·b½t«ÔfncƒÏIY±n1ž|I¾^îà´N!žÊöŠÇ&¦ÐS®“R›å}ÝôÛM›Å£‹•ú(”>'Ç·Ë‘úȵ»aÅ}ùåÝ N!žbi)–d£»ñç[*ï+äî‹ÅUû.á^µS#0 @€ °õéÝŽés¼ @€@- |»³x|u®¾ºÃ @€ @€Ȇ€„{6æI” @€ @€ PåîU>AÂ#@€ @€ @€lH¸gcžDI€ @€ @€U. á^å$< @€ @€Ȇ€„{6æI” @€ @€ PåîU>AÂ#@€ @€ @€lH¸gcžDI€ @€ @€U. á^å$< @€ @€Ȇ€„{6æI” @€ @€ PåîU>AÂ#@€ @€ @€lH¸gcžDI€ @€ @€U. á^å$< @€ @€Ȇ€„{6æI” @€ @€ PåîU>AÂ#@€ @€ @€lH¸gcžDI€ @€ @€U. á^å$< @€ @€Ȇ€„{6æI” @€ @€ PåîU>AÂ#@€ @€ @€lH¸gcžDI€ @€ @€U. á^å$< @€ @€Ȇ€„{6æI” @€ @€ PåîU>AÂ#@€ @€ @€lH¸gcžDI€ @€ @€U. á^å$< @€ @€Ȇ€„{6æI” @€ @€ PåîU>AÂ#@€ @€ @€lH¸gcžDI€ @€ @€U. á^å$< @€ @€Ȇ€„{6æI” @€ @€ PåîU>AÂ#@€ @€ @€lH¸gcžDI€ @€ @€U. á^å$< @€ @€Ȇ€„{6æI” @€ @€ PåîU>AÂ#@€ @€ @€lH¸gcžDI€ @€ @€U. á^å$< @€ @€Ȇ€„{6æI” @€ @€ PåîU>AÂ#@€ @€ @€lH¸gcžDI€ @€ @€U. á^å$< @€ @€Ȇ€„{6æI” @€ @€ PåîU>AÂ#@€ @€ @€lH¸gcžDI€ @€ @€U. á^å$< @€ @€Ȇ€„{6æI” @€ @€ PåîU>AÂ#@€ @€ @€lH¸gcžDI€ @€ @€U. á^å$< @€ @€Ȇ€„{6æI” @€ @€ PåîU>AÂ#@€ @€ @€lH¸gcžDI€ @€ @€U. á^å$< @€ @€Ȇ€„{6æI” @€ @€ PåîU>AÂ#@€ @€ @€lH¸gcžDI€ @€ @€U. á^å$< @€ @€Ȇ€„{6æI” @€ @€ PåîU>AÂ#@€ @€ @€lH¸gcžDI€ @€ @€U. á^å$< @€ @€Ȇ€„{6æI” @€ @€ PåîU>AÂ#@€ @€ @€lH¸gcž¶)Êæææm:ÎAôô÷ÄGÑl¤l—À1Ço¾ùævµá`j_ ­­-9äHß½ °%©S§Æ’%K¶TÍ~ä²ï”pï㓵­­%Z’?DwÆß¢}<:Ý PííííñÌ3ÏT{˜â#@ J-Z$V%s! Õ,ÐÙÙ™ûû"}÷"@€À–ž{î¹X¿~ý–ªÙO€œ@òî}r²¶ÄSwÞçL«‹¦¦Á1¸©)y¯‹3.¸2î~jyŸD¤S @€ @€Ø> ÷íóÛ†£WÅΓ¦1fÏëzøœY—ÇÇ'Ž n}ªëŸ @€ @€ @ ê$Ü{yŠÝúõ8ov¹Ó™×Ü÷Üu[\qþÔRᬓâOY½bƒ @€ @€pïÍIj[ß™1«Ôã¥s^ˆ›¿ö¹˜ö±3ã²çÆÂ›Î/í;ï²)÷‡  @€ @€T½€„{/NÑòßÜ¥tûùÉ]í§OèÒûaç~-..–̹#~·ªøÁ; @€ @€T»€„{/ÎÐK¿y¸ÔÛ3OŠÆÒ§âÆ„8íŠâÒ2s≗eÜ‹2Þ  @€ @€ Píî½6CÍñ»‡çz›'OÕmÏ?¦T>÷±—KÛ6 @€ @€ @ º$Ü{q~–ú•>tÙØs¿˟ו7m @€ @€ @€@u H¸÷Úü¬ŒçJ7¬ï»6ußqkȲw/£” @€ @€Õ- áÞ[óÓ¼"žYXèlúá±ï&îpï­pôC€ @€ @€;V`ãçvîØöµV¶_||zÄœt÷9¿‰ç[ÎÃvrÒýðÃ/ö¾UïMM›¸í~«ŽV‰¬ ´µµÅ€²¾¸ èEô÷Åøñ㣮®®{ÕYHO :4‹¡‹™^hooƒ>Øß½ì®;Õ ÐÚÚÚã0²¿”pïñ´nëQ^ÃýÈO[H¸¸í ðY³fÅÊ•+{ì{Þ󞨯÷¥‡¡©L€ @€ @€@–,Y[}ÜðáÃc„ []¿¯*J¸÷¢|yuö9ñÒ›-qä°3îÏ?ü`)¢£Þ·´ÝÓ/|á ==D} @€ @€Ø·3o^ÏÇ1³tÈœ—¶Ë«âÁÏ.|œ“VÞe‹ @€ @€ªZ@½§ç )É"î…×ìó¾Oµ?åß—Íý~\4¯P6ýŒ8X¾½+O @€ @€¨b ÷^œœÆ ›J9÷Y1é߈^\Ë—/w^cO¹¤Íõ—Oùö‡  @€ @€T½@]²0ýÖ¯L_õÃÉ@€ËæÆ´±§DñFöî"žté]1ÿª…ö»ÓQF€ @€ @€êp‡{oÏ˘i1ç…»âüIÝw<óš9q¯d{÷8J  @€ @€ PÅîpï³Éi‹e‹Æ¢ÅoÆú$†CGÇÄC'Řîkï³)Ñ1 @€ @€¶C@Â};ðJ€ @€ @€Š–”)Jx'@€ @€ @€Û! á¾x%@€ @€ @€E ÷¢„w @€ @€ °îÛçP @€ @€ Pp/Jx'@€ @€ @€Û! á¾x%@€ @€ @€E ÷¢„w @€ @€ °îÛçP @€ @€ Ph,nx'@€þ-ÐÒÒƒcíªæh6"’M/t+Жü¾h+ìi4(üºè–I! ´µDóÚÖˆ¦Á1ÌêøL€lµ@[47¯hkKþ]ÒÃF «ª“ø÷ÑVOdv+¶,º54#À̘¿úæ8rXvÇ"rv°@Û²¸û_þ%®ý§ËcÞ¤í©S#æÍËu2óŠ›â[ŸüÎØÁèš#Uæxôö›â{ÿô/1;÷ £8ŽIqþ—ÄW¾xVLåOË¢Šw6hy*.<)f¥Å“®•O^#6¨â#ýOàÅ;¯oýüÅØcÈM ~M¼µfB|óú¯ÅÄA›¨¢˜~$°*æþà{ñ7ç%9Œ.£ž×̹>þûé‡UEâ½®3yu‰Ï‡šxàÊiqâåéi8=I¸ß!á^s3l@¶Q ù‡ïW’ø^·ÙçƜ~§Oð×íf™ì$Pó«âçìçÍÞü@¯ä͸pò¨ÍW²—~(з^08fä²íÉð§ß«ï¸ \Ó‚!Ø@àÑk§Å1—tM›mP%ù8=Ir“ýÒØ˜F þ$в(¾1ù ¸:½Yp¯I—ΉG¯:=ú:ƒa ÷MLPM·5ÇSw·l¯‰;L %k²ýâëo‹û¹?n¹þâŠ^æÅôýÿ.–U”Ø$@ ÿ ¼xû×»$Û§_|}ÜuÏ=Éï‹KcRÇEÇüe,j©(°I€DàÅÛ/-'ÛS‘ÕX 4Çï.&Û'ŤIÝÿDìMÀèçmq÷Ÿ©H¶OŠkn»'>;?n¹bfÉfáÕÓcÖ‚U¥Ï}µá÷¾’ßiý¶ÄÜÿ.~üàü˜5{ν¸Ã} ô_åsãðѧDñÂðMóWƹG–¿ØÝ¶lnœ9ö”(þ¹âþ7ã²)îZí¿'Œ‘÷oeqåácãòÂ/Œ+îz!.ûØ„2ɪñ•“Šë û¯O~Ÿ\Xñû¤\ÑýQ mÉqÔ¾ÓKsä ¦&w¸Ïu‡{<Œ™@W%ÉßûæþƘzýü˜{á‘]wûD€‚@ú÷DSò÷Dþ55îZü‹øØøò}ì‹nÿJôéü÷÷']zWÌ¿êc}º´Œ;ÜkîÔm§“µ˜7N¶×Ü@ ˆíXõÒÓ¥øÎ¼aa—d{Úlã˜iñ·•ïtŸ÷Ä+ÛÑ›C È´@ó+1¿xuîü9qie²=؈#ãâËÊ¿/2=VÁ °ƒ–ÄÕ§olßÁ=hŽ ´¬(ý1õн2<¡ °³æÿø—º¸ô®Ù]’í鎉g\<¹2ÿZøóç’ïÏôíË“­úÖ'ôÞï¿äú¸æ­HÖ+¾þÓ%1»øåУ& ÈžÀË÷ÝQ úè£÷-mWnŒ=ôðÒÇá¥-ô?!qp²nÌœäo‰IÆu{§H[¬é,FL€À¸ò¼Ò·c®™s[¼6ýÓ[xvÌ›Thyõ¥Ò7j÷3º†Ff(ìXåñèÝÅïߟŸÿИ›oœ7·®ï·¥»û| w ÷§(ã%ƒbÊç.Œ)¥Q´ÅÀ»$ÜK6È ü™¿Œ+^;åïΛãg ór‚¬áÞâú P «ü v?ê¼ÒPnX¸:.8lXé³ ú·À²wÇ/­ŒÕ/>ÿrùu¥%ª¦&ë%þ"Y/±JþÎíß“dôúR`Õ£qÆîÇî\½4^h½*&´-ˆ3•/³†{_ÎŽ¾ TÀS?8'&7{ ñL9ÏÞ§Oôo‘-@ÙM fZ݃šQßÔ˜ó’ÿëî5)n¸çθ`Úøîvöj™5Ü{•[g¨v–xôÖotI¶ÇÌ[âs’íÕ>qâ#ЋÍqûyóf̈‹*’íi_úò‡$Û{q&tE :’~Î+&Û#nyöò˜P¸;Uº¬:gLTúJ uua•åIÉÚuékê̸ôŠ+ââ™SóŸsÿÓšs—çÖ‰¨(·I€@hmÍÿ®Èÿ¦H’í…_“’ßçŸ_|jª±0¾xʾqãS}½‚{„„{9;“[X¶ ¹|øà8fÆÕåšÓ¯Å7}.ü¹Lb‹ˆáÉ?Œ'M-ü¥[Iÿ­üé±GÅKZ ОúÁ_¾]‘>˜ýs ßyi.0“:ëÇ'‰¡È ¬Šÿ¥°&óÂ…qÍ]ÏFçÜ›ãªË.‹ïÜ<7V¿pOœ_’š§üå/Âïˆ ýR }  PE-Ëĵcš³*°|ñMÄÚ;.ŒñÖL¬¢Ù jçÞüdòî“Ñ™<˜hñ»âüä/ßäßÊÉkaLÿËŸ†”{5Ì“ô¾@sò•ïIçžé0ó¦øþ‡•ƒ<¤|øÀä)2^ôoqÎ]‹ã…žg¯Œ¯}lbŽa¦Åÿ|á–rÙ¬ŸÇ þÀ({Ø"ÐO&)÷Û^¸)>6qTI qÄaqÙœG¢t¯û¼»â™>¾É]¥4=6 Ðÿ–̽6ö=å’.Ÿ~ñMñ·ß˜=¨‹‹t#Ð8(Æö±¸ñ×÷Äó£Oɯ¥8û'ñä?}.&ûjL7`ŠÔ¶Àó¿üIy€³ï‰+öx2V$%C’Ÿ5/_¥•šçü[\ô•'#ÞZþæßÇ™Öf.»Ù"ÐFŒ#63ÞÆ ë“»V/Ê-ÖüF¼“|SÆÚu›³‹@˜þ¥øhq­ºÊñ;8ÎH2îs _œiªÜ×Ûî}€®KTƒ@ó‚»&Û§^÷ÿ«1eÂæþì­†ÈÅ@€@o ,¹ûÊØ÷ã—']N9‹§ï摨£Ž‹Ï'àΫ’?p{ÓG_”š–·#I¯_}]åçÊíy1ëºüãÎ&|åo+wØ&@  ´µå‰ilÜTjjp Þ@ •n†í{DîîõÂ?5º­ÉwçÞsTr…nN÷SÝÄA;­xS¿ÕvZ‡&@€*h^_:ê‹¥@οáþ¸þ‚)n)‰Ø @ (°â¹ù…Íy±èõµÝ'Ü“Uß\]<Â;ýU`ÈÞÓâü‹÷‹‘ƒ»[0fm<’dàóÿ ž_zLÄŠµ1qWÿ$í¯ç‹q÷oæ§nLž “ÿ÷ÈÅsÇwN¿1HËóñ›R†mÏØµ»_-¥„Zhª¸_}Î’X™Œoã/Ó®ŠÇç•“íébúò寛¾Ô×7úHàÅÿ¸±ôµî©×<7^0¹"Ñ-Õ.0rßýJ!^ò½9ñ…Éçnôõï%wß—ÿ¾:-öÛø/àR6¨] §_7ž¾©ñµÅžIîiòlúçãê«Îu¡STÊ ô3ë®›ßH~”WdÎ<:ë²(<"ââSc¬~vf.‚À ƒcfòå9¹_WÇU·~>nüÜÄ.<«ýaÅ¿GŽ‹÷öñ¿Güºê2=> @ ?´Åó ž/ôµ_Æw¿{_´lê!DëÖÅèã?çN›P>ÆýF`üGþŸ˜…µ—gŸ»7¿ó¯ÿBL;,šW-‰~xmL¿¨ôÏá¸øK§n”ï7XJ€ÀfÖ–÷­^é§Aå[ô3a}(.NÆœ[yjÞE1úœ–xä[3ãðñ£#š_Ÿ}ï¢øôå¥ÛÛã– >Xýì$1\%AñɯÜ1ë¼\ɬ%Ϲ+þ꼓côàÖxö×7ÅÌ_Tª}Å_Ÿ·Ñ¼ÒÎ^Ú¨ëL^½Ô—núD 9~pÆð8/÷ÿ§¦ÇüÕwÄ‘}|•§OtJ€@…@sÜ8mx|±x7jÅžMmN½~~̽ðÈMíVN€@ ,¹ó±ïô«·<Ê™7ÅÊ›7¾~˪A€@í Tü»dê ±zîÝ|¼öŒ²ÀòG¿£)'ÉÊ{ºnͼᑸÙ7r»¢øD   @€ @€èF@½E @€ @€ @ §î=SŸ @€ @€t# áÞ Š" @€ @€ ÐS ÷žŠ©O€ @€ @€ºpïE @€ @€è©€„{OÅÔ'@€ @€ @€ÝH¸wƒ¢ˆ @€ @€ôT@½§bê @€ @€ @€n$Ü»AQD€ @€ @€z* áÞS1õ  @€ @€ @€@7îÝ ("@€ @€ @€=p縉ú @€ @€ @ ÆnÊ @€ ÐËm«Å/îy:bÀ€õ¼~ýúØýГbÚÄÆ˜{ëœx¾y]Œ<â´8sò˜µ“¥ÊmËŸŠŸüôáhŽ‘ñ±ÿtfŒ”¥èÅJ€ PËuÉ«–hl @€² мà»1ü¨‹¶-Ô©7Äê9GÄôáÇ串©×̹_;rÛÚÊÀQ ¾;-Žº(7Òxdõܘ<,A ‘ @ _XR¦_L³A @€T½@ÓÀmqźhkjб…†×øßMK#¦mWs$ @€ÀÿßÞ‡ÄyßqÿšjÙ^: ŠÝL³¤´ºJÒ? xAÇÈIÉ5¦Tºya cDN¦e—’ÃÊÖª…)M i‹Ø cêÐvLŠf9Ëâ–‘4RtUvǪ­îñîžÇçÔØ4>mBx<Üïù=¿ß÷÷ ³$ € €+RåÎÊZÑíÊÚ0°¿x CIDATdõenzLn—[Z­„Êœ5Œ € €Ü'JÊÜ'x–E@@ànæïfв1®Ì4E&tÜW¦‚”¥,ùêZ5<µ<3?¥K­:~ü¸:&V£9ïP‡ñbRÛ':¥ÞŽFùÊÊä)(PqxÊ|j>ß«amÓ¦FÔ\ç‹Í‰Ý‹q?ž2Õ5Ÿ×ÈDÒ ¶Y œoÔ!Çë‘Ç8|G50>£4×£¶qÉÍ©‘˱ç6׉?{™š/ kù“'Ïä @@õ ðÒÔõ@@¯M 2ÒªÌüñøÞ¦!uUßáe¨sÃ:”±Kç¾ôN¼êŸìR‘¹™>2(Oâe«Ê/V~¨O!3†ñ2Öé^ŸQ®FŠ üÊ­{׈ïU÷?¨$/¹€ü`ó!í9²ö]ºoª¾$×\ÕXl\ûžTíâ{Q×üx5îRabÇÿpë!í:¼ÆZ-ºÙîS.ÿÏwMU."€ €Ü»;ÜïÝŽ™ € €<àÅ ´tª³Éo»Ï ~qæòÒ¹íe«ZL¶ç/]Rf¢=7²,ÙîÕ©ö‹ v6Ék ªtÛÏ4lÛ°;Ÿ”l÷ú[ÔÝ߯î‹-ª*¶&ª¡ôW±¶ŸGÔQ™œl¯ðŸRKS@¶)K“­èø;¶d{¾üMêéïÑÅ¿¬G:wX•o ¯˜K € €N pwJ’8 € €<@Åþ ¦zUï+Wyõ …¯]´Ï¡?~¨‰Uî5–˜U¨ûÚ¤´ÐßÝ>Ø\oílϯéÔä|—޽r@ûË«Õ5SMVÖýœçG¬È7º­¶?xC]'|*)*RÉŸZ{Ãê¬2Sá}–¨>¯Jk“z±‚×Â:{â˜|Õõê¿­– +dRãÚå u^Ñý¨.—§È£¾º:ÙoýÃ@_×ûš±FÒ@@@ÀYîÎz @@@ FoöÇJÁ˜7ãÚñ#5ã¡!ݲíD7Ç„Œ”|ðv»Jv˜õfŒ+ÑQý¾ÖLfWéÂéreÙK²¤æªúìß­„vðBŸ•Ð~<ï¹D’¿J/íË3—I|»Tø¼™p—Òb½Q}pö k\ ç‚öï°½!65G¾·†¬µ¬FcÞVmþÑéOí—¤¬çåo?%À¯@Ùve$_å @@Çì*;”@ € € pÿŠ/*oÅ_úɯ_'¸—ÝcU½öå$Oœ»1¬6s˜·P™Ñˆf"Q³'ö‘ú-=m´biù¾^ý;R­ÝFž<«¨ZWªãc£QEff ªO>™ÒäØ5.meOÄ›T¨×¬ ï×Ë[â?1Bé…úeÀØùÞ\à}Óã[Ìj;¸S×»ýúéÁRíÎF¹9ní~å˜v[#h € € ðõ$ÿ5ýõ¬AT@@ø2³7ÞÓjÞÂï*ù•§ÆÎñÏþ³+xX[3â/p]ê\Ù²'ó#cz³ñ7ªm3wɯoõD>ÑßÌ|»7W›­ É›2“;Œ³¼²:òÛÔ˜ßwî¤ø'_UþWUñòK*²ïÞ_…@@Ö'@I™õù1@@Oàó{¼¥Ï“wÁ/FÉxâ™UK¸Üy…°QÞ%þ™èmTæ¶½«&Û‹+*¬šòV,#So+ cu/oLö®’¼7JÛÔM«¿ó”¼K•jSCj;yD{wf«¬q`y8Î@@pL€„»c”B@@àᘽõQ¼TŒñhÞSý φ5==½âÏÎj6vüI»³æÑ1ýú…Z ¤¸¦Iý¡šœkv~A½gÏê½Î*ëz¬adê­Òòa#DòUëlkÙÞœšêVQù1u]]Pxú¶†úƒj Ô$%öƒµ{õÎøœ‹ € €N pwR“X € €Úõ”~ROroÏ[Q*&:qY¯Õš/>5¶ÄÇ ¿»µ}Y¦O¯·ôš+[ßS½í²¦Y½³ºòv­Nž<©ÚÊ n[ýfÃ¥¢ÒóÄ(L¿Ô¤… € €€“$ÜÔ$ € €@®|¶Ò/wþPƒcš3ê½D£ _jÔæ=G¬§n:Z{ñjjtBo´Åê} ¯©c`L‘¹9ÍE¦4x©Yû¶–ÊL·Kçôá?·³§ê¾ãV¬¾†Œšë—4µ¸˜±‹}ôr£²mej¬F:ÿ+QRû}­1ÿa`NãÃï¨r¯YÞ&_ÛŸ¸›JñKÑi!€ € p·$ÜïVŠq € €<àVýó¯xŸ_6oGùëj±Ê¦÷©rÏ6e¤¥(--S»¼f"[*ôèç…îøêîçTo•h7æìݦ̌ edfk÷ˆ-Ù~xW¶Ujî~ µ[¬õ*;#M))ÚYº´Vò#¦ÊsôŒU«=ÔvX;7g¨   6ïÉ]?¶êÐ~«’œDM›ä œ!€ € °nîë&$ € €ßÀ#k­“f•mqeÆê³¬1ؾÃ;M[#]Üi^–|gÃêiZJ„/îïÒŸë=Æuó“®¿»©–*³DŒÙÿ®jêÑôì l—Cÿ7v±ð•V] ’'$Ίý-êN$ € €<¼Ñ™ …>Õäÿ¾Ð† õXN޾ýdžÜéw~æ™ñ}46¥ù´4m|,KÛŸÚ±4>:£±q£î{j†6oÉ6ú—RöŠLhø‰µ6º•›÷´òrlIöU—Œj|dHWÿuK_lØ  _÷¹å;Êÿ^¾r\¶Ø«Î¥@@õ p_Ÿ³@@@@@ˆ PR† € € € € €pw‘ € € € € €pç7€ € € € € €€$Ü@$ € € € € €$Üù € € € € € à€ w  € € € € € w~ € € € € €8 @ÂÝDB € € € € € @Âß € € € € €pw‘ € € € € €pç7€ € € € € €€ÿætX\÷¦IEND®B`‚concurrent-ruby-1.0.5/doc/images/tvar/implementation-write-proportion-scalability.png000066400000000000000000002630271305460430400312470ustar00rootroot00000000000000‰PNG  IHDRÜ„»8óÄ/iCCPICC Profile(c``2ptqre``ÈÍ+) rwRˆˆŒR`¿ÀÀÁÀÍ Ì`Ì`˜\\ààÃyùy© |»ÆÀ¹¬ 2 UŽ +¹ ¨¨ê¥¤'300ÙÙå%@qÆ9@¶HR6˜½Ä. rвùÒ!ì+ v„ýÄ.z¨æ H}:˜ÍÄb'AØ2 vIjÈ^çü‚Ê¢ÌôŒ#Ç”ü¤T…àÊâ’ÔÜbϼäü¢‚ü¢Ä’Ô Zˆû@º! A!¦ahii¡ ¥"ŠˆqŸÁáË(v!†°(¹´¨ Êcd2f` ÄG˜1G‚Á)Ë„˜I/Ãþ©15C}†}sïPoì%¬´ pHYs.#.#x¥?v@IDATxì½ XU×ïÿµ…ˆI0A«éÕö¢Å¤š-6&-Æ£ŒÖÖã͘¾(¶1iÀ›é(¶SüvŠ} í(<l3xpšbS3l ƒÆÂu õ˜ 6B”IeRh`ÂI Óý_ûœ³÷^ûœ½ÏËæ€ ßíƒg¿¬—ßú¬µ~k­ß^{­IŠ8ÀƒH€H€H€H€H€H€H€H€H€H€H`DÞ7"ßôL$@$@$@$@$@$@$@$@$@$@$ @ƒ;  $ îI€È H€H€H€H€H€H€H€H€H€H€H€w–          HÜ“‘A î,$@$@$@$@$@$@$@$@$@$@$4¸'"ƒ           ÜYH€H€H€H€H€H€H€H€H€H€H hpODA$@$@$@$@$@$@$@$@$@$@4¸³ @Ðàžˆ ‚H€H€H€H€H€H€H€H€H€H€hpg           $ Á=  ÐàÎ2@$@$@$@$@$@$@$@$@$@$@I @ƒ{ 2           Áe€H€H€H€H€H€H€H€H€H€H€’@€÷$@d$@$@$@$@$@$@$@$@$@$@$@ƒ;Ë $ îI€È H€H€H€H€H€H€H€H€H€H€H€w–          HÜ“‘A î,$@$@$@$@$@$@$@$@$@$@$4¸'"ƒ           ÜYH€H€H€H€H€H€H€H€H€H€H hpODA$@$@$@$@$@$@$@$@$@$@4¸³ @Ðàžˆ ‚H€H€H€H€H€H€H€H€H€H€hpg           $ Á=  ÐàÎ2@$@$@$@$@$@$@$@$@$@$@I @ƒ{ 2          H!‚kGÀßÕŠŸU=ƒ§«ëÑà›‹¢â¹8º³sóÖ`ÝÖ|f f\Ãòw¶¢á̸Ši¸Ý ̉,þýÙI¼}øØç¾ˆ%³ÒâïïlÆ/μ)Üše°–ÍÖ xãÝ«¸õ#÷cUö¬¸âކqþD*ªëðÞÍB¢=Œïí^‹ôh váä §ñ»«7ᦛ,^½ ̺÷.žt›ü³c¬†8ÜwU?¨@ÝëïAkÍÿ÷=¬”*Ú3 in˜[Í'pæÍwEžXe põÝwqõ¦[±ðÞ,Ì̸æ\ü¢Ž½"êØ­ÅgW-D|531±;NÇ+¿»Š‘ß‹µK2 €®# tCý?ŸF¯ð5~uáDÖ׉eÇxtMïGy¯'™ºÎÕãôoÔÚiî× Š>á §ß€uƒ" ÚuÜzæÞ™…;³f%M_wœ<Š_{“§ _\¿$iá&šo­ýL4}t?þ ÷œÃOŸ; ?¦cÕWÖ#ÓA§hpp)i)èó#5=â4î#V°è*®^½¬ËãÆ>Ôñâ‚ÿ ¦ìsX¿d"…¬Sgw7ye¶ù¾ƒ1š9€ä]qì—<–I éZ¶ßILFXPÃ8wâ§8Ý)´a¼ºd°'þù ÞUCºõ#b\™mÙŸPëî±_þb8,ìLw`åÚXŽˆ…ýèø/^ý"áîê­¸ÿ³«Û„tÇã‚AXVÆ}éGó‰_àMÑEýÈòÏ";6lXÛäâŽpÌŽ]{a‘$…Ç5 0 Ô•æ)";bü¹”Òºök _0Ê–RwH>·ÒÔ?21ú[Jõ´·ôƘ –÷û›wˆ©«¸IŠcHénoSÚÚÚ”öË#LˆjòN‡”ÚB—Î'P.Ü¥J,J2ÓØeÉ­”Û”%K–"qC—kWX- å]´gÉãrmCê¿(3mmíJÿP¼²ô+¥®XõÚxî.¬Vºã z”ÜéùïŠ]æ‰0Ô¦ä™ÊQžÒ7OG1^Gžœé.Y7˜uá8Bc«¯Ç‘Œc,Š3]H»0õz‘·ïÑ%àS3¹0³7òÄh#¢·íj»~ɼ£«^£Ý­v .¹d6±$·ýt¦kãJÖuîh ­:ÔÍUZÆc;AþF=4×ϘÁ ]VjË‹·Ötkc((¹E•J{\lDpÇ.ûvz¡TÍ©mu·Ä{";pœW %ÚÙ-¡(p,÷ïìÊqŸc¿ÐœÚõ™b…c”Åxëo²ÚïX’ày‹nW‰W— ]òJö {Ú^m¶ƒy/[ »‹¤ð •Ëñ$GÒæ1ÐØ´óã‚A<œ¬ÜH슛bY¢‚eß>¿­¢ë{×RN.)#Z¥±>Î~+·’¢u#¯°ÅÅEÈó§~ø°må<”5÷éwÆò$uòìPtS‘:ÒˆS'ë!8˜,¢ûÕNbÉ6]–ØïÃæ-À‚ ðPÕkZãçw¸?ßïÓåq¹Ýð,úbNˆ‘˜êžmO°E”¥u%õ¶uc~ÐþÒÏ!I·Ûƒ©©A©¢=3‡2q¯|•¹2³`ÁCxm þtL¿Û†ý1sEzâ÷’t—z]š>9v™s{ϯŽCÖvWÏ·\æ@ükëÅ©î’tÃÜ´kïÑaš ­…·2ŽNÊmCuªslF#ÌhññYlFaî[éº8v!j»>%õqû°v˜]¦Qj¬ã¼«Ëù(âNRÛO§º6BªïÆ™š‡í¿.oÔCsýŒš¸ÁsØž:«·ì_,‡\64è^ªölƼ©+p¼cP¿g{ò¶í“˜‡D_j[§&cÀ3ÖkçÀQ^%*®Ó1Z¢ñÄë^êßÅö±_lFfNûLFY4‡g•¬öÛ>†?ퟯ.IÉüŠtSV~}ɪ]Ds­ydØpÚºóƯZôd¸‹V#Ñïu®…=h¼1ÐÆs"µñ²Ÿ@›,Ivs-å¤Á=É™3¸¾“ؽ¹JwVXÝ‚¥ûvcǎݨ8v½íuÈÓ•°mé`­†ô`®Û“¹k¾ÊÊJñW€Ʋ¥ß…o×TÜ<ðAƒ‰Ô`ŒKÃÎÀ{ø&mn%NÕ×ãØ Ñ—“ÑÜk¿îR\ê@o/zÕ¿þ~ô÷÷¢­©ÆT–¼;Wb}E«æ+ðkÇxȯK…rß)Ô×Ã# ƒËÉD{f |_Šy®üú&yÐØ=€¡ èýè¾ÜŽÚò#œ†-¨¼F/Õ !Fël¿<´3"ðm?9÷‹ŸÏ7Òñ®»n¤¼ƒ´Ž\çD i¦Þ w®âºKíx =×ÚõÀo7Úk+ µsåÓ×ô¥­$JOǸý¤®M<ï†ýb¹2,Ûc–äzð1ˆãÛ\8(%¥ ´M¨.•úzh€gÞwÑ%¹‹±¼‰W÷¿jù|ý<êÉ5·QñáXˆ9‰v¬ºÞãó_|šêpÖa߆ìˆ$gd­@Å©¼7u1‚ú¨o‹„™A[g„û‰w#þb—‘•ƒGÄ_|GrÖo@„ë4uõñÐ19–Õ^s8†¿é7ëÆuÏÊ¥úyBLŒiéi¯y:Ëü%ëQq¶²ëÏððþà È»å/qòóõÈ õËíß<ù޹x dh×dŠöLs3ÑI$éHâ,5·¤¥‰uROýJ×c¡¬×üQ¯¿Ïõà¾{ìõ¦Y¦koºö ÌDxum p†ûXó749æfÏ·=ÝXø8xxq¾;¼%658Z‚u‹&aÒ$ío6m/ÁÉëåzΟDÙ®|¬X´H÷³hÅ:ì*;‚s] ªÔáœ<]vexÉ÷o¶ÏN†ePÈ»’íùX·B”Q6-Zü]e¨?oµ€JŽW¨y±‡Ov‰ÍZ[Q’¿.X¶66— Qöê—ˆò³.P–Õ°W¬ËGÙ‘zôD”n™®¨]ÃîiEÅÞ`0dª@k—áQåQ&ÊÅßÐ,Å>üÃþèåD‡™Àɽë×鮥q”~/ÑúÚÓzx Õ^•zxqôåèõiPl˜¬–C¿M¢›zÂZÃ%®åaû&S“D9ÝUqR‘Š,þïj>(£{ËŽÃR±QΑ€N)A½¤TÏ›hº«C—'ñ­>ìÅQÏE}(éÖQGߊçƒÁŠ´/Û%ê¯Zwƒõw“¨¿Íaõþó8*tt…Э¢ªiݵ)TwEÛ ¶1%GÔgª ÕsâUõôÞ’#è:X´O›tÙEÛ¸«çB™ÖÙ,dTõ‹T7ʢȘ°.-“@»K…ëýð²”XÝÐÊUüzVޝçÜ ì «ëjŸ ,A}¥…™˜ìFÙI¦îÔdqþcñ·YŸÄvº>•`XÕABg‹ºp¤ÙÜßÐ\wž ê±’ŠúÈö`v:Åf颯¨÷íD=^—¯ö-eý/Ú˜QëCi’ÚÿÆj?UŸñÕÛhº¶'D¿$Ðþ Þséú‡‘¬ûpB赿¹Wp–É%ªÛt ubrËõ^}rOòí è¶ ‘éˆ9y¤D´¢*þVˆ¿|uüÔÙ'69•&éèðíOúÞxU_~1·ÜgÛC^Rf­À÷kŒ™î ê&õ#=†â }j*ü]'úU¯Ï¾¸è÷Ft˜Ó8ûáñÕ­0ÎcÍ¿³¼JF»ï-±6'~ÎÛßhì—X™K\?Äê3Ùæå‡í·Vbé ytXÇü'Åx}“Su¡:¦.vˆ¾¡T±iâÇŒ{îƒ>ǽê_q) Çk/ÖõÁ…¼<Ñ‘ XÝáôSK ÿ¥3ú$U¸WàžÐ{̾sÁñ®ÑßWíaªMiŸSÃHÄ6¦J°µ£3Ú Œxã·9©~b³3BŽÿrË£n˜8ÐÝ®ø|b³OŸO¹,ïÚ8ЮˆO p´ð¤ßB¯y³Õ¦ÒܨîU™ŠjÍ›oùÊ5?óFHÝŠøœ9zxîbå’´ÿ…)ÝÑüº •6ic!» ,e“6zlî!]ëÌCq»Šë•r‰aQ£ÕÖ•b#1ÉM¥,˜]Aº¤”z¢³qz•`¥Ê™ıq™‰©»<¦`Šr¹¶ÐÈ3É}8ãþ–bÃ]˜\Eÿ÷olŸ›k )zÙ±fá.ªUdQå¼r¹Í›µ Yµm;†.Ç*{¥¶] Y ו—g×”6·RÚ°¥©8l[Ý]<›ô+•zþ{¢n6ÜXll¨•WÝ&ÓPœÔW9óríÒÅUT§HUSÑë’T&„×óÜJ¥[öh’Øê¢[)Ö636ŠBß+o~ã©´-³íµöe0X— 9›:ñR±‘s¸~^»•š°:ßRê •ë² of¥m0¬’I8o¤r.›y +îbÏ4©ñ”J›¦E WŽÇSX¤äêy^‡E]‘ ‚œf9Œˆs¹MPZôvÄ$£HRÂõÜÄ8\^ùÚ£iíš|?xîuÃ|ŒL—%Uç„×G]/IéÚÝXzL.“ᛢ'\7¤roš5Î-1Ú ˆ~’Ü—ÐüÙý&,»Hf‘ˆî´“!ú}s!o2©ëb‘·²þ°OîŸHmØäL _zÊmÚ<^ EÚ”Qßœ]–I*Oe¬°Fk«úG¡%Ë!¥I]úÖ~ D*»á:ËU\+µa.¥ÖÔM”ù f^S»ªt×ý é™ݦ&Û‰¿Ñ)×Jcu©R\Zª”––+ååÅR[6Vò+êi‚º-–”o‰êEôÓc¡‚e!¾ô´H}¹À¦¥‰h«ÔûÎáí…s‹[æº!ëÇRÛ^¦Í×Å4ô‘˜Â¶ž@Ý’s’Ǫ‡y•œv%¾1ZÂmN\œexæs¹‡ð~»Ùiàjâý”9‰q¼ú!VŸÉ­éVRÚï@ˆÒ«úsXÇ.ÕÅoû‰é­n“ý¤Æ4`“Ɔ®b¥­Ý«·•áqˆõô-õ¦Ñ¶Aq{ÌãÝ@ßIÊÿØö &=´³ºçˆ“Ñeˆ.!›SPÀ˜ì¤ö#¼n›(o vŠŒ²Öf:/ ¥Ã²|mÛ‹ˆ`ºÓ/F€Üé t|\¥¸²Vi»Ômî¬ÛJÒ«”ë=U º”ÂÒJÅë­T $ã0TWÈJ9Ô^­+,5NOa¹RÛØ¨ÔÖ”+y&?¹ŠO²UZW ¥&Oy”ÒšZ¥±®V)/2ï8í)÷é©0u´Aœ;O)¯®‰ð‡ÜjÝk-ƒb !UnII”¶0•(…¹º2‡;W),,PJÅ ‰ËuÒÎ×Ò€Húr­áO4 ¦±–îH>â\™K)®®UZZš”êb3›à@x@©--T „|z'8$_è ûdÔÃÄ4ŽN—" m (í!ãi8cµÁ)ÜrÝF#–[P(8*Ï>aûÌÛ”Xn å­ X©ñz•ÒBÍXj¼Ë%C ”wÁz!qô„ î>Ý@ä¥ÖÅ+FºT¹Æ ¢ðpeÏ­‰ô˜óµ:Øí«e¤0"ý¥J›T?¬3Ç<( 7d©~†z•–©ìIu5ð|ÄõÕ`çÎ-TÊ+Ë•“΀â•,XzþK/6ÔŽ›‰i^µþÒÃ:Ý‘wÚ$½£ÕiS~„0‚aô·H/%E~¹<…J¥(?b-T£žˆû†1)qØï3¿jYrå+µM-JS]µ"öÏâ1ô¨*ÎJÖ;RÒå:)wT FØQó&†î’¢´<•å0u`MüC²¸r•âòÈ2¬c¢½((RŠ‹ ]¨Ö¡<ø$Ç¥ù äYuµ¨ó’n ø«1Ú9I³Œê¹)o ƹ…ÅJy±¹Üh2BäaQq±¨†žSŸÕ\2*yRt™šnQÇG¦sowcé1£LJm¨àè¨nHyiðžfµà]ª‘êšÚ—©Vê딚òBSysË/T6‡#ÙEX £ìD­Ÿ6ñÇwÛÜFȆ3YŽr_ô@¯IOíy´YAù¤øõ~ƒt/P^ƒòŠË•µŸhÒ‰P´É£Ò‡ÒÛ*kƒ{¬öSMcBõ6†®•ó¤¨î²‘Ŧþ”Ê«P‘§¬tKýK}B‡“>Œ£C²ìZ½L~¹2M2˳+ÚYâº-šC#4\X?J (-RÄŒLI©çfÝh—ŠKu~qè#›&|Hdp¼úLò.Nå:C.6EåÕ¢%M¼éuÖÑ„û“ë}¨žPÝÒCv˜Çó*yíJì1š£6'Î::‹SŸK×áµ[&]e´†~–§ñ:ösTæÂ'¥¦µþ5xBqÜ~‹ ¥WXMœÙfÌc!„ÆEyÆ„0­í0õÓ­˜î6cþ‚ih·a[q6 ?—•BM÷ŠI†­e@©–l*åRãdmî»krÆ^RþÇc î°5%:ìb4D¶e±lNAáagŒcÅK ÓÄ]—RíÓ¦BÊ}h¹m okã“Otx•åHñµíÉk/Â2?ì’÷0 £) RAx§N»v)žó]- ÕyšÒ2pŒÆCª@²B³ÑM/-…ý’‘MVΦ‚P¬•M†áEøëm1+ýêPÀ–2÷–÷ìmÈ0àÈ/ä©j¤•_6¨^Û« ƒlne›ší¯ÙP¨æy:ðåFyF­dȳ“Ï6¦àÓ¸:]ÆÌ7u ¡ƒ-YŠ(Œr#ؘ“bÿ¬·I´¸”ò&i€*Â4¿I†qͶ%åXtD tr•Ú6£ÙUS,7\®‚jólë°·¨z>Káã<1K[ ,tô6IÆ]W‘hö#Zú Wágò (X¯Ý.—â’þ´Nö[Þ"K$s‡â¬¾ªñº”ÊЛ砄ÝJ¹4ë½°ÖH©žÿZº\g2¶» j„–Hüh,2tQQ–Æ!Å[ éÑFÔ+a<—^zJ™ªb&„1(úG”ËÄu¢˜™©u„A¹´Ñ¤‹ÔΟü•Š»Xí•Í@\®“FGEÖW‰å’Ý ëa³Î/-Š´¯mÔôõJm*§˜á/u¨†Ä H½VV„/9Íj™Î«”^¤©ÏÛjLÆÓíeT7eÕs‘7ªìE{()½âKP¯¨ÏT#CôiH©“ʪžoIÐe:ž ã°ÝUÓn§Ç ^Rû.jº£º!åe"i6dºÀ<}80[Ké§ÏÄVSdw8”]'Ë‘ˆî´“$ú}¹Ù›åÈ«nR._jWÚÛÍm¾Èø¦/¤¤¼ë•!“¿^¥{jûë*PšLý—n¥Rï'Šçy5ÁIR\ÉèC m!oƒu5ÑöSqZomt­jz,†obã,‚·àÆFýªÖ0„µÉr¿WògÙwZ·æ±Ó¼’ËýÈÛÞF7¨y2ÒöÒ’³uÐïšú\º×GžH_=M¸±Ÿã2g|A™HŸD…g×gŠk¾#—;Çí·ãôvÄm›1—_ãëû`º.7JãcÑ/°îO˜ÈW½M†ÍÚЦ>—¿¸Ð^Fí¥úm(”¡6E¬¬è³›&Ò‰Ç2k5sKkÍ6I—™ä¶­Ëm !Qí~F“Y?ÆosJ„]ð‹-al—^ž¨}j¹Ý4å‡Ñp*Ÿi‚AÜeYhcÓ$”øÛv™GRÚ ›Â@ƒ» ˜Ñ½Ý+f6ÛͺӔ‹ú+f|•×I%óÛ>ÓlMàËÞrF…¢ ±ª[zƒz^„QYõf4.FEQï…P¾¯vHƒ‰¼JŸêÌ|ÈÊLš•fê ˆÁZ˜ý6†±\ƒ¡Ø­e°‘ÍNÁÚÝRÔJÆ¿bÓ·•²áOÌÄ -7bN¬|–7¦° wò,—<í¯­|†?«3Óx:]ÂÔ\¤7^FžÆÃX3ÎkrÈ~ägñ¼¤¥ÚHTb¸†ó65¼yJ›U’gqhS¸Vþ¤¾ñBM§]5Ö¿ò H®Ëöç…•AãE(À‘×Waô [¢F z@ZfDža¥§SÌBï›ÙîÒ—?²N­í]S~™_fõ6JŸ/†}9"7 –Ç0^ 1Õê/,]b™š°z'Ï@Ô¼„éDÓÌû°ø5/¢å–¾¦°Ÿ¤»ÈuR7ÜŠg:cQÿÉÙ@nê4†Gv-Ëaògª"]aþŒ¶ÀêeˆTW7-oä¸`šb.ÏØÑå‘dÑï™ÊU}aZÕsqÛÄXÓ­šò€‘í \î´v59ºÌ* Géŧ*ª‘³.R_9iw£…)Ç¥Mr\7¤¼„੟­ÓÜRnÌ€Š¬CJSe±ø2 P)ƒ)íݬ–¥á¿Že7qO°~† ×µÜFí°êÕÈûö"h”ž/ÑKy¡×+“\Rüz¿Aº't”6áÁìMþBN+ŸÉìC©±™åˆH«Þ1ÒÞ~&£Þš¸ µ+bõí`¿Zj/äþª&§6ÉEL-0fìiK§9ÕmNý šryЬ_ö}S¾Ç¼óÌ\žcz 8p¨Û¤r¿Î1—Wc"€$©WÑ7bƒû€ÒTmžQ®~Áëdƒ¹nÄàlbcô_ŒTZëc¹¿aÕw\·µ_Îó*™íJ€™ÄSÖ ŽÛ)<+ÎF>YŸ™û\±—o¯'ìØÏq™31Ž¿O¢7ô¦ÖÎYçCø]ßÑ>imƒíoXûí8½êØÐ%c)Hm›œ.ŸÔG“˾ìÆö\î«£(ô˜<éJð ½ ì––Õ&„ µK_@jíh(2™µé+M)ÿMrÛÝA;«Eiù;j ÂÆ¾ ØœaW)&>6éK©ªå:r©U5ÝF˜ZÛä\>gãqÔ^XEIJ€Ç˜ÈÀª­ÄÈnÎiÆé_5âÔ‰çQÕØ5B’Ƈý[Vbm%z=‚ ᪾Ÿ„kîŸ%¹ Îzím> ‰ uR§Ï Üœ‘³g•­AÃÃð÷õÁßÿ6Þz«Ý¯ d³¶9d(Œ¨?³ÿÌYñ nÐ>¿o¿õzzºñÊ?•è€ÚSš¿VÏåy®mÞàÞ“í|'ó~ >¹é1àà¶@ Õϵàë9«‚²‰Í"ŸlÅåÙŽOβ’X–EΛ<<|ŸõNÚwßÿ)á)Èûw]ïÈŒÁy?~+ÅçžKú†l’íÔx6ˆæZm£U`õÒébóµ> hÕß”)ø€ënqâ Ü­o¾ˆ­KB» îˆÿòvãÁ0Þƒí­ÐCödcê°ZîÌ»°LIùôêñº+– [ࣘ‘f ’sMšÀ¯Ý}“£ˆ  KŸ@fXY~§»§î‡ØC4pìß¼ Ï¿^‹–}Á²7òúêÁ£Ÿ‹ÜYNéÔYŪ˜,š¡§Å8µo-Ò­ÜÆ¸×ó«=¿\…›M»ÎgÜ·¹Ø¬¾øeÇVlÈ nK?4tEÙ³îÓ°ÐpX¾«¾GÕÔ¤bΔ!ûøÅ§‡ÞþµGÞε°¬©éwb¥uWŠéEü^â,' ô˜´‡y£yO⯻ø‹È OÂO-žþÔ¸öÆ›¢-šÆÄó·%Ï9«…ßPá «F €ãzn’ÃÜ•)3¢ñ܇9Áâ¦ß“Ë]ëoa÷ŠiIÑeÉÓ9#owÕÄÆÒcCCz Õ )àDÒ|Ûtc;®CàBm!¾ºq5–¸îAæ¬ ,yd–è¹ýı즲3~êgôÔJO^Âù‚Ì7¥Czžè©»«CúØä5}1¶¸à=l¸‚YžÌ>”)6qá¤ýLRD%%*Ò}PM·ïÎõìÀŠ~œ©öaÜE¸ó¬ØDTôëÚ0¼6)]gñ|(ŒÜÏ/ ´¡NuÛ¢Ëû>¦ò0žËõÈu[ü:§¾úPÇ …øò ‹Ö?-ß(rûGÈ…!þó.±yø·7{pH‹Nõê)Å¥Ê ŽúTñÇlvé.zYNú½ýð‘Ô-'yì<¯’Ù®˜iš¯·9R{i5Þ1Ç’Œ«‰:öI™3¸Å¯ ?Ú™œUÚ½¤þšÚ7ñ:Ö÷çõÍžóvÿ™eß}áC[áÞâ…IŠMÕÿ¨ob²øgWþë î}ì›X¥õÒïÂj1ŽòšÊ´õìFfF;žõ!àY»CÃÿ÷,l²ªÆóü/|Ø·j.ÿûËzà¹ëÛêÍ-×Ý9=qÚ>/1µ³±ƒäØœb±Û¼`¦)QEM^¬«³9ù/ËÀøo/"šaY^Œ.´ ,^õ/Ç>Töáò¥×qæ/önÛ¯+Bx7㯎æ â³ï¡.ØÇ/™îÇÃŒAaÓ5a„ÜþŽ“øaÉ÷±ó@„“n¨;Æÿß/Þ© ðlë4厹bˆܬúbg·­»d>Hw­A¶á ïÁŸ£m¿ÈÁµã—?×ù<ê¶Uôº,ƒ—Œ¼áÙ65+eêt=ºß±:ñÿ¿ÓãJÇÍIïIÈ Ø¦¨õ¨cœx²?Šð¢=ôÞï _Þ-˜=e‹qmsž¼©1ÍM69¾í—žÈÇB«²°{:N”`ÞêÐ}ûWãØcXꨌ´¾†§ÝYNà宯cUØËØa â—‡öèÎ|ûWbE“ o¿¼5]Ô,¹óöãŸÅ†A³Ú¥Óµº¿»ïú ~.Ÿ¤ÍÈÂBmœµ_ÌÉ =ò#çM¿½»”›§aºýãQ}â¿ÐšW.¢ñ¬Œ˜å9òÈÓáZ'V\Kà¸8hä¹îíJä½)¾âEyG¿øäZ~ ØËµjÄÚѺƒ®w‚Ž“Z_õМ4`uîSPkDBGÏiüXí_IGƒøzÇç þ…ÈÓ°ó'è)Ã9<ªçsæÌXSDr½‹S'Îùô–€ñWÏÞ¨œ†Œÿá ¦^ûB'Q¿§©v–nÌôiöº}üÔó$é²deÁ¨¶»†£Z7ŒhŒ31{xwK/«‹á‰è:øphÿ6,/nוœ4üØœ¹ì6r¨·‡û:ÐÚÜŠæÖsè ïè wãuiÞƒQ3Ìf~ôNdfeaþüùú_–z½Ä’íb3 íh8sÞèj7m‡õ•S”þ‹áq:nÕêz²úPò:i?G§ÞÎøxpö*â‰W.Âßî õ¥\¸÷ñøÞ¥!韇¯ÇóMÚüöBÜ›48ÕmNýEà¯7ÆH·’/Þ¦ÅÑ«@wèë…D‘uŠ±Ö”Ù‹MÆvOA%Úº‡pàÛòG­ìQRÑAÝr’Ç#É«$¶+Q!)mNçh1:{6qÇ~#(sÎP%Í—³ö{éuPÇæº¿ªÛìÇB‘HRo¶!>¤ŸsÿJ=€–×^ùæÕ¯ÍFta˜þ‚0ÎŽzaœ?;«½´ÌÃÒyvFua³ëDé1Å>ÍvvTÈcß(}¶è6§ÄÙ5ìY'›ã° ŒD>eY)ã¸m£öÂnt»tÒEâ^Gî⥡™/ÅèVvX~Â8eùV1Zpßp¢}[ݸC‹Õý¿0E;7ý£¯§/`ÌOIKGÆ”Ëøöʺ wA)¾ýèÌÿÐL¤§§#M”€ŽÕ7cÞFÍÀ¬;µ<é8¶;ÅÈàáFiÍ·ÅÒ6ó1sZ:ÒÓT…x^Lc\ - 94ýNÖj¦»âbฺ7õ6{£L¸·‘^/ZûUh‰ªö¾Š¯‹uIôådòr±(#ŽÄÌ3=oìÛ"øß|UŸÝEGÆaâNÎ}J÷äYmÿy–î(á“>œzZ+GÔ]®Ä½¢†Û’‚)‚WðˆO nšÂS܈g¶~ Ã!‹k¦è3SÔâ8˜p"ÆÔÃÕ½2ãîHj}M41yå-¨x,›R]Á:ܰE|]óiT¬_¢Ã>äó¿|V/ã®ÜB<ñ©L\¹"úÄgˆ“ßAíñÒ.ÌA<ß²'°´Ðå¦=Ÿí:€Ãþ>ô ªy/fW¦Kõ.NøÛ“Õ’~²+}xí„‘7ñöç.9eæx2h7+^ê|EÓíŽëyÒÙŽž.s"j2ÚÝxâ½4ŠuÃ6þ” älØøó÷uá«ÿ†S/5à©=õYÂÞËpô â  ñÒ*¬k"»• Âô]µy6”› ½g‘#÷!ÞÁkº¿;l¿4³Óš×¬•‰O°uíed;«9 ÿ¼ˆSZcþL½3ÜíŽ÷Þ´À1·Kãߤô¡ì"r?¢ý¯‡G¥¢Î¾oü·¡ã&ÿ{Hªõp‰¼±x™0\¨_¥úpæ_E»ñ|ÐPà*ZÌK§ºmà‚þOnãéÑXé¶@šEC®•`ˆxd2HföºÜÐ¬ÌøIù[+0GkÁ]ˆÆ}9Yrå?¼ñçÒyÝr”Ç#Í«$µ+Ñòaü´9Ѥ&îØÏy™‹NdôŸ:k¿§×I»ØðS½ˆ®3CŽÒæ?‚~,†àHI7ë»ô;ë_·zk‚¹h …R€œ0#ú¨Æù*ñ'^hW<ËÚ,ïO0Çn¨ m¤?NÛçxâcfsÊCKÿßãæÚŒÕ¼¶--š¡K•I4F Ÿ“²¬¾tÑË©“¶} Ú Îp—ÊǨŸ¦õ ­' ¾L~ ]Õ•¡kÑaОƒlÑé ÇðJ…÷®1mæLÌËxÃÝpAs–[ ï­ÈY˜…Ac»ú¨ë·º Í¥Íï0þýeMYºPÝö/غ>Y³f„ŒíÂ[_n4· §N[Ç×yò9ÝP‡ÉšAÖ.”äÝO›¿\|Ö Ï÷üsøé‘çtîE¹èGEQÎo-~m“·NŸH-šs[Ô }h7xPÃQ+÷êõ£«¨?I>¦`Ö!ÂlúýSž‘Œ°¿)Ý/ã»Eß ü½t98«;– ©·ÍÒxϽ‰TõeRX¸)xù÷»âïÐK¶ƒ)= ¸Oâyoj˜h¢ƒx÷—p&'·¾F‰Úê‘»ßËÏvì…(k)kÇ¡‡ÇI+]£90ýv¡¦X{éìþÎ>äççcëÖ­Ò_¾¸·{ËÅ 6tlûÉÉ@~Í^ü)ížzáý\>yqÏ´€~›9s9Î %®çHq{Ñ0}ÉqÀÿ:jµÎžè"~@¼82¢LX¨(à ev}£\{2X]/{õ)Ñtûµ­ç²ä£§ËäXìÏe“œv7žùÉ©ö©2?ÄÉÃ%صkJ7êzÆ,dç¬ÅÖÝľ3ýðê&t½½­[ÙÍ) ¿2^/úð»ð†Y DôÜËÏÍ‘ ×ááD½_ΖXŽG­úQÒÄÉ»qê­Ã}äbÜ:ñ“Ââ8Ìú/)}(9ªÐy¢í'Ä4”Ñ郈ÙwªV=ª¶Á³%ØÆ¹ ?Ügd† ëCMùž‡=úI¼'èGüïT·9õ§G<®O’¥ÛâLdú‡±BS) ÏZ¡ÐƒÚ§ƒ†…8CU;ØxbñÝy^y#ê÷]GÆv5iNë–ÃÓñÁ;ÂGŠÃ¨ÿÁ÷u%igX©ÚR„“ái1³·b·–^¶|n4 Â"!VP1dZ·=4˜òÄÆ-BŽ@‹`¿ù©ŽD?™‚Ì»žÄ/¾ÿL³þD?ñ7ã€Ø6x¸ñPNü³†õ0ìNĬ4»®AWóa±¢1@A->ÞÒÙ…›Ðý4Ü»ÆhÀ7ÿísÌûð¿±{öï ü½5daµ´ˆ3-ë^±Ö~è›{>w>rêz_s%Voáîgz5×Iø­Â…"ÖÉŸbçÑú²mxX_çÓ{>,r0©õÕ.n›ûSû³V¢Ò£] ]õõ#y©=7~Ï¿ Ä®÷x Óx~¶`•X·>aäIÿàsT·¾=e¨7ô÷D¹¦&°ÿS|¥“¨Nœ2=3X½E ;÷Gê"q¿õÈôN¦»ØjÓ±*œyͬĆ;Š&µú­¦ ɇ¥îJr# ®a["¾6ºý‚³v¬¾Žvñ{më¹,Îèé29ûsYç$§ÝUgÅÒcÉ©ö©2?À+OïÄþýû±SL¿l~(®Ò‘³z•q7ºõc+»!–Õ™1G\ô úÍæÁK¿Ñ_èG›ek®í=IwË3}¼µ§Ãú˜Ã8^ô5£f`Š~Ùé8^ØëFõ¢n„mêþ%£.ŒƒöS ˓ұеw6~6˸æÓóC7faùz­o®¹ÉŧµáÄ-§ºÍ©?MŠñý›,Ýo*3p×RQ'G¾SnL€ÑB詯Ô>xÕnÅüíøE…þÕœ»¸ ù9£n Š)TÒ8­[NóØi^%·]‰†q\´9×õØÏi™‹–k‰<‹ÝgJ$4[·zûí4½ÎêXú‡ï2ÆB{¾…ú®p »ð£o+$„?ï: Ù«U3º1áO=+üÓO›VØ‘2kÔ¥” §ro”dX ]Jíüè¶³£Á`¬lNZÿ5>Ã¾Ø ¾:=,Öä·?œÊç¬,㿽 Áݾ´ŒÂ“4|þojŒp«6cÚŠí8Zߊ.± LOOøëDkýQl_7žýÚû=à«Þð—³å¯ ) ü¦²èË+ û»p¢,Kuƒ±öxÊpž< §A(ÔÃ';àÄ ¿ÍÇËðàìÕÒàK5"…[¸ qÕ}ï:ÍH&:«E‡ÑÑçÇ ¯§£eùbåÃàä=Õ"æŠD.aÊZ¶<Ç[;Ð×'–‡èlÆ®çAŸ€·ËÞ¨12ùަ¼§ÐÚÑ ±ß—éXøàFkàPøî"±¡DD‹`ò&]¤`Õ×öê×ÞmKCy¼5ØÕŒíŸZªwÊQ°÷eèÎG~"6Öýó’2”•” $ô·w×v¬[1 ³—n–Ú¯\øŠâØð¡D™ŸÉ¾¡Vý Ãøg¶eD5ŽÃ/6“*Y7 bÃóà!fT{æ›Fí¡V?™È¯6և߸à38ÜÜue‘áa?Z—`ÚÒmºÇÒí«“:àyîÍ¢Žj¥H&ÆIrÿ¼eeZž”¡DÌæÜµw6-šŠ•ÛŒ™àîâýX!Ê|rëk ñÂ÷Ë7Ò‘û¤×¨"/‹NDôÆdóÓ5Oë÷rw®µ_2K¸JÉ|úö ¢f}Y„?cþZûÜD艕3óqâ|Èãat?üåË Cx©'ð¹~Â:qÖ§Q\  º….šŒ#(ø šoÇâ-Uz: rïÓÏS K¶,ÞŒ£­]ð ]z®þ0ÖÏyXªgº—Ÿh¥ÎNw8‚$ êö¥!žjžEèvw)>¿ÐîÕ *ȵ­ç2ŠÑÓer,öç†ÎIN»«Æd„ioÊê†uˆÑî¦ãÝøµkó+ÄWÚ‹ÔAt¶ÅæeÚ`Ï…»Ô’Qޱ•=Š âEÁâà”.áȇ‡çý9Ž‹={üƒ~t6Ágz³î^Ñ«rxˆšn€·—µ><ƒ^l0þg{¢ËïGOç9ÞµžÀæŸQât‰Z¼s)òËŽ£CôIûÄ^­GwažÇxi¶ó±û#y*<ÈÄÛO5„‘Ô[§•®MË\¢¿ô¶.,[8KzþríåP¨mÉ]»MEÖ©nsêOmŸ$O·Å—È|:ßè§7ìY)ö‡8C©ëžÙÏ”—…‰+Ða\h½`¸üϤ>ŸÖ÷“~÷îÅáúø÷à2¾ögÎê–ÓösVæ¢åZbÏbõ™ MrmÓ~;K¯³:¦–ß½úL¶¬œ½IôUº_öœCÙ¦Ù ¿|”R¨ŸÎYò€~_yn(ÒÒ n ½&fÜæ´å)mŠÒï+Ó_®ÒÔk$×Jõ©åýE¼Äã)m1‘îk²¹Ë}ÆóÀY¯Rî1sªTOððUæE¤SŒ_Ãî(¾Ï@ðB¾\+¹cÄ?S-þ<¥îrdš,YЏíî«bE{ÖÛO^»…,CF ¥<2åáBœu+b’0–‘×î¢:E9f¸ýŠ˜É Ó(çj´¾rOX\ây$>“„¢¤G”#­ÌÙýæ×)F°É­¯²pry‘ëyé.Ò›sÝ4»W>½‹×UJ]w„‹ˆ¾JMLj<ðTãhSÄ‚6aìï •v=“%1(ÄèoQÄës.—"º¦{Õaz¢»NóMnìòµ´ÅPd:c˜Ë˜Ä.o©üjñDê.-ã7žðä2 ù4ä„"Ë|n]Wä¸4í~kÚ’.§Í,‹ƒz.4d·`,éXX”s9 ²,££Ë¬9ªŒítŽÓv7Z˜¶¼œÔ ©œÊüÔøƒ‡MšE} ¯s.QÃË»¨Q (ú¯ÙEˆ¶,B±Ù•[aâÒ¹z¿J Çêþi®´_Ñgqº¨´ÉP¸Eî†áLÅÛTŨ ñ·[¹åRßJ%ð›Œ>Türhé1·ŸAFZoµ°Ãu­l\]EÊe9ý½¦¶!OïƒËŽœé6G}­Qž,t¢xžp¹–“¢ŸÛÔmýyôǺͩÎâ´XôÓµ<7ÿZs3§H”Y©šýõS¾ï–Ç'æÀ¢\%ÀÙ)›˜þÅIÝrœÇNó*ÙíŠàb;FsÒæÄÁ9JA0Õ[¹\ÙŸO챟“2gß¿ÔÈÚ×'»~˜æÓî×з#k¿¤×qëµ ÙŒq¬ûvv4¤ûCmаëm§»TŒæmŽîZSŸÐUPkŒç%/kmWǤûZ}1Úy§í³$˜Ýé(0P£rbsJ„]Ä8Pè;ÍΦòó„úƒva:‘ÏqY<µíÉn/lÊg¸‹3ÖÇüõÐÛ^‡Bm²¸î¼"ÔµõâÀí³Õ Ã¬õûp¹±R_zÁìÝƒÊÆK8 or˜†õ åêg:G^izÚõ5ÌU'¾ß¾p™:ùæcšNZÖzw¹1ó5ä"ðã.@m{/.ÕIw/àñ&7UšZX^}‚©äž"øzŸÁyÊ—>£ÔAõb%›º¨²æ*}ª´TIZ6öTë¯qƒ1Fì ŸU¹’±Æš¸g_‰XøHÚkKM||ÒçQî‚J\8ÛIžzz0íÎRoÖRkçB½ï‚'¯Õu>ô+bµÅŒr=N»ðìî«áG>ËX’þöZØ9¨ùÜÔýB`F·Bð06¿L—>óÒžg ÿ™~Ô• S©ÍQXÝ‚v¯>U³)–þÍiYøù=åTìýó˜lÆÖ½'P¿»ñÌŽÒl|çõ1óQEw+îiçS¥ç¡ÓìǾã…v~à=é(tgðR‹ñGîWqï [§úƒò—%ÞT J@IDAT_á’:Á5m>ö ]B¥XãÏê𔣽ŸiÖÄt¢5=ýí(• ©¨¨FUu£\Õ£šE3ð櫆•êvå•£¥Å«?Ó°Ð/â(º[á3.ÝeQ½JM•â‘óӑ‘AèÅÂ⑸%…/9(¬¬Œ¨3Ç®<Ñ6ôc}–¬ì꼓z.bÑÓi-›.¦E9ן©'z8â›.‡ºL“ÀÔ™"Ñ.4—Ák;ã´ÝUCµ ÓH§YguážõéT›¹­ðÉ ¦¿ ¼ÞÝ9A@±þwZ¯õ<caŸîÖêa螪'Ú¼öm Z.ýH¬i#5]ës™Š¡Ù‘~%œ­_`[ásúò19»†Ë¦ ¥u-¨-LUvR]«sXN̦-ªñá™ül#RÓYrúP#k?ƒ9ª·qèÚÅ«7ê)v¯_\¿]»#6VÕ?½óÿ}¦öDúu¨ÛÄ·b‰÷}D´zYÕ2W%üTwþ ‘ë8â ιns¨sDüÙ¢ŸÞæ•Ç)†PîÂrT ójàˆ'=ƒ¸"Õ##$û³(ûÛ{2=‰%—S6vm²¹“ºå<æU²Û#ùR ÝtÔæÄæ,G~~£ýœ”9[{@8ÌÀµ¹>Ùö™,ý7“Õ~;I¯ã:–¡Ž…|(²Ôˆv¬¼¦ÚèÇ8m#ÄR1nÉèãY÷)û¯Ÿg,ÆcÒÐoýç\Òx^bmaŸ2žªg6:0j;ï°5Gl}5 ÔˆœØœ¬ígf±µ195ìë¡ïJ½ÆoÞ-8'Æíva:‘ÏqYIpÔ¶f{!a¤â¥kžŽ1¾®óxÕ÷:Þì}7ÝtpÓ­¸ãCs0ÿÎy˜±ûD˜pb)޶ øý{ª¸ù¶b^Ö,Kå¤ú쟿Úу!áø–Ûgà®;ç#C³ ÷¡£³W|•1Óî˜)î‡U²°¨1؇sg_EφDÜ·`Æÿ¼ ó3 K¹¿«Ýb ë)SŇ32,dŸŒŸ ÿÑ#V•FÌ[fe!{¾Õ'Fá;¿K?t‹o‰R§ˆªØð#<‰Ç·cŽç` ‚¼êvTlÁë>¯àâﮊ|½Šw¯ÞŠ.ú8JŒœ§d¢øT—ñáü¥n ¸%ãvÌúð\±É®QNœ¦d¸¯ ¾WÏ£û*ß[pû¬Y˜;'Ë(ÏNŽð7Œž®î@KQ7jM×*L„äßHj}Mºtc ¿§Þø}€êÍ·‰}#f‹ Ÿ£äA‚:QM…Êù•¶‹2zõÝ«¸U”Ñ/^±o”C,£Õyoõ«/'S1uúdÎÒº(Q¼9|Kw9 6)Þüç*0Õµ%V¹où ÅöŠªnïú/¡ÚS1#3 ¢´KÑ„»zM õÙèé²È˜£èÇín”0#Ðï8«º÷N†Ñy®gó&®Š~ÐMW…^¿ã#p}Ì…Y±úA6±Œì6nËåFtïnÊÀ¬¬ˆ¾Ro#£ç3uéÀK—ÞÂ{¢•zóTÌ™—¹©™MXƒbyÃ×Þx ¸ª®ü;²>–-òÂÆqèvRûPÑ£Šó©Ì?¾>ÈXéZ§ºÍ©¿8];gŽuÛDKq¶þ:Ô¼%™Yw‹þiŒB>‚è®/¯‰×­åUòÛ•hy8>ÚœhŽÕ3e#.ÑF+\«Èõ™¬Br~ÏAzëQs\³3q÷±ï_Ôqó”]kŸ±Úù ×ÎŽw›“ù—eQºÆa{Aƒûµ®õŒœèCÙŠiØÖ ŠãAKÿ±ˆÙgãDPŠA$@ㆀlpŸbköÈ_¨›ÄQ 8 °'(:#   ¸A\§ï®nÜc2GL@Åõ»¡›ñöKBÆv±útq!í#&ËH€H€H€®gìC]Ϲ˴‘ Œ„ î#¡G¿œ€?ùÂlÌj×’âÆ·_¢]ð—H€H€H€H ‚ûPHxƒH€H€H€H€B¸i*‹Â M ÿmsò‹k„®ˆ`†Â+ °#0tEzÂwø ž’ÀuO€}¨ë>‹™@    ‡¸†»Cpôv}èë<ß¾ýžºo+¦Ïu!3úN‰×G¢™  HA?ºz»QÛl¬ˆ Àx#À>ÔxËÊC$@$@$@$0^Ðà>^r‚r Lh\RfBg…'         /hp/9A9H€H€H€H€H€H€H€H€H€H€&4Ü'töQx          ñB€÷ñ’”ƒH€H€H€H€H€H€H€H€H€H`B Á}Bg…'         /hp/9A9H€H€H€H€H€H€H€H€H€H€&4Ü'töQx          ñB€÷ñ’”ƒH€H€H€H€H€H€H€H€H€H`B Á}Bg…'         /hp/9A9H€H€H€H€H€H€H€H€H€H€&4Ü'töQx          ñB€÷ñ’”ƒH€H€H€H€H€H€H€H€H€H`B Á}Bg…'         /hp/9A9H€H€H€H€H€H€H€H€H€H€&4Ü'töQx          ñB€÷ñ’”ƒH€H€H€H€H€H€H€H€H€H`B Á}Bg…'         /hp/9A9H€H€H€H€H€H€H€H€H€H€&4” -ý„~~ÿ@0©©HOK›ð)bH€H€H€H€H€H€H€H€H€HàF%Àî æüàù#˜4i’øÛ„V‚ž5çÃ]8^¶‹&¥bêÔ©Á¿)S0iÑ&T?‡aÍI€H€H€H€H€H€H€H€H€H€& Ü̪35?ùphmïiƦÔÙðl;_xܾ*lñ¸ºé0zŸñšH€H€H€H€H€H€H€H€H€H`\ Á=Þìöã܉2,ÛÓ¯ w~~|)ªô'nWzQWëEqž[¿‹ªÍx¼¢Õ¸æ À¸'0IǸ—òš 8ˆúŠïâÙS-8Tå “Âƒ–þcÈN»år¸ó8RçxB. àë?€…’ÿŽ{1oõžàsw)zë·"#Jx|D$@$@$@$@$@$@$@$@$@$0~p†{Ô¼«Oî±0¶GõdûpàíÿÔŸyJ7™ŒíꃬUP ¹h8ƒ‹W­Ñ‚à/ ÀØH»¨&bL©øøÎRÿHÃdLžüN=¹U‹¯'ž¶þÁ¡HOÃïá=í®{!>,Í~×nó—H€H€H€H€H€H€H€H€H€H`| Á=j¾¤!gÃVäèn†1¹Ö¹Á=ýÎA]PF]œ¦ag*î;ŽüœÌ`èÃ=8òÍm8¤Åuç|.'£±à/ L\R&¡LHÈu„ãôÅøFqnè¶[–ÍÁ¤›°}{>¥ÎÄÆƒÚ†¬Ô}ë3àÛ‚¼A$@$@$@$@$@$@$@$@$@ã– îcš5)ÈÙQ Í䈺¡ ‚i•šÂo`Å,šÛÇ4k Œ î#˜˜÷.”¬˜*¸to.O. òòà6îû—aEÉIýOH€H€H€H€H€H€H€H€H€H€Æ?N£Ã<:wx'vVQç³{àm«ÄÚùA *JÑ|¤K7î\7ì\†£_ÂúLgY4oÞ<¼ñÆ ¥nòäÉ ¹§c HŠ¢nNš4)ò!ï Œµî©ï{çŒdL6þøÇ?²îÙ°ámMìwŽ&]†MöØï´gÃ'$(+W®$äåýï?:;;1kÖ¬„üµcgÖܱ–òºˆ¯ OWé))oyFÛÓõk K6ìCão_ò궪bsÕ†6¬d¡ä&þÓŽŽ䉙ó·Ýv[ÜžæÎËÁRÜ´è¬ <õÔS¸ë®»“cl·lí’wI€’Ià׿þ5^zé%$3X†E$'žxßûÞ÷póÍ7ÇášNH€’E€ýÎd‘d8$ö;ãE×$€:YX{Íöì»ßý.†††´ËqûKƒû˜eM:îY傯ô̹²±ÝâÞµë€ÁÝß?²´k×.dffóŒH`Ô 466âÀã?>êq1 ƒÀ±cÇ ¾lÎÏÏ7nòŒH`LüÅ_ü6oÞŒÛo¿}Lâc$$@Aìw²$Àµ!À~çµáÎXI@% Ü'ÂÁï®Ç,—pátÐØ®Fy“]¼CƧývnxŸH€H€H€H€H€H€H€H€H€H`Ü Á}4²dÐ.±žº¦Pß A*Ò¥Ií•?mÕH¿~<÷ƒ'õëuKæêç,þŒçòYQm²˜;2ž“ ÀuEàÕ½ÄÛÿo‚%IØÙÿçêÁ}‚ÉMqI€H€H€H€H€H`ŒpIÇ ¥õaÂÂHlŒB'›žÍÀÖú~4VÁeº/]¸ráõõb÷*nv*Qá) À8 0‰=Çq H€H€H€H€H`<àê„r'SðH ?ó©€"þ¬tälسŸÿ:|¯âÂoûpU8¼*¶QýðÜX´0S,>ÃH€H€H€H€H€H€H€H€H€H`¢ ÁýZåXJ²²sÄßµ€ñ’ $“? N&M†E$@$@$@$@$@$@$@$@$@$pàÁý†Íz&œH€H€H€H€H€H€H€H€H€H ™hpO&M†E$@$@$@$@$@$@$@$@$@$pÃàî7lÖ3á$@£A`ïÞ½HOO & @Ë—/ÇÝwßÅ‘ ŒÓ§O³í-¸ —¢`¿3 >"Q$À~ç(ÂeÐ$p Áý:ÉH&ƒH`|øÈG>2>¡$pƒ¸ýöÛ¡þñ {ŸøÄ'Æ>RÆH$ö;YHàÚ`¿óÚpg¬$0‘pI™‰”[”•H€H€H€H€H€H€H€H€H€H`Üà ÷q›5ŒH€H€H€H€H€H€H`"è;u¯þNˆ~+îýì*d¦EOEgó œyó]áü£øìª…ˆáÔñâ‚ÿ ¦ìsX¿dÖM­'ðÆ»WqëGîǪìñ—Žážsøés§áÇt¬úÊz½Ìjeó¦›n²dõÝwqõ¦[±ðÞ,Ḭ̀t3–7ýÍøÅ+o².%tÆA€÷$¼A$@$@$@$@$p½~OÁÕÿšx©»é6 å–IOpJL7(‹/| ok¤¾¸¥;²£"[±méjxU×®RôÒàn”ÿëøÎÆÍPIº‹ï¸wÿkøËÕž@:\ÅMãÒàîûÇmØ(³n4mÐ î~xóVc›ÏÈ’hgîÂj<»ofDs4ÊÏ.<_¬{¬K£LšÁG#@ƒ{4:|F$@$@$@$@$p]¸X­àÿåÿ7&M Å5•? ÿæ}píyÿu•LÌE`ø Öü7†ú• •ðiÙ“°ôlj›NR'ÏÖÓÏlõtÍõôÉH<6Íóuø›š äÔx@NÓ‘:.¥4ÊìT“„Sç qã4¸7ì߈™M~t×ç_3£»žÖ¥qYÎn¡¨Ço”œf:I€H€H€H€H€Þ3ðߘX0”á‰%/¥%pº…±}bÙÛqµw‚ ž×ãƒ@ú]øvM5¾,–”™¶àƒãC¦„¥ð ±û'¸O¼2š¤!ø{»ÑòO?Àê-ƒ!6lAeóç±cI”¯:Ž{|yP†„BãaxÿûÅD† 4“Á|ÔÎhp5´ ˜H€Æ?!¿‚ùØ0†'˜ÑAiäþ6aã¿„QB   ¨«"Ñ~-áéC 9ë7 g‚'ø–´4¤ˆ/ Œ‘XÒf¥cUþÔužÅÊý žh¾x]Ü;¦Loîÿ{‚çfòÄ¿í/þ3ÊÊ’àu’QG®ƒÄ0 $@$@‰PDáÝ‹ÂÏø¼óÚ8±l¡k    zp¼¬gß–?öuÜ—êÃSåxöhÞ𙎥k¾€ü¯}Ù³"×[é9wå?(ÇžCÕáƒD]”î݃¼µÙ¡Y‡Ñzô)<ÿ†ˆäÊLløæ#ÈŠ õ‡ñôËݘŒ+¸í“_FþŠ›G$Û`g3ÊöíÇNI6—;¿š‡Ç7äÀjntúÔTø»Nâà·¿£Â_`•—y*ƒí‚Á YpÁ®B°ë¾‚/ ¹÷¼…¿û«"T«þr+ÑÿÌ#ЖñîiÅSû`ËÁª #õnáøÚWÖ"mOëqT>"`|ý‘ûà;þ*þáY4] åÊÜ¥øÂ£ùøŠÎX PÝüõ§ÁÍ_ïö`}N¦zƒ]Í8ôÔ œ<9pm÷ß«¼îA}U%ž=v.^ ”‰é"îuŸÿ¾ôÐ ˜pèûqòÈqèÇ'ü¦‹ûw.Z…Ü‚Ç1#]|þ5‚ãÞõë€Á}ªE8=b#á|º ÇžoBƒ/¸FËíÁšuŸÇ—Ö …á^>œq–Cˆ<îiÆ“åAÞWþë î}¬«²ÌñFú²¸£p<*SQøòAÆ8§Á= o À F€3n° grI€H€H€H€&ÿ8¸mgp£Íßv‡E,¥íó5àÐþgQwù¬˜e˜xZ+6añÉ€¬%ØçÅ6øË-Ç¥Ê|d¦ àÌ“[°§!ä`ùìÎ ßò²ÞïlÖÝT¶bP§²uœ(Á¼Õ;5‰ô__CÔ¿ Ñ>°/Âð_µÙ…ˆ©é0¨Ëƒ.ºÊnK\ 8 ÜèË_¾¢/‰ÒY_†9+·é2è'Âýþ-êŸ5m^¬Ÿoeß`6Þ7—mÂÒm¹'ò[¼ûEÕ^ÂîUÁj@Ž8ëXœôf3%fâÅKw¦‘¯>x‹à;ŽÑÑ# ŒiÃPŸnl3¯‹ŠPX'EÚ€•ß}Q7"w•Œí.–V£®±5å…pi¾ª¶`ó“­â*Ÿûë"í.ö<÷+=ý¦˜…ý”f¤ucj|v(›¿µÂdlwy Qéõ¢ºTñõc?/kÖ¯"OÜ(*¯~ ¥G^|íÀ ãZ’OXtáÓ.œ„¦_ûÏ6Û]¹Å¨mjAS]5òt÷ xx'û¤ õ q…¡:dlw碼²ÃoÏJüKghµsIyó×›?°(0›ÞívCþó亀gÒF¦ƒçÂŒíWÖÀ[]*ÌìÚáÅêy£Õ¯]ûqx³ÙØž[XŒòÒ"„Ǥùˆ÷wx°O|%±ËtK¾¹«çëÞ‡;Ž˜ŒížÂrÔ66¢¶¦yRä{Vÿ5Î êÞ o~*^SÄÍÙð8ÓךÆöu²±=¯½Ï<‚Æ;ª0Ÿ¼$‘`Ñ?ú&       Ñ''fäV#a(¦o~1Ó–n ^ÕŸA7Va–¸j;a,!“[û"ö­ ùÈYõ­U ÇN¡ok6fÝ¿¹Øœ-}°mû×b¡41ºã¥Ÿë³Ãs·¯Õã‰ü‰K¶>ù˼—§´ Ƕ. ³­qã3ó_.jÛþ«ækôü¨Ø½Ywæ)mÄÑ­9¡µÉ³±äìrü¯u³±-€²ßúÑIÔï°Z݅ʦñÈ’P¸<„ù›>-!C|S[7Öfª¹b}ÌßpʆÈgꋉ©UÚ[ Ðû}d‡&c7—íÖg¶» ªñâw7è†ãµŸ÷ lýœÜU(:²ÇòÂßz›õ ænxŬýµ¡YûùO<†ŠÍ³…Ì‘r˜ïx±tªØKËå -i|ê -£¹-oy9ÚÐ~²V¿(ô¶cßZ-Ws°J¬kÿ@þ§°ñú•€ï©S襲§{¯Šœp=»ê±nöJhµÂUPƒSÖëK qðŒ’G€3ܓǒ!‘ À(ÈCÛ߯v5‚Œ%_A¥6¥Ùׂ7C³™‡„áR;nî}[; þθ…•Åb–|!ŠÖݱõ£0pº°±@›Ò]…Ú3=’Ÿ>¼øãC¡káîÁyÒ3í4>ÙÏ{!Vi îb<©Ûƒ·Ò²Öb‡>Ñýyt hák¿øQ‘alWï¦Ïÿ,¶[0Ð|¨¿>a¬õ^®”Œíbíôóÿ„-º¶?ÒíšÏYØúL‹x<v>‡}º´æÈ«~Ö0¶nÏÀWv<¡;hzý-ý<Þ“á®ð,6^L¸‹ #õðyüƒx<òð¬dlÜKÉr7é3ݽÏ6ˆÕã‡ñò3OêÑÕ=«Ûƒ~f!ÿG-ºݡ͉ºþºjd×þÂuúÎCš¨ŽéY÷†¾¬È×Ԍ횯tdß§•=ñá„v;ì×çÙéTg¶ËÆvñ†Æö0¸¼—=£2%       1w飘aÁ1¯¨­+o›~‡ß¡ p¡¶_ݸK\÷ sV–<²Ú¼ò Ã|rÓc‹².«ŸkÁ×sVg{«›LjFrÏv|RZ'^‹$^Ù††®h^àY÷éÀl|ýFèdù®vøUÓ•Š9êÛÉÈí.zYq20…›·†É=4d¼”ÈÛi3k?ýN¬Æüª€}û"~/^˜÷×ôàÑÏÍ7E¥^ȹ25âiŒƒçñÍÙ«³ü.Å:ã^ifý`{+´×ðdcê°}~ ’ð4%å¸[üÄn¨ÇëþõðÕkëÌâË+´Yþ’,iÙøF‘˜ùu=yuy¢'¶¿ë;Ý8}t?¼¡(öo^†ç_¯E‹øÚ@Í®9[qVÙŒlxþ¾>øû߯[oõ »ã”Sï%äS‡œ«6bf•N1N‰¯#¸j»Ì„ç£E BUVD —H€H€H€H€H€H€H€H qÒ Þ1=g­Û…"×!ì @ªöCý .ä>†Ü/ 9úò*b¦¸k ° …#ßÁŸ‹eeV–•éø¥±œLÁ£nKce¼²]:]«Ë~÷]ÔÏå“´YX(Ûƒ%[òÔ™·ÈNã>÷d4b•Y–ì…³mÂJÅ´¹êìë Hí…†ìØêžü<±ó>T|qA ‚þÄæ±•˜˜½÷{#HïÌžbÌ„7˜ÏRß} §5{»'ÓÌõ«[n‹õzÀ…/=‘…V–ÄÝû o†ëÛ¿ÇÀúЦ­þŽ“øaÉ÷±ó6;_6®“äp>—»¾ŽUa/_‎H A\R&A`tN$@$@$@$@$@$@$@ñ˜œje¡”}KæÄX6OٛݹXVdwK/«‹áQíŦÇCû·aÙ‚™XWrÒx’’…/k;XBíÙ>ñÌ/-'ãÁs2 ÷Îæ<ð¨¾lIæLóŒ ò‰Å~Ežsô:çÓ[ôåb® IV}SÈiÈøÓMwFó¢~ïŸË܈­Lë.EÌèŸòá{t†ñÉÒ!Qüâ¡Ý]Ëîǘåowd­Ú:1K^;ºÞ :îª/ÁÔyË,íîÜÜÐr3š¯ÑümÀêܧÄ;úŒ ÀD@Zv£õ7ÝÑSÞ{Yß”ý¦UT¢û‹ö4%9Ć™gô‹ð[½(-*07½;—áh§±Úö¢µ_ÕC¬ö¾Šaÿ¯ådòr±(CìèärS¾q¥‘{Øß‡žžñ×gZÜQ„Q<]:Y­o<ŠÐV©‘ÎûðÚ m=óR1‘nGv§ãèv¬”–s)oùVXÌÄxóU¡G¬íÞ?ÐÞÞÞˆ¿þ þþ‹ÓÔW'¡#Jùš½.Wsåø÷j‹Á+Èp¾½r§ž» ¾vt÷öc`HAý3Ïà¹ê<ýy²OòÊ[  ùô—+hØ‚¿:Ú‘ìh D Á= o €ssJ÷|èÉŸAÞ†T:9ÿBµnpw»ïÆÈìÚƒøÿÙ»øªê;ß÷_l ô„ã'è 5ñ4\.èm|y^¨BGÆc’ëø"Á{™ð*ô4ö’›XËÃulˆÓ §Z‡mO¦×dÏÚ!ãKð#d$cM•T¢l5‘lÍýöÚÉNØy$;ù¬v±×Ãÿñý߉ðÛÿý_GöTióæÍªÚÓä_=1)Y™+´aËv³–ö%¹Ê³? MYNXxŸYŠ&Шæ_¼¢ÿ¶ÿ»]åùÚgY–Þý¸Òù<‡ÉõFÄä¯m¥¹sçšý>½nG‰#&ÖEçø|í­ÈeyÞV½?¾U7úŸ09ép®zNíтվÅ|[ÉÓ*̈ü.ˆ¿>ÙJ&שwŸ¨¤¤¤^{œ~]ó¬ž}Öì5ÿ oâ-ʶ†Üý’ÞˆøflWýOêì²û;èû]gÊ.}r“ã+&±÷ÂYµ’øÖ£ß¾A™i©š“”¨„à?Ú~g§°RŽÌkVµ~P˜a>OIS¥y޵լ~BG"X)xE`ø܇oH  € € € €€-øoï4‹‚7w©¾³ç„uöê9ó²q<42ç¾¾á ËpÅ“N½ñ“RUTT¨t½KïõIŸ¨ÌÜœÐÕ°j²Vn ÎrnÞ¡µE&ìŸhõ=Î…ÕCÙs”xóm¶IóÖ]jìôì8¢j;îüþ(šuPÓGÚé³SìÙþîÒ ‰°ÎȉýÏ۳ɳ*#=°ÕQàPÛͲ?ëíÜù;iûªþß ©‹ÍZûÁÍ<ô•3¡o(X—;šj•[¼U[·šýõ‹ær’n_jÂÝú~u£•Ô~mo¬U©ýá‚}¹×A¢fôû¡ƒG»Šµº¦9˜'KwÝbзP‡Î´ËëõªíÌ!Þ·,àÞ™§”Á×uޏäûUYb¡]Z6+Ж@]jÚ³Q‹ŠB3¾Kòìè¶ê™û—Ëç¾åÆôòËûµ¯}Ï~5µùÆ1E…Ž%XÖÞñ ö4µ¨Ëkf“{=:ñj•f--¶›°sc®ùfBœî/|ƾæÞºÜ¬ßÿªÚ}™LØùÌ¡*Íu,ûb'ìsP§ü¿¬Ò®]Uªªòí»Te¾I±ù™ÍZw÷L-/®±sdUVø—ĉó¶é…š@Ý[¿«=GZäéêR—§]M¯îÒórý¯ÓëoõþÆ.rðfùœÐ–¨ü\¡÷¶ù°¢üP[è6GŒ°ÀHüÊá&Q € € € ÛK6½ ÊC.{æ°{G±|{ä-KõõO+´`H ÕàWU‰3ýíJ¯Xîä7×é³§§§«¹Ùš}(;«üyåô^'w e‰xä|VmsM©ú{[™ó+ôâ¦àø%-Ö³Dûjµ¦­Ë"·ÕÊ[´h®Žî;­½kúŸåo¥ìk\ò ÕVç™RoîŠÜRå]Ü«%‘Wïlñ¤G L€îaœ € € € €#!¬M¿zO®J{ˆ…fTêØ{¿ìü6ëkXóÏg^i­ +¥©ÂÌ$?zº^Öns©w°½¤ºA®-™Ú“¤œ|G{ͬû‡&DH7Ķ%,Ô¶îóª-±Ü +;¯¤Zç.mSª==tˆõ»›‚%'NëÇ.1C»/ÓÎp(G°=KÕ‡Ïkûš´°6Ê~ ®Ã<½ìÄ©Jš›¬?¾mæ$ÚÑå]¯ZO×É~W—§NÕÔË—5õ¦?Vú¿KWòu¶¾ºQóó‹©ì;§ÝkRG¸]â<í-:û/0ëvÇ+~Æõºù¦yæaš‘‚û£R}X¡­§ôÆéwd„tù“˺î–[õµEiJ­¡ «}è'ÞŽ65¿yFÌ›jêÔkuCr²nŸª=m:ñÛ`žk“”’z§R“£j½™þœ>ã7[ÚÕmÆûÚæèöÛ†ÚéíPKëEó€ÓéšuÓ\s}|Ã{~úS}öË_SdâdŸñg¦ÄG“ÅJ¼s|¿ƒÇd¨¨@@@E¸D¥,Ì0û(Öѧè8¥¤-ñï}nõ{¡C®`»™³¬ÂoŒN°ÝW}âœTe˜}ü‡í*v:œUY¦ŒÑŸø< té"L6î“mÄé/ € € € ` xô³Gæk}0иœ¥ï=|ð¥Ž@hxhj4J¤A@@@&¨À¥Ã;VYÿ¢2cg…ðÆs†\ef¸_å z@@@@àê $jÝ«§•õágê6˜}kºRÆûÓB¯5#€W à~E" € € € €W É<Í5©¿ZNÜnÓ3@`TXRfTX)@@@@@`² pŸl#N@@@@@FE€€û¨°R( € € € € €Àd` ÷É6âô@@@¸‚€§µIûò3Õ»õŽ»YÍÁôéYyÊÎY©uùÿAɉW(e’Ýö´êÐß¿®OL·¯ûã{•“‘<®<-Múû7Þ5ûýYNš¢h]kÓ!½þî'š:ujÄÔ—?ùD—§^§´Å™JKIŠ˜f,/¥cÙ>êšÜ'Ç8ÓK@@@@ w=©åÅuÓ6»]òí;J׫ ú°vfF¸XØ»è9ëRîêb¯Ò+»€ûÙ_”iu±[Jß©‹QÜ=räªØú´å ã•U¶O/m[£9WH7š·ßÇÑl eOV–”™¬#O¿@@@@0í/œÙ'Øž_P¦ÊÊJ•ä…¥®)Z¦%Ï4ÊvuŸÄO³;kB¼}<^â§Í 4eö4E;wæ­Ñ·Þ]±Vs³w«=ú,#žr(}ñFPठà>éß € € € €RÓ®õZ[’È*; ó—z´w÷6mÚ´IÛvTOç{rUæÛ‰š·.× Mö9U O‡/tª»³Sö~IÞ;§úê’P§ÝEªåýòàhR Dû֤ġÓ € € € €À¤èhTY±ËîjAíqí~,Ã>·’µbÓ^Ö{ZVj–'1[q…Kë>&Vt·•&äÁµ Š3 ¿‡‚‰ J0ëøçnWCëI-¯¼5½£MK®þzî£5ÿåØƒêþ²k´Š¹r3“QÎü˜k÷h6˜KÙ € € € €@ 4½¸Kp©il^­~)ØîèGæßSºuîú‰Îz¬“À«·ý„vo\§)S¦„ö»³µy÷«j VÙ~æˆvm.TöÝwÛùîÎ^©Í»öëT[¯JLU§^UÕ3Ï虪ýjóvéÄËUZéÏ{·öœ ¥o?uHÏ®´Ëô·ëî•Úõê õÛo»÷T©påJ{î6åf¯,Ô®ýjï7S¸Côg¦í¯îÖºl‡—±Ë^·Y¯žh šü}væ»[ë6VéHKôß<ð¶7i—q¬ªªÒ3›ŸÑ¡–ݕ۷¯ZiÏ´Bƒ×öq­ÚsÄ,Yäõۮ̖o ¬qØ=ÐØ…ª¶†ÛG« ‹]mºtùìˆ׀@èC)D@@@@&¡@‡š…f·Wþ]y¶zÒ=zåXƒÎ~j¸._«[¦‡ØZwiþòÀÃCCWÍQ³[E¾=KN»´jaøœø¦]ë´4ÂÃZ­µV˜"ËëÏkKNŠ]ì;î*Ýø¨Àý›t¹]¡'|^ê¬.b÷:-*ª³óØÍ.ç™=¿Zçk •−yÛŽhý¼eê“«¹ÙÔQ£bå©þÜÏ”“j¦|wó¶jתùr|ÁÀ.Ñ]W!ßžUæ’kÛŠðqéjQÕƒ ü¢Ç@«n‡o/U™ëœ¶­HuÜ‹pØnú:×Ñ×üZ]HñMxн;BVëÒo_;hê¦gØÇ¾ƒ¡Œë»G­qÍRKǪ© «¿ðà8¼PÞ ã[²³îêôÛÇPŽ)f¸”$å € € € €±(àyG¡éíºÿß͉¢qJ]’­œl³ç,Ñœ`°ÚsjOX°==¿RõÇŽëXÃ>ØSâÝZ}GžŽ8&`{[ö‡ÛóʪUø°êT« +Ôœ­¹ßÑ)ÇìòÀC2;ƒíVoëËŽ`{ºÊvîSÃá¨. ÍЯ+ÒúNXY¤®S½‚íyª¬= ×¾&Ìnm.å.xB'ÂcÒÖÍA¼z´g½3Øž®Ê}õ:~ü˜öUØå¸+ò”WÕdŸ›¹ýÚý-g°Ý×·Z¹\µ*qxUä=æl`?èÖ¢W:ƒíûtqïcöxZéû{õvu˜oÎÐ’“÷é«+çgr»õݨqS¦?ý¹#õv¾ðYÙ™ÊYµFZøuó@Wß,g>óMµ›Xšýœ¿³^?|2ÇŸÚš¹Ÿ_ÿš¶å?LÈÌÖª‡sýÁf_ ÷Á£êØ!ßÊãM»¶Ø3ÛÓKöéµgר學fžc6zÊ÷oÒÁÂ4“kh›çÄ~­·§Ñ盓Ö*3øéEFÆÝwÏW5o™™Úo6wi™Ž<ѨLÓHω½*²»æË·×ä ´aÅŠo)kóƒÊó¯©îÖ+GZ•¹"ô­_*@°­Q+ç-—ULzÉݾ*|} Hó§KKgNQVzº>´¯™¹ôf¦¹s«>þ’¿}Öµá«UJºj½¦Ç–;øØÃZ¸î~g½;}A+R’­Äöëàûhgåa 0Ã}X|dF@@@b\`úl-²fEß:W³†Ø®3?Ó+õ¢l· LÖ†½Ç•F*ˆk ^€€ûàÍÈ € € €L½´ã¾®“zÏÄ—F1òvyäé £ã“tþ7¡ea2Òæõã¯Y·úf«–"qÎV÷´ѪžSi5üŸ""^Î×Ây }ܬòôm ®|b=„40]e+ÿÛ*sa ØÝýÙBe¸Š4ozQ輟#gúIùr×y5X]5Áýyý˜ÇÍœíŸýì‚ùTÀ‘/ë^ÝÜ·Û¦¾¥.L‹\oŸ«‡ôë¶§•“ÜOüéÓõè“…J‹”dË6µªÒ‚ÜRÊæŠ\|¼S«‚”Þ¸š ú´w(¢éãPÊ%}XR¦¯ W@@@@É#h–”±WliÔù á3º#Ct©î[35kÖ,ÿ¾ÿ´Góï/²—‹ù¼»¿2”ôof÷)²­±J3,‹lÏÊÏ=à´ONë‚ùÈÀ9íÙºl–€Ùrü¢ï«TžÝGëf³j*ŠµìŽ¹ZYuÄqú-wÙËÅX©~½±Úóïšéçö—úÏ7c–ÂÄœùܾ%f†»¹•›ÿã+,ãQwgÿõ¤ælRC¹µ.‘Ôöq ñðǵÿ:w'š>®DR#П÷þd¸Ž € € €L yº{©ÕÑfUÿü´uÒÿ«ç¤Z³³M˜}ñm‰:dŸý°Ñàc9#äïÐ[‡ìõkÁjo‹¾·<0;Ú—!«d§7ŸÓ…‹—ÔÙݣƽ{õʾ‚eEy).I™kÌÃMOöèÒÅ÷tü°K;ËK‚ø®Òez¹µKï¾i?D4¯ò°.u^ÒÅ‹ûì—:;Õéß©ECZNÆ´=>^7Y]ˆ¸.Jà¦Ç´ÉóÇåù²¾X{Þ*Ç~õª£½]ífïðtÙW­ƒ‚êãêén¶? ‘»Hõòð‚÷—[­ Ö2Úãju¦Ÿ×Ñèc?Uq0îaœ € € € €“M N÷ä—ÛvmÑ‘+< ´©Ö¬ÛmåÈ[®Û̲&ó}ݺ¢ƒ¯½e‡xÞV½—½U7š'•z/œÕY+Q~­\Û7(3-Us’•\¤íwv +e¯]:²§J›7oVÕž&ùæÜ'&%+#s…6lÙnÖŒ¿$W™cVö‡Š¿>´ºëÔ»ŠOHTRRR¯=N¿®yVÏ>köšð—Ecú&I˜¯ ³ž½sÕë·ý˜Ÿ=Úhç½{þõfµG>÷A½Ñnß´½¦Ysçj®ÙïûÑÉÐußQVµ~P˜a>IS¥YÓÞÚjV?¡#‘Ê &ˆô+¯ïA®ŸÜäø Iö8fÓ'ç”©Ö ú›yôËžÞoBç‘¶DÍ0ŽDÞÉS^fŠ]‡ÿ l½øDå¿à²Ë’ù¡üP[xzÿYòÿ²J»vU©ªÊ·ïR•¯_¦ëîž©åÅ5vž¬Ê e›°ÆÚ¸ÚUõ0¤>ö_wŒ@¤g &?i@@@@&€@RF¡ÎÕ¬¹VZÚQ”'Gx=¬—Yeôß·­P(¸§œòZìXdÂõ¾­F¹w˜£ôt¥77Ëšÿì»S²¯Y+LPÖ¿%-Ö³Dûj&· ‚/ÐúÀˆ-š«£ûNkïš…ï‡.Æ){ãv¥W,÷×Ý\S¤;ÌžnÚÓlÚãܲʟWN°= ×|_Õõ5 |6`Ú³4r{²ÊìœeùÝuª°&å÷¹¸uë:mX±B͵J_«+ÎU‰ç›&š6:3–¨¹<'d='[¯(Ó‚ÕþDV>gßqÉç´$¤ï}Ï:K^¡Úê<óaH H_aÆ?ïâ^¾Ï­Dæµ¹¦T¡7‡ù• zqÓ’À•QWG…QÔÇ(‹ Q 0Ã=j*"€ € € €[ 5g“º/×Îà/‘{›§ÚÃçÔ¸m•úÄr3´ûÒ9“ßšYnJ ¶g©úðym_“æ(:A«þú¼ªyw v6èbç9•;‹üÝÇþñÓfSúf§GØL`úèéz9‹îl/©nkK¦#ó†ý?¨µlßqýjKv(nrÇÇOs”qåÙÁäií6tì Í27YÁö¬’ZïÜ®´^]L]µMﮕµ¸Lx¾12Ϋ|KÐ7«y3­ ¡×ŒÇŸS™í[§ç]gü7§õª3”#ü(¯ \ §/hï¦lÇŒÿ¡«¬¶öY`(¼Þ@#׬|ƒè£#7‡ŒˆÀ”³HI2®¦L™¢óçÏ+%¥×׆ÆU+i \mËõèÀlóÝÈ/¯vKWÿµæWÛÊóѬ‰8¸rIÀX ZÒ­ÿi,k~]S¾b~öþ5N3’§ ¿0J@à* œ¶¢ @IDAT}ñKßø…¾øô*5`ˆÕÞµåÝ]n~ÙˆQþÞ›×ÕѦ³o·è½ë—æTͽm¡îLMvUûï[Gë)½qú]ÖT]þä²®»åV}mQš’BSâûdöåy³¥]Ýññºö†9ºÝÔ—d­ÙâíPKëEó°ÏéšuÓ\s}€‚ú”ìUë©ã:ùÏïêòÔ©šzÙ´ê¦?Vú¿KWrbÿåxAó›gtáS“~굺!9Y·ÎO µ©O=øÐÕ¡S'ßÐ;øêº¬O._§?¹ûkJKéó±Fx%f©›–Ógõ‡Ï|AiÆõ7k£þ{ž},ÎFo\Ç¢õáu<÷C½uñHøÅI|vÏ¿ùʺ%Lb%ÞIÀ}LÞc_I¬¼Ç^†@À)À?|œ#0¶ÜÇÖ›Ú°¸[¼"0¶ü½sl½© ˜ˆ±ïdI™‰øî£O € € € € €c.@À}ÌÉ©@@@@@`" pŸˆ£JŸ@@@@@Æ\€€û˜“S! € € € € €ÀD à>G•>!€ € € € €Œ¹÷1'§B@@@@@‰(@À}"Ž*}B@@@@sîcNN… € € € € €Q n"vŠ>!€ € € €Ä’€G'¹õ/ŸHS§FÑîË—uùº?ÑŸå¤)AVÞ˺îïUNFrŒBO«ýýë2]¸ºíè§kž–&ýýïšÆYný$t\nm:¤×ßýÄŒIäA¹üÉ'º<õ:¥-ÎTZJ’#çÕ9J¯NK©u" pŸÈ£Kß@@@@Xð¼¥ÿ”›'÷`Úš¾S}wGÞôÊcW-àî9ëRîêb®f;ú#<û‹2­.6–[ íë¹ rUÜl_ð «lŸ^Ú¶FsL5º7ßÇÑm¥ON–”™œãN¯@@@@ñ#¯y#КيR†XDü4;ã­ W±v+Ââ§…gOS´3pgÞ^Æ@gš›½[í%å{Céã(7‰â'¡@´?_“†.#€ € € €Œ¹@V¹šë×ÌîŸ)ÿ"&‰·ë{öéÛŸ\Ö¬;n8w‡(§Ã~¦{%¯]B·</èøÏŸWnÑŽÀUw‘j›¾©MK®þò2v39@`Œ¸1xïê¼]ušÿ~x½æ×U\¢’’ÞFœ#€ € € €À$˜9Wó““eb»QnIÊ\µF™Q¦&ÙЮMHP\‚ _ÙÙ”œ¨œÂíjh=©å5½3¡îÿe¿W]—m„Ip_Úå,úʤwp„~FœW9îW ëÌ~M¿c­¹Ÿ¯ã—ö*#úßþaev´4êùÿò}m­ _,«`§~ðý'•1‡¡ ã@@@&‡À¥Áv³Cûÿ›Îz>×ì;ó´*3Å_@û‰WUû‹“Ò-÷ééÇîQó«?Öî¿}IÇÞùÐö­KõÈ_êÏWd˜¯Fؼíj¬«ÕK£³ï¼#_._ž•ß|D>œ­93E('ªK]:ñêÕöEr†Š²òËT²ñ)­è÷A°5½ü#U:Šä¨õû+ª'T¢.5î~V/=n~1Gø˜qÐ}õêµgKe}žšU^¯_mÉ þG$M{;Ótãôtù3á~AMm+'™!43@@@@ v\/(oe½"-MâëÔ%³¼Ëmë´û±´Aô1]µÇ^ÓcK‚ë_<ö°®»_EÁYïÇN_Њ”dyM»¶Ø3ÛÓKö™XÎ;½â›yŽÙèu*ß¿I ÓŽð&{Nì×z{òw¾y0i­2ƒÑ%ºïž¯jÞ²b&wi™Ž<ѨL³JŒçÄ^Ù¡*_¾½&_ ì+¾¥¬Í*Ͽċ[¯iUæŠÐìq_*´©­Q+ç-—ULzÉݾ*|} Hó§KKgNQVzºiërspyë¼úøKþöYççŽÔ[‡½fÛg*Ǭ»ÿ§…_×Ú_¤Ì£Ï|Sè˜ØýØ…ò ¥ÎÜ#0tf¸h×­7_Ø:BÁvSQÇ?ªÊ|¥'°•«Ö¶/%¤©pŸ5ϽYÍïûcÒ`Á¼ € € € €±"à[êÅ,¡ÒÏî[üì¥8éÛÏ‚}/…‚íþÛsô盞´{ûýÀ±÷Œþ¶Ô Aè%G°ÝŸ .Eö³gº»^rc…‚.ý|{‘݆òÃ?´ƒíÖÅäÌ :^mŊܪkh1·|ùAx_ºò†J;ØÈ— O•ÍŸ'ƒ}³®ÌKT—oÖ·3Øn–¬é?Øne4KÜ{_ÝÚCwG­ÍgLëBÛìÔÅ&\îÛ ôè½—¶ITÆ=»¾ñ¾?"lQ3ï0úè,†c†"ÀôéÕâõµÒªüƒï¶iš6íc}¡T½—ü°ÇÍŽ·ÿÑ¿ž˜ïR~íj…¶H¸pÍ^u>ü¢ÿ$Î<ý™ @@@˜\éÊËóbû™ˆxé’n½±¿ðl$©<ýÅ7ö¹á Ù[³é»ÎP•2/C3ÍÃ{ÿéq7êNsäË»õ¶gƒ– þÙ›¦„n]¶»X Õ÷D~úä÷~ݤ Lƒÿ ícs<בϾЪ߼\a?°µbý2ýâm³$ζÀŠsÌ'{62y½òttÈséC½ÿ~».´¼¡ªÐôþð‚í³èÇÎÎâ;RÃJà! p.A™k6(ÓNãÕ´ú¡Ü÷ÛSÁ’Òµöùj?Õ¨Wê_Ó‰–ý×gÿÛ Ý¿òÊN‹ð‹Òn € € € €ÀÈ{R?;Xyu‘!v;Úð|÷gfÖ¥µ¹Š4ozhºu¹÷k´e÷Χ®ój°&Ó›àþ¼~¢tq3gûg‰[k&„å˺W7Gœ¯™ Ô…Ñ.usH¿n{ú ˧ëÑ' •©[¶©åP•ä–ú»Ø\‘«ƒwjU𲞖#úQÕs*­±:ÛGbÀ Cö +5š>†eà! °¤Ì è:•:ÏÒÙ©æb¢î\d-ßâÖ÷kôÉ×TWm_{háÍö±ÿ`fè49§Lµv(Ê­eOïWßûÒ'jFä©ôæžG»ŠµºÆL2õoYºë3í?ñ6=RhgÖí©¦„ðÍÛvHß-µfÅ›»Ñ…ÑÿÙúØqÜÁÄ-}ice³Ã½±ÒàXnççŽÆ?¹.K‘ðoËÊ5©¿Hgó7Ím·Ýæ¨ñʇŸ~ú©f̘q儤@@@@&¤@Š Í2';ÖÖø{·öŽuùØ‹úÖ¢TÇñ¨ù—?Ò¢¼Ð2);7æF|¸«ë¥*m¾pKÿ‹Ñ›åhnÎzJžzFªD¼]ÅKµNõúaAŽæ˜¡vµ5©,w©ê,ç’Mº')p’Yô¥ouËâv—.Óº_¾û•Ô}A¯Õ~O¹¥V>Oy™)V ×KÎÓDå¿àÒvWž¿,™Ê×Þ§m9¡™þÔuÊÿË4=þUÓ.DÞ4ð£÷õ‘ ¿ûr…ê¬X»IœUY¡ìdõêhÓ 5€º{ëwµç¾õÏS|·G'Ý?UY^±½TŽL/_ë‡ÊȘãlÜЇÔÇ¡WGΡ Üpà úì³Ï†–yçŠóÇÍå¦%jq¶ùê þÂëçS»Ä›o“ï³?ëó½áôøìÙ³JIéõKu€ãÍ`l € € € €ÀÕ° :„ʇ“·wu ×|_Õõ5*òGºÝZ¿tÖ÷NdγÊôdF0Þû¾»NWîdݺNV¬PsmÒ×üuŹª+¬FlHpl%j.Ï MÞœ“­W”iÁê +Ÿ#ƒÿ°äÀsZÒO­´qÉ+T[§EE˜UEn©ò.îõçsNm®)•iÚ€[~eƒ^Ü´$&i±¶˜%ÚWû»f—Ev´ ,Z4WG÷ÖÞ5 ­K#ö:PG¬ ´ÀG}4¨>°ˆ»¿ÆÖw"å¨ã_þ¿ ¶û*ñг!U!0a<=úðRììM[Ù@@@«/ÝD#·3Þ^®$q¦c2¡‡é½˜I„Rì´¾{sT¸÷’vöÿ@ϲ}Çõ«-Ù¡¸Éï üD¨¢÷¥™Á:ÓÛ­sõ;e-.ãKç ¶g•Ôê|çv¥õêFêªmzïp­âfï²¥<Õ>¯í«|KÐ7«ŽåV¬[?§2»uzÞuÆkZ¯:­ô½_ó ÊÕpú‚önÊvÌøOЪ¿>¯ê»à°l;t±óœÊ·›÷q ÕV{dò†ŸØiÍeëx} /Œ³±LÜ2–& Oé1ÛXBÆv]íY9Sëýøåéø¥ƒÊˆô‹§Ë£¶.Ê·²ÐÌ›R”d¾eãÛºZ^Öô«'*Psçn¥ï.vh÷ÊY ~ ¨êæK*ìýÛ4˜ûJ/S¦LÑùóç5ÃýJer®,ðÌϾÐ?žé‘ùŒ‰-Þ|@°ªJšcÿ%¸6EZyÞñé˜Ð¦‘„ ZÒ­ÿ)üÚx?›òó³÷¯qš‘#¿äÆ;(í»*g_üRÇ7~¡/>½*Õ¹Ò»¶\£»ËÍ!1*pù£˜m-ùelu€¿wÆÖxFk½fY”æ7Ïè§—5u굺!9Y·ÎOµc=#ZgW‡N|Cï|à«ë²>¹|þäî¯)-å SÔ½µœ>«?˜•9|‹̸þf-HMû0`DÛ9„Â:ZOéÍ–vu›^{ÃÝ~Û¡·C-­ÍC\§kÖMsÍõñ½ Ç–º/Ô|>Æþ=„1‹6ËŠÿuŠ`lþŽ+ñÎñýŽvdÇYºS5yJ/vû[Uyì¢6¿»“úïý¢ìk”n¾aS_÷]ÝwÇ\uwœVíÓù²Ÿƒ¡r}cˆÁöqÆAs˜T_šÿæúþ³+eÆØ¿w&Õ{‰Î"€ € €ÀÕˆKJVFfïõÌG©] IJ[’­´Á—¨Ô´ 9æ²¶„QOŸ”’¦ÞKÉÛ•Æ%)5õ *؉¯þÁ3ùc\¾ú=¥C à>T¹òM›gßM›€™¨Ç^<¬ײÀ/šk”›X£ËÎà?H×Ó%£_çáUs† € € € € 0$Öp›/S¤µd…ÅO›a—j-e_˜“©½f}ªê‚,ûRØA^™Ž½w\«ö_~XzN@@@@@Æ…3Ü5 f†úÁ=v…< ÍÃ.zÌÞï–ªÂÝZóݽÕÒªOÍbï—/KsoKSFêœ~³q@@@@@`ü p¿Šc“˜œª%fgC@@@@ˆ}–”‰ý1¤ € € € € €ã@€€û8š€ € € € € ûÜc é € € € € €À8 à>& € € € € €ľMý1¤ € € € 0I¼gôˆ7¥©S%pùòeͺëO•½pΠò‘¸Ok“þþõwM‚Yºwe¶’c(êæi=!÷ëÿ"ó®k{kÓ!½þî'æíùýuù“OtyêuJ[œ©´”¤þqÆèŽ§ÅŒÁf ®ûýYNšƨ^ªAÀ)C?úÎfsŒ € € € Ðùί”·ºxhYÕºÔX¨Ä¡åž¤¹¼jo9§»¥ø™ó”šÒ;ë*Óêb·qÉÒ±K&àº5î­Îºþ“òú´Ý#WA®Š›£k~VÙ>½´m®æG8gƒôºHÀ=º#Õˆ °¤Ìˆ“R  € € € 0FñÓ†^чŸË;ôÜ“3§§Y,¸CwÜq‡®{kÂÄO›ìËLÅ;z5óVÇÉÝk57{·Ú¯n4oÛý˜=MÌ2MiÊH€÷Þ@:ÜC@@@Ʊ@bÚãºxááðÀy\‚.½ñ#-X^êoyVyƒþ{É×äíê^OÐÕ_dãFjš‰F[¡é[œ¡iéÖ‡¾§Ú™ß6¹féæð[‘Jбky:|ágºÇÌÚ½‹ºå¹xAÇþ¼r‹vúã.RmÓ7µi ï¬`š;‚ÜG“¢@@@@±ˆSÒœ¾‹x$ιÞnÆÌëoPR¢ €ÆÐ'vãÇÛAÂŒP‹¦…GÕ“R3õ˜Ù'êvmB‚Ìg9Ž™ã J0ëæänWCëI-¯ð-§#jzgBÜOnýB=_LÔQ|¿æüoS4ïAQqÊpwjpŒ € € €L³ÄxÔ[Ç©WõâÁ“ú|Zªúa½p—ÊŸÙ'—Y»»¶ù¨K DêÛÏÑOR§ƒ¿8&ws`aïô¬<=´ò›ztÕ7”ÖkÑòö¯ªö'¥[îÓÓÝ£æW¬Ýû’޽ó¡¿m³o]ªGþ¢P¾"£ïÃ-½í:TW­êí[ýí°:“W²S[ÿs2’#<Óä9r𧪫;¨c.·ü-LOWÞÒ‡ôÍGÕ7²ÓúùÌÁ£¦—¤ŠgJu¥+¿d­ žzB™©¾ÙÚ^zÕôýXƒê‚y§þoUõñ,]ÿ¿¬Qavª:Î4ê¿ý¿gõ¹f+ïÏW)%¬‰]:ñêÕöEª Ä¥ý¥då—©dãSZ‘‘luÑÿ:,;SÂ`Ç*¬ò!œ,^µR ÜgFÈ?Øö ·ÿš o{“^¨þ•º¦MÓç}®Å—('uðŸB½ù~)™ÿ³n{’€{ï÷÷Þ"œ#€ €@Ì œmëÑÿŸ/ä¡™&·›Å-¯9iŒ €Qà÷•n DÝ¿I—Ûin—º ˆ4íZ§¥ÅV¨Ùº+5»]þ½Â<·µ¼þ¼¶ä¤Ø7ß=j•›¥–†US*ןÈíÝ®½`–¼9¾%;4sº£Iëf-µÛvæÀµ£Ø¿ï<|^2Cu©ýˆÖÍ]Ö7©ÃåÛk*̳L+uþW›”⌆uµ¨êÁ*uÁõ5«n‡o/U™ëœ¶eýAÅyëåLÖìÚ¡f—”^ù€?àþί¾¯¢àƒG—¬qܽ­Úµj¾ŠMÚÞ›»®B¾=«Ì%×¶öC¶3 e¬z·+Òù@âüöµƒv–›nt| `ˆíNÿí†8Ìûc½óý‘_« )ƒ¶;‹äþœ¿búKÃu@@`\ ´Ü£ÓïJ—C JŽëöúwËeîã~h  €“D ð ÉtÓ[_¼WPÜ\õ¶ì ¶ç•U«(÷N郷ôw/©&…Þšû­ìÜ«´àÌnû–&L]ŒÕûft?²‚˜… €WO î+±p¿zRÔŒ €DÚówÖë‡OæhN0jtfO½Á?Û{EjðÍÓöœØ«"; ›o ºW™Áæ­Xñ-em~PyþeRÜzåõ8mß¾ÝD´OéÝ`À=ï‘MÚfï­~†¿zNì×úà‡ ’¯ŽZSG6#c‰î»ç«šg><ðmîÒ2y¢Q™¦Ká[”v&Ó¹##1VáµÎ\Z:sвÌ=:n7—².U)¬ý#ÓžèûoµÃ÷êWnkÔÊyËí`{zÉݾÊþ&3=ÇŒ”@ðWçHG9 € € 0™vúBŸtÅN§¿Ñ£ëchù©Ø‘¥¥ 0QÒËêµwCNXwf§.VºY¬¥Yzô+Øn%ITÆ=fv¼?à.…?FÔJ#ì{)l÷_ž£?ßô¤ ¸ùÏŽ½ý¾”cî&î±²5ÿ^¿3ÿI Ï}——<ú”Êß¿Eš®Û¯ŸH™0[_Ï7-4Áû‚ÚÁv«˜Äi&Ô­^ËÍtéçÛn_ºò†J;ØÈ— O•Øë’7ž4í[‘bî¡€½Áû@žÞúêôÏw§üðí`»•29sƒŽW¿®EE¾¨¼[u -Ê\nµ)a$ÆÊj[¤WkíþH÷|×Z›Ï¨+cŽý™ËH´g0ý·Û5/Q]¾e†œÁv³lÏQDz=vZaî# Jq € €L&WSzzb§Ç ÞíÑbó 3ó¥6@¥ß×çê>Ù³!pÝë•§£CžKêý÷Ûu¡å U…¦p÷ɸ§¿øÆÂ>÷¡kÙÚœ~½n²SîPúô“*«þʽw‰îšŸ¢¤9K´e[`Ù;™’U¸÷¤ÙW¼]ux<úðý÷ÕÞ~Aoü¼ªW°Ý—®[—íȾyðë½&Øß{K~@çN7«Û44~öüÞw£8wÖQ Õ÷§Ï÷Êyç½_7W|w³JOÛÇþ×Ѓ°3™†?V¡šÃ|Ëí<©”iáW?¾Ðªß¼\a?l¶bý2ýâízß–ãŸa>üö ®ÿvëêÖjn€4x©’`»ÃÁh pmaÊG@@@bB _ ç9¦“;Úìi9¢U=§Ò{ ÇÝ+ö7ó½OθTm®/WMîÖà-·*ŠÌÓÛªªì™Z¶6B°=Ý<ÄÓ,7Óg3ÓÖí îî–>·G䂳ŽKý—7c–f÷{PwFo¬<êîì¿)©9›ÔPže'hû8xôÚcWå[¹ù?VG”©I†Àp¸G¼ € € € €ÀDð¶è{Ë3—}ÝÌ*Ù©ÃÍçtáâ%uv÷¨qï^½²¯`Ä’R3µiûAõt^Ò{çŽËµo§Jòœs—–ç—ò…Ü[nS©ÛjB–v8¬sï]Ð¥ÎNõœlÔÞ½/ù×p·Rø_ããCK×d}Õ¬i󪣽Ý,KÓn–¨ÂKœuØkæô­Çóî›fõöÀ6@\¾oÆÞW®ÒXY͸|ÜêEðÊUnOAõqõt7‡ÆÞ]¤¿zy”>\±xEÀpçm€ € € € QÀ{á¬ÎZwòkåÚ¾A™i©š“”¨„àêm¿³SX)‡üêm;¢g6oÖæÍU:ÒfÂé ‰JNÍЊ5´ýàI]:ç’=úìïÍ,u¯þç¯ëK×¾Ó¿Ô†U™JMž£Ä„à:1íz¯w‹æ+Ú@ï>¨7Ú{'0çm¯iÖܹšköû~t2B‚+\rÖáª×oû™^}öh£]ÐÝó¯·{0ÚcáËŽ&vé“›ˆ˜Ä£ÝGå}³ªõƒÂ ).M•õeöýšÕOèH¤±¶Sp€Àð¸ß@@@@‰)x›)„¸³nOUb¯^zÛé»öôrsw˜ nw¾ÿ†¶VT¨¢¢T¯4_èU›”hf¾çØqÝÏÍ}~ÒZý|¶n¾©÷bì^5>ÿœ=ƒ\Ó¬&êÎEVèÞ­ï×éSWS]µ}í¡…7ÛÇö]–}¥×Át¥Üi5Ö¥çö6õºoN=MÚ^l/&¯‡3Sû¦‰öʨŽU¢fDþ€¯jÜU¬Õ5Ö8dé®[Ì{aTÛsÇ7 ’sÊTk}¸bÞ ËžÞ¯!|_á r÷G € € € €8o›^¨ ,âÞú]í9Ò"OW—º<íjzu—˜— f«N¯¿5¼éÉ7ßn¯ ¿#7W»ÏØÁÑ.O«^~f½JƒqÝô¥w)ÉüoñJ+šjçå{ÔÒáQ—ic{K“v> å[­€¶ä:z\V 3‹¾c×å.]¦u»©½Ë+¯§M‡vji©•/Oy™)¶Šµö»ë¨['ZZå .%o'°â”óÔ3ö™«xi°ŽÀ¥®¶&müúR£ÜJ6éž$ëdð¯£;VuÊÿË*íÚU¥ª*ß¾KU¾o"<³Yëîž©åÅ5vƒ³*+”mN:ºí±«‹|pÉy9Qù/¸ì±VÝZ•js&ààѼ#ÊIa € € € €ÀHZ¬-f‰öÕþxª[ë—-ÐúºW´h®Žî;­½kj€[É9zÞ<|sÙV_¿YÅËïP± •¦§7«Ùš@íÏž¥í³ýGw>”/g‰»w¬×³÷»Õ­×ܺÔéÎÝZ8'[¯(Ó‚ÕþäuŹª+äÀsZ)n/2{Vu³ Óúfô]I^¡æÚ¥¯¤­:ÒÍÄ÷ðþ”¨¹g°=«¤Vç;·+Í™­Ÿ²Â+žÙi‡>Vý½¦9Û±òÀż‚r5œ¾ ½›²Í;ÆÚ†ÞžÐû!ŠØý7õZÇŽ%e¬Öd<þœÊì÷ižw±nñŠÀˆ Lé1Ûˆ–HaãB`Ê”):þ¼RRB_y £Lpïýô ûçØùµßÕ£oVISb§ÉþwеæWÛÊóÖÚ‹üME÷¢øÍé/õÜÁ/õ™s NT9¯^¢œ¿éÑï]½ú‡R󔯘Ÿ½ÓŒä)CÉNž *ðà÷¼Š¥Q,8ޣſ’¾r9¶ä®-×èîróCȆ@Œ \þ¨Gf›u7¾Œ­ð÷Îðñêh=¥7[ÚÕ¯ko˜£Ûo[¨$+ºêíPKëEóÊéšuÓ\s}Xsµý{;Zuü“z÷âeM:UæOýñíf¶ûÂäÈ3Á»:têä›jÿ´[ññ×jÎÝ®…)¡©éž¶V]èôjúÌYš;')¼ ¯G-§ÏꟙeèÍ?5f\³¤öSi×,©sÁ¬-?=N‰‰IödÃÅzùÛ÷†ÞùÀןËúäòuú“»¿¦4G{åòéXÕ•:ÞÚs¥ötÿ¤uËóÏ&%VÏÒmÿû-þ¿‡ÿó>¹u/Vâc£a©ðŠ € € € “I)ir,eÞ‡¸$¥¦†‚Ûá7‡v—”¢%Ùf6{B’Ò–dö›:19¥ÏC_íÄq‰JMËc.»}+ÒA\â%G1ù:,¯¿}ÙJ »8:'c=VWêÅxkÏ•Ú;Ðýÿqê[#~ Ôÿ^ܵ¿ƒí!÷ÁŠ‘@@@@&¥@üuSݤì:ŽR€5Ü£„" € € € € € pH‡{ € € € € €D)@À=J(’!€ € € € € 0÷t¸‡ € € € € €@”Ü£„" € € € € € pH‡{ € € € € €D)@À=J(’!€ € € € € 0÷t¸‡ € € € € €@”Ü£„" € € € € € pH‡{ € € € € €D)@À=J(’!€ € € € € 0÷t¸‡ € € € € €@”Ü£„" € € € € € Ä t“{ € € € 0þv¸¾Ð?¼Ù3þÖO‹â;{”gš;¥Ÿû\F@`¢pŸ(#I?@@@&ÀÇŸIŸwÇNw¿ôÆN[i) €Ã`I™áè‘@@@@@ wÞ  € € € € €Œ€÷@¤@@@@@XÃ÷“D §§G¯½s½½&1Q K—Æ\»i0 € € € €Àä à>ùÆœOV¯Wm< ]C_l1|妛tëï?YG~#€ € € €Ä÷,šŠÀˆ|ùåˆ3f…˜ ; € € € €± CS]c“6"€ € € € €LVî“uäé7 € € € € €Àˆ pQN C@@@@˜¬Ü'ëÈÓo@@@@@ à>¢œ† € € € € 0Yâ&kÇé7 €c%àýýïõå'ŸŒUu#VOüüùš?båQ € € €]€€ûDaú‡ pÕ>øö·ÕÙØ(]C_,ózõGo¿­©·ÝvÕýh € € €±"@À=VFŠv"€Ä®À_H_~Øc¥qü!V†Šv"€ € €Œšj7~Ðh  € € € € €½¸÷á@@@@@!pY@@@@@è-@À½·ç € € € € € A€€ûÐÈ‚ € € € € €@oî½E8G@@@@@`܇€F@@@@@z pï-Â9 € € € € €C à>4² € € € € € Ð[€€{oÎ@@@@@‚÷! ‘@@@@@ÞÜ{‹pŽ € € € € €À¸, € € € € €ôˆë}s@@&‚À—ú²£#æºrÍÌ™ºæºëb®Ý4@@$îãè]Ðåñ¨Û´gúôDÅ12ãhdh  €Ä¢À§÷wú ?_º&†¾Ôùå—ºáé§uã~‹ä´@@I/CÿúcÕuf¿¦L™böu:á¹6ÚS¨éf6ÓL³¿Ð{3±FN‚’@@‘˜â›)þű³÷ô¨Çë9JB@@1 à>Hî×üM0ÇÈEÛ}Aüôõ5ƒl É@@@@@Æ“ —D;^N½V«e[ÝÑæˆ.·Eew¬.-©@@@@@Æ­÷‡¦K»ŸÕKG«¦Î5`Ê¡ÝôêÐÖ‡µch™É… € € € € 0ޏ8Ýzó…­ªi0Ño¶ªPnÅ(>äV‘@@@@@`(ÜT‹××JwªòR‚¦iÚ´uô…RÕDŒ¼½Qù¹[µçï”ëëÿSyE¬ã>àpp@@@@ÇÜœe®Ù L;WÓêG"àÞ®],W`5øt5ìÚ ×:»@@@@@bOàšØkòÕlqçˆT~b×*>{µÄõⓤÏ>‘¢)@@@@@à* pcxÏ©ÝZT|kÁ>U¬HãP € € € € €Àhp ÕþÊì:¥ÿ”^¼›¯ã?XcÖ†gC@@@@˜¬á>f£èÑËÅ鲋ZÛü¢2C•ÇO O‹Ÿ:ÆQww·|{´[|||´II‡ € €ô+Ð3ˆ‡ô[ÈXߘ2ESâø'òX³S €ÀäLÜ2–”øÛÄX–ç-ÕYÑvSgÃOËuòy³&ü _>ÓŽuvK^ÚR¬3·š«³Ò¶¬#.o§‰æà¶Ûn‹&™æÓO?ÕŒþÙ×8@@@#à ¶·L:˜,ã"mÜý‘æ·¶Ž‹¶Ð@&ƒÀ 7Ü Ï>ûlÂu•€û˜ iøìñºŠŠ~kv»jä¦júWõmé7Ùoœ={V)))WLg%`†»%Á+ € €L6žÏ?Ÿl]¦¿ €\U>úhPõO‘ô ¸jX‡‘xúÍúfy‰n½(MŸÞwɘÎwiG?Ì®¬ü-½Eê¼a¾†3@¾:AôaŒY@@@@@`T&jÜr8ñÜQž…vyÔöÁEùVOŸySŠ’|OFKÖš-Ûµ¦ŸzÏì±îlªPaS퇊Ë € € € € €À¸¸f\¶*Æuª&OóæÏ×|³¿x²#ªÞtv‡¾¾øy·YÛ @@@@@ ¦¸ÆpM›g—š¾t»}@@@@@‰%@À}Èã™ØoÎøi3ì{Óì£è†’'úÒI‰ € € € € 0¬á>(ÕD=v°G]!ÏÂÇv«ÇìƒÙÓ ÕÓS8˜,¤E@@@@GÌpGƒAS@@@@@bW€€{ìŽ-G@@@@GÜÇÑ`Ð@@@@@Ø à»cGË@@@@@Æ‘÷q44@@@@@ v¸ÇîØÑr@@@@ÿŸ½»ÎêºïDÿSFá©pÁ†d á`gÉ^å!›…“§’3©i&Ó±“”—u¡i€Éòâ¥m 0çgL kjðr¼\_ÑZ0ãØÍEܦø¶5à›Àm¡±è2´˜Ø¬jC‚nPcdK5÷ÑÛy$@ðH`žŽ×í³Ï>ûìýÙþëë“} @ îy´†B€ @€ @€…+ p/ܵ3r @€ @€È#{-†¡ @€ @€ @€@á Ü w팜 @€ @€òH@àžG‹a( @€ @€ P¸÷Â];#'@€ @€ @€<¸çÑb  @€ @€®€À½p×ÎÈ  @€ @€ @ îy´†B€ @€ @€…+ p/ܵ3r @€ @€È#{-†¡ @€ @€ @€@á Ü w팜 @€ @€òH@àžG‹a( @€ @€ P¸÷Â];#'@€ @€ @€<¸çÑb  @€ @€®€À½p×ÎÈ  @€ @€ @ îy´†B€ @€ @€…+ p/ܵ3r @€ @€È#{-†¡ @€ @€ @€@á Ü w팜 @€ @€òH@àžG‹a( @€ @€ P¸÷Â];#'@€ @€ @€<¸çÑb  @€ @€®€À½p×ÎÈ  @€ @€ @ îy´†B€ @€ @€…+ p/ܵ3r @€ @€È#{-†¡ @€ @€ @€@á Ü w팜 @€ @€òH@àžG‹a( @€ @€ P¸÷Â];#'@€ @€ @€<¸çÑb  @€ @€®€À½p×ÎÈ  @€ @€ @ îy´†B€ @€ @€…+ p/ܵ3r @€ @€È#{-†¡ @€ @€ @€@á Ü w팜 @€ @€òH@àžG‹a( @€ @€ P¸÷Â];#'@€ @€ @€<¸çÑb  @€ @€®€À½p×ÎÈ  @€ @€ @ îy´†B€ @€ @€…+ p/ܵ3r @€ @€È#{-†¡ @€ @€ @€@á Ü w팜 @€ @€òH@àžG‹a( @€ @€ P¸÷Â];#'@€ @€ @€<¸çÑb  @€ @€®€À½p×ÎÈ  @€ @€ @ îy´†B€ @€ @€…+ p/ܵ3r @€ @€È#{-†¡ @€ @€ @€@á Ü w팜 @€ @€òH@àžG‹a( @€ @€ P¸÷Â];#'@€ @€ @€<¸çÑb  @€ @€®€À½p×ÎÈ  @€ @€ @ îy´†B€ @€ @€…+ p/ܵ3r @€ @€È#{-†¡ @€VïY@IDAT @€ @€@á Ü w팜 @€ @€òH@àžG‹a( @€ @€ P¸÷Â];#'@€ @€ @€<¸çÑb  @€ @€®€À½p×ÎÈ  @€ @€ @ î9^ŒöööèLÿÓÖÚí9ŒÇ @€ @€ @€À°îC¤k?º=JJJÒ¿ùq¨mˆ7÷5ï</Ô=5SKbÔ¨QQVóÙ=vlŒ*+‰ùlãÃí·¯  @€ @€ @à† ܇Hþ7ÏýQïÃLÅÛÇŠ²‰1kÉÃÑÜÒÛUss2ŠÆ‡Æí£kbçñö¤N @€ @€ò_@àžíu¶Åá{΄ãÙÞši×;—¥bS¦"–o~.öîßÛ6/ïWÛµ·ÿAœêW£H€ @€ @€ù- p¿âú´ÇžôÖ/‹çÏŽ’²Ñ‘šµìŠ­¯zñÌ÷cm}¦UÃÁ³ñØÒb挙1gécÑqrwÔ&—ާ÷IÎ @€ @€ @ ¿îW\ŸŽøû'ŽúƦ+¶Êöbëþ>úv‘™·¥%L3àÖÒ 5ñߟ˼éÞüw?pÝ  @€ @€ä¯@iþ-FV[µ96ü$¢ouC|íl\H¿í¾tÎ}1eò„AÃö®¾KË+bÂä)qßœ¥ñÌž qú•½±yymÏc›×ÇÝ÷7DëU¡ @€ @€Èo«î¥7Ç]é9Ô®Û¯œíˆg]Ó*Ç {Vã&ÏŒ¥íˆó§[¢auuÄ-#m+3lM7 @€ @€ @€@¾\}K™ÒÉñè… ×}¼åã¦Ä‚G÷Ä‚ëÞ³  @€ @€ @€À¸zà>Ì1u¶µFk{g”––ǘ1öh&£Û @€ @€ @ @®¾¥Ì'Ò‡^Øk/Žç¶õ¶ìŒCÛWDÙè±1~üø;vt”L]/µSû)]$@€ @€ @€‚~àÞy"6ÖŒŽé³Æúúú8õfg7Ä™}ÓçnˆÒR³î[÷…ò/;#@€ @€ @€….0ìÀýГËbUsfú=Ÿ>mïÖ¯J*«mˆÍ«k“ó…˶‡÷Ü @€ @€("áîG£nYS/âØò|,ž–Þ§½í¥ØÑØ[]½!ž­[KÝ{7÷†îÍ»âU/¹Ñ¿>¦B€ @€ @€}à ÜÏ¿oôö°z÷×cÆ„òî³¶c"‰áëþ×ÛæãŸÝ[z5~tº½·ì @€ @€(áîeé÷Ù»Ê_ì+E{qO"óé“’rù¤é1¯û¬%~ô“óI½ @€ @€(áîéÙ';äÃ÷ž£5þjGßûíËcZeÏ[ï]×Ú_;=;ͤ¢ê£zÛûC€ @€ @€ŠG`˜{Yò†û’ÛãTgÄñùˆê¢_ŽÛKûÚâÏ{¬÷ä¶xÿØLß×Â_ @€ @€ Pèà Ü˧ĢuÕ=so\ËJâöÚõ‰Åº/~:J£3﬋Å5£ãÁú–žkÕ5ñáÌ4I{ @€ @€ Pèà ÜÓ³žùµ'cuê2Ó¯ÞKjº>—z>¾¿iIÔ7gÚ4l^˜|H5S«D€ @€ @€ _ ÙøåJSélo(/O¿µÞï(¯ŠGžŽÏ4n‰†»÷tÿô/Ä×WϹ$TOÍ[O|ãk1³ß¾îýzR$@€ @€ @€/0 Cl6-õ_ŠéË"Öm™ŸûÌ'#5yBOø^:.j¬Mÿ.wgE|ùÏÏÅ:ÊbL…}Û/'¤Ž @€ @€ŠG Ë-eÎ¥gÜ/y0¦ß>1ÊJjbÅÆ­±ïð‰hK0u°£´¼BØ>Žz @€ @€(*¬÷Û>÷û±yõ¢ÈlÙÞ›V-Œ{R“btÙÔX¼æñxáÀÑhMï<ã @€ @€ @€ïE¬÷1“gÆÒGë⥠çãµ#{£aÃê¨N´Z¢~ý²˜u÷1vTIÌ^±1žßw8Î\éÕ÷ä^ @€ @€ PY–GeÕÌX°òÑØs¡#N¿r0žÛ².j3¯¾GÓ¦Uñà=©?º,j毉í/ˆ^}Ï* @€ @€ @€@Q 1pïoPã&O‹¯/]ˆ³'Ä®m›cQu&}on\sgÝ“ÆŽŠ©³GÝÎÃq…-ßûw®L€ @€ @€ Jà÷ó3¡*4êö¼çϾ{›bù¼~Ï4ÕÇ’µÍÑ6ð6g @€ @€ @ (JßY”©ŒOT×FÕ'>ký—øñ±ƒñ|ÓñÝ['Ĩwãú$@€ @€ @€9¸Æ7ÜÛâÐ [cÍâÅñüѾw×;ãÐöQ6zlŒ?>ÆÿûÇô÷ü×?—{ Êsº#önî Ý›wÅ«^r/ž{Ì„ @€ @€áîçߌ7z»X½ûë1cBÏÎìmÇDÃÿÖý1®·ÍÇ?;»·ôjüèt{òp @€ @€ P,à ÜË"Òï³w•¿ØWŠ8öâžÄåÓ3&%åòIÓc^÷YKüè'ç“z @€ @€ P,à ÜÓ³Ov†I‡ï=GküÕŽ¾÷Û—Ç´Êž·Þ»®µ¿v0zvšIEÕFõ¶÷‡ @€ @€À0÷²ä ÷%·Ç©Îˆã;ÿ óÕE¿·w}Cµûh‹?{ì±Þòmñþ±™ ¾·Ò @€ @€ Pðà Ü˧ĢuÕ=“o\ËJâöÚõ ƺ/~:J£3﬋Å5£ãÁú–žkÕ5ñáÌ4I{ @€ @€ Pèà ÜÓ³žùµ'cuê2Ó¯ÞKjº>—z>¾¿iIÔ7gÚ4l^˜|H5S«D€ @€ @€ _ ÙøeÈS)¯ŠGžŽÏ4n‰†»÷tÿô/Ä×WϹ$TOÍ[O|ãk1³ß¾îC~ž @€ @€ @€@ ?pïšT鸨Y°6ý»Ü +âË~.¾ÐQc*ìÛ~9!u @€ @€ P<WßR¦óx¬©©‰;u¿Å>”©—–W ¶·Ÿ‰=u+böšÑ>”Nµ%@€ @€ @€y(põÀýüObss¬ª£KÒÁûö}qêòÎÖ±³nML5>î]²)šÖMïöî @€ @€ @€…-põ-e*¦ÇS»·ÄWî]ÍéVÍMÿÒsž·zK,|à3ñ±;*Óo±_¹›öÖSqìïÿ6v}çÿˆU›š2b©E±ëٯĘL @€ @€×Iàg/_ˆ·ÿ¿ ש·×ÍØÿ¥$þ͈’÷@O"p®œ”w?¤4&×,Ž=ç?Ï?¾*\ÕØ]Û¸~I4®ïEªº6îžz[|ðßý»¸¹üætå[Ñþ³×ãŸÿéÇñÒþÆhnéi×ÿWoÛ«ç̈Šþ•Ê @€ @€\7|ù_ã§ÿï…() ìú¿Fü§“¥qÓ„ëÆ #7L ‹À½w,åâ•ÏÄùy+ãŸXKÖgÞToinŠ–æìƼhöXñ•/DÕ˜ì]ÏZ @€ @€ 0@àôÛíïDÒ;î%ÿfÀ œ((«ïá~ÑtÊ'L‰Åîˆóg_‹½M ±zQm¤.j3à4Uó–oˆçv·Äéó¢nåaû ' @€ @€ P Ã~ͼ|Le̼A÷ïѺÎhkm‹¶ó碣£‹¥,nºiT”—ŠŠŠòbp2 @€ @€ pEaî{-Š1cºë @€ @€ @€÷†À·”yo°˜% @€ @€šÀuzÃ}hÕš @€ @€@¡ ´¿}!~ÚVX£~»³°Æk´ ]@à^è+hü @€ @€7DàÐñ ño¿ï+¹!».ùoDÜz]zÒ ÙܳQÒ† @€ @€@Z`Ôˆˆ7ßBA€Ë ØÃýò.j  @€ @€ @€ÀîCâÒ˜ @€ @€\^@à~yµ @€ @€ @`Hà ÜÛâù5+âñç÷Å©VŸ:’¸Æ @€ @€ P”à Ü#~úò¦Xöà=1qlYÔ,~$žßw8ZÛ‹ÒȤ @€ @€ @€ÀU†¸¿õj¦ïæú‡ãÁ{R1vTIÌ_óxì9|"dï% @€ @€(~aîñÏî†uË#u‘QãúeqojRŒ*©‰5oC'Z/já” @€ @€ŸÀ0÷ˆqU3cÁÚÇ⥠çãµ#éð}ÃÅá{s¬_67¦O%5óÓû½ï‰ö{/¾ƒÌˆ @€ @€º†¸güÊ£²+|_Ù¾Ÿ<²¿;|¯Î4ˆhnLï÷~oLJï÷>{Åã±ïè™þW•  @€ @€ @€@Á \‡À½¿AyL¨šÑ¾ï92š6 ˆÝ»6mZ÷Ü9>Jf¯‰ Þûë) @€ @€ @€@á \ßÀ½½5ïÛWÌŽ’Q£vUs¤RïòÞ‹Õ´>f¥ÆÇâíG WÏÈ  @€ @€ @€@¯À5îígÒ!ûóñÈâ®}l¤î©U›šà–––ˆêE±¥ioœ<{.ξv0ý±ÕyÉõú¹ÿ-·'§  @€ @€ @  J‡;êãéý鯯X_Ÿ ×ô•ªu_ýÍxðóÕQ5¡"siÌ´ôÇVŸ‰ê(&ÍZŸ®o‹7;ÒÊ3M” @€ @€ @€@¡ 3poï>ô`¬O¿¼>ðHÅò +âK÷6¦WMˆ+u^–Üx.)) @€ @€ @€B¸R&~Å9¼%s¹vù†Xò¥ÿ¿<}rTdÙãøé¿Ï5|$þ%>•éK‰ @€ @€¢@–ñøÅSŸ^Ù[–ß¿þÙé1®|èÝ”Ž›,˜rqÇÎ  @€ @€ @€@A ó£©m±Ûc±¤öîøí?>rÕ‰Ÿ9P5%%Q2kzÇv @€ @€(>aîéØÛz6pÏ&@?Ü´$š»ìZþ1Îv¢ @€ @€ @€¬÷‚9º}M|ñ^ŽÛF÷ ½ÚÔó·éÉe1{Woåe=ÏESoÛ¸ä#«—½A% @€ @€(8¬÷7òr´47]š™·4GS¶Azí/Åû³~bÁY0 @€ @€¼‡²Ž¿?ô±O¦™š"•J¥ÿ¶DK¿½§îÊŠ·Õ|9Yó…(¿r³÷àÕöؾxFÌ­o‰Ú-cÇâiïAS&@€ @€®UàìúõñæŸÿùµvscï/-üÿ¥øÀ}®§ @à]È:p7se\¸°²w­ñøÔ±±,ºWo>{– ‰‡½>­ß?J‡íÝÇ[ÃîÅ @€ @€À{\àü_þe´¿øba)¼ï}ñN[ú ÷ÂZ7£%@`P¬÷=Œ‰Ï=¶%^}öPÜ6éæ—œe-Ðvêp4¬ZÑóAÙ¬ïÒ @€ P$éÀÝA€bÈ*po=~(þîÔÏ£¬#bÂÇ>“Ǥ ~ñ®øõyw¥ §bß¾SÙ™Œ˜Ÿ˜19²zhv=\«ö{bÝ£ÏÆËûë³ßû¾àfiÀ @€ @€xï d•}¿úÝß{—5wëlØ.VΈøîÂ{º·”Yjsœ}iitåõïÕ£ã§ëëëß«Ó7o @€ @€­@V{ÿÙ——u•ÅÈ[ú×*g+PvËÇbó†ÍÑýõØ‘#£ýÄ®Xµ¾)ÛÛµ#@€ @€ @€<È*p¿ë'cÿŒŸ¥§pS|$UÑ=•9 -ñÑ×ßLGïe‘Þi&‹£#Ênýð{úíö.¤òÊ™±tåÌÄ«óèH{¢¡@€ @€ @€ÂÈ*p/ŸP3& œdE唘Q9°ÎÙÐÎw¼5ô›ÜA€ @€ @€y'àSÐy·$D€ @€ @€…(Õî­GÄS?×:ò qÏ̪Èê¡×ú,÷ @€ @€ @€(Uöýê_¬ŽYËš¯}X©Íqö¥ª÷ü>î×™]O?ýtŒ;6»ÆéV=ôP”–fõ¯DÖ}jH€ @€ @€‹¾õ­oEGGv_½øÞ|>—®æóê\ãØŽ;=¹Í¦«wÞy'›fÚ @€ @€ @àšŽ9o¿ýö5õ‘7g¸ß5¿!ZªÏGYÙµL¡#ÊFÐÛí×B8Ä{¿ùÍoFe¥/Û‘Ms @€ @€Þe'žxbHOxê©§†Ô>W³ ÜËÇTÆ”1¹¢ç @€ @€ @€üÈ*po=~(þ.ýÑÔ²ô–:>ö‰˜œßúA¤«†vŒ˜Ÿ˜1ÙGS‡¦¦5 @€ @€€@Vû«ßýݸ·÷£©öŸ‹•3"¾»ðžXÖ2Äv4u©me†È¦9 @€ @€ä¿Àû†:Äòî}ÜËbä-C½S{ @€ @€ P¼Y½á~×OÆþ?K+ÜIUtkÌih‰¾þf”¥ÿIï4“Å‘þhê­övû•¤F^é¢k @€ @€ ÏYîåªbƄӨ¨œ3*Ö9º@Å”ÅqáÂâ¡ßè @€ @€È+¬÷«¸³íLùáÁ8üã³#FĈ·Óƾ?>rgUÜ^9ÎGR¯è: @€ @€¼Àµî§bçþ~Ô®ª"5/¶=ñ¿Çœ™“oã  @€ @€(p!45™oçñXS6ñÊa{Wã–Æ˜{Ïí1uÅóіܬ@€ @€ @€ŠK`Øû?üJ¬ïgQ½h]<·{yåµxå•–Ø»k[¬ž—JZ´lz0~wûÑä\ @€ @€“Àð÷öÃñĪæ^‡Tl;x:öÔ­jfDÕäʘ¿¾)Fù—1â†þöÛ1âßßííök t+ @€ @€ä¯@{Ä„÷Ç‚ù; ##@€ @€ @€¹¸1[ÊœØ%%%QR³1NåzÆžO€ @€ @€Þ¬Þpü¹íqxß_Ç?´¦·‹¤Ñˆô>4-çö\mþ~ü¸-ýÆ|Å U @€ @€ @€¸†ÀýTÔÍžKš²›y*ÑÒQV–]{­ @€ @€ @€@! {K™Ã[We¶wt…í«·=ÓÊ ‰ÇX  @€ @€ @€@và ÜOÅŽÇ{ŸP {_‰Ó¯ìŠy½5©u»âäéÓqdﶨMƱ.VÌ™’œ) @€ @€ @€b^àÞözL¿±Þu,ojˆ3'ǸÉ÷ÅCzâõ[Ò;ºO7.ªfΉçOîŠêî–ÇW?Ð]ò? @€ @€ @ Ø†¸§÷aïûîiÕmc“›nî)67‹ô·Q»Ò ÷ÅSÏ-ï.7-kнõþ @€ @€ @€b^à>ˆÀ?ZÓs¥ùhœîÌ4ÿáÛzO^Ž×û’øÌe% @€ @€ Pðà Ü;"yƒ}×®—„Ò›Fö–÷ıÓIõ€Búåx @€ @€(:áîwÄìÞ/¤6­º;æ?²=ŸjŠ;>Þû‘Ô–˜õûÛ£µ›ëLüiÝÓ \:«w @€ @€ @€¢^àžÞÁ½vÅ–£ñá¹1¯1ý¦{ù]1»ç»©õsclÉÔ˜Z2>Ö÷~a5îŠ[G%·) @€ @€ @€¢fà1fÚâxm÷æâ–ò®byÔ>œ â#ZÒÿdŽ {WÄäÒ̹ @€ @€(aî]•5KãÂùÓqä`K<»hZ·IWî•ݱº6‘ªEóª#U½(šZNÇÊ™ãŠÅÍ< @€ @€ @€Àkß¼|\TM¤WL®‰Gw¼x” @€ @€ P¼×ô†{ñ²˜ @€ @€š@Vo¸·=Ný<7æ5¦ßt/¿+f÷|75¢~nŒ-™SKÆÇÂúÞ/¬Æ]që¨ä6 @€ @€ P4à Ü#ÆL[¯íÞœ@ÜRÞU,Ú‡3A|DKúŸÌ±a\š9W"@€ @€ @€Å"pMñweÍÒ¸pþ7âè˯Ç-wMé6é âϽrG¬ÿ±þÕÛbQê\ì?yG<²ùqÿ”qÅâf @€ @€×(ðÆGÊã_ß:e?ûù5ötcnãÍŠxç‡Òö;¬7f žB€@ή)pïuiúÕöŽ3ñ½?ÛŸœ]Ò=VL®‰uO5ÆÝ?8·MýXÔUŽÉÙ=˜ @€ @ ?þÏoþûxû'k£ä'%ù9À‹FÕvæÓÑñκtíM]qJ€kúÏqglš²ÑqçÝ÷ƃ~#~|>ÃzþÇÍQ[{o¤&©‹ãm™kJ @€ @€º.Ä;éþµ ~]cu @àJÃÜ[<ãïžÍIï?MJZê—Åí£çÇÖ‹¯8'@€ @€ @€Å!0ÌÀýL<³zYF v]ìnÙS+2UwýFìßµ%j“ªÆXôľäL @€ @€“Àð÷¶Åž¾WÛ=çw¬š)•‘ÞÍ=s”‹÷-Ž¯ÄºTOuËûâD¦… @€ @€(áîe7Çm½›ÿêÀ ýbšÒÉñPýæÞÚ—ãu{¹_,äœ @€ @€Š@`x{tÄ›Éä;“Ò`…Q7N.•%% @€ @€ P<à Ü;:â^ƒ§ŸÙíWñxé/v$-:’’ @€ @€(áî·Å¬Þ¯¡¶lz0~mÅÖ8Þz™Ø½³5öm]w/kêKÕÄGú}XµxÍ„ @€ @€Þë¥Ãÿë.–4=Ø}{ó¦…q{ú—ªžŸ«ž¸9âõWÇúMºßPÿ1f@ @€ @€ Pà Ü#Ê'?¯íÞ“î]–H´47FKsr: °¨á`¬œ1n@ @€ @€ P,ÃÛR¦wö•5Kã¹Wâ¹ Ë#5ˆHõ¢ ±÷•sQ·`Ú -T @€ @€ @€ÂöîÉÔ+&Ç+‹~{}œ9ýFüô|ÄûÇßçN¿£ÇOŒ1×þˆäY  @€ @€ @ O®_^Zã&TFצ1íím1jbúë¨×¯÷<å3, @€ @€ Ð#0ä-eÎ?Ïo­‹ººqªs cû‰}±föÔ5jtú7*F••ÅÔÙ‹c랣:#@€ @€ @€E&0„wÐÏÄö5_Œ¹ëû¾ŠZsLH¿ÈÞu´Þ£Ss{NúýoKS},Lÿvo9Ï,¶{?E @€ @€(",ßpo­óÇ÷ Û»~ÚáTlº(lOU×øjã’éñüñö~÷( @€ @€ @€âÈ*poÝ÷T,lÌLºzù†ØµÿÙ¸«÷íöö£g.Çæ½¯ÅK{vÄKÎÅîÍó’+<ýý¤¬@€ @€ @€ŠI ‹À½=v7®Jæ¼ºé•ØóØÊ¸oFUôæíqì{»“ë©u»céÌÊÞóЍYú‡±!ÕsÚ²þÿŠ£íûžÜ¨@€ @€ @€ Xàê{ûˑނ½ç¨Ý_»òEÓm‹ƒ/f^ÿêì_t}\üçU‹zë^Ÿ¿è²S @€ @€ PWÜÓ“lëhí¬OƘ‹'Ýy2~äí‹â“wô½÷ži8¾ª/¤oŠÇZ3” @€ @€ @€@‘d¸'ú[—L»ýÄ¡è{>j?“Ê/ií?ÊlIséU5 @€ @€ @ ð² ÜûÞp‘e—Ìøäï%uµ³RɾîIeºPú¡ÍÉé­7•&e @€ @€ P,YîeIˆÞôì÷cà†0m±ïÛÉûíQóñÛ.ër ééÞúÚ¨š˜¼/Ù¶ù]ÙíííÑÙy½¾üÚmmm=¿t¿ @€ @€(\«îåwFmß7O›—Äïm=}qó™} ±°©oòóâSw\²Ã{´ª‹Yë[zÝ7êk_8ÛÏŽº5󣤤,FeeeQ2uv<²õ…8Õ‡1”étžŠ¯ˆ©éþFÝóK÷[2u~Ôí<œø¥Km  @€ @€ @ ·WÜ£4þãC É(ëN²šÅ±&@¿gYR‹j#Õ÷òzg{´ž9/l]£§/IÚÌÛ¶8&ØŽ2­‡¶Æ¨ñ©X²>ù2lÏ|Zšâá…³bbÙŠ8œì¹“Luð™1¿lbÔ.Û}ÿ"iÜÒKjSQ6kœI* @€ @€ @ ²Ü#ʧ,ˆƒ[ú^sOO«¹>Ö SÑ´æ?¦£ùžãðÓ_бãoY ×g Rëâsª2ç…Pê<¿7}af¤©E±m×îx®a]T'µ›"õÕí‘]æÞ[¿rwd¢ûêØÐлw5ņE™£qa|¥îPò @€ @€È¬÷®iL[\'÷o‹y©‹'5/šŽ¼÷W–_|!s>os¼r`mTfj ¢tôÛE²C}ú?¼r°.æÜW,X{ÎŒä?A4Î?Íâ5÷ÎÍý¶àY-çöÄÊ÷GÍ}÷Çʺ=ñÊ®u‰KÓ³/^´_~rI @€ @€òP ëÀ½kìf̉g^ºçΞŽÓ§{~ç/<÷Wõí%Ó3ò[¦Gmí¼X´zC4í-.<³4&_!ÏC—ôÎÄÎ IÜÏ}gõÀíp*¦Åš¦åÉÐÿd×ËIy°ÂùŸþsr©vóü˜2-&ß7'’›ÿ&^Íîµù¤O @€ @€È@ß.0CAŘqqQV<àþªÖÆŽTÞIëÑx¡o“õÔ†øôe6Ÿ¯üÄç#={±7¿ðÃh]9#.ýlìå§~®½ãÒ oÆ›}µÕSâCWBîkç/ @€ @€ä…ÀÞpϋߠA´½úr4÷>«zî'bÜåž;¦2>×WßüâUßH¯¸ã£QÛÛ¾yÕ¢¨Ûw¢ïîˆÎ3±ýkË2[ØÜQ•uxŸéD‰ @€ @€r% pD¾¬,satù¿Íœô/•Žô%èéϦ^æõþ­#*¦Çïl˜×[×Kî™%5ócÅŠÅ1µl|ÌÝÔñׯî¯ÿZòÚ8#@€ @€ @€|¸²*gÏœN®¼ÿÖ›’ò• ý2úAš•ÆÌ•¢/rïnÔÜ›6ÕGßî5Ýu«'j& k·ŸAž«š @€ @€Þmû “%–§z.N›2qVC­>k&Fczç÷¾#•þ¸ìòE‹¢º¯¢ëÚú{¢f㾤F @€ @€ò_ÀkÔƒ¬Qçë?ˆM½¯:|2bJÕ -3ÕWÛRæðÖU±ª{ט®Žk£éHCÜ_Õû™ÕºÍq`ûº¸{îúî›WÝϱ#¨þ=ýôÓ1vìØÌ¯Rz衇¢´tøÏ»J÷. @€ @€ @ [à[ßúVtt\-Q-<,éê kVzÓÍÉ•7ÚÞLÊÞJ**¢ÿ¾ïIuRhæ?iLζ|&¶W$çå1cΣ±÷Ÿ^Ž{V5u×75‰Lé×fhÅcÇŽEEEÿg\ùþwÞyçÊ \%@€ @€ @€Àu8räH¼ýöÛס§üêBàžÅz4úQtÆ´K?bÚv,võdãéÖ?w”_©³Šø¥ûÒ_Xmò¶Ëá¿vDoàÞvîÚþ Ï7¿ùͨ¬¬¼Ò \#@€ @€ @€À xâ‰'†ô̧žzjHísÕØîƒÈWÜñÉÌÇMëÿ2Ž´_Ú°õå£/o¯®ùh\>Bï»ï|û~_ëˆ}Õÿíȼ3îâkÎ  @€ @€ @ oîƒ-MùQ»¨ïb}lüŸGûNzÿžŠ§V/Kê¾X}WRŽö¶8uâDœHÿZ“ ¾,½½K¦I÷eN’R[|ç‰'“³Ù3nKÊ  @€ @€ ß÷A×§4~õ¡-ÉÕÆ…wÆšíûâÔ™3qæÄ¡Ø8{bïPÓMª·Ä¦dÒôÃõµ1qÒ¤˜”þ=õRkoåñ®Ëô·dzÌßø|om‹ÎÎöî>_ü©˜[ßû¥ÖXŸ›>&i¯@€ @€ @€ù- p¿ÂúTLùrì^W´X?÷ž˜8~|ŒŸ4½o›õôµT45|9Dã#'&÷”—%ÅW³$6gº‹ÆUÆícG§?¶:ª»ÏeIرn×ò˜l‡ý ž @€ @€ò\@à~Å*šµM±kC²·ÌÀÖ©yÑtä¯ãþÊÉxÙÈ›’v#“RWa\,Ýs.ön[—Žé9ºúl9kïó±ÓA„T @€ @€ @ /&Åy9Ä\ª"î[YÿåëÑòãqúço§4"ýFzU¤ª&Äå«ÔÅ…ôïòGEÌœ³6^úÂCq¼åïãØ?µFWo§ûüÐmwÆÔ)•Q~ùÕ @€ @€ @€@ \./Îãáænh¥bÚÌ ×o¥cbò´™éßõëRO @€ @€ ;[ÊäÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€tÛÆ:@IDAT @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆîE´˜¦B€ @€ @€¹¸çÎÞ“  @€ @€ @ ˆJ‹h.7`*ÑÞÞ¥¥¥Ý¿ëñÀÎö¶8ßÑÙÙQZc*,ÉõpÕ @€ @€n´€7ܳo?s8êÖÌ’’²5jT”••EÉÔÙñÈÖâT:'ÎÑz|O<2¿&ÊFŽÑ£GÇØ±ccì貨Yüx:3ÌN‡3÷ @€ @€ @€Àu¸_…±õÐÖ5>KÖ7lÙÒ/œËVÄá¶—®vv|çš{û½ñpcó%M›ë—ÅôñÓcçñöK®© @€ @€ @€ü¸_im:ÆïM_˜i‘ZÛvíŽçÖEuR»)R_ÝÙfî§^ˆ_¯]ŸÜš·!vl‰ƒ»·Å¼¤¶%j¿òÇÑšœ+ @€ @€ @€@¾ ܯ°BG¿ýXÔ÷]O­‹WÖÅœûjâkcϹƒ±¨ïZãÜøÓ¬^súƒUÑÒ{_õº]qð™•Q3mJL«™Ïœo‰å}}6?†»_M_þ @€ @€ @€À ¸J}&vnHâöxî;«crÿï™VL‹5MI<²ëåA{J.´þ 6nê‹Û×EÃÚû¢—Q>%oë{Ͻ%Z~œí{óÉ @€ @€ @ G÷Áà[Æ }ÙxjC|z@ÚÞsSå'>©Þû›_øáU·€iýÇDß®íóŒÊË<»jÎ3qþüùîßoÏs™ª @€ @€ @ ¼`ÌÕ˜Ú^}9 Ç«ç~"Æ]n c*ãséúî\¾ùÅxµmqŒ©¸\ÞºúááÞ‹©˜ûÙIqæðžøÎ®¿ŠCÇÚ]˧Ågf>j¦L¼W @€ @€ @ /îƒ,KYYæÂèò›9é_*©MW4uU¶EGÿk—”Ûã5öÖ¶ÄÆ¯þZ47õ½ïži¼þá%‘Z´%vn^•å™z% @€ @€Èo[Ê ²>gÏœN®¼ÿÖ›’ò• ý2úË4눟¾ÑUݳ M&lOżE‹¢¶oošt‹–ú%1éK[Ó¾ƒ @€ @€ E@à>ÈJULþ•XÞ‚O›2qVC«ÙÝ<½Mª§ãy›wÅÙŽ—♺ºØñRG´<·.ÓaÓÂh8К9W"@€ @€ @€¼°¥Ì ËÓùúbSïGS>1¥j–™ê+o)“i--‘ZÞ Kï‹Ì”Æ”ÖÆÁÍcú²î=jbÇŒ¥3fô»qhÅ¥K—Æ/üÂ/d}SCCCŒ1"ëö @€ @€ @`8¿ù›¿o½õÖpnÍë{2yo^óÆ®ô¦›“‡¾ÑöfR¾¸ùW¢"úïû~q»®óLÛˆ¯Î¯î¶gZßQ=+}Ò¸Ž+oR“¹ëò¥»ï¾;n½õÖË_¼LíûÞçÿðpU @€ @€\g™3gFgggÖ½nß¾=ë¶¹l(pÏB¿éТ3¦]·‹]=ÙxDí§âŽ+~ä´">^“þÂjSï ƒdé¸#ªÓcºôsªY ô¢&sæÌ‰ÊÊÊ‹j @€ @€ @ · .Ò¥¿ƒY‡WšY¥Š;>óú®Õÿeiï;Éüm}ùÅÞwÑ#ªk>™K—-•õlâÞ}íÄ«g/Û¦õG{]ÂöËv®’ @€ @€Þ5û`´åwFmòMêcãÿR3Ç ‡OE{z¯¢¶3‡ãñù¿Kú¶¨‰uñù~}öÝå/ @€ @€ä§€=ܯ°.S¾»×=÷>Ü“¬¯Ÿ{O¬¿¤}*š¾cúל˜œ•Ø«½"<µ7v7Ý]-ZêcVª>i›)¤â¹#ËcB¦B‰ @€ @€ò\ÀîW\ Ò¨YÛ»6${Ë lšMGþ:î¯øß-ÊFÞ”´ë·m{Oݸ™ñÌùWbË¢®O£^æ¨]ûOŒª2oÌ_¦•* @€ @€È3Iqž .?†S÷­¬‹ŽÿòõhùáÑ8ýó·ÓÃã'UEªjB\°jA]\Hÿ=Ê'Çâº=1çëÇãåã'âço§»Ç”˜6yÜ ·¹@€ @€ @€ù+p¹¼8G›Ã‘•VLˆi3¯ï&/&ÇŒôÏA€ @€ @€…/`K™Â_C3 @€ @àÿoïnÀ£ºî{ßÿp$ó W¶Á4GÆ\3´P?`×8¹Iá¸ñpsœ¸5rbêAsý€|žSq ·•OM„ÓkÄ“Û ü4¢1â&ÁÍñЛŠ4j„“ˆÇGØ©Eca‹:¨‰K[M¼ïš—½gÏ«FƒfFßIäÙ/kïµÖgí¥-þ³fm@@ÈîyÐ@@@@@ ð¸~R@@@@@< àž@@@@@@ _€€{á·!5@@@@@ÈîyÐ@@@@@ ð¸~R@@@@@< àž@@@@@@ _€€{á·!5@@@@@ÈîyÐ@@@@@ ð¸~R@@@@@< àž@@@@@@ _€€{á·!5@@@@@ÈîyÐ@@@@@ ð¸~R@@@@@< àž@@@@@@ _€€{á·!5@@@@@ÈîyÐ@@@@@ ð¸~R@@@@@< àž@@@@@@ _€€{á·!5@@@@@ÈîyÐ@@@@@ ð¸~R@@@@@< àž@@@@@@ _€€{á·!5@@@@@ÈîyÐ@@@@@ ð¸~R@@@@@< àž@@@@@@ _€€{á·!5@@@@@ÈîyÐ@@@@@ ð¸~R@@@@@< àž@@@@@@ _€€{á·!5@@@@@ÈîyÐ@@@@@ ð¸~R@@@@@< àž@@@@@@ _€€{á·!5@@@@@ÈîyÐ@@@@@ ð¸~R@@@@@< àž@@@@@@ _€€{á·!5@@@@@ÈîyÐ@@@@@ ð¸~R@@@@@< àž@@@@@@ _€€{á·!5@@@@@ÈîyÐ@@@@@ ð¸~R@@@@@< àž@@@@@@ _€€{á·!5@@@@@ÈîyÐ@@@@@ ð¸~R@@@@@< àž@@@@@@ _€€{á·!5@@@@@ÈîyÐ@@@@@ ð¸~R@@@@@< àž@@@@@@ _€€{á·!5@@@@@ÈîyÐ@@@@@ ð¸~R@@@@@< àž@@@@@@ _€€{á·!5@@@@@ÈîyÐ@@@@@ ð¸~R@@@@@< àž@@@@@@ _€€{á·!5@@@@@ÈîyÐ@@@@@ ð¸~R@@@@@<(Ƀ2P@@@®˜À/n*UÇçË4óGÿ튕a²ŸþŒ9äöÉFz@¸ÌÜ/30§G@@Èow¯/ÕkféW?ÿn~ÔUº_\üÏ®5@@ _˜RfR-ÐØØ˜À¤ŽÊ4ñØÈˆFÌÏe:}¦Å  € € 0í>0nM»:Sa@˜z œÖþhÆŒRÍž=[¥¥¥š±bƒž:xL}S{?}p³fÏ«¹æç¯»†2(I@@@@@òI€€û­1tê fÏ÷hËîC±)»üÚµi½–>¡Ó#±»&»6væ°<›Lö0Ò#€ € € € €ä‘÷t8£/¬ÚMá©VsK«Ž4ÕÉëlÝ+Ïç+ë˜{à¬j—mtÎÆ € € € € €@a pOÓng¾ñ¬œqçž:õtî×Ãë*õà£;u|¸SÕö±‡6êï³æб]ŸÔ^û<¼#€ € € € €¬@IÁ–ü²|@Gëp»Ž|³Vn­²•Úá¯Ñ_8\þÕ–×õèòÕ“*Uß±ÝZ¿»kRÇ@@ xέºF}ˬÙoÔN%­'LYÇS8 FI@@.§€;„|9ó)¼sÑ1;î©×Gc¢íáê,ºóò˜ñéÁdmÇ^ÕГ«UžiMŽ«jý®pêªùïþù¶Dü™ž†t € €Å#ðæï–©«â'Òùæ‚©”¥š‚)+E@@àr 0%…ðÈ[¯«-²Ï»ñNÍK–®|‘î···½¤·2žÈ}@ûº/r~Z÷mÕoÎ|Ï>ï € € € € €(@À=E£•–FwÌõÁèŠ{©d¾nõÙF4n/Nð~jßç´-ͯñS•fXü{&8ˆÝ € € € € €y-@À=Eó ô;{n¼a޳œnÁ£O™läô~­Úæï¯nÖî*R¦e € € € € €@ápOÑVe÷ªÆÞ¹rù©&¹yì´þ»gKä *u~éaÍšä)HŽ € € € € Ÿ<45E»~úCí<4õÔéóÒò¥)RF7§ŸRfD/lóÈ~,jS×sZY=¶tftyféìèÊ%,mݺU×\sMÆghjjÒÕW_qz"€ € € € €Ùüñÿ±.\(¾y¶ ¸§¸Jæ\ëìùÙHêšF/‰2¹ç}w¶F^×!;Ún¶µþ¿uzíË£Rh¶š÷´wï!;¥¾¾s›ÎÜlæu¿î~}içrÅå4™,¬Y³F7ÜpC&ICi®ºŠ/½<:Óúé>-\¼X‹ÍÏs¯ 9çH·0: þ¸™Û € € € € €@A pOÓ\eËSk×I±{ã=Z8¾æ/^¥íö\2òÈßô˜ÊTfaæBgmVìÔíÎv@@@@@ŠK€€{Úö,QåN¿ZêSLÈï©’¿ûŸõÀ¢Ø™yJgÎqÎ:ÓYÊ|!›c2?;)@@@@@.‡@l¤øräPðç,Óº'÷küOþ/u½zFýï^45ºÚŒr_*ÏÒIjºôÑý²ÌÏd^eË7˲6OæÒ"€ € € € €ä‘÷ £¤lV®]aj’!€ÀT\øàUX^ª ƒ?œŠÓå俼x‹É'f’©œäK& € € € €W^€€û•oJ€)ÞY§véoO 8k, € € € € €ä·÷”í3 £õÑèø‘oÖª¢Ä•¸l¥vø££Ò¿ÚòºkgòÅ¡7${™ªÆ.=º²<&aÉ‚JýÕ‘è9Û^y;f?+ € € € € €ù+@À=UÛ Ñ1;:î©×Gc¢íáƒÝù y"Ç·{UC©ÎÙþÖ÷^tRÜqÇbgÙ½°ðöÎê\g‰@@@@@|pÙÎ÷²æ´|#o½.ûQ¦Þwj^²ÜËé~³=—o{IolVyY²„ám·=ôgªû÷ÔlÝzmiÒ„¯¯ÕÙ>ì,±€ € € € € ïÜS´P©+>wÖ“§*™¯[ƒ“®ûƒ»G4ž<•³uÖ¢Jí|¶ÒY_:uP«¶r6?ä]â,³€ € € € € ßL)“¢}ú=7Þ0ÇYN·àŠÑ§K–dߘNÞ¡ëVmŠî«jÖÃËÓ —¦d @@@@@ ¸§h„²Š{U™ }åò…)R]úæ¾SGµyÅl­Ù¸;z2_ƒz›áö( K € € € € €@¾ ̰Ì+ß y%Ê7tr®[³=”uus·ö?¼4I1FtpÃ\m M)ãSÇð‹Za”|¬ï”öýÅ&m?`?™5|úš¦í~tµf%Ém2›f̘1™ä¡´¥îyt&}4‚Àãã*¤OÙÞ/™¡_Î+•5ùËùŠ5ǯ×êý€yäqýj½æ?ÌUa½ÅÌ&›ñ ÍЯÐ/Jû&{èKí¯~¥9ïŽq*Ø÷~UZ8Ïzÿj.Î7×òkæIg<ëÝ«TzÑ2E.œBÏ0w‘ÿ(ù‰ÞŸñ«I×÷Jpµù]|} p%²Î:Ï‹¼J£×Ö¬ Ìm¤pþÂø@`†æŒ]Rß›¡Ñ«~¡Ñü"ëk+×òwçåçïÎËoÌß—ß8˜w^~gþî¼üÆäÀ¸‰SMöÕÛÛ«E‹Mö°œ¦/¬¿æsHS2çZ'·Ÿ¼ç,Ç/\p6”)Óxõ¹ã{´ø¾p0ß>ÜWÓ¤/î¨ÒÒySÓ$Ðàà }úŒÞã7~CW]U8ÿXʨR$ŠÒŒ_Î?Ô‚…ÿåÌQÏ‹öÇØ åßÚûæÓ±ÑU2ãR?6ËaÝLÀ}î¯ +|ÕÌ÷uõ‡ (ˆvñ¢fôÎÁ«ï⌠z÷&3¥Ú>ËñÒ²zwt®JuÝ¥$—G_˜¡Ùÿ!•–NÐ/È3s¡¹ž³ŸG/—Âá¼ÎŸ×Œ,þÏ}AÃ9ƒÀ¿øµqY×\s¥Š0é|GÇKuUàCæãÐÂù;²¤ÿ*Íù@aÝûJÊ*¹¶€ÊÌß“îK“=€¿;'+–]ú«®6w.àïÎìô2;*üwçlówçÔÄC2ËõÒRñwç¥ùeztÁýÝ™iÅHçœ;wÎŒWÌüßCsçÎÕ‡>ô!çø|](œßfWPÐêM3–r¥°FÞPKht»)œïn-É ¾6rjl°Ý[«öçþTk+ʧ´†ŸûÜç¦ô|œ @@@@@ ½@á CI_)ß[¶ä.UÙg=ðuÙ+Ñ÷¡×_’o÷VþÖÄs®œÒçWmqNPÝØ®ÑãOOy°ÝÉ€@@@@@œ pOE=k™|ÕöÎÚóµ3öJä½OÏÕns¶=ä½ÍYÖØˆúÌW"‚_‹rêÏ~{¿ERyë;´óÚKž«=š)K € € € € €WR a–”+Y˜üÊ»D¿ÿx£t <"ýЦeúðÕízücKUúÞÛjÚ¶JÛÛ"%ö6êÓË£OK=}À'϶ðÎúŽA=¹:8]L@oœz#ZÅÿ'íÛ÷=¹òÑféÂÍÿ݇õheEÌfV@@@@@òS€€{šv)[þ˜Zë¾®ûv…ƒç»7Þ£Ý é=ò7=¦˜Øg.tRÍr*6ªsv„^jÛ»KÑ5'yÌ‚·á~pÙÄ  € € € € €@ž 0¥LÚ†)QåN¿Zê¹ebS{ªäïþg=°(ös‹Ò™sœt3¥1]˜ë¬d´07zpFéI„ € € € € påfXæuå²/œœ#}êzõŒúß½h }µæ/^*ÏÒŠ µN}() € € € € €ÀÔ pŸZOΆ € € € € 0M˜Rfš6<ÕF@@@@˜ZîSëÉÙ@@@@@¦©÷iÚðT@@@@@`j¸O­'gC@@@@˜¦ܧiÃSm@@@@@© à>µžœ @@@@@`š pŸ¦ Oµ@@@@@¦V€€ûÔzr6@@@@@i*@À}š6<ÕFÌ12ÿç…S-ì_c¦hhdlªÏÎù@`ʦώ™{"7Å)§å„ €WP Ûû[¶Ç]Áª’5äD $'¹  PPc:}ôï´gïj‹ÜW]§-oѺåó¢]K¡sjo}YúÈGtñ'ýZü;÷jé‚Y®îÅ1}bµ|{»ÔØ9¬Í+ËÜ;YF ¨NÓ³{öhw¨ƒyäõt©­ËTÙ[¥¦¿øs=º¶"¡þgîÑŸë¬n˜3'a_xÃ{úù{ú Oj©«ÛÑ/Sp±yú ŒÑžm©³snPÊ^ôÞÏõëûÚùàÒŸ±Óú»g÷hËîCÑíŸêžØ¢ÇªÖiAÒQtîT»^þI©>rã»ê¿¸X÷®]*W÷ŒžË,ξ U·|J]¾F ¿¸YÜcxX)H1ßW«¦y/ͽ+Z±÷Lÿ»~eµê6¯U¨K]BŸåÞueiú Œ9¬ÙË6šŠW©søy¥ûgVv÷7)›ãè—ÓïZ¤ÆÓ\Àâ… à´šªd™[CÊŸêæ.WúðbOK}Òô5MÖxBjËín §÷Ô[ç“ìgÅ*ÐÝ\“´¯¸ûœ·ÖoÆtÔ{'ݳ˾ۥ©V÷7s¾,Ž£_¦iv!PÌÓ䃪‰L,0ÞmU»FÕú{bŽéjªŽŽ°õ5YáÃV“=Š/4r/2.w¸;:º/n{{d4|•}Ž˜lXA h¢#ŽÌ(¾ê¦è(¾PÇ­ŽÆªh3ý¦ß‘èµê<áQ‚ñ£o$1 ôËV0ç[ë"ý+ö› épº›]÷=OÕãœ>ÜsÏlŠ síjtú±û[^îÑ}u­ÑÞm™ž^lŸ#]™Ø‡@Á Œ»;Ž]úÈ6Óªœ¿=}VëùhÚÉ÷Yî}¶.ïÓI`Ôjm¬³ª«|νÇÄïœû]ªîÙÜß‚ª“?Ž~9®Fꊀ[€îÅüi uCI üð¨ØGT›QíÄÎ#½üÑ'Ucï÷¿¨W‡‚+¥ºiUxhnmýŸjõ¼Èì´eKõ'µõáÔ]?ÐÛÎп>5> ßüçȵ¶'ïÓ@`H¯´µEêiæÔlxTå1µ.ÑêÏ>ifÛŒ¼L¿yÓî7cï¨38Ç»yyo¿)¼ö¿ôË´<윖ï¼Ñ®·g•>œÑé:ZïÜu䛵ªpÏÕ^¶R;üÎ]Q_my=tþqG·V5®vFëV¬ûœ"ƒyÛ~ô¶“ªïسÚüÕ`<£‚9Dz€@A”¸;Ž]âà¶þü*¿Ü|5t<§J×&ßg¹÷…%ùïô×þz—²¿V•Ií³»¿IÙG¿Ì¤EHƒ@1 p/ÆV¥N •À›?üs\]ÕG ³QúDý%z¿^y+q×/ߊ&™`éÜ Ïh— zjZôéŠTŽ›à$ìF F~¬íx»÷n-IvùÏZ¢û\SËØ[ŒSö?£>¼`~Fµ§_fÄD¢i#0¦=¹WÝüaeÔ‹†ÎèXäƒ.yêõјh{nÑŸp¦Pk;öªÂwEu¶3Å“½%á=pVϬßm6{äß±!åUŽcE pîè®ðTJ¦.Þºvm]=ÏU«,ú¬9š{Ÿ‹Åi"PªßÞÞ ú†544ª±±^Uñ35ÅKd{Ëò8úe|°ŽÀô à>=Ú™Z"€À„Á9¢ížW÷.uÿ£'zpÅŠ5ÎÊñ—ÃÁ‹«ß G$voÿ²N ÂûÇΪéË‘yÝíÑ„fο§?œ¿Ú«gw¬KÐwNÍÅ'P¶BÖX§ššÕnX’<7òš^´»¡°GÊŽ¿÷ŽãÑêÚóÄ#ÚPY©Jó³aÃfí;|Bv׳Ò/m Þ ŒëŸE¢çeýzñàSzdÆPª¬Ü Í;öéÄ™ª‘·¢s¾{7Þ©¤wÅòEºß>ªí%½e+%´m—ž9|J‘»¢Î^Û"E°¿©ræ{¼+zêžÕ‹’¶OÎ;E&0tRÛ|Á«?øªÑsµkËÎ'ßgƒ‡rïsY˜6³´öá­zrëVmݺY›7ÿ7ÝwsúÊg{Ëö8úeúö`/E+àž_†e@`ú ¸æ×SêùmG»š,sCýø:C\ƒ ζà>_u•eV8Ûjü½¡t‘ù©½ Ó—™š#R ßjªö8ýFÎs,««É5·»«oÙ}1üî³üÝá'+³ _¦„fÇtírͽ?Åö!sÿªóGžObYî¹Øíû]"]²{ç Õh?Û$Ø_½>«ÊçêÛªµBwE3wµùB‹éóæž;˜xf¶ P¼ãVKM´OÔ·»Ÿi©u}6x$÷¾â½j¨Y¦±÷¥ds¸g{Ëö8úe¦mG:ŠK€îæ_¼@iP?~Ëv¸Y×ÚsYØ›"ï㺷E*_½UÝþ:g»ÿÀ!Ù߯nìÐ3,’†Nè¿o ÎÒY¥/mZí¤U`LccæÇÝÃÓF`¬ï¤vTÎצvÏ‘š¾ø_œgŒG†Íz"ßöV©¶ÎŒ–¯²§x Rùå[æÓñÈPwúå´¹|¨h&ãï™Ù¢Ã/û›öU5µª««1߹оü»|ºû©ã¡ ƒýÎŽo˜ã,§[ß:˵ùkݪ·§‡jóë?Ò·=5ê诓¹+êäßÔ…¦Šò5>¥Õåѳ†î‰æ¾È b;û ­ßkÝ£QŸ[›äû#YôÙ ÷¾b½j¨×T d{Ëö8úåT¶çB €Šëójƒd)àŒ´3£íÌÈÚѧîj4£ñ£ãGüöX­þ#Vss³Õ|¤Åê:mÛZç WÝÜ>óh¯Õ\;j×WÓh¹è¦(›("Ñó–¿¾ÚéSvßjh +$\ÓAË$Û‹H`Øênù#ÓiØS®u7׸úp4ü½àc¶=V [ zï1×¹·ÁJ~W3uÌ¢Ïf"ÍŸ¿I3ñ"M! ÄÞ—’M)“íý-Ûã&R¤_N$Ä~ S€)eÌ_ò¼@™G˜Ît~¦qûiζą²™)æ‰I:¦o<þ^}]ëãª0ûŽ?óPè!qÁdÕ ~õœïUkSmä¨CZSwÌyÈ\d#o@àœöTÎÕªOmw¦^2s8«±µ[ãÇŸÖÚ³êZ¾`‘**–jé"×¼®T%ëÕàÌ‹ñ3ýbÂþK¿tñ±8f•kQE…–._ªò¤Ï&-Ñï?þyGâg?O%s®®¼ç,Ç/D'Z+Si·Å±3ß/8†§Nœr­ï˜Úyx¤§ZþÎõv·ª6Ò§ýÛÖèè9æ]‹wg½0~øUûA©Rí“*ù]ÍÔ-‹>;±÷¾‰H1²½¿e{\zSúezö"P¸Ü ·í(9L±@4hà×›ýÉç}ã/9¹ÞqÇbg9ÕÂÈé¿ÓÆf¯·A[*˜…!½Ñž·ÓWß¡ý[P… &V>ú´zšÍ¸÷àkïÿROòìÃûù/+0¤ƒ›k{[´µMí´^ÔæÊ¥æc¯ä¯@  àOê×lÍ›zoüúe¼ëÅ/îCéºQiiôcçxÿ©7“<ò†Zü‘Ô¾»µ$ñó²¸Sèk_ØÚVÿå- ÞG~úãȇo>u¼´_¬¬Ð¢¥•zúŸº¹+ê[ßï‰;« ÀØiØeß«ôà½Áêui}6ÙY¹÷%SaÛtÈöþ–íqñÞôËxÖ(îÅÓ–Ô.I Lwm¨rÎà?Ñë,G†ôÒ×EV}Z½¤,º+éÒš¶m íiüÒ&…‰5ö–^Šü[«ò÷n‹9꺛fGÖ3¡s(+„Àéƒ[µÉîBªV{羽~tmê~¦V#§÷›Q³¥¡Ÿ'ŽžK^ϱ7ôC;è§u­Ý•’¦¦_&eac Œèà†p*-Ý¡½H½?t ‚I-[r—yÌwäuà;êNòAðÐë/…|Lå­ü-çAÇöañïC'›´)ØW}ú“ȃ"{_~9œÌ·^·¹o«%×ËîÊoüüñ§b‚xùE9·Àšò¤ü€*»>›„{_zöN'lïoÙ—Ú–~™Ú†=¾÷ÂoCj€S$°lmxê—àémzV§ã‚ }ÇŸÓ6{`’oCl` IŽ9œ¾ªYŸ]‰"ÌZ¢»#_“ñ[¯Æõ“{'²~óØÃXA 0gõ'ÚîSûà~­]”2Ú´N{÷ú5dÏÉ;ü"IèUs¿n)±Wßé—‰&l™N»õõIzÑÐ }a“Ó‹ô±ß½ÅLi±L>óDâðë€ö|팽yïÓsµÛœmyc?Dvv8 &}u8}Ó?ëçßqG8…ÿëzÙ]´±·eß—,¸Á9 ¦@@-/8E¯û䪔ßêr…&ÑgcŒYãÞÃÁÊtÈöþ–íq)¼é—)`ØŒ@±æÔó”¸î‡ìfeàØsÞêïï·:ýu–ù½ïü4t¦|ÌU¤`½–™•=”þHoìê:ê}Îy|µMVgw—u¤¾ÊÙæ©m½•ãœ\Qñó-®‡¤ú¬º†«¾¾>åO]]“Õ|øéxOìC†«ê­Ó/GÇÇÍ3åz­#uÑþì£ÍiŸ˜J¿¼¢™_1ž#ÕÎ=&ØOêtXýÃ£Öøø¨ÕÛyÄ27G÷W5[ös‡Ý WÛÜn7÷ÄþÞN«Þç:ÆÛ˜úá‘Z÷úkÃyTû­˜»â`»e>‡ŽäﳚZ;­®ö#V•ÇÞæ±ZÎÇqÅÉìz­:çšöZ­ýéÏ”mŸM~Vî}É]ØZœîÏù¬Ÿã/È$RIDATdM Ö;Ûû[¶Ç%ZÓ/MØ‚@q ¨¸ªCm@K8ßêú‡¿ýýØwOmKl° I–=GjBÁƒ`Ú„— FÿÑ{n©ÆêN8‚ ¼ÀpgC4 ç×â¯÷º×êˆô…þŽÌŽ­jìHëD¿LËÃ΢è·Üò”}°ÚêˆùëàÞçÂ`qz¸î±K&Ö?Ûû[¶ÇEJ@¿Ll ¶ P„3‚u24óBˆ¨ïL—Îôöë¢Ù~õçkéí-(O39täøÀÀi}÷‡oéê__¡Ê•‹bÎÊ \šÀPßýøì€.ŽëÝ‹U¾p‰n[^áÌêìôËT2lŸvcC:óÆ5ð5>þ®¹Ç•kÉòª˜—þ™ ‘>u½zFýï†îŠš¿x©|«îXµTeüe•ÄiD§ŽµéÍ_^Ô5¹KëV.H’¦7tæØ!íonÕ{sL=~ýSúÒÎT–¢JçNÓËoÿ2Í5•ìÀàuv£>ºa­æq%šô¶‘s'Mß~ÛwîÚP©Eî:tæ¸üßû7]Ð5Z÷ÙµhÖ¤É.ïcçtìÿ{Y¿ ærÍGôëV*Y§õâwþUW_#]Ôºïµ*OV²‘³:úíW$ó«ûâÅkt׬ӂd'Œ9¶ØWÅT–@¸Œ3,óºŒççÔ € €@Á œÚW©UÛÚ2,¿WíMÚ¼vQ†é‹-Y@g{ôθT:w¡*DBÎ#'U9w‚Šžú½öäê"ªx@Çv¬ÒúÝ]Ñ:y4x|kò  F´¯r®2¾¤¢g -5tkëÊT¡ü¸Ä¬פÙíÛ^u ×ê¢`ÍŸúFúÔs~ØH—já-~8wT¥‹}‘«6u›œ=¼Y·l<I'ùÏë$Ÿ– œxJóïÙIW«óÖӚ𣾔¿«R»:a@p 0¥Œ ƒE@@À-P:s¡{u‚å6m¹g±ž:10Aº"Ý=Ò¥‡nY¦e˖铇^OZÉëMð­¨^ý/W°ÝãõÊ·â¥,ýNöcã잎GfpMKšúF—ÍÍI/ìjª ý.X¶ì“z}tbå’E¿£:®M¯öŽØ+®÷1l‰Ûƒ;Ú~pε?ºøæ;oÝú‰ƒíNêðBÌïª4®q‡±Š €„Òþ{#@@°@}k¯¶ÞqF® g`T?9ó}ùñOé@dó®{žÖÃãϪbºý•ebéöÇ7ÏrÖËnÕ_iÖgÌ”2×-»©¸.§Ñ÷ô3»FUMzéùGSN%NV¦Mÿܯ?r]BÁí%%Ãzî¿Ü¢í¡/SøÔÒóœVÏ ŽÏŽ}Í*K:yFl"Ö¢©®I“âæûÿBMs?c–®ÓM®Ë5zp.¥©o®k ðßœa€î}Ð+u…:^êìÕæåËc‹=öºZÅnÚûW´ûÁЏég†tò˜ßI¸îÞ¥ÎrÚ…T¿«òÈ5mùÙ‰ €y#0Ýþ)˜7ð@ K`Ö¯]§Yeeqr•Ï{Pû_2£)ç®Rxìåk:7$UÌ+¬ú]rig'0¼fº#˜åZûàÃZkï+¦÷²9N€Ýwßg9]ËÊç%I7KóM€Ý~Í_8OåÎ7m§æ=¥@ÊkR*¯X«GÍOQ½ÒÔ×]O3ëÓe•δ³(Sél{9ýûÒ{×™á€û¡ÖÓzîÑå1¿oG^IÁx{p |èóÍàÂï膵ÜÝ_FÞÒñðiLŸî¼=Ó_Æ)~Weèj2ã… €„˜R† @ÈH ~¼±ë ²%ºÓž~ØŒ~ô¶‰¸‡^:ºžzê)<ѧÀÐ)íÙ¼A+fÌÐŒGš½íטNݯG*Íöà¾ÈOå#;tôTŸ(ú>rF/ì߯ýûêÔÀ˜NÕŽG"ç5Ç®¨Ü =/œÔXôˆ¸¥Iæ§tõø[u=¨§vüe(Ìè­–¯hÏž§´ÿøY³6¤ã‡MY÷ïÓ '’Mÿ0¹²ëºÇxî9xÂŒ„Ü6›‡^®X±"ôS¹a³ö=•¦îq®ÕÀÀ)íâÇ?Ô+*µcÿQõÅa~ºÇç£unýª4õ<œÎÝ•YºÅ4Ñ¡Óáú?µç°úÆî…=Ú`ê>cÆ <½¢Љö)dc_S&݆Í;tøøi×µgÄ´ñ¾àµºG'úŒlÐâ©ÍªŒ¸®0›wìשxˆàá&¯cŸ2åˆ^»A» OìKž>rÌäÊg—sD'CuvçµB4Ýwø¸Ì¯h^ € 0Ý‚Må… € (ÐÕXe™¿ C? ƒ‰ œ-ÃV“/œ.˜ÞI;Üa™Rø¯ed:ç“·Ñ q¼×jpkçç~÷Öú­a'/ËîlˆžÇ}Îøe_½Õ;î:0¸˜E~Vºzܳݺ;>ßȺyHª)lÔÀ[ß[˜,ÊÒÙàÔÝkUWyR:xêZ­øªÇf»ÖÛ:‘©×:Òm·Â Õàqµ¥»þž†p»Æž~‚5÷õã³:íl’­¿,¯/¶þÎu×ßnU¹Ë”lÙwm¸ÚÉS]{­ÆïµZÏ»d;&Ì«¡½7¶&Ù”/x†Ñ«Þ›Â=RÆZOÌ5çîGÁåÐ5iNuôZnï,®I÷5>)»`9\¿câËZ¯jLìÃA ÷ËÕvñç°ëëþ]ŸÆ½î­owŸÙ²&ÙVõ±×dôÜqα¹DÖú­Wûéu¥ê·êí>ç©·º{üÎ5êkˆý½bæw~/¸÷EÛ«%¦.®j±ˆ €E)Àwó×/@@`b43ñ ¼¬!•>­¾92¤²´Ô™×<87qWp û57¸0¢ƒ›k›s¬GõÍ-êììPs}µRm»}òí9é¬+:_ƒ³Íã«USs³jM¨Õ~ù·kñÿù‚k.ðlóKWktMjkªBS=„²öV©¶¶F-½ArÌuOûeÝ£sC·éÀ¡ðÄùÞªZ565ªÆù–üºë>ý㹸!²¶KÜûÈéƒZ|ß6g«§ª^-êhmVµÓfmúÔ2ŸN„QÏÖ­ÕªÆÔÙyEê\³ñÖôMuÈn!\ÿp¡Úü‘ÄœjL/üÙ=ÎÈûà” GZÔÞڢƺè5¥¶íÚö·§£GºÚ©ëÀðàa3Þ¸¶®Î´­ë8ó ŽûžùnäšÓÑ/¬qò ^ƒÍþVµ¶Q]•§m÷lÓIgr–å3£²÷ÿ¡=Ï}°ØÕ64ÉïoR3,ZÚíûœNüòmHwMš££×‘û!¢—Þ?2·3_ 8÷‚Vm±G‚ëÓ¬ÖöVi¬ö¥C[´é¯OEÛ)ÙRéÄõMv˜·ºÎüΈí7mÛ×1ó ‡ðkòmõ‘õ;M߯U•7ÚþU5Á¾²A׺gšJV ÍÓêuÑNüýWÎGS tª9r¹{î¿SK+~G÷Göú_|É|ÇÀ~ét«m*­¿{‰½#ÒæiúŽ«„~Weâ:vZ›Æö·ú¦#ò77˜žg¿üZËçtÊéövÞ@@ hŠòc*… €L€{Th]K·58Øoïï·úÏŸ·úÍûùÞn«õH}t{p”­/2r=˜ÿh§3úׄy̨Ë*«¥»ß)Ùpg£33¸¯½ß5rؤ:ßîuíµÚ#ƒì‡»ÜÇɪnŠá9Ü}ÄýiþˆµŽD†¹g›ßDõUh¼Ë©«¯±Ë©£ûX÷hÓlËântµš:¢žf8®Õèõ^Ûr>ZŽ”KÃV£ë¾†ö¸‘ñçc¾38USæ•jGæ#Ücë/«ª¡ÅйlF£í O­?°v¸»Ù¹æÜíán§à5£ê&£} v¸®9O’u]ß2£Žã¿ÒÑi쌾ϲ|±ßêö•hÙLG³üµö7dÕø##êÓ´OÔ1ú‚l¯É¬ìLñ£e0íØS¡ÐÈr° ·•7ÃoMdTßà9ƒßÖp·V¬_]k¤ßdÙVÁ–évF™WY]±¿ÖÜ —°<Øýç©iqúâù–Z纭‹4~k­=šÞ|ëÂæï¶ÌÇC‘´U1ßq{¯ñľý}Ó7Ò¸vÔûœryjšcûbÜ·%b~/&Ôœ  € PLŒp/ÚR¨ €L¥À®õËtÝuóµpþ|Í_¸PóÍûÂÅËtß§¶Góέù‹ŸUd|{LöÁy‡ýç›´n©ý¿1ýó[œ4uíÿ·Ö΋E¿`íV™)'"iÚt¨58'zÜËÛ ÿùèʘeKÔ¡&û8éPh$ôÔä—XHÖ×Äã\Ë1%³W¦¦,ÕÍ_×£«mÏà¹çé³O~ÞÎD?þ©³œjaìÌ?h‹ý O½žÛº6n„úm}¾S¶fÛöoê¬=xRuNU‚ì·{j[ôüÖuйlf]¯»#£Ë«Ÿø#UÄ|«@*»e¹S—Ô9W«ûÿyÔhF_å«?+3mRøÕÕ©·ƒ£uM3;ƒv»þ]?‰›«zõ=®:3Ú¹¶¶N·^yrfVå ^/ÛœÂÔµÖ›¾â¬š…YzàñgÃñ×"í>©ö™škRÊÐΔv<ª§9ƒï8å-Ì»SµMõ浪Ûp«2zîh†õ­n~N.uÿ–š¥æ3Nþm?ŠøeÕVáÓŒ_°O7¢÷Fíå‰ßËo[íŒ ïÚû²ÂcÜúßßþVä`Ÿ>yêòõF¶µé»}¡åÀ¹E^mV}÷iIY$IÜ[Ò¾—ÆYMå8£¯l·yTëëÏ<ÛK™ßN}ü_o3ßÓà… €ÓA ö_uÓ¡ÆÔ@¸žjµ|óKZá´óªÞ©/pÿé5®‹N´²ZŸº3&‚h¥ÛîºÛ,‡§HøYß/œíö‚ï!oL`ÔÞ¾lízç8Í nšü”P;ÇɼOEY|úãO,MÈÔꟛ°7qÃø¸ÓªÞþ@RK™‡âÞg‚͇B±µ·ôs@¬HÈKÌáòmÙþؽIN¾@›ŸÍü„wÆF442¢w~úS ôë•ØãL“äàÐ&oÃk©ûR muËš)Y‚Ûf_kÁi¿öÊ3û5Õ6þW­¿kµn_¼HåóVkçÓ«í‘÷lÊç¾^|ºÿ®qç4« >®žî.›b–^¿8qÿ„[Üydß3¶3å¹öú¨ÞËôFK­þëÆõZí¹]‹”kõ£O*^oÂjL˜À«ªõ ©Æ£rEûM6m•pêðµ’¸9ù–²[µÞô5¨¯µ©{`§•÷è[{#óÉøÖë¶òð¡ón¿7ôÕ6³ú­owééu tþ_¾ïœ·jÃ*¥ê¦ÉûŽshF c=§\Áý•šö5ûÓ¸ð)f—Ü ÛÌb¸:Çõã‘­ZªPåJ"@(„?¥ ¡Ð”@ȵ@MS‹þpY¹.^¼›µ‰ð}pA…n[ºÈŒ³Mýò­üO±ûÇzՊ˜c|+µ0Å_e%s¯Íç 7%dPù[¿ž°-¸¡dax$s0TÿÖ™~i¬tJòK¨GÒÜ'Ø8Eu}'Èj¢Ý½?hq’¬\¾ÐYŽ](Õu7›I"3›OE¾±çÏf­JK¦ºâFtâðßè¯ê·+é4ïdçžÕóGZë|+fòÕJ˜âwMbÚà–I¶Uò“Lbk¹îZ_e"ÔÁß\mzù̈Ö-ˆ¶«6Ü ¢—ß.óy£ÚÚLÏÜûm{vζwòºoÍg9v!]߉M™nmü½ŸGwû·háì-ÑõKùñ»#EáØŒ €S&À”2SFɉ@@ ˜–®ºW«W¯ÖÚµkc*+µr‚`{È%~š¨wÆV§–+™s®O½Û çM=‹ŽH¾þºšîS”_|=Ò•-Õ¾©*KªóObûâßÛâL±ra±Í¦|îë¥-É´JÙ?z¤;KéÑ3N¼d¦ÙÙ9¨öæzù‚Ÿçļºt`÷6ݳl¾6ì9³'g+Ù´Õnñ]÷9gé|ýu>ù=g=6ˆn‚ó™à|èuÜçÏè¿f4Y­5·$ýdƤNÑw"gÊômö‡ow¦‹Éì˜á¤]6³cI… €…$@À½Z‹²"€ €À¸0>:µy—–F§ãˆÎáÇÈÛ?ræˆOK$vç^kîS”_B³ÙGeé=Ñìšb%Õ‡Czý˜Fy%‹sÛû®ôûÙŸÖv§¨^5iWÏù~ ŽÊzí¸žþëÎ SUÖòеzòÙeë|O§üÍ ª‰‰ ûuߟý£‚!÷¬Êç¾^¼¿™b>ó€†Ì´9fZ¸Éä3©¨;Kè™d“¦¤\k~R/¾fixð¼:Ûýj¨« }«ÅNçß~^8—EìdùžU[e™—û°²%«œkÔßò5}å‘Ý5ZD_òQ;8ß%ÿþ¯Êé¦ÕÓâTÝÙÙ%,šßÍΗ”êÛMÖàà`ÂO°ï†~þQ«˜NæÄ9@ à^8mEI@@ ˜f-ÖJ3WqèåoÑ«)ž¦÷ÆKÑ)V,¾6AàØÉ·¶7ô}ßïƒ4ÓLd0Eù%Íl²ó¨,‹WÝí”þÅï¾î,Ç,ŒüX-NûfÝ0;fo­ô/ß·ƒ“5wÿ£¶>¸V æ©lVd´ïÐ@äA”—^ì@ß =µc‡vìØ£}&œ>«L *VꇷêÙ_Óp?4Çv(§7þÝŒ+β|îë¥íE½2¤ì}ßÕuÁ›Ÿ{ÿæµ$ &ØäÎãú㹸véÄÁ=Æn‡ö<ú0¢¬|V®}@[w>«×¬aùkÍ|)‘Wß;SüŸ}â”ïY¶UÂù²ˆ0ÏZ¢à¬2 ~ìàß«½f^¤Ðj¼ZDŸuËó˜ÚpÒC{Í”<ÁeóªþØoÇNáÞ<¥ÿ-½6ú,ÿé·Uj®ÿòòò¸Ÿ}ÿÀ3zæósàŸCí<¥…àd € —Üó²Y( €¿Àl-º-F2Uõ믞?™Xå‘“zv›=†Ò«O®M|ØaÛ¶:ŒÖÎêËÛí¹ eb¹Øœ{jòK,d’-ÁÚWË’¶FåúEÎhâ6cv"ÞÒêð—/¼õŸTE\Ðo‚,r¸{DÿîL©q½nº1~J€Žù¯œ d胘K(ÝèO_Ѯݻµ{÷v}³Ë<' îUfF¾¯³/q]0{³-_™n[eŸÛô?›§X9y¨ÑÉýþ¥79ËÎBÞ]“£zå«ÛÝnmßäOò!H™Ö®_çÒs‘LXßè©“/eÛVñg;¤wã7M¸>K+×Ãèöô0á¥Úßÿ%t½’[tµ¹È¢ICgÿØ‹&Ì%«.×Yw¨Æ>É¡úæ™Äo! lÒúm»´k—ùyyÐNÍ; €¹÷"o`ª‡ €ù*P¢u?åοmÙwL‘˜ÍXßI=q÷šèt'5OêÎr'¹³à1¡à5×mÖ±3 Ì´çNjÇÇoÑn;åmЧ—G™NM~NÆIÌÌÈ¡—ÿ¥6:{N#fÐsò×å/Kò|·–,ø=3ÿ¸ö랈e8å˜N|B«¶r¬©ºÓYο…rݱÁ)– L×ÔÙ¡iàìIíÛüqÝ·ËþÇ|ÌóR§’ Ï´^e7Ýê|X±wýzí;~FvÈqläœ^xj“¶G®CÏšÛeÆþf]¾µ[þÌÉ«ÍL±î+Fútlßf­Ùn×Ë'ßÚh°5¯É2ݾƾîvëÍûufÈÑÓ¹S/hÓ=Û#MáÑ­Îl¤xæõ¨•³o«ø3óÛ'Õ7`—,~oòõÅ«?·Ã«ß[QÝY¢ßù?–juGüPø¸“]µKû»m‘67‡Æ×‡N·qÙÖÁ“g5f~ï#:ut®[³Íɪá‰õ—}Ô½“  € pe,^ € €Iº«,ó—Zè§¡s0iš´G;-þ ïkèLš´«©ÚÉÃÎËã c¯K5V×pôðá®Æ„c¢ic=Ò3=Ð,e“Ÿ•A=Üiì²x»,÷öxƒlÊmŸÕé2±+鶉ÏÏN“ð>Üi™°Y¬©Çc™ph̶šfS÷˸˜™/Bi2ÎË}¼³³rAÒåå(0âXÔu¾éko€÷¿Æû¸+ÿ~²V £ýh5*kêñÞt‘¤¿\oí\ƒ0ÅQév^5žü¸xÁåh=%ò”";Eš~†×{Õ5ÆùØõuáèÏãâ8´?/â½"Ž9 °ô–ÈŒñ¸SSš˜Á‡–£?Ço„ÝGïú e%,#Ñ‹²~4VäX¬Ý'ðêꑼuøDmgĺO’m=_—¨»«ålòæ 9ê3ÿ¾ìƱç_ÅïEß¶™%Ú‘¢éˆër>›ç"ݱl×^—Þpó’-w]|»OàùWßßîûW^‹¹ós0?'+qíTQ·þñ1¼ó>pÓgïE^Äõg¸<0vv£»¥èÓ8zíâÑMéx†®µµÕ8|ôV§6Ü0N‰6òÿÛÈ×~b9–æfÚF»óؼö{q¼ˆ!²öwôûÙvÜH‰& p ÆT £&_å„þWPÛfû½J¹+¸¬«\é ³äxÍj-wÓâVšûãÅPÿyåÌ™3â¯CéŠ?<§ú[Ëõ} ïˆÆÝJ³âîGWi³Óf’pz¿Rî6ò_Dé•òkykì;YÏ+Iš—Çdg9æ›!åB‡šïÏ(çÍÆºsŒÒ9¤Ô»ÌÇ€{<ʘøòãÎ}›¤4+çGÚ‰Cg”|)?׸ÆH!Æom+»ÐÜy£u»mêÔØ"¨®%nQ–Öž™”KŽöè;±o`pHNytáèy%Iórt©‰iS¾ñµáóóßóK›qò‘<}ºsŒùîÀOöªK`p¹Ý˜»ðÃãSÆÄ‘¯üÔàA¼þdìÅKí»pŸøõ‰ÓÐ×ú<Œ¸Ü5Ž¿L‰ª jĆÅ×àíæ Ø’7Ë)y£;=5ZiŸ–ˆÂ>$¶ÑÖ!\Òb­;õ6F"Ë—ï‰Q)Ç1 .L}s»(ú“ãO}¶(ÛåßHcC|[…ü¢u°£&…²Ÿ£ëQñK|k„ø•øQ=ænÜ“][:Òý¬o‚#˜ÀÖÃg'…Q§@ò v¾€íFW ÂOàX×CX“ÍÃQ1QsGµ;}Áƒè½p©ã)ièí»˜·<Ðr—ÔãÇEŸÄ𠵓9 ™éÃøzm ¿ žqÃuÉŸùô¦cÓKðK’RRúñ½ÏÍÃvµÇWtaÖu|yê´ÍCZºý¥!óRüæ(~½}¾˜ZgæÜÑéÍ4Già=ü^›’_…—ŸÜÒðÖfîgüù1·È¯z"†§Ÿ?):܋渣Åû„>ÉUòy„é›×—‹Oi“èl¹ÅTÖ øpáÍV|gÓ*“‡­Åÿ÷78] ‹˜ŽÞ6X?Æg;Vug|±äÚ ú"L˜sWUˆ¨ÏÀu£r±-N•¤©ÏlÒá.Ç9of ÚS))¢#mçO×㱂õ8<'ðn_ŽuWµâÙÂEF Ní…pé 7ÏyB%¢¬+è[nžak+w¿ýø×;Öëç·/ÿ!6);1.—ºòÀ„Þƒ–È;¥1L™d !þ¯Ò§À\b†| ÕôÀy»ï·§õÎv—K]ÊfhkÃì©Fáé;Uiêl÷äçãÍêjøe›–`Úuç°g¥|‘§ÿñ›ü—ø¢ëÞÄ'kÁm¿ÌÄÕ[sƒ±Àrõçì/ê-‘/CK×^ää˜ì{ó5=Íp¯…ÃSgÌa%Ã~6Ljß(0&ìáfn„ㇾoCцxÛ°F\iæ ß”ŽÔi£)’‚ÌY¡ÍçôYWé͸êjѱ.:˜n$Xºî>,Õ—ž8#陳l’”†kD»6\3{2Íí+m?ãÈ„m¾IS¢¤F¹6IûÒFâýLŸ®çÏò%úx¼ÁƲ~¼ùq齊»v¶ú7íÝú<º·äÙŸŒXîüÛ¶öæX¢;:ë¤]!:aÄ¿4£Y–––†ôÌ•x¬® ³WNôð+ß–ÑûåÏè¤.¢PY?FÄä¸Ñ_0Úu§c8c¬"¬/¢ŠN˜03s–b£øKÚ!‰ê³£Œ©˜‘.ÊrËÓÀsóÖ¡òd/>½ãsX¿×§¼›¿‚c×€¥ú} í…pé 7/$rsB"ʺ´«g -ݺW™K×áÉóuhÓê]´â 0Ëá\ zE£žy]‡<0òŠh ‡4†)“äÄ%¢]œ¾ ÊP!Bn+W7¤^“»ìDåýX¼¹Ú¿i·øEʃ Â×sÁ?M½YéÀËÏFÐ>óáÇ;7Öq¡ùŽț%N¸ÿ'ì»ÿl÷{·?…‡W>¢·e{Ž}›Åtˆd6åéDp»~ÌZ€•âz@£ÿªA5ZÏ} LwôáÕ:5}æK uÇÎᾜ\ÓFÞ<Þ w¯Ì‹ðbT|ûYß G(0Á.›`ñet)0q†ÛQ½+ШŠÑv¦Ö_¥© òn=Œ®‘R6;ƒâ'\•; ±pÊL þ­-܇c¢%h7 ‹Ÿ¹ܵ åÕõÖnÛ݃vkˆiƒ8q¤÷/3¯³ìþ8r¢ÛaÐÉÝ-‡°{÷nìÞ}¡³Åfºphß>±Ì>4tB}Î~ñý_ 4fÔû~°Wb¶ièËîÛVˆµË–aáÂ…âo wìGC{i¹X¾DÞpëCáJTVîÇácòÞëÁ‘ýj¼wãбn öœÀþm÷ã)âºì~TmDMÙ¿C¤CMC ÷‹t´tY¬%DìφƒûP¸v-–ù—_ˆek ±ÿPzVÑVú3ˆžöcØ/ò£-?.\¶;ö©n‡<é‘ážìfûÔ<±c7ŽZòttû\ÛâØèưØ•»ñÔœ wT†9Ì‘ìk?âϧûDüŸ²äæÁNÔâ½ï0ÄæLƒ¼n MÖ|#^Ptä Hó¿êwS½Y÷á°• ¦°€k1]M-‡öùóLÀ<*œGndƒúâ¤ÊÛ«ÿ!yùP‹F´å€0¯ äûƒ"ß÷À¾Âµ²êþƒˆ.7ؤ#L~Ì\¼Eú*»ð|»½„ú8ý§²®¬ž,髊‘hótß©#PóÅî}‡Ä¾f‡Å¾ñ qðTÜ©D-+ª·%9 ¢\8vx¿(Dy¨Õ "k wàPÃ)ûÄh ‹´ïûüyw÷þ£R^rЏ4=®úQ¼ÌÕï.×Y qÿ6µn´¯ÁMŠ—@ªùS+·ÔOµlÞwè˜}}m½8¬Öo¢<yãP‹}½Ùu,PGî«l¬¢ß7ÑÔ’øˆ£='¬y{¿hhu•ðe¨VvµÁõx—ë¥ÃryØ\gÃayð°(¯Ä‹%ÕúϨ?DžmÇú/LŒc«Æ¿ŽÖŒ÷<&útÄ1$Ú^þãXr4—í‘ב—e#‡©æ±ÊÊJì¯mÕâ5ºº"ú4‡ÙñbVdõ™è3SÛ¢-&óSDÛqGåØ5‡V¶÷‡‹&Öíy ¥zùÞˆOŸ’V°¶§÷WÕíj=M:Šº=Ê6j´y!±e¥±&©ûG³nÃ61Q¿79æ²Ý+#Õ‡ÎõX7ÚÎS®õ×?¡­†Ð<`„$Æ¢4÷¯+Ö‰þÜдUqÎ6¹ÚÅþÔ¥˜Ó¨ÓÛêí¿ZyJzüÓ;g[‹ºã¯"º(“Šë2WqéWíjé¹ø_ÅâÉèêÐö*~£g†nT<øåuÍ¿ÜÇ 2³p˽°Á/OœóoJÿ¯ïu<¥vê‹óoW~<Á›õ«Ÿm¶´#}h«ó/è_uí׃©¬°æå‘ëž`Àã–Ïõís„ñLÔ‡Ï3Þ˜hšJq¬úÿÜ%êK6{•ýeeP*ÚÌ/J ¤¯_©ò/9ÑÖ·û,¶¾Œ¥·Ùôr@»uÊ›,/:§”°=w±W‘cÚV¡½Ö£Èïpi-÷Ókÿ¢GùBåâBÍ¥–8ê/c‘×RšôíÙ»¸Kê”p¯œ)ßô·UèûÉãôR5éå/îRéå3Òt;smš§¸DÉ—ö¿6=ðéVê/˜_S3t¾i„ýéQê:âJ¹”×ÌûÒά¹\ÛïöûAMGI9éyE}鬨xYQ¾¾¿ExùUŠ‘üö¹´\Šh3êû4ÄY{é‘Ëø…¦}}Wq½i®œÕ°½çÌû­©ÄÈ×þyRÜüùFúnŽí%iº›c:és—6™âfÿEz³5<íe¶1”òñ—Ûl.öw¯ F[.ûFÎM¥ÚË›¡¸m_bl~‘œ§¢-„'–<-¿„Íí1öµº/Õr-ÜqYÓÛ¤¿ (PÎÈYÌzìX÷©úÝ]ª˜²¥”ç¢:>ZõãÔš6«]Est/x­~ºŠè¬ÒOë1¤~/öš_HØQgÔÅvË‹ ⊩(éxhUÄé´?^öùQzY°ü²âöMdu§SNt>Îä¼m臘ϣ””8×â±l҆Ô=–|+÷ ­§(Fh- ⫝̸Óe,êhÃØ­ä›Ë9n.áè?ì¥ü!ÏWǵúB…³ÖeÕïzýA˜r<›åÊ;†cC+¢4›r‚õK˜<¥Õgb•sõåaˈמ‘f~Áf1òܹÚ"ÿ¶]Ž/0µ†ïü½W_¤§ Öt¾,·ÃJêÏ(uÅZdÄÅò@›ÞTÛÆ±Ñl´UíÊ k^–¾ëù?è,×gã™Ï%9‡‘ òE¹$(»À€R“¯UÖPjÎ:F“Hq²déÈ lK>6Ö/(­Pjk+”KãºJo¥‰7™Ë»<ÅJ·^©¯«UJL'uRE)º@«¤8ŠŸ”)¥5uJkk³RSZ`œ ˆÊPî@0Ò`>vš®ÊOµóæB[­R\\¬ä»µ J~Q±x[|¹äRÄ‹’Lñð•*µ^¯R^¬uîÒì©:Àµ Fø)Ç+l‡»ÔùdZNš®7 \ùJiE…Räp1ÃST¢”–™;) ¼FÃÍÔ¸QÓèQJ«joM¹Þ©ØV¾é¢G„I.&ç5ó¾´†3ÔQcÞÅJ]S“R§æIýEg¾Ò&]Ðó„Ü+: µŽ) jL³1ís»} N¨‹KJ”â"s^F$ Xé ®å¼b\X ä½"¯ÜQtÞ¸¨æ*Uümt)nþ|#: Ë‹ŠD¼òýïÎÇB‘Rì(ÔÝô¿8 J”ªkžr)u#^@PêÊÕãJ:–‚Û+*­¥@lå€"¥Ë¿å²É3úîgä ä;û›œŒ}Økª+ÂícÀ˜TÎIe»)OhmwRQSR_#¿Æè ÉÁíÅd˹¡5}Á]ìÆàäfý2(Eµæ ø¢„1Ú!¢l©­7Sy<ŠÛí¥ ¸\i:cê¡¡JûA\`iÕî0RËbí<\;×ÐÛ®ÖŽþðqvœkºCÊ×b…z½ƒÝ¥Ô‹6ÓéB`©tÅÀ©Lí{ýR¥”Wýe¥µ¬æGzþ£Œw>w„ä D.À÷È­¸$b¸P/]õ v¼‰Ð†ÎÕJ'¦ÎÉÀƤ†›Ú@s)ÍZÅì_à‚R¥]YWçkW«¥JM¼ÍÜÔ©®&ßý¤8˜;"ò•&ÓvÄ8MòBƉ‰Ñ`–OÄ䆭yz ]êIÑñ¡ÅAwF?!µÚI‡:CÜ•!~ôr)Ír·§z“vW€ºŒèxÖÎñÕu£äxÙw”“ŒMËIÓÕ‡»DþE@¯R#ï/õ®*©sjè|‘F©¡Þ\j\PpÕHw‹¸Xî03u¬E‘nµÑX¥w^Ùï3-8c…Þ=ª†c¤Q¾ #å -mç륓LÑùUTk4ÜÔźÏ-ûâŽy-òþ`¼gí@—“FåA¹ÑkíðSÓPg\(¹P§w¢»ËÕ_µˆAŠ›)ß wŒX÷¡qŒ©y[½OîÐ ÷bãîî’zóqبÍÿÛ‹µÓøEA¾Rr’aÇI‘çÇ@ÒÅ qÜs{›¥òËæ@Üy:X6å—×™OÇô™Ë@ÿɉ8A/Ü2þôò.X§ä|l:'mRÿ¤«ýÒES^“ò »‘ÒzåþžYÑÙ.•MêEÚý¢o˜„[gÅX?š]¢ÖYrÀæã"p!L¯RG¼G;&ƒ« txòW½Ë]Ô?‰8Löz¥ü­•‡ê<É8ª}#V5ò°¥îÔ·i7"Å#l‡»Gñvè§ÕJ¯èÄ”9ä*®•ÚCJ}‰Q&õ»¼-5O(æôëwýùÓ^d\t6Ê@©nJPý0žu´‘.ÕÃ¥TI¢»C©n0Ý éP~«{ØÈÑÕÏJ˜0xþ±FXQ¦Ù.ûjÓã.u†‰òÔSÞdÔÏþuÏ›~Õ)ÿJÌOqH¬e»||kñµ~Ê—ò£Ry`*GÓ+vš—€ãÅ©nµj6Ž<ÿy<š²NjƒŠ¼PPÓ¬œ?סtt˜ÿδ…ÞdTPsÆØcNûD_B*ç¤}/Ÿ[¨å[QU³)/ö¶J˜b~V¡;l/&s)¬HÏ õd…ŒLÂvqHÕS,¯Q×i7ÎÈË…tÛkbúë±à§Çt.¨žÞHmR±Œ§@ºéF|×nÞi þª[?‡·Ó¸üË qó‰þóÇsJ±g-âœT«çÝ%Æ/h;jŒ:Lç+Rþ²-+¤ù‘–gãŸÏcBæJ0 ðî¢4ä@Ñhá)ýmÞùÛVé/IɾSzvã<{<ü3ÈkžQ_¬"?dn6~ë€xMKp8P“ê3ßÄóŽõG¿µý¿µÒçÑžÞˆW´wøÞ„ôCÿ{†ÚÊšp>¸~wkSàE—âûçÝ7†„jš0,=¤ü}iܴ袪ùÖåyâEl+x@_ªñõ·ôñ°#¶ÛKL9 žþïù*¬Ì })qØ8Å53 ë·iåðÃ#§¥Ð†Ñâ}Bÿ^ôÅ•Õqçi†«¸OnYi>>õ­F0ÒØˆ¶¶6ãϺʛ¿B»üå´™¸]<—J ¶}9â[ò>o yŽ<Ûñ‘1}-û×á½lr£öÌ˸/7¢˜Ê@lõ£šW·êá”Ô—Š:Kÿ*FÒ°æaí˜N¾%žÁêÅf­q—âqñr]yHËYƒGôUžC÷@bŽyÑG·oœêÎè¶i¿tAí·±&ÇØ·™óëï ¹O¼ŸftL¥àÖõF™ô\ ¾´éXd:Ó±no•‘gË~€6½!#­ML› yê肚§°1OÎijð÷<¤'¼ùWRÙn[~¹, ¦ }$1ÇFTiÖ·m3â÷ÁöŸ^4¨®â*Å÷¶,µ¼1K´ŸZõ<׸ýt‡†wÙ¤yJú_a±4ŶÝ$͇Czý‹8ÌKÄñb[·'¨M^HDYw`ÃÌž3óæ™ÿnp-Á†íúÛ^Ô"TÞ—+ëÇ?^P‹G7æ™òb梿˜ÔÃ~ú9¹ £OŒÄjõ¹¡e»¦¯“°]lJŸúeÏîñèíøòª/™Î%ü‹½§Ÿokgwâ×Ù())‚ñ´tñ®¶]ܾÛxÑhfÞœñ–è[ôŠówÿ»LÅ”‚Šf<º&è;†¯ø_Òšom’Ú+â}AƒƒâϦ¬ÒtÉÄíkµ|Ö†æ3¾wÇÞà:î wÒ™µ‚‰j<üo£Äk¿0ŽU·Î±Ý’mYa»¤˜èPf!)ò¹S¤9‘ °Ã=r+.IÄKDJµÊÉ… «HáÌšŒ.‘]Õ¿^ž&-¦ŽŠ—´¬²ö¨¨ÓÓcs‘VÍþ†ú´«Ä뵡 ®iê‹¡áØ©NôùD =+;÷ìÁž=;±Òæ.ê'¶X‹|Ò§…Üxëíú—ßw¿«ÖˆqÒ!:wê4C`Õ’™â²}è“ÿ|ƒø°ËèÔlhys´¢q¸îÒ{aíŽ6N€Û϶„%u´_˜3ØqÂxÑ£g2†}æt ‘rè)olÀ¯ô}i >A_g‰‹/'EüBª R†áëëAwW;N´ÃÑCûñÐ&íÅ·¬Þ€k®¹CïlJñòù„º^bö¹»ü‹È•¯Qù£$9‹ïF>óÏ´ý/ûV·ÞÁÔøR»ßÙãÁ4¸EãZ<°ÄßZ~'»ÔVð0Ú~þ\0¬Ü9ß謲Ý@DÝÈ_eÍQâúš”©2" Çi¡•;±"+Ýi£ ›ž»bƒ±DGp—òp~²W;•ñà^·8‘± qçiÞöﲄùWñhˆÇH ¢Bú+/Eqvb$ÂjÛ‹;æäá¨þfÞ,>yRý¥"*7.Àð ==Ýh?uÇŽbÿW·ê/ÆuŠI¬ÇǦ®Á’­^=Ø’f¯¸Kµ~”óª«oÍÒã¢d­@Ç™6œ1žyðFÓqâY{7lÖÀ];:Ä3âïÜ4MÞÆØ×‹±î5ý‘”iºÓˆ#¢ÜYn-w¤2Ôs æX.öÈe’ýE@î¾Ù¦‘v#<¢(yHPý4u´_ülh§ž¤ŒHËöD”e#û'âØH\šâ;4d4† ¶¯ í,SWLŸåz1û&Þ¶¹>OÙî7óô~üVš ïwir£‰9^`S·'¦{^HlYgCÜøÚld³@ô“Ê —›:Ûµ\ž/êmLÕ¦†~Ælõ¹aè¶å)“½]<Øù Ök§žž Üo¾Bì§ðý…~.Óæ)…ø‘ž|lvî| J?êË ­m×röŸs×ìÄPoê½µ¨©©AMmÚÎ÷£²0p1¦á;ÿì¿Ñ¬ æŸ°Hm^ Š—±ï/~N†iÓÄ_êñ¢ñʨóçüÛWé»ñ¹¦ÀùL×+/èÓÖÞ}}p|îÜ,Ûã?»ÕÉçñŠf".¶ßêtncSVèˆp$Yòy„Ñåbpû3bǨp&§À`ûsØ®õõˆ¹Uw/ ªw‰9mâ®F}8ð8Žs–šîú Î͘jÛ@ƒ˜:{¡Úá®näMüVt¨/JÏÁŽºXµ+¸r#öŠ[û´«×.w|(_øÌRÌRO”ω ?¸¨èÔíP2¤dÌô7õäWýùäØ :{&‘þTàý!µcÖyP×zïmcïfÌž¶Ùøî0~«+E9Ù×y ßÝ÷ml? eœ(0-~¯t+M´‰Ùç êzJÉúÖ‰ÃLôÝ¡ñð/Ñ·s)~{¼. ×JÜ÷€ ‡wGaO^Àšì!4•”‚Õ˜gé2%?â/¸ÂáØŒ8ˆp &¨ð,ú˜¸¿x†¬Û°Mœlògɽhÿ ŠóV:ÔQv© L‹¹~”óªûV\gKŸ†œ\ÃôÔOƒÇ«Øô×_g©´Y9X õž×z1QûÆ6¡QM¡Üé×–fªmG±gæ:ì³Ý’ˆ»ýüí™^µ=cWè%¨~H¢::‘õv|e™ín4O”¿8ÚŒ‰L³9‚oç^5ŽùE fÛ-"¦¥bÆ\­ mw±*¾²Ýa£æÉ¾·ñ{}J:¦'&1Ç‹]Ýž¨6j“¬{Ú×¶¢ð“Wa`ȸ¼‘ššŠ¡w߯‰—„ [Ë+6îÂCU«Ñ°e‘}@ œšrí\ýëÍ®ÀÇvÁÇlžå¹¡ÝÆ¥i“»]<Œç¿Sª§¶´øï¤_qé“‘~ã—p®ãsxo×Þ‹LSu•Že[þµÿÝ,:î ´^éÀºì\=€”Ì,[c½ -nÙé:‚å»ÔF_1Qa1ØŽmÓn@0Wêë{Ë6Ã[ö2š{ŸDž]ß¾¤1’>ÿfÿ¯zÔZ¶í¹ÿDßž;¤›Úòá¾ÑèFÑg!îÏW—D£èq_sËYè÷éç߉ù¶õ¸xÓXÎ’%Ÿr£@l¼Ã=67®EˆŽ×þмl›ôع³Ý¿T˜Gµô›ƒ1}ÓÏwgâÊÔ@mŸ½r'z;šP*ÞÔiÚ`ëú;pÍ´µhè¾¢Á©ßÀf;)Óg`¦5°X¿mÜBH‡k­q—@+àÍÁ¨6Iã²Ì´¿ú„þ¸˜È"Я>QhT‡î†}Șw‡mg»;?߸C'âX4bUþ–Gá$Û>ÏŠ ÁˆŠ_üÊׇSuþž]¸V 9Ù.¬¦·¡¹]<2çŒ~«øo?uGdÄt‰\0Qå@˜Gâ$2º¡a¥cÅæb}òŸý/ÿ¸ü8™Rq‚`: .ž%h<^8³ô\<òTq\}þ›0‡»°oYîØ`ÓÙîw%7£ƒŒâHã®Ux¼¥/ê-Ä\?Êyµ1²Ç›Í¹ó‹zYš}ÃU9ò6^/C¯¶åm^*ãÞ²sr››«ÿå¨ßåá¾-¡£V¾·çHzN#ñ”íF#bæ´+œ6€xÌ£:7tŒ6c·‹ûšP¦Ý4ƒä;õf§eòÑkg»f”‚¿~ø!í ~ÿö{ú¸óÈ ž²Q‡’ú‡ý¿”nxôózg{A¹çÅrUZ{·KJŽŠßÕF8È¿êQÏgºÚð µ÷]òW™:ÑÓo¼]/CËÿíêmE¡`Õ"ç›klÊŠàj$O>8Ê\¶N-YÛ…9‘ˆR@Ü!Wí¿B­®çBqùCȧÙúù¤:yêTqáºÛËwß\—z%]Üáî4¼÷®8!ð¸ZºÚœ™³<&þöúÐ}þ,þ³åe4>ýÊô[!½XþµŸa¨|®ñÛÛÑ¡û~óºþõ0ýÁ¸„ÿ8wüåð ˜æöáåj¿aó ^<úfñèùÆEJŠø‰vŸÌä(Þ„y gˆ;J›Ä3¢oÂð@HÊ‘"~^¨§\Ê&ÆD|îÄ×—o×Cr•ãë_\Ü¿¼éééH쫦cÞm鋚F *ZQù`*îOu{ѸÿxønTм’oŸßx÷Z5õŽ/Zῃ;fõâîñ€Š»‹]Ø+]ÒÖü ^ú…¿KTLwãîÅYâs âØ¹V‹æ•Úæõ™uÛ:Ñ©º×Ì4îz ]_ÍÂÏõÇɈ»s´Û—¥-&(OK!&~4}¶~ç›úl µtë|vOð®wusn”×~]þ’¸®8w¬F*ÿœ ¦>œ>ªÖëÁèòÔ¦ŒþçñÃÆ;F<«›Þe“˜­Þñ’Tù? ,§:@ "gù=¢V- œóœ÷…žoh Z?#(Û§oŒ²®Š?éïʸʹÃ=^óˆÏ +×ØÞ  Ç{²¶‹Û½Uúùn~ÅZÛGІ1ì?%K8µRSÏßíVðúøO¡Ü娼L=èÃÙÆ@7·§´•Á÷Ïäl܃ŽËÄù–¸ï½ì'èØ»¹ÿ¥cÉÚ|q*£¶Ý¼øAå\4#RàÉ3w¢§Í7D‰¦¤ºhC-žxï|pIàμ9úøhŒ$S>ô1ÌKGÀ¡h¸t˜R Œ¦@Ï«ÏJ2؉=[ÖÙonøVœîj}†ÆÇq¬ëAñH Ëáé­ÇY߯ÀsÜL¡táGâyÅAܵ'z]‡»aïwêÄdWcÕÃ_ÆÒ¬tdå,/=÷mAIçxæy‰³¿ƒ/ÍEêÅt5oþ«¯Ðö±6g_ÖH†…s® ns¤@œ¬K ¬s´ïòˆÓ5ß%lÔ‡¿îŸ†eY¡­ŠÁΣxô‰ãþn~°H<Ÿ^C wb}¦^etÖzOý©iKEgš5 >Ýÿ(Ž¿+¦_u3¾º%úG;XCtú>|á,Îj3ó«à}lcÈÉa÷oõ%´%ÍŸî |«p‘Zi]1ªWvt`ý—¡!øòÃäÛçé7Š»†E¬Õãt«'p÷‰z!íWàG îÇ·Ú¹+~‚¼J;w¯Å'múxÍ Iò-mÎ(–c”Æt¾(Þiáõß™teöêw¹KÄ£,Ū«„äéQNÞð9qñVÛ†x„‡8Åÿ¢"¹Psægâ…¥–‚A¼[Á85ÒVNÌgyë·ú¸ï(•áKÿvYÑFâ«¥¼Úø,^ëÙ‚eÖã¬ûE̘½Ê—8I}yÕíb< øÄó¯aKžúSióðâ®X%Î]Õ㺩ÿåÄSµK¡Ò¶¤Žij‚F'@½'îª{Cô«Ï ‰j¼ú»BfJ>ÉS?$S=feÙ©+æ,6Žùg_<-âîåÁ÷+Ôiõ5æâÃöWïBV‹fÂp˜…}'*±\¿( |qå a–ŽuÖè/ã›ÿÕ±Z×w˜Ï–‚°i:ˆ¦b+Û_~õ, ÚÀÒ&Ðu콓×6ìౚ#ÚsC±½L9‚6㓳]Ü#i-.Ö;“>\›|Œa1Î){ÄMu¡Ã¹æ_ê¯ýðt}Ü~¤U[7ûgU|kSà½êEœ`µìný]þef\§X¿Ç»êÕBK3Ð~Àœ%ËŬj¸Ä©õ½¢Ñ#>Ñ&~©{³5éÈ[%~a^-n¢j«öŸâ¨ë´µ!/;Â9Eb„éÉ”ÏGˆ*gS ¬)–‡3)À ^¨Òž¡.^ )eà8¤Ü€õú‹OÛðƒ£jDzu¨FÉw[¬Ñy¤RïProÂ"Qÿ ¼õvíÝ+î¶ÝŽgÚBŸ˜.î|_©V®þA½ß~²oÔ&xñí'C·_ ÓO„ݸg©v'r0Çj?Ýgš;ÜuúEÓ,éK5þ¤KÃͫΑMÿúŒx¥¦uèÃüŸU"Ý»üo Ù4„­«L€ïi97£H‹§xÙè3í6)o©Âª­"Ý»Äßñ^méÑù?Eü|AàÑ*îësB:Û‡»âŸ›Û'Cv»!ÈZÖÊbTi}×âTãŽ/ îÛ$ÜçâNú¹ÖÁ|öü¬·‰;¢Ìƒçó·xÂb^C|³;‰ Yh4&Œf90ñµ 3Kï}08£ e»‚'bÊëo¶[ÁÿÒ¼¸ó´}ÈOMÏp> óu5à~ƒ–Ëý ‘§|øÝI­ž˜‰ë®µžø £á;ߎèä]8ª­ )EmúšÛïÀÁˆÞ0oý˜ŽkG[#¾QuLƒ6ÒRmÄkuîuH¿n¾~|¶íÚ/§¦-üì;† g»ú}5>’Çñ N|µû´½u¯Z—5Œ#%ûÆø¿Êugü¡N^ì­ mgt‰öLàò«Øªx´†ÓûØÔ^…diŒ{-׉¨ŸÕ.‡i›â86lÉÓffûû‘ÔзïÅ1sSԿч¾ã¿×Dýâ.½'ò_èø×Žà?ñëT§náî–ƒ¸}ñf#¢:üõfcnc£w¼Œoþ£²Nj³ªŽ‹·l¯Þ\šůS*wj ›?{ƒãþŽÕ<úsCÇ(3&c»¸» 5Zóʵ·DtLîÅSǬ Á$Úÿ¸ItV‡Oß6Oµýìiø¶ªëù5ø{ÿ›RŸ0¾=ØÜyö¹ÿ2­÷Û_¿ü>WM3Í û%mÞñÊSµã<¸˜ÿs>e“ÖìÛ>m Ë¿N‘6‹š–‹é‹T÷$U>)1\‰v¸3'P`´z^E©v\Tkkn¶Þ~'oXtÝct¨x7?‡.y¶:..){·/Aáþ#èìéAŸøéû‰Ã;0Ï£Ÿžbûƒ·ú×J¿îzý$£lÕ*ìoÏ”†7èëÂáÝ›ô¹º–¨7)Xùðîàâò­Kpÿþ£è ®4ØÝ‚m·/1î°,z·ŒpÛƒü ºÍ‹7áð‰nø|=8Õpëæ¬×Ÿ§oÔf䙟· »'дÍþ›BãÀ¿˜èxþ›m‡ÐÙ§Fp¾îØ·v6«w諃¸ƒÚc½Û30gþŸÂãùõnølé„úÔƒáaNÙ‡K¶êé*ß¶*Òôu¢IîÆã·Z4îúg<Ö ßà žm9²+Ä¥¹j¨êÅ›h¿¼Åtä?îÕó+ľ-9Úí_ ùö¹zÒZˆ¼z‹‡\«o3~j:k~!+0X{§ùn”ÀÊöÿë'qâV–]ï?ã!ñåÀ'À¿¹ÌÅ«‹TêõDÂU‚eBBò´˱ÿW½éóØ·?öíÛüÛÛv`÷¶µÈ˜³Á÷m‰ ¸ñ‡Õ‹™¸y­v¥Jt8—塃âXìélÁþÂâ…[Z(Êô—[as$ÆaiÍô¢NôtÂÁâ±Gú³aml0I®;ܨ¡¶3¶U6 [ä[µmÐrhæHí™òbahƒä©Æ§Ž¶«/â-Ëì´¡“â86ì•©)Yw‹÷Çü3Ç|`cƒh9¸ ‹7ë uåß’øxx7áïÛýzÙ¾»wlÃÚeS0{É&©-œ¶’Ñûuâè/ã“ÿµ5jeÔ±ñΉóZ{,e»8›ÃwâȉNôõ‰Ç˜uµ`ÇŠyþ»‡ýé*؉»‚7rhé4Æfý¹¡y«öß&_»¸»­I?.Ýën Üen›øt,Í7Î϶ßq önAoP´+Ñuâ0ÖÎ0Új'úgÂöRwá±åõj¿ñwÒ¹\:nZhï5îºkwĉöS8¼ï~¸‚ù®âÏÚþ‚Ó6ÚêÄ”9ø´uÿbî’»Œóÿ”À)Ù7‹W·š‡"÷Â7d^#ü7ûº'™òyøøs. ((@Qh«ÊWÄÁçÿs•Ô¼6%?¸¼º^E[¿X§_©ðÂÐÂrú̯h5m£©Ä­o?°ŽK}„–in¥þ‚±Z[Ue>lÖ)RüQ ®ÖV¡¥Ó£´ªQÖ† õЏ ž]üË[{µµ”¶ eî@`vos…ež]ø"Mç‡ôð¢éo3¶á)7›šÂhUDóÇÓrNÓƒ+^Pätf÷+ânï`eÏ JE¾6ÝùÓ-òY)wض)ÕâË€R[à»ý›_sƈžvw…ÈÙæ¡Õ´ßó•æ`–ˆiŸ°ÔãÊÞÙ'Ûoçëqú®çÃ’úó¦ÅšKåã®Hé°î§¸IÓ5CwE›?lÝ rž06qž5V»±U/oLùW,K9 †g{<ÈÛŒj<Ž}$¶cÞPòƒ–öQH@žvØ7öÛ L•÷›¶ÏÃæ+uç‚…¡b £Vχá×ÓòkrF]}Ä}å`/­Rvõû_‹ÇRYS?*JGmñˆEµÆæÎ(âÄq„uŠMÇmLǃØbhl³]µN–ËCÉØz\á°oÄÌpu§`“Ûæò%l¹#â©·Wäøƒ—ó¶‘9î6ò~)¨518Åe4êc[£_GÛ2Ûk)·ws¥|¢ûú"ö²Ì9L5oÙ·ób96œÂ1ÍÚvŸR~4ò[pAQ6‰~%ó1ïíaË´¢š@}«?R<µåì>åý¦íŸðŸ¢Ý*çø`¨Ò~6¥+\zÃÌã%ÓØÚ¨#ËŽrúc+ëä|lwl[÷d¯Rá6òMy³q²KÙ.§%|^0Ú¿þ9å%6óи|nh• ù>YÚÅÁ„ÕKçÏÖ6~HÚÅ~×çÍå‹¥l ìïý¼&4ŒÀñ¢^8®âºÐE†:q¿€ÃvÌçå¡+ÛOé¨5Ÿó—6yܺF}±KÚ¶KñÚg;æÕ`hNó¥éÚ±¡ÿ(ɔϭ(üNx‡»8²9P ñ>œª7îšÙæô(yÃi7`C±öyàåÖóþ¹â=”Á#½Qn¹œURÛ†' ¿>–îü1êLË‹—9ú2\Ì]„ú¯é¹· 6V¢£®\¿kP]R^Ç]T…sa'1?uªö(i¢º¢¸›ðÇm5↡ƒ« ­­^}ÞTi‘· ú IÁéCâNuÈÌ+DG ´–“ÿ=%h¾ð¼x¾{Š1-ž19b!áw0¦g¤Js¦K‹GÃoº·o ŸìG½išÃ+®iÅó;—%èŽ˾4m* ëþý*vBAy=z: ßH*Ömûí»´g˜ôYôà·aÜ$[ïxÛýÓcÛç‘ïÿcoB£ã<%k1ÔS7n[`/\~´eáç’f¸±!ÌϳÕÇSÄš§Ë?iëΣx§]”TÕãÂГX)=33-gÎ7U˜Êk=Q¾×uôâ\]‰> âí þg|Š}¥‰šË.iQ}T[20AûòÒ·ôE(÷÷@y7Wâ”ö³*=,m$qõcκ= JTŒ¶…À§UMçð˜þ"f15-{†Î¡JüÚnðU £é±±€Z׊»´CÊë[QW*æ©u²©<Œ}ß„«;Cã`LÑÛz®ÎÓ³§¶×uLc¦ø›æ¾èáHóÜj{ÆRÞg«uHå:éî>çvÆh×vQ7R!»ÄXGëÃ2¶`Ó—Së‹ØË2ç0Åöôm›ãÓ±á–)­Ú}YmBŸÖuDÙTÙßr¹Í"¶FsØ µœ¸o)ðxÊöÔéf'SÀú—xD]1jêÛЯTÚ¾—H­WµËjkzõðňe^¬ÇËÈuûØæÿX˺Ôtí|%„FV Ž‹gÏ6&o-~F4X,e»üâÌ⊊óÿ–Ä9L[ï“È3ý‚Ø)Äf˹¡¡à06©ÚŃxë·ïêÆÍ¹w49¤\Lž…-ÏöŠómûúL]/pî\iÙ¯–Åc[¿´¾L]ßùêJËLñ5%;O^Û)–Ú|.”Öâ¼å¼S7™DùÜ࢘¢vÌGµ¦ÆU`°§ §ßx º¨>áüjäÜ´⨎Ãp_Z_;‰ßô^Äå—_ñ?>z½ ®Ü,çÎÙÁ>œ:ùÞü½ºÎEüñâ•øØÂObA¶©è¸Mó ñˆƒ®óx«_ítMEÆÌ9ÈaÿÊÃèé¾ OEJZ:2CÞª>  íç.øÓsEæÕÈú«¹ÈÉŠ%~æØ&û·á¾n´½ÞŽ R÷͸:+ sçä Óúç1HHŸx<Âë=û銫gáúù¹F<†ûÐÙÕ+‰Ó0ãÚkÄôx/‚\û|Xj;a¤ºs<÷½ô‚9Ol\¾Ð@IDATžÝ(žo+Ú3¯ÿWÕS¯˜…œoí™Xp’§~Ë::\}kY.LÇÜã±áÞ(ÍPM^;ó¦¿Ýxñq¥h7~rñdÆ’åF)Žcìè/c—ÿÇ¿¬‹¯li?_÷ˆs9Q7\‘•ƒEâ¼,–!ó˜Î c‰\Ö‰©LJÀv£B”ƒíg…ž?\ÄÐПD9“‰ù "gÖÈ'hÃ=§ðâ/ßÄå¹ËeG½éɰÂHûy²çóɰ™{v¸Û»p*(@ P€ (©Ã]¼g¥·¡PtGp (@ P€ Àäà#e&ç~eª(@ P€ (”—ÜMÅI¹) P€ (@Ñ`‡ûhÉ2\ P€ (@ PÀ,0ÒsßÍKó(@ P€ &œ;Ü'Ü.c„)@ P€ (0±úß Æ÷Í÷1<±¢ÎØR€ (@ P *>Ã=*..L P€ (@ D+àëé†O¼ ©éÈšæmïÑÌå)@ P€ (dìpO²ÂèP€ (@ P€ (@ P€ ÀÄà#e&æ~c¬)@ P€ (@ P€ (@ P ÉØážd;„Ñ¡(@ P€ (@ P€ (@‰)À÷‰¹ßk P€ (@ P€ (@ P€H2v¸'Ùat(@ P€ (@ P€ (@ P`b °Ã}bî7Æš (@ P€ (@ P€ ’L€îI¶C P€ (@ P€ (@ P€˜˜ìpŸ˜û±¦(@ P€ (@ P€ (@$`‡{’íF‡ (@ P€ (@ P€ &¦;Ü'æ~c¬)@ P€ (@ P€ (@ P ÉØážd;„Ñ¡(@ P€ (@ P€ (@‰)À÷‰¹ßk P€ (@ P€ (@ P€H2v¸'Ùat(@ P€ (@ P€ (@ P`b °Ã}bî7Æš (@ P€ (@ P€ ’L€îI¶C P€ (@ P€ (@ P€˜˜ìpŸ˜û±¦(@ P€ (@ P€ (@$`‡{’íF‡ (@ P€ (@ P€ &¦;Ü'æ~c¬)@ P€ (@ P€ (@ P ÉØážd;„Ñ¡(@ P€ (@ P€ (@‰)Àwë~Äàà0†}èó ZçFö]„áóùàáp (@ P€ (@ P€ (@KC€îÁýÜsê(vÜ¿ SR§aÚ´ÅX‘—Ó0eÙý8x¬3òÜ0x …"ŒŒŒ dä=޾È×ä’ (@ P€ (@ P€ (0¦(b˜ÀñOHÔÛmà ʆå.öâg{Ö -ìRƒ8T8 òT ÿÙB¤‡]‡3)@ P€ (@ P€ (@ P`2\òw¸w6w¶»‹P[ß„¦ºyŒ]ܸ׃’£ÝÆ›±ÎÃÅFg»:¿ßf!N¢(@ P€ (@ P€ (@I)pÉw¸ÿòÐãÆŽ-¨BoÃcX·l)–®¼=;„æŠ|}þÞíÕèÑ¿™G†»Žàžõáï’7¯Áo (@ P€ (@ P€ (0™.ñ÷>¼ÖØÜŸùh-߈LÓÞMAÞß?½Ë½íU¼á3-üÒ…½k–K–IµÉÇvo®`o{©·E6Ëp(@ P€ (@ P€ (@ Ln”ɼR—¾_«(ÁÂö^L›;véðij^#œ!cÔ?ÖslîØèµw7á‘5³p¿e~¥(@ P€ (@ P€ (@É/piw¸# Ë wb™ã~îÁÁ¯@ïo÷¬ÅéÒÂ}-øÒÛƒŠñLÉR`ðlŸ:#­ÆQ P€ (@ P€ (@ P€˜|—ö#eÂìÏÁîìXv 60žÌ^õÍÏÁèo÷áà¦%zg|Í™]È ^¾0– ³΢(@ P€ (@ P€ (@I%ÀwëîìÆ‘}…˜6{ öjÏwË”×ŸÃÆ\£+ýÔÁ¯`SðÖ÷üŠ6Ü—|¼xæŒ|‡û°5|~§(@ P€ (@ P€ (@I)p‰?RFÞ§>œ8ü]lZ¿Æ=íb¾»MÕ»°4Ëx£ª¯ý\›VίÂ÷ M›nÜŸ1ÓŒ91}ö³ŸÅsÏ=Õº©©©¸ì2^K‰ S`’ |ðÁ,&Ù>er(0ÚŠ¢@ýcb´¥>&—€Zn¨Ã”)S&W˜ P`TÔóµÜ`Ù1ªÌ œI/ðþûïGGõ\å7ÞÀG>ò‘¨Öë…Ùᮊwaߊ9Ø.ÝÑxPQÿM<¸,V¤³Ï?mì§êz”|ø$ÞS¦‹¿÷Þ,Cµ6×ûClÝvxû=|úŸ¾…uÒòÚ"#}=zóæÍÃÚµkGZTŸÝu×áŠ+®Ð¿s„¸ô¶oߎ/ù˸öÚk/½Ä3Å @L§OŸÆOúS¨å P€‘ ¼øâ‹xë­·ŸŸé*\Ž vïÞûî»999Ô .aµó\»x ã>Š?üáIßá>E$*pKB$©š”Ëôáàý3°Iï%Š«šðÕK‘éÞS•káÚ¬¿JÕa)óäÒÖ^<²È)Dó²ò7õnõ5kÖàÇ?þ±<™ã  ̞=/½ôæÏŸv9Τ(  ¼ð ø—ù¼òÊ+Ú$~R€Q ¬¬ 껂¿q .@ P¸é¦›ðøããÖ[o%(@ˆÔ_Åœ`¬Ôÿ>Ôoa7–æ(@ P€ (@ P€ (@ L`KºÃ}à­_¡Mßy^ìÚ:ÒsÙÝXQ4R‡» ä’6Sð(@ P€ (@ P€ (@I-pÙ¤N݉aÙ³‘2-Ì„Œ0ó8‹ (@ P€ (@ P€ &•À%}vfÞ(Ê–ïÐtl|VÁƇÊà(@ P€ (@ P€ (@ P ¹.é;Ü“{×0v (@ P€ (@ P€ (0‘Øá>‘öãJ P€ (@ P€ (@ P€I+À÷¤Ý5Œ(@ P€ (@ P€ (@ L$v¸O¤½Å¸R€ (@ P€ (@ P€ @Ò \Ò/MMÚ½"EìŠ+®ÀG>òi G)@ Œ,ð³ŸýŒeÇÈL\‚òòòðýï_šÂQ P€# |á _ÀÀÀÀÈ r P€’@MM ²³³¥)¥(™À•W^Ù‚ã¸;ÜÇ?’MèCBZZZ$‹r P€ºÀÂ… õqŽP€ˆD ##ê P€Ñ\{íµÑ,Îe)@ ø>þñS‚ @Lj_i²|¤L²ï!Æ (@ P€ (@ P€ &„ïpŸ»‰‘¤(@ P€ (@ P€ @ò tµÅñßü—_\¼x%nþÌJdôІ¾v©Á•pñÊá3+@[m°ûžõÀ|§¤_¼\y-æÎÏÁüœ,}]ÓâƒÝhø¯¢WL¼ò£·bå¢,Ól~¡@"ØážHM†E P€ (@ P€ (@KNÀoÁ*lm3^\w{V†ïØî¬ žõŒ•\åè•:ÜOþ <[ù#޹QQ_…ÂeæwøNÆòõ[ýk»J›Ùá>¢#ˆG€”‰GëR€ (@ P€ (@ P€ȘkFØ[óÍ“,ßúðbu ³Ý¥Í™9òÝÁ©Sgks"ülÄæås°¯¡Ë¼|êTýûÜ´T}œ# v¸†*ä(@ P€ (@ P€ À¥,Pý4Nö…èiÁãÞÀ|éÆxÇJëÏa ¿½½½–¿ 8ÓT‹|iÍíˈé;G)0–ìpKmn‹ (@ P€ (@ P€“U@¿U]M ?:f¹Ó\Jwç ?ÜÑî2­+-M»zÒÒÓ‘™™iù›…Ü¥ëðäù:A´â _hœB±`‡ûX(s (@ P€ (@ P€˜ìrºHkYí+•éÃsß—žÝ.–m³¬J5:Iž’u¶yŒ |pŒaÁ±±`‡ûØzsk (@ P€ (@ P€˜¼ù¥(/rÒWý}·{¬Lw ž¾ Õ]Pqkz.ÃOœÑ‡!}Œ#[v¸­7·F P€ (@ P€ (@I,ð—XqÏÚ`úñŒÍceÚ_2'ó@þgqíˆw·SSåש†òõx[ƒøÀ\|xZè2œB±ŸSÇ"Ü(@ P€ (@ P€ (09|1û–þ—˜V‹•ý %k6"]O]ž×'S÷M³P¯Ïs9qê4º3>ŒË“e†Þ{'ê~€ ÛGÔÔ"‡½žÎ˜œ3ªÌz£ÊËÀ)@ P€ (@ P€ (p ô¿Ô”\¬/r¡ºLܺîý!Ž÷lIJYƒáîcÆãdJW#Û艋t`Ã]êa-iBå}¹aà, Œ®)3º¾  (@ P€ (@ P€—Ž@ >?}é=‚inÄS¿èÔÓßñ|-´'È<°F<¼}x>}nF_B{BL@œÄ%%À;Ü/©ÝÍÄR€ (@ P€ (@ P`‚/.ͼy•x¬Ìv¨•9Pý"¾µ.G§‡ùÀš…úx$#ïYÞ–jY)gù=p£ êôó>„_Ú²r_/Ÿ7ê 8 °ÃÝI†Ó)@ P€ (@ P€ (@˜2®@X[}ÙiYÙ×ð¶ÿ3jpêãdÒÔ‘Ä Ó®Àl)4vzJS¾4uL¹¹1 P€ (@ P€ (@ \"i¹øÛbñbTuh¬FµÿösÀ]ÝãdDñ¿xq+ Œ—;ÜÇKžÛ¥(@ P€ (@ P€ À$¸mx¬Œeø‡Ñ=NƲºýWñ.UŸ6Ç{çGë™2Ú6øIv¸;Àp2(@ P€ (@ P€ (™Àû‹¥»•Ñg»JpW¢'£ž>«ÜÚVàùÖí ?)0¦ìpSnnŒ (@ P€ (@ P€“O`jz0MÖǹ¤ä"¿Dï ‡ç¡ÕÈrJ¾eÝÔôéú’Sõ1§‘¤KqßZü ú‚‹¦¦j‘FÈiœNˆ¦(bˆhI.4.3gÎDAAöîÝ;.ÛçF)@ P€ (@ P€ (@ Œ·À”)SpîÜ9dggwTÂnŸw¸‡åáL P€ (@ P€ (@ P€ @dìp̉KQ€ (@ P€ (@ P€  °Ã=,gR€ (@ P€ (@ P€ "`‡{dN\Š (@ P€ (@ P€ (V€îay8“ (@ P€ (@ P€ (™;Ü#sâR (@ P€ (@ P€ (@°ìpËÙ (@ P€ (@ P€ (@ÈØá™—¢(@ P€ (@ P€ (@ „`‡{Xž$˜yÙTüî™IF (@ P€ (@ P€  ¤„›ÉyI 0åC8ýN6^{ã|ò£¼>’{„Q (@ P€ (@ P€“C`° ÿïUôŠÔ\ùÑ[±rQV0]>œhhÄbÆå—;'õ¢˜uíµs‘sý|de¦9/åœÎc‡ñâéw0uæM¸w]r”áâˆA€î1 é*~ g½=µ`ïS0ï/¦Œéæ¹1 P€ (@ P€ (@É)à;}Ë×oõ'ÎUÚlt¸ûNã+Ë=hŒ"Ùî‚ T•";îÞñ><÷ðzlmw•ÃÃ÷(öMÞ2 {a„8|xz?6¯¼ »jþŒßõ*#,ÍÙ (@ P€ (@ P€ˆ@ uª¾ÐÜ´T}©©˜m|‹h¬ñÀfÌù›}èŽhñ0 ¥ cnpöÌ©àÝÂa¨8+)Øáž”»%4RË^†{n¹ ÿTýgüáOìtâ P€ (@ P€ (@„ ¸Ëq®ý½½èµü]8׆ÚÒ|c“Ûñæã;Ç(p °Ã}íôu·]†;?>ŧûàEvºO ]ǨR€ (@ P€ (@‰)13ÒÓž™‰LË߬ìX÷È“¨+vëik|ý7ú8G(p) °Ã}‚íõ–]†¬S°û©0ügvºO°ÝÇèR€ (@ P€ (@‰%Ð?rtïúÂçõ…2ô1 »åvïÞÝû Oš®váо}b™}hèÔ'ë#³Ó1Ø×ŽÊ…X8e ¦ÿÖîñNŸ¾0Œ‡+±ÛÖAØ¥.ÜÕpп­}"N• ]Òú¥@âø¤ÄYŽIHjÁò•¿½ ;«?ÀcÞüãê4 (@ P€ (@ P€¡¡÷õÍÊýóoµ<]»¼bž+6­A^º¾˜ÄwÚ‹ Û·ûÇËW Ë`yãjõ\Sm^Gýæ=°ÝÿW\{{ÖåŠ)8þøfìj .{×jì\:+øEûèƒ÷›ôeªÎi3øI„ ð÷„rŽM`)š‚÷^†® žxჱÙ(·B P€ (@ P€ (pé ˆGÊ„úp¨d«¾È¬«ôñÔ©Z{¤W²êó!½´Õ˜h?VPZÚÚ ¸Œù{×߀ƒíêîéøì×Jô»žù¥¸çÝ2t·à ­CÞUŠÕ¹ZÜ,Ëñ+â`‡{œ€ãµúô©â±2ùÂ+güß&vº×~àv)@ P€ (@ P€ À¤ðžÄéÎ.tvvZþÚÑrô —ÍÀfõ&vÿP€ÂÏäh_óé*Bó…!T>Rˆuë Qyòª¤^÷MýêÃh²n] ýõ­eµ8cyBMçK?A[0FùÛÖÀzÿ{b"ËP(°Ã}ç‚Ì+§à_E§û‘–ðÒ)vºOà]ɨS€ (@ P€ (@$(Ã’ys0oÞ<Ëß X²jhw‹Ø×_¨D®å©0ñ&ªæ™½È›%?{6~ëûðâ÷¿‹åVÌ“æq”‰`‡{b=Ç<´¬™Sðõû>„î¼ÖÉN÷1ßÜ (@ P€ (@ P€ €_à•_¶'VÂ]ŽU96=øé‹±Yï\Gðq5)¸íþõí×<Ój,Za—¶Ñƒo»iôÛOöO}_›7W¦»8Srpo©eÛÕ+Pwò›X—"=Nƃ{—fk+ÆôyùeiH¿|FLëNƕغWÙáj2a§,_xúþüÓ“Æ¿ýÇpõÌòvg2â (@ P€ (@ P N_[nX¼ÕŠ«´'É3…øÎïNëßÓ3îR×é­®’+urýCÃz˜#œ;þrøEÄîNÃ{ïªnW‡ \-ÝQ¿pÍ?þw Æû:¾|#ŒÇÉäc¡ùšC ˆ(þŸ{ÕB¨(à$Àg¸;ÉLÐéën» w~b vVÿï+4Œ6(@ P€ (@ P€ @Ü©F‡õÜ«¦‡—:Õ¸ýöÅsBæG:aúU³GXTlǦ?ßè4wXÝ[qüÍÐ…m÷§›ÃN˽ %Áw§¶=÷ ž>ôŒÿÁ3êÂ%ùwBê›· —“(¿;Üã7LºXvf‹—©~ãé0ügvº'Ýb„(@ P€ (@ P€ À xOüñQÿ¶}øŸ“mz,ÞâÎt}%›‘©Úã]LóªqütŸiÊp×aèæ¦YÒ—j”|·EúíÔ¶À[=˜wÍ5¢¯n¯7:Ûó+Zq_ŽÍCb²òþ?{÷Uyà}üÎ$  v uÑ– °.hEMl­ÔKؼ@°°nÛ ÛJƒ@5¨)¨åòn-Á*TjÁ–ð¶Û’´ê¶²–TC_¥*VÉ*QR%2“÷œÉÜ2ä:™L&3¿é'syÎsù>#ÊNž£¯û¿ihnçÎi—·Ý gˆ »…¹ËB Ëž¬âRß4Uªð}ÁWQªÙW_ ÜÅ;z¿{¸×EpþÚ­j@CËg8ô_o4éé?º·‹ÅI@@@@ &-}N;W´9²‚5»õÌœq-Ï''k¸ïHºo£í÷ÔgN–ÍÕÓ•Þåc†æê¹ªÍ»ì¥”]°N{÷–ùÏV›—Ò|á^¡6¬i½ïE[«´)´ßþú3tCþÿž²WèÆÑ­ól!1ÃZn$¡×i<°MÉL €æ,ÐÖ%_Öð“ïéçëfhuÐ×m…;é¡Fxʆ{] ¡Îm 2D*.|{×¹+¥j>nÒ·Ÿt©à‹¦r²ùŽ% à € € € ÎU½º_‡?=i ¸Ÿ2†Ðù—ŒÖШäÐ ª=xH;jµ¬ô!£”9—ªwìßP{P¯¿ó>=ù©Ux².§Ž.?¸c¡FåYë·[¯‚Ío«dz–g›ÿë»ö2ÚÕÕÕÊÌÌŒéA$|àþâò\]½Ì{g{Á)™¥ÀŠUÚS2[ç–6O¢õmØá×î‘ýx…p¯ëê§!»Ýæ[5MZü”K‹§™º,‹Ð½«ó@y@@@@¾"P§µ¹ƒ5ßùåiï±í-—Ìé+àŸ-úJàžàÉkþRá Û•¯½k‚Ãv{>“4á«÷Xg¼¯ª?êÏVá^ç«(úïŽ0ô½©¦ÚæÖÛVøÎ @@@@x°ï„?XS«Ê-{Ãvëa©+ Ûãi’ûÀX;pw¾©í¾¼=ç*]ØÚ¯Ð¤\¨ë‚²lOj¸×õòbü¦þc²©¥›]úß#„î½<4 € € € 1§ž¹m”F¦ñ3|K3çèþ¯MˆX T„@g’:S(nˤՒuE»ÿˆRÏ»ÐZAª•—ó5mZÇÝzH³õä†0¯k¥úhʵÖp¯ûDºw“K?¼Ë¡AgÑîí!€ € € € qc·¬rÅÎÇ5)°vtË“ì!ÐC‰¸+E¹s–*·MÜZmüNüy{Þ]âyžC¸×µÙPTO|åJSŸÔ7yît_9Ë¡Ôþ„îQC@@@ˆ°@šfîxC9—}Ãì󲕙‘àÑg„…©®s|êÚpj¨Ù£¢ü‰*ö-9c•Ûðƒ¯¨£ç'‡{]Ýè±Ãwæšúàïn-Ö­¢¦’„î=†MÅ € € € €=.‘9Z™=Þ Ð®@b¯áÞMCv¬œ£Ô‘-Ãö5»«5kt;q{¸×µÖ‡(³Ÿêûí)¦ì•ܸݭ¦&Öt;M € € € € €@ VÐJÒê™`§*·ýX³§-RUð„çê…Òeš4¢µ'ªÚý.¸‘¶·¨††¥¦¦¶](äÌÏ~ö3]ýõ!G[ß­?Ѥïntiì(C_û¢£õBE@@@@"(0bÄ?~¼Ó5=zTÕÕÕÊÌŒí_c`I{Jjåõ£´¨"x~ó´n÷tWîhµ‰îuÁÍt°””¤¯}íkZ¼xq%§‡ Øé`Ë^¿ýÝý„Kg¦¸uÇ5üÒCdœF@@@@n ìÝ»·K«nŒ9²›-Fçò6³äè4 ­Ôiãì–a{á†ôÝY“ÔþCŒÃ½®ëcNKK“ýOO½i…î3ú¶ºŸm :'›Ð½§¬©@@@ð 4ÔTê7|Gê×Ïwèô÷“'¥3‡ë¼ ³taÖµµÃé¶äÀ‹Ûô»×?Vÿ!—êö©:]¯óà=ÿÊ{Våƒuå”\èVºh­±«Bï|rRgž¥n×sùWûœí sÎ9§7šíñ6»õD÷. ìÛ8O³K} è…ê5š”Ùñ]á^çk)ÖÞG 6¬‡§:´ø)—ž!Ë"tµ9¢? € € € _¯oûŽòæ·Xr¡ƒæX+2lМÜî.©Q§_}sšæÛë*g¯Q^÷·Ê 5ÍÓç½|Ì ÜÛyäaƒ±Vj~]ß™œ'[ {ÅËî‚Q /$vªÚx@OúÓö<½p¤¤Sa»Â½.Æ?Ž0T8ÍTñ6·Þ®iŠñÞÒ=@@@@ o $÷ïêš{Ý(­,?ØÍ')ýQ ÝHè%eOuo¤ç—[½®«­õfù¯\iêš1†–Xwº×Ÿ`y™Þœ ÚF@@@D½³=dÌ#>§…ycþ›ËjËÊåZ¹|¹¶ì© Ú:øâ-·Î¯,)×ik;ŒLSCÝ~•,ž£±†!Ãû3eÎJ½xÀJõC^uûËURR¢µ%ÛtÐ_Y­v¬]iµa]SÓ¨ÆÚJ•,Ÿ£Ü±c5Öó“«9‹KTYã¿À[kÊ·”Xõ­Õ¶ËäÔìiîïòµ;TÒ¾g·Áss{åBêl¬Õ®Ë5el`,ö˜¦,\ÛJû­UÎ1º'`4Y¯îUÁÕ=)0dȨ¸¸¸'›iµnû£±òçnýTÖUM%9¸Ó½U("€ € € €aì+™©ì¹Í ŬÙ{DóÆe´SKÖæVó3Vó¬–n×ûwg¥¦¤—½nCŽõàÑò{&„Ôá´®Ko¾.gŽ”ÏS†œÚ8%]³;ZìÁª©pëzhêh•ks5ÞÿÐÔroö(7}bóÃO­Kë×­*á¿ÔÚÈÑîC¿Qîï¢ÎÀu9+öZ}ç)\¹vŠÕ†gDÖ8½mUã¬\«ôñó=GZ¸ÕíÑÌÁýKï]âß\ó‚µtϤLÿ>}GÀþ⤺ºZ™™±= }‡{ßù8õNOíñ·§4DÝîßÍôÎ<Ð* € € €Ä¿@ÿäöW~®«ü™7l·-ÎÓY©^ëVwßÊ2é)þûÞ[€¥§ûvÛ@jÁŠuÚºu ²}å¥âikãþÀsšœ,ßã_«üa{Ž ‹ŠT¸À àý¯ ]÷ðïä¿—?èºô µt’ûûGhÃ_‡µ‘Ü?xϻݠß „íÙy…Ú\¶[»wnUQ~`@󯞯=á´R‡èž@ûÿ$w¯n®Žû®ö¥·™ºg£KÿÆ­‚/:â`T @@@ˆ-Ê}¯«&ý,ë¡©-ûuêøGªÜù¤f,Zï?Q°y޲"™êe/ÐË¿{X†6W:uê—uÅœÏköúæ§Î^õ¼n/™ÚêúòþNolÐá’Yþ‡º~÷öq¢ìúýö{¬;ù›_¹7LÕõ—ÏÔÄù¥Ö2íy«NÚým‚Htˆ:U ’ÿh&ªaÜ;µ¿¡å3ºû —ÒRܺã~1"î'"€ € € €@TÖϘ(_^ÜnÃE/¨dz`‰—vËvòäæŸûÃöæK†jÖ#ëµ}ýDÏR5Z_ª×™Ú¼|L‡uèÂv»xÆ„¯jCÞÜæ%lªöê=ë󾛨;¬¯“¬g5úo\¯ú_½o-ížt×ü„;¾©¢þQõJÕE}¿Ðɺ)†@HN»€•ÈEiè™íøo·Ê«Ü‰LÁØ@@@@Þ¨ø½‚Vxé~?¬uÝ'g%Ó¾ÓÆkî‚ÀR,­/Vã+xÏYóo}Ú-¾Vôêl]A—t¼™:PÃý¥V+;5W‹K¶èÅ}Tç´~m`è-}è!=ôÐRÝÐÚxýײ@÷Nûøw¯:®Žgƒ =t§Ã³¼LšõEàåò}M<Ï7cC@@@è nÝ«9— Tý©@8l­q~ꨵ¤ÌKÏhÆüÕÍ©X¦¯o¸Qåóš0Úí¦·µ®{’F޵w{Y™wõ¾ZKë8J ZÙ½Û]ëRIYZ¼³Hë'/ó^V¡â¹Öw/;§@w}=_wÜ4IC[ù~¡³m½óA“þv¨©³Åã¾Üõ—rXKRó tüOI ,[è¼áöšî-Æ¥ò ýÓ?ð @@@@ »™ÿt¡2³Z[g%K£ÇMÐkÑó ¦5‡î¯ì·–OçXjûm7êD{޵sÒáÙÁC]Û©%ò§ßI´¨;ó†¥:òöµzü?Õ¢Õe-ÎUU¬·:ký(O»oS®w½ú…:±óѱ&UU¸û¨>?Ö Ü};¼{Üù tY {”¡¯ÉÔ}O»ôè]Ùw¾óB@@@_àÄ©§¥†T•uÝ—•£Õª°rªýÒA7¼«—ZfÏA'­Më÷¶^ÇúVEO× nÜÞVýá¯~å¥6/ÍÈš¤{VY?ÅNÕzKÞó’*~ö„V—5?Ö~hêuK~­S%·(œ`ô_.2õ/µÙ<'k‚ð!K 'ÛÔ´Ï™ºw“Kÿ„oõÂBä"@@@@ ³©ghdPÙVÃâþ­¬Ž^ÿ©]wÚfÙn½åËÕ[œ<¨gù’zëÎûVªnQ¼GvZo7ðE@ ÑÆšµ|ñb-^¼R/ÖX_G¤¤iDÖ8Ý2}žVmMÇÞ.³¾°ð¾ÞúßÀV}ÇxG Bî‚LÄj¾|¥©kÇZ²Ù¥ú„î‰ø`Ì € € € Ð éAmZË«øòò²T]Ð)Y÷Áï(úfó]ñ-ŽèÇ{‚x¶ì(±î§o~eÎÖ¸^¹Ã½T¯¼2¢ƒÛTàÿ" Ðíúþ¢eÅÅ*.^¤ŸWœðn¥Yw¾ßଭœÓÊqî ¸wW0Á¯¿3ÇÔ¹g*zÖ­F¡{‚> € € €ô”@P°®²Jò­)c=XÕ¿ò{Ù\}eù6Õ8ª=¸OOUÞjßR*mt,;[e‹&jÎÚ:P[«:g*·-Öy¾ÇJ‹îº²‹{æprÐ*7sÇÏÖ¶Ê9µÚW¾QSGMó<Æ5´å´³/’/O_=y²Ö–ïWƒ·Pƒó ¶-Ÿ­E^Šì‰ŸUFhì#!÷A&j5†aèî)¦Lk÷G~áVS¡{¢~7 € € €ô @Úyšì_e½~³·¶¹±”1*(òŸPŲi™ž®a£²5»Ø·$ŒUÔ—F{»è¿Ç»ª9…^??O ¦Áéƒ5~Z lÏ_·WÓ³:¾½Ýw—}WZ»nô³Ë¿Xk®O?RééÔ}Ýlk¯×ˆôŸ~‡*Í¿îb¥c5Öz¨gjú(M[æ»2G«æ¶Q ‡è¾{÷ ¾†$‡µ¬Ì­¦}ܤǟw'¼ € € € €@g’Óø‹ÝÔí?Ör#IiA‹¸Ï/ü¹ù˜IKŸÓÖ¼–Å={ÙZ³{¯v®°ÎÙ¹zÐR4i¾Ûâó µaMA+×JE[«´iθ–çüõU`ŸÜeŸ–ÞÑbï¸nh®ž«Ú¬VGT°N{÷–ùÏù»cõÂvØÙb,Uò~ŸÐ<†œÚm­åž;´y—ÿG ' ëŽdnIî ÙÕ9dÈXëO¾YŒPÕ¯Æ~xêÝO¸ôùKMM¿†ïr"L… € € € €@; Ö²+ÕÕ踵üLò€tº Si­>]õôJjêõw>Ч'?µNRÖ¥ã4"8?ý’(i°–Æ9¤ŽµÚJVúQÊìD§ëjï_^Ó{GNª_¿~²þ_ç_”­ìÑ#ÔIŽ(Œ&º*`¯´Q]]­ÌÌÌ®^Õò|Æ¢Êß :ÓЃ3úö“.!åfºÇ÷Œ3:@@@ˆ%”´¡=&¼Û·S†fjœõ[¯ ÍÌRWG””‘© ¹ÖOl †Þ$ˆ‰h‚Lt´†yÎ`ëªÓúñN·ö¾Íò2Ñr§@@@@è}÷ÞŸƒ¸ëÁ# -žjêÛÜz«†‹ân‚ € € € €´*@àÞ* »+pY–©oÜhjÙf—j¬‡©òB@@@@â]€À=Þg¸ÇwíSÓ®2uo©KuÖUy!€ € € € €ñ,@àϳcûò¦®ch©º?AèSB@@@@@ ‡Ü{–jwæ˜Êfhù³n5ºÝ2l!€ € € € €@< ¸ÇÓlÆèX ÃÐÂ&t﵉ a@@@@ˆˆ{D©$\kǘšv•©{K]ªû„Ð=\G®C@@@@Þ pïý9Hø|ù S9c -µB÷ã'Ýþ € € € €}T€À½N\¼u{fŽ©Ìa†–?ãÖ©FB÷x›_ƃ € € € €@"¸'Â,÷1†¡…y¦Lëùèv·ššÝûÀ´ÑE@@@@ pÂ`³w’Ö²2·™ª9Ò¤õÏ»{·3´Ž € € € €tQ€À½‹`ïY”~†Šf8´çÍ&mù¡{ÏjS; € € € €DR€À=’šÔAgz0ß¡_¾âÖî×Ý#‚J% € € € € Ðãî=NLáœ3¸ùN÷u»ÜÚû6¡{8†\ƒ € € € €Ñ p®7­uAà‚s -žfêÛÜzóQíE@@@@@ Ü{&;/pÙù¦¾q£©e[\:ô1¡{çå(‰ € € € €Ñ p¶8íuYàÚ1¦n»ÊÔ½›\ªû„нˀ\€ € € € €Q p 3tWà_¯0•›mhi©KÇOºwדë@@@@@ òî‘7¥Æ˜™c*s˜¡åϸuª‘н‡˜©@@@@ pŽË¢/`†îÎ3eZŸÚG·»ÕÔDèýY E@@@@hK ©­G kY™ÛL-ÚèRÉ.·æNvÄb7éÝh:yRM'NÈó¼í;æ}W;çÜuuR’õG¼õE•ýe•çe¿û~ì¾mïyO9ß±VÎûëò–½Þ·íö<íz†ÓþøbµÿÑöêµöìÏ/@@@â\€À=Î'8‡—ÒÏÐý3úö.¥¥º5ãZ~Q#ç¹'ÇÔtêT»av‹ »•PÛ}ìXsXÝÊ9;(w;žîæ-êôçA×»?þ¸å­_å0úõ“Ñ¿¿ä}÷ìo[ç|e|çä=f(¹Ý²~¤¹^ûÝ÷cñü†Hоÿ\Py»_Ù óö1ÿoš´qÞs÷úHÖç¯+¤?´×r¾;;?ñôÛÚó©—÷K!OuÞ/{zí ß—Mm|¡äé—¯ŒÝaßvPy™6Îû¿ôiç|oäù³äŒ3dÿ:™á°¾Ô¶­¬³ÛvYï5FÈvSc£ŒÔT…oQÞ{§LÈõ-ʵц§¯Ö¹àë»´mµÙæ˜íþðB@@:!@àÞ $ŠÄžÀ 3 =8Ó¡»­Ðýì 麱üE8–f©Éå:ííŽgÿÝVÝ¢lP(í ³?ùÄþÚav‹r¾;ôÝ{½'$·¯ ~µXÛw‹;hß|·x›ééþëìm;ÀlµžëƒÃtÇ AÍ{pÙF x{+Põ‡ò¾/cÚùBÄ.É/ü_Ø^v»¾Ÿ }Ú |!Ó–—ýg«ûÓO›¿°³¾´³ÿ<÷|y×Þ¶=÷öyûK¾öÊu¦.»o9O}]Ýö^ïë‹]W—¶}íwôÏõE‹1`€ç ¨ß^`ß™//Âù’!¸^ßõÖìÿtêKŠà//¼×ûÇÓÕ//º9þN±<æàmßøí~oû¾ëhN9 € €@„Ü#I5Ñ8;ÃP‘u§{áS. ´þÎûÏ&Nèn‡­ξÄsgµ/xöÎv8í?r®Eyß9ëÝh{¯oµLPÝž0ܾóÛ°Ù‰ädO€<›gžé¹3Ôw,8p¶™iižShðmÚw\fd()$°öÕãy÷žkQgP`î©ßµí¿ˆóBˆ xîì¶þy~y2 >Ä6}VÀ¾C¿©¾¾ãðÞþ÷sg¾Xh£LÔ¿°°~ãË÷¥D‡_LXÁµç¿=|_JØc ÝöîwXWÈ!öovØ¿}ÖÝñÛ×·ù²Ãyë·jÚý-o€ß"°ïÛÛöž‹»/,Ús°—ýß|ö¿¬ò~ûËŽHí·9±œ@@® xn¾±ÿ»Éûãÿo7kß¿mg;Áû픵ÿÑþ÷¿ÿZ»¬u}ð~ðvh½­žó¶Z¶«cí­òî½%O»¸àC‹§™zègn=0ÓÐ?Œ\Äã¿ãÚ8ÛѶÿÂíÛ·ß½Ûž0ûøñæ¿´ÖžóÁå}!¶¯LÈ9_}¾÷ÐÀÛ˜[×ø_ö_ƒh+”öü%'øXPàì ­­¿ü‡Ùþp:%Ež»´ƒÊ·¨Û:î)ÛFÝþÀÛ ÔM«.^ €Ä‹€aÿûÖû…p¼Œ)žÇáùK¤½|\_l´yÜþË¡÷Ï_üººí½Þÿ—Æ\\W‹mû¿ICÛ³öÛ›Ýû/®Ö{[e<¡õö¹«Ûžåú¼_šØ×†þ%»3ûžë:óÁ´‚~O¸ï ôý¡~Ú÷ô9¨¿1¿oÍKð—Uv=ˤÙï¾ûï¾íH·¼_ìD¤=»>^$¨@§VûÏoûß%ÞwÏ¿7‚öí<Äóò:×â:ïù°Úô]k·eÿ3ëÛ÷¾·ÚN[çBßÐkýãl«¶_«|‡×Úuz¯ïTÙVúúïÎ.×Üÿ††Î}òƒþoñgºuÜ¿oÏKð¾½måDž¹ò^ï/R®Õßy¯ ­3tßWg_ù“œÀ½s9JEXÀóohxí ¡ƒÞ}³Û »e—:ç ³3­c³N\ eë¿ ¥Ç¬á 5þ ÜW&ø:O¾zZ ¼íàÜþÃÎ~Ù8ÐíÎöÚ´ö_|ÁtÐu¾àÚ¼}Û¡ïíÖrÛåì»Ä=ÿÑ%H0@IDATÛÜKþ@@À+àù­û¿éÓö¾ß|8-´ 1bdßæ‡A¡Kœ·C)«=_ãytûö'ÉûeLÔÁþúÿ×Þ§ß÷ ™à (4@b¿e ÖC¾¶ýÿl„†ŽÞφïóí™_«Lð~ðvh=Áÿlœv®3õ„~6½ý ­«Í>´Òÿ6ˆôÇÓFPûn3¸ûzûψö^] ;íŒä´/À‚ÿY Ùn54õ~žBÏïÛ7;x^­õ/ôóè-ã dƒë±·OÛ·®·ËzÚ°ß½eZ+Ûê¹6úßjÙ ºýç[é¿ÿœ·|ð~ð¶g,Aí‡Ží´²íµoÝ(éùo¦ö>1x®Éx¸÷I ·‹þ»±CBåÓgë›.Ï])¾:èÝxÖ¾»¯ƒÃìu]\&ø:YeÖŸ¾Î¼õVÿÒ&­ÝáíÇCÃpk?‘^3sú Î¥¢gÜZ>ÃTrÿi•HóÏX@@@@èM÷ÞÔïDÛ.ëW…>ÍÎVÚôé(M[àîpÿÓ–ÇÓ]°AGÊWijî$MºaºVm?¥—×åûÏ/*U­woÿÏVi½ïLv‘ÞÞ[¢é7äjꬥ*?¶W¾s¥3ô·¹û4zå=ëC÷N3µâ9·þö~S¯ôF@@@@@ þHúÂ¥„î‰üy`ì € € € €ÑÈÌÌÔñãmg«ÑéEä[ Í’#ßBÌ×X§³[†í…^ÐwgMRF'ú^VùŽ5î´P^η´Ó÷´Õ¼«taàùNÔ(bß©~Ï=÷¨¸¸8p­ˆ œaXOuè{O¹4ÈzîåºG˜Ê@@@@èÊŠö¥†a„Ô›» Ÿ,îÛ8O³K}“S ªëõPa{Ú…W*ßwÉúßêßNà½îõ—äËÛsr/õ_ô@@@@h ¸GKšvâJ o‚©/Œµ–˜±B÷OÝãjr  € € € €a ¸‡ Çeäç8”e­ë~ÿ3nl$tç € € € €@¢ ¸'ú'€ñwK`Á-¦R’¥G¬©ºÝ„îÝÂäb@@@@ú¸{Ÿ@ºß»‡¡ÅÓL>Ú¤u»Ü½ÛZG@@@@^ pïU~”~Ö²2Óª<ФÒߺÇÜ2@@@@ pGkx†¡óÚ¹×­ßþ…Ð=„‡]@@@@B€À=!¦™AFC`x†¡å3zü7ný÷›„îÑ0§ @@@@bI€À=–fƒ¾ôyóÏ6´äVS[QÝÿ>QíóÊ@@@@è‚{°(Š@g²Ï35ïfS÷mqéýÝ;cF@@@@âA€À=f‘1ÄœÀ¤Ï˜š~©{7¹tÄIèsD‡@@@@è÷@¥Jl[&˜úÂ¥Ö3¥.}Ú@èΧ@@@@x p÷f|½*ŸãPÖ9†îÆ­“„î½:4Ž € € € €@ ¸÷00Õ#°ÀZÏ=%Yž©ºÝ„î|"@@@@ˆW÷xYÆ3‡¡ÅÓLÕmÒº]î˜éA@@@@È ¸GÖ“ÚhU ¥Ÿ¡¢UhRi…«Õ2D@@@@¾-@àÞ·çÞ÷!ô†œéÐÎÊ&ýæ/ÜéÞ‡¦Ž®"€ € € € Ð)÷N1QÈ dh¹u§ûO~ãÖ¿IèUjA@@@@ 6ÜccèE œ¶¡%·šž‡¨¾ñQM ©g¨ € € € €q.@àçÌðbS û>Fè1X*B@@@@ —Ü{ žf°n™`ê —ZºÙ¥OÝùT € € € € ЗÜûòìÑ÷¸ÈÏqè‚s Ïò2' ÝãbR € € € €@B ¸'ä´3èX˜o­çžÒÏðm#">ÀЃ3ÚYÙ¤ßü…;ÝCxØE@@@@ ¦Üczzè\" dhù ‡~ò·þûMB÷Dü 0f@@@@¾)@àÞ7ç^ǹÀùgZr›ÃóÕ7Þã!ªq>Ý @@@@ NÜãd"Fü d24ïfS÷?íÒ{µ„îñ7ÃŒ@@@@ ÞÜãmFO\ LúŒ©ךZRêÒÇÇÝãjr  € € € €@Ü ¸ÇÝ”2 x¸ù_L}á²æÐýÓB÷x›_ƃ € € € ?îñ3—Œ$Žò­»Ü/ix–—9ÙHèÇSÍÐ@@@@ú°{ž<ºžXón2•ÒÏÐÊçÜr» Ýkö- € € € €@_ pï ³D°C‹§™úØÙ¤ïtc‚ € € € €1&@àcBwhOÀ¾Ãýþé½ún“J+\íå € € € €DY€À=Êà4‡@wÒz ß¡]•Mz¾’;Ý»ëÉõ € € € €DJ€À=R’Ôƒ@†2´Ü ÝŸø­[{þFèEzšB@@@@ M÷6i8@l œ7ÜÐ’Ûzän½ñQíÙ¢w € € € €‰ @àž³ÌãV {”¡ù·˜ºÿi—Þ«%tÛ‰f` € € € €}B€À½OLD m«.15ãZS÷–ºôñ1B÷¶¥8ƒ € € € €@Ï ¸÷¬/µ#›ÿÅÔõ—™Zb…îŸ6ºGF@@@@ pa¾*oÝå~ÑHC÷YËËœl$tï«óH¿@@@@ú®{ß;zŽÀión65 ¿¡•ϹåvºŸÄ@@@@zP€À½q©h 8LC…SM}ìlÒwº£Ý<í!€ € € € Ðî =ý >Rú*šîЫï6iS…+‡È˜@@@@ˆI÷HMKcƒœN§ç§¡1R•Rá ¤ 0ô`¾CÏW6iW%wº‡§ÈU € € € €tM€À½¯†ý[d†õ3S•ÎV :øâ6-œ™+#9Uéé鞟ÔdC3–h_-É{›Q6ÈÐr+tò·n½ü7B÷(óÓ € € € €@ ¸·2é¯lý‰÷hûiûžµ35êêiZ]ZqZ-¥«ç*{X²JöÔžvŽDKà¼á†–ÞæÐ£¿pë÷xˆj´Üi@@@@ 1܃ç½Ñ©}»Öêêe§èÁÅìm羚8¿Ô8§`…ÊvïVÙ†Êñ•æN¼»Ã»äƒŠ³‰@ÄÆŒ24ÿS÷?íÒ{µ„î¦B@@@@¼îjPyÉrÍ™9ÅZ&]Ù“çwâÃѨÿzr•¿Ü‚ÍUV÷è–Ü\Ý2ë•׿­"ê^ª—Þªó—eÞ¸êS3®5uo©K#tï9 M@@@@ø p×)ýõ±eZ_ZÖ…Ù®×Áw«¼åótûÍcZ^›’¥;,ð+å]ÿ6ô–ÀÍÿbê‹—™Zb…îŸÔº÷Ö<Ð. € € € €@ü $ÅïÐ:;²d]¶hV|$¥¨¿ú÷?ª—[¤R_žÞj5ÖÃPùNÓÉVžZ丯€®¼äýÛl Лö]îµG›tÿ3.=8Ó¡~IFov‡¶@@@@ˆ+îp·böIÓçéžyó4oÞÍ™s·®;¯£9ÎÐ…9ÙÞBºz^‰6®©­Ü¢Ûf¯÷8ÿÜ4ÿ6ô¶À·n6uFC+žsËíæN÷ÞžÚG@@@ˆ÷Óæ²þ´#­ÈýæzåûN”ÎÕ¨TC3ç,Ôœ)c5lü ùnÏ[±[S2S|%yG ×¦¡Âi¦Ž8›ôدݽÞ:€ € € € €@¼¸‡;“´b§7r÷Þì^º~µÖ—ù¢ö抿ýµ\±nO¸È\×Sý“ Mwèµê&mªpõT3Ô‹ € € € €@B ¸‡9Ý5å+5rr©²í°Ý“±g+¿` òrü5Ú§®-ºn‘çÊ*+lÏ[±Sî¾A^Í55{T”?QÅv‘*å­þ½N­º!¬;Ý›ššôá‡êÕW_ítOÏ?ÿ|¥§§wº<W`Ø CX¡û=]t¦4ñŸø.q? Œ@@@ˆž@•¬ºÝñw¨aº<5±ÅçÈ©SÒ5»Ì>˜§½Ç¶k\È3O•%J?·ùª¼u:¶}ŽBŠHu/jÊà«å©F ôÆ©UÆ×ƒ ’iš:묳Zô²½Ç\×\sM{E8‡@ }ÖÒ2Eϸt¿µÌÌ%ç-αƒ € € € €@¤ÆŽ«úúÎ=OÓnû­·ÞRuuµ233#Ý•ˆÖFÑöûfeÉnçM¾òô°Ý>q¹¦äIežÄý]µ?;§¥òzÚÚr8*((Pqqq[E8Ž@·ÆŒ2´àÓº¯œíйC Ý»J € € € €m ¼öÚkmžkí„aô¼Šõ#Z›½.;vâT¥Û:ÞFq#ÐËŸ»ÄT~Ž©%¥.}tŒ_|éåé y@@@@>(@àΤeéóW©Òyz% ûÿ¯wYë\v®. ãîöÓkå=+pÓ妾xYsèþI=¡{ÏjS; € € € €@¼ ¸‡1£iÙŸW¡ÿºROŸ©m{ÈÙØ¨g­*w¬Õ„‹gøK,º^þ=6ˆmךý†î{Ú¥“§Ýc{¶è € € € €@, ¸‡3IY*¬Úte©¦M¼@éÉÉJM¦ñyóUå;›³FLíÛã>!ð­›L™bhÅsnëiÑ„î}bÒè$ € € € €@¯ ¸·;m¯“6f–ê«_PQ^v›5ä¯(Ó‘òyÚf N ›ÓPá4SuŸ6éG¿vÇf'é € € € €1&`4Y¯ëSŸë޳æ€^Ýÿ–ê>9)<©~ƒÿQ_6V™)ÝË!CTPP ââân×EtUÀy¼Iß~Ò¥«.1tg®£«—S@@@@ˆ†¡êêjeffF¤¾žª$©§*N¤zÓFdi’õà xH`è|‡î~Â¥aݺa<¿osÌx@@@@"'Ñô¬±¡Ázh¨SNë§¡¡1r½¤&è5aƒšC÷'çÖËûY^¦×&‚†@@@@b^ {ƒî{Q[Ö.ל)¹kÝÒŸœšj=44]éÖOjj² c¬rgÎÑÊ’-Ú³¿F 1ÏA@ 5Qà -»Ý¡G·»õúÿ° UkFC@@@@ ëKÊ4ÖªügëôÀŒeªèЯJ¥öÏzoÉ<­ÙZ¨ÙS'¨íÇ‘vX)@ >›ihAž©ûŸqéáÙ;Ôè…^Ð$ € € € €±+Ð¥Àý@y‰¾vÝÜÖƒöìåeÔð<£=~üCªzWUUA£/ÓüiÖr´nçcºë†ÑêR‚jb¢/ð¹‹MýýéÞM.­úw‡ÎJ'tþ,Ð" € € € €@¬ t*ïn¨­ÔÚ»ÇkQiÐ0r ´æßÿU9²5jä0¥¥´^UcƒS‡U«jO…6ÿd¾J=·ÅWhîä‹57§P/o(Ô„Lîw’e˜¸ñr+tÿTZRêÒ#Öîg¦ºÇô„Ñ9@@@@¨ t¼†{C¥nÛó 7hoõ5Yw»Ï›~ƒÆdh3l·G‘”’¦YctÃôyÚTÞ¤Ão¿ 5 òšXQ¬‰·lP]Ô†KC  ךý†î{Ú¥“§XÓ=¦Ô € € € Ð÷:Ü“êkœyE›õö‘SÚôÐ,ËÌ{äC³&iÞªíª?\¥ …9Òþ,+¶&"Ð{ߺÉôÜݾâ9·ÜnB÷Þ› ZF@@@ˆ£ÉzõDguªkhTRRŠ22X2&\ã!C†¨  @ÅÅÅáVÁuô˜À ëîö§\:o¸¡oÝäè±v¨@@@@ ± ÃPuuµ233c¢ã;ÜÛí¾S•»6jñœ9Ú¶ßé-Ù¨Ê- •œ>XÆ ÓàÁé2ÆÎÑ®ý,Ó.%'èƒý“ ݇Cûª›ôT¹«Ž€.#€ € € € 9ð÷ƃZ™›®ñ“g«xýzÕoôôªöÅjüŒÕ-{Xµ^“/¬û|¡|ËÓì!€@ßH`èÁ™ýöÕ&íÜëî»¡ç € € € €tS ìÀ½ò±ùZTh½y%öýjý"ÿÁœ‚ZSè}@ªutöü-< Õ¯Ãñ#0t ¡å3Ú¸Û­—÷ºÇÏÌ2@@@@®„¸7îWÉü2o;zùP½æŒ³Öiw¾¦í¥ÞÃ9+ôlÉ=š÷Ðv½°ÆºWìÔ»ÜäÞ•ù¡,}F`”µŽûÒÛzt»[ÿïzäÑ}Æ‚Ž"€ € € €$¦@x{ýq}èõ*Üý}M‘âÙs¾µGþþßoÑPo™Ë¯ŸâÝzWïnðnó†ñ&ðÙLC òL=ãÒÁÄîñ6¿Œ@@@@ }ð÷dɺŸÝóÊäÛ’Þz©ÜßÚ5Fù·SFW¾g¯Jï|Tï?ÎÄŸÀç.6ugŽ©%¥.Õ%t¿fD € € € €m „¸[µùW†±Â÷æW~·ÝwûËl¾ëÝ>×P½WÍ+ÍdkôÙ©Þò¼!€@¼ Üx¹©Éã›C÷Oê Ýãuž € € € €@K0÷dÿîsWnQM£t`ÇǨ|N$ùrê—«VywÎÓðÁ ÞW‚wˆ?éטºä Ý÷´K'OºÇß 3"@@@@Pð÷”1*(Êi®«t®F&º ¯Ø_wÑm×(IÚ·£DsrÓ5m}Uó¹œ\XÆ_ž ˆOoÞdêÌTC?xÎ-—›Ð=>g™Q!€ € € €ø ܭ«'}÷1fûª zÏY£¹¹öãRëõÇÕsµ¾"pnÚÙþ©޲…ñ*à0 N5uôÓ&ýèWîx&ãB@@@@À#và®”ÑzhïaíÞP¤ü¼<åY?E›uè7óN Õ³ó‹ôBu½fáöv>w$š@ë7`î›îÐÿûŸ&=UîJ´á3^@@@@ð¯´Ö˜“†*wÖRë§µ«ÓtׯéÖSÉÊHcÝöÖ„8†@¢¤YËÊ<ïÐÝO¸tVº[_úçð¿ëK3Ɖ € € € Ð÷z4õJJI#lï{Ÿ zŒ@ غÿ´Ü­?így™A¦R@@@@^è8po< Å¹¹Z¹£RÎHvµ¡Vå% 5eñ5D²^êB˜Èfhémýp»Û³ÄLÌv”Ž!€ € € € †@Ç{ýGz¹¢B‹òÆ+ݰ‚÷-/ª¦ ycÝAí(Y¬±©ÃtÝÜÕ*+Þo=^•$ŠÀg3 -Ì3UôŒK7%ʰ' € € € €@t¸§×ã»×)ǃaï3®ÖHk=晋KT^y@uÎÆ™êj´ïÅZ¹pŠ’RÞÜbUÙWehç_SF‡5PâIàÊ‹M}5×Ô’R—jºÇÓÜ2@@@@ ‘Œ&ëÕ)€†m[»HÓ•žV<;'OÇž§8ç Lh?¡†£èßO¯½\ª OºÞò²ÂÍ/«pú¥µ<Ì^ˆÀ!CTPP âââ3ì"Ð÷¶üÁ­?üÕ­GþÍ!ûÁª¼@@@@hMÀ0 UWW+33³µÓ1s¬ó»·Ë 5ûôÓÿ\ª¹Åea ¢`Åf-üÚ­‘Öõ‰v{¢Íxâwíÿuéj›ôÐL‡ú%º'Þ'€#€ € € € ô•À½ã%eBÆš2bŒæ<´]õGªõBÙä);¤L‹Ýìå/X¡­»«t¸¾I%÷L'loĉ-ðMÏÝí?xÎ-—»s¿p“ØbŒ@@@@ Vº|‡{ëi”³Î)gý1:e—HÖ€©JIIUZZJë—p´SÜáÞ)& õq§š´ø)—2‡šw³£†î#€ € € €DZ ¯Üá¡u]’”–‘áù‰4$õ!€@ü ô·–’¹oºCßyÒ¥Ÿ–»¬ªºÇÿ¬3B@@@@ þº¼¤Lü0"ˆû¡©ä;ô»W›ôë?»c¡Kô@@@@. ¸w‰‹Â ГC6‡î?-wëoº÷¤5u#€ € € €D^€À=ò¦ÔˆÝ°×q_z›C«ÊÜúëA¢Ú J.E@@@ˆ²{”Ái:øl¦¡…y¦–?ëÒÁÄî‹Q@@@@ Ücaèœ&påŦõðTSKJ]ª=Jè~@@@@bN€À=榄!€€OàKÿljòøæÐÝYOèîsá@@@@ 6Ücs^èx¦_cê3çºo‹K'NºóÁ@@@@ˆ]÷Øz†^oÜhjà†~°Í-—›Ð € € € €@l $u§[uô»²_éù?½¢w?tvPÕ1þï*+™®´Jrp˜†¾÷S‹7¹ô£_¹5ïfGði¶@@@@ˆ °÷ƃ»tý¨ÉªèÊ0rnScWÊSð ôK6ôý;úΓ.ý´Üe=P•Ð € € € €@l „¸;U:¿•°=;[ÙÖøªªZ¤u0½¿Âl°µ 9† &–jè|‡î~Â¥¡énÙUå… € € € €@¬„—7¼¥Ýe¾!ähà ëö+²”^m¾ŠxG::°9t¿g£KƒÎ®¼˜Ð½C4 € € € €DE ÛIUþ†Ç4ka{Tf‹F@À#9ÌвÛZUæÖ_òU> € € € €±!^à~Jò="õªñ#cc$ôJà3çº{Š©åϺtð0¡{BM>ƒE@@@bT ¼À=íl·k·^=ý_Íü? e+F›ÖÃSM-)u©ö(¡{”ùi@@@@ D ¼À]#4mQ§ªªâÉZûbMHµì"€Ñ°œú¥ñÍ¡»³žÐ=:ê´‚ € € € К@Ø9yí¿)_ëUjÕ:ÿê‘*/\£ûüe~ÆJN–NYËδ|YXwÆÉTض¬=@À#pÇ5¦j5é¾-.=t§Cý“ d@@@@ˆº@˜Ùw6Lžè Û}=.+ž¯²bß^ïÙktäµyÊhã4‡@p¾q£©æVñ6·–ÞfÊaº‡kÉu € € € €á „¹¤L’ú ¯A®BzBÀØ¿÷SŸXËÊüç/Ý=Ñu"€ € € € Ю@˜w¸§éÖÇ«téGÇ•lýï´ÕcZmò”’Ï:Ÿ»Û[µá DB Ÿµ”Ì÷ïpè;OºôÓr—õ@UG$ª¥@@@@:%fà.edÑ„¬NµA!@ ji©†Èwèî'\:+Í­/óy¢ÖcB@@@ˆ°÷–ª«=¬?øXGÿ]J¡ñã²T_[«äŒ¡J‰P+-Ûdh]`èÀæÐýž. :SúÜÅ„î­Kq@@@@ ’ÝL¡µoÇZM1’5xØH]œ­‰¯ÖÄÙ¿R£´åóÔš¤ò’¥º{ÎÂæcǤzkkœUª»L9Þ’ë—?§ÿU1¸ÑèÔ¾]kuuÐ m÷Һÿè6WùJdkÅÖݪzc¯6åûªª8Oë+ûʽýþn³@\ LoêKÖϽ›\r't«Ée0 € € € €@ „¸7Të%ï:29+^Öœ # € € € €@ „—~§ Ñxëù¨eV(½lá*ÝùÚCÊ AñäÌžcúýÓÏzÏž§áƒÃk2¤úî¦hÒôyšä¯±Qýwv¸7¼§òŠæ ² ÿU£T«ò-?×ï^©ÔÇÇ­ã†hÜç>¯›oÊÕ’v¿,Ä‚@¿dC÷ÝáÐw6¸ôÓÝ.}õ:B÷X˜ú€ € € €ă@˜éw¦®a= µÊJ«Š5*Wz¹t™ü‹Ë¤÷—½ˆLCí~=³ê{š]ìM§ó&ë¢öo†Sûq¯í¿ª÷Ëw{UñJ}ÉŸw„ Wk®²µn÷ÍÉÍ g z]àÌTCä;´ð'.•îÖ—‡¹ºV¯„ € € € €Ä’@Ø)Ó¤»—ÿ± Åš82UéÙs›ÇV¶J_Ê«Ôa[a»/š–¶>úUeÄÒèÃìË©SÍ+Ø[7ù[/+loÞPvN¾ ò‚j­ÒÜëF©dŸoÅû Sl"€@¯ œ•nèÁ™=UáÖ½áîÕ¾Ð8 € € € €@|„¸+)K«ŽìU‘u£ûé¯*UT/‚nÝéýò!MÍŠ¯õUìz²öª|í|ã°^+ߤ’’í:u¤ª…ËÜù[xhêéŽ Ðëç5ôýÛZ]æÖ_6õzè € € € €@ßsIï 3Æiiù)M{ñg*yô'VhÕ¼°J¾u—wézûÎö®Y 9³oQfÌ/%ÞDVY‘ûÖ·7膬eRÆ--{Y{Ó'6/=S±S¯;çhBMMMzóÍ7µ}ûöNwðŠ+®ÐðáÃ;]ž‚$²À%çúöSËŸuiÅW5ÜHdÆŽ € € €DEà—¿ü¥OJ£Qh$w©1§v•<§ ¬¤$ž4]«¬Ÿ‡TJJKKÒcÔ+5-MÍ 4ªrË2}çãôë’©Š«ûÜó¾®/…í~Æ´K4ÅZ]¦Ì»¢N²ÿD×6Ün·*++åtv~Yš#F¸w™Ò .0q´©ÙŸJK7»ôè¿94l¡{‚$> € € €ô°ÀúõëÕ`åÉñö 3p—>;[“wÓ¡íó4«’”’¢4ošžf…íö«¡fо>Qž¥ÜsÖÉ~$i_ÜÓF]*{¥öÀêôöHC_©:w¼µÞŽ÷®ÿгÝw8ºýöÛU\\ÜÙK(‡aÜ0ÞTº/)mÝÓº‡ÁÈ% € € € €@§vìØÑ©r¾B†Ñ7²šð×pO·†Z6_#§”¨Ö7êïN½¸q¡RGzÃvûÜÇ'Z”è³;ÉA÷«—Ô‘VR§?W4/±cŸ¶nüç…1.pÇզƌ²ÖuÚ¥§XÓ=Ƨ‹î!€ € € €1'vàÞß7”²¹6sc‹ÐÝy \ ǦëêÙ«}¥<ï ]¥0–1oQGLì¤\¢ü_OŠõЖý¾ÿ{Ýž§µÈ—·ç\©óãbàþá±@Ü |ãK¦2Î0T¼Õ-—›Ð=n'š!€ € € €= fàž¦Y›ª´ÀסÒÙ6g‹jê´kí¥_pVWùNZïù+´÷p½VMç]Ó=è\ŸÜLÑM 7ø{¾~ÆÅš³v—jœ ÖBÿNíÛµV×Nœï?_tÿÿgïNà£*Ï=ŽÿÏ™L a a K€€ì‚ . Á‚VD!*‹&¨H ¨­XÑšjE *‹ЍlÅÛ*X jIØT ‚Ȫ¤’@23÷Lh€Éd›™üN?¹9sÎ{Þ÷y¾'—{ûäÍûUTñ'N@À—LÓиߘú_®K/üÕéË¡ € € € €€ xYp·²ï¬ÉGN)ºÏ¬aõÔ7uÖ))&hÆÇÛåzýaÅGùûÊí§¤e†¶¢53’Š/ÎJí«&a²Û#×7U'~ß7~‰êE¹½Šü@ Ønè·Û´í;—æ}ìðƒˆ @@@@À¼/¸»£/(º¯Sñê*§d”4q±vç,WJŸØS®úÛéÙ×é‘òº¶ByIÒ´@϶¦†]iê÷óÚ÷cÙWâ h,’C@@@ª©€G3ÜÛ$¦ëãNûe·Û½gr/-ÕŽÙíÞ ò$T±ÀµÝM¶¶jpÝ' ³)ÜZb†@@@@ÜÃc:«o¯E"¾#€*p{oS¸4ÁZÓýOwÙb§è^¡àtŽ € € €ø‘@å,)³k¡Ü»È}žÕ?Â!T@ $û®3U/ÜPÚb§N–—)Ɉk € € € €@uðh†û™ar•¹ê}qø¸‚ÏÐ(88XÏ.¼»âS}›-E‡Ÿ¡1—@?0MCãn6õ¨µ´Ì ï;5:ÑæQ" € € € €@E ”¡à¾G3û7ш%ž…'edÈZÞ³ö´B|Y ØZJæñÛlzpŽCs?vhÈÝ}ù} € € € P^/)“9wœÇÅvw"îbûøO*>´2Òb @ âj…z*ɦå.½ÿgÅÈ € € € €>-àeÁ}Þ›<¿(±ÍY¹]û¶/SRÑ•¸‰Ë´{ß>m]¹@‰ÅéOÔ˜A‹?q‚‚@ýˆÂ¢û‚OœZ½…¢{ ¼Sr@@@@¼ð®àž½Wë¬ëîcô’9Ò+VQ±×jä3…åõHkE÷è¨(µë5Hoï^¦„‚–tÏÔµgü@ šGYËËÜnSúR§2³ØD5Þ-¹ € € € €¥ð®àn­Ã~bßÓv-ëW£váéŠ_ÉÚµàоV//]p¾$u‰v]ç Hí›{“©'9´óŠîônÉ@@@ðTÀ»‚ûzoÚµOáÛ´/ÿd£­Z}Ø¢½'*ñ'os†„@϶¦†]eê±ùíû‘¢{@¼T’@@@@J!à]Á=OÅ3Ø—-ÛR<\P¢óåúj_ñåÓN¬Éñ €@À \oêú L=jÝ¥è°/šÄ@@@@¼+¸‡·Qÿ¢R—Œë©;ž\¨Ì=¹ osAÑ&©êûÄB.p¿Þ™ùjñÐV­žhÛ{›êÚÒZ×}¡C¹Ç)ºôË&9@@@@àï îÖ î‰cfw3Â`%Í·fº‡vPÿÂ}S¥YƒUÏè¢.F U´Ãª:¨~Xñcœ €+po_S‘á†ÒÞvÊá¤è°/šÄ@@@@S¼,¸KuãS”õqzqW‘¡îÓP%N8Yˆ—2¬ÿœ<žY9F±A'?s†ª€izø7¦ŽsiêûÎ@M“¼@@@@Nðºàîî#¦Ï(¹röiëº -JŽ/èÖ]ˆ?²ýcOŒ“╜” ¸„d-ÉØ§‡{E24§ €@` úÃí6}¹Û¥¹;;Y²C@@@GóÍïX¥ek¿µ¸êéò[¯Uô©O…F©]üé…ôðØ>zú½z`@ š Ô 5ôT’Mc^uXKÌ8uã…eú=g5×$}@@@@À·<ªüìüÛãqjõ–—ñµ÷C< € € € €@y xTp·‡4)/Böò™~@j$Ð,ÊÐãÖò2éKÊÈbÕjôêI@@@ª‘€G÷jäAª €@… ´ofèÁ›L=µÈ¡?Pt¯0h:F@@@ªH€‚{Á{:¬a½¡ls¯§Íi‡>.У­©áW™zl¾C?ü§<{Z@IDATHÑÝÇ_á!€ € € €¥(eÁ=\ö°RõOã2 ˜Á.í ù—>ÝóN{âqðkâMÝp©ß[E÷#G)ºûÊ{!@@@@ ¬A¥ë CËÞ[ªÝÁÒñÒ=XغVK]ݧ³B½y¶š>ãÈ5›ÛGd½¤ŸŽPß)ÕT‚´,Ûz›:˜íÒã J»Ó¦Ð`#°$@@@@  ”ºà>n@¢÷Lqé:´‘‚{iÃ\u56~¾fdÞ¯ý9»4¨í 2Ù¾¶´Ž´GÀ×îíkêéÅ΂¯Ço3e³Qt÷µwD< € € € €@iJ¹¤Liº¦my Ô m¤1Ý^Söñƒšž1BGóŽ”g÷ô…U `š†þ©Üã.Mý«³ "`H@@@@ò(å ÷8Mœ3Ní½^R¦XÞû×TS#:OÓ¢¯žÒóîн§+2¬‰÷ò$T¹@p¡Ço·éÁÙÍýØ¡!Wت<&@@@@ðN Ô÷þIƒÔ¹”OyO•$`3ƒ¬%eþ eY34iC’FtzQÍ#:–Ô”k à'5C =•dÓo_u(2Ü©/äüäÕ& € € € pš@)«:ÙÊË9íy>T‘@ß#tsìCz1#E™VTQ ‹å%QXt_ð‰S«6³¼Ly¹Ò € € € P™ÌU¯Lírëü†×©NH½²ù·ºþØ>õj2°œG ;¨LfQ…ËËLXàP횆âZ°‰jeú3 € € € PVRÎp/ëp<_Þ­ëœom¦:O;OïlVN3cËÛ˜þ¨LöÍ =t³©§9ôõ^WeÍX € € € €eð¨àžwlwÑ0G”WÆy¼üÖh©±ñóµó§zÕší~Ü‘[þƒÐ#TšÀ…ç™~•©Ç¬™î?üHѽÒà@@@(£€G÷–W?¬3f(}Æ}jd/ãˆ<^!áÁõ4ªë«}Oý|¸²¬qè*GàšxS7^`êÑ×:r”¢{å¨3  € € € P6 îuÛ]«””J¹E1¡e§+N تáŸWLD'MZŸ¤Žî¬¸Áè*\à¶Þ¦ºµ²Öu_èPîqŠîÎ € € € €@<*¸—q ¯DÓ05 Íx%4½C“7Ü¥í?þ·Gg((o{ûšªaèéÅN9ÝËÛ—þ@@@@ò à^žš>Ô×eMipÛ'4kÓhý÷‡¿ùPd„‚¥0ÍÂMTÝ3ÜÓßgSäÒØÑ@@@¨l î•-^‰ãu®Ÿ ‘q3õîŽçôofWâÈ …å)d-+s»MÛ¿wiÎGŽòìš¾@@@@ÊQ€‚{9búbWÍ#:êÁøúÏÞ¥Z¸íq9œù¾&1!€À9j†zr°MŸdº´t-3ÝÏÁÅm@@@@ J(¸W {åZ/4Zcº½¦¹ßiFæýÊÍÿ¹r`4(Hk-÷?ÞaÓÂ:µj3E÷rA¥@@@@ (¸—#¦/wUáûâf(<8ÒÚLõNÎÝëËáœA iýÂåe¦Zë¹gì¤è~&.#€ € € €U"PN÷|Þ¿GÛ23µví*­]¿Cî…K²÷ï·fSWI^ Z‚@i×íŸV§ÈË4i}’¾ËÞVB+.!€€¯ ´oV¸‘êSo9õõ^—¯‡K| € € € €@µ(cÁ=_™K§ª¿aW½MÔ>.N={öVÏ¡³ î¹Zxe…Ù»èÉ·×[Ÿ8|EàÆV£tCË‘zaãÝÚrpµ¯„E P Ï3u÷Õ¦[àÐ?Rt/M@@@@ (CÁ=_>yµâSµä—áE†^‰tËЄÝ–²P‡ÙŽÏU&гq ëøœæm¯íy»Êâ``ð^àên¦n¼ÀÔ£¯;tä(Ewï%y@@@(¯ îûW=¯¾VG‘š#€ € € €å*àeÁ=[ïNWÈŒ5»µ|æcúmʘÂkG¤ë¬GÊdål_¢„¢–³ž|G{ŠŸâÄ×l­±ñ ´åÐjÍÝò°òœÇ}!,b@RŒ¸ÖTTmCO/vÊá è^ :š"€ € € €å*à]Á=7K«‹Ö‘IxfRzD•“w¬8¸ ¢³ÐØ~š³d|á§ŒOµ7»¸ '>"P;$ª`¦û1ÇQ½¸ñýœ÷£DF à‰€in¢š›'MyßéÉ#´A@@@¨ï îÊÓ‰ºùÀ¾ÎVDð¢6K´m7Û§ž¬ „Øj(¹óT5©yž&­OÒþœo« †Do‚ƒ =~›©ß»4ç#‡·Ýð € € € €@¼+¸[³(OûöŸ»€V£AQó8Õ ;1÷ýD|÷Ó°éÖóÕEoÖóëïÐΟ6úJhÄÔ 5ôT’MŸlriÉZfº{@F@@@@ \¼+¸‡Gª{Ñþ¨ÆLÖ®BÊ/¾–¯OÞXTô©¥Ö£à^Lã£'W5¦[Û<¢—2ï׆}÷Ñ( J¨nèVÑýÍ•Nýém‡vþÀšî%9q @@@¨ï îŠÑ僋¶BÍHS‹>hížSfºG„ȽˆLîþmšûÈ-ê›¶¢0öľ:/¼"Ò ÏòèÖàjÝÛyšÞúêi­øöõòîžþ@ šÖ74ó~›Ö‘žã°6Suè«=Þ+œ®@@@@Ãe^YäïÐ{kM)ñá8%Xõø+2N»»x{Žn‰ =íÎ.©ääd¥¥¥½aÝu¯åþRƽjW÷"ÝÒæwr/;Ãþ#ðs®Kï­qiéœjßÌÐí½MµmbøODŠ € € €X†a(++K111>íáå w+§ XM>´N‹&ºŸžeÆ/Šíqš±fwõ)¶çç*;;[Ù¹'Ö9ÝÇ>E…5ÓØøùÚýó—šµ)UÇGý'x"E¹×u|¹©y£mêhÜŸxáqsڴ˻ߵBŠ € € € pfï îî>ëÆë±åyÚºrF'ž¬¼'%'˜ ñéK”ud£RzDŸ9 »“»maÁoL ã­Ï.ep¹™J±‡)""B=¦ëp)÷Åæ5íu4²ËË 1Ã4eÃPýtl¿/†IL pÐ`C.557Õ¦‹Ûzö]‡Æ¼’¯uÛÙ\õ,lÜB@@@J%P;˜©]¯Ašl}ý97W9yRxx¦?—£°ðp•Ã¥J¨<¶ø•¢nJ]m×ÂÔ8Í:DË¿ÌÿDø§~·›ÁÒáY½·c’&­¬{㦫qÍÖ§6áü@ Øn(±§¡ë/0ô÷ .MûÀ©ÁN%Y³à{´5 ~Ùèi" € € € à“e›áþ‹”‚BC­b»{ö ë»Ûó³•ùáTõž°â™yöqÇÛã5¸¸Ún=sijçü¥•{¤›Z?¨kb’ fºqx¿„Nœ ð ›¡ëÎ7õòH›ú÷45çc§FLwhå&§N–›ù@@@@Ê6={—–¿ÿ¡>úl½žsiï£:9@ÓŸî§pB«¬F¹Z>óÏZ´zfÍ_âõ ù»–êæ%o!ëu§>úà%Ñ·¨nH#ÍÞü nŠ}P=÷÷ÑH Î%`3 ]ÙÕÐ] ­ÞâÒ¢UNÍ]. ²6W½¼³!waž@@@@À3¯ î¹»>Ôu-úªTsÁ.ÕTÏâªÄVyÚ4}‚fe”eÈ]Jë—¨2uQ–á«àÙ‘—ê.¯hFæH>öƒú¶H©‚(ÊKÀý,½:º¿L­ùÂYPxÍúþ¶^¦®´Šñî¥h8@@@@Î.àeÁ=[ó†–²Ø^DZ³GS%wíê6.]ÏB¢Ÿ´zú8Í/Eõ|Õ“C5¡¨ý3KëûĪsÝ›†·ÓØøùVÑý~íÏÙ¥ÁmŸÍ´WÉ[dP(?žmM¹¿Öïpê•NÍÿDhm¸zM¼!÷æ« € € € €% xWpÏþJËŠ§¶'iIÆ3º®}åçç—¨¡EÕö¤V±¹h±œS~á:×";%¾?¾Ø·ÅÝû ^ÌHQæâu‡ü8#BG_ ´hhè‘6MM¶é õ'=w¿àÐÌÚÿ…÷_Zñ@@@ª—€—k¼DéöÓ•Ú;Uʧ&}~ÔÇÓGêâ ,½³•˜ÝËÎx9¤½—ìm 7tVaDIsôrJç“Ñ…Õ(^nG! ;yÇ«3§Ó©Ï>ûLS¦x¾ kÿþýÕ¢E ¯Æ+‡Îox½ê„4Ô+›«ëíS¯&Ë£[ú@hièÁ›lú!Á¥E«œJ™æPBœ¡ßXë¼G×cw{]„ƒ € € €€O L›6MyyÖìå;¼®~GõºO3”ªniº¢}Ú¹iÒuhù(Õ=wKŸnñÕßß:ßü5±þF´®Ô°¾Žîœ¢ù'î.yM©c6JŽêªGŸÓ-í¼[læÀÚ²eˉ^ÏùýŠ+®8g›ŠnкÎùcm¦úRÆ}ÚŸóúÇŽ•ix÷+ý#€@ÙÖ14êF›’.wé­ÕN=0Ó¡‹Ûp‰©æQÞ˦ËÓ € € €¦ÀÖ­[uüøñ€KÎpY‡7Ym[˜¢öƒ‹fy{ÚA «àžâãwkmöþEËÅ$jÝ‘÷ÿ‹:yæÌþŠqbõvÏ’fÝ!=_ú_5DFF*99YiiüBóP*µUöñƒš™9JµC¢tWû?)ØV´ôN¥FÁ` P™?ýìÒ;Ÿ:õÁ:—Îo]XxmLá½2ßc!€ € € h†a(++K111>šw3Üó·iòiÅö%î©È³®Ÿ’£œ:1òn@ß2¬Ñ¸•oK+ß’ÎÑš´)*\½Ç¥ëÐÆQ¬ù~¦SorÁÝçѼ#zyóhö‚UCƒjžš>ç PÍþ½Í©7W9õãÏVáÝZ÷½OCÁÖŒx@@@¨ÞþRp÷rI™ …DVïLöå#Páû­åeƒ#­ÍTïÔáܽåÓ1½ €€_ \ÔÎTú=Auƒ©6:54Ý¡¥kÊ=îÕcù¥A#€ € € €€ÿ x¹†G¸n}9C]•ÝúϯV)Ñ#Oöú­˜Ý^¢Mõ¾dÚugû§õþ×S5i}’FÄMSÓZm«7 Ù#Pͺ·6åþÚ´Ë¥ÿtj¡õuË%¦®;ßPf¼WóÒG@@@Àg¼,¸Kuc;«G¬ÏæE`~(pc«QŠ k®>®»ÚÿI"/õÃ,ÊS SŒ¡´;múb·« è¾ÈZçý枦n¸ÀPx ïåiM_ € € € Pv î‡w¬×†=?ËnMeîv‘bëJ;Öÿ[Ö¥ÒÁѺȪÒ{4héz¦u€ôlÜ_uCiöæ‡Ô¯Uª.‰¾%@2# (‹@Û&†ždÓ×{]zc¥SCÒºñBCý{˜ªS‹Â{Yly@@@ÊOÀ£Ú÷ο=¨+RWŒúÌš#z¸‡ô·¡½Ù4µüÞ="жnO¥v­™÷ëPî÷º¡åH¹7Eà@Z52ôè­6}w °ð>ü‡®‰7tóE¦êGðï?! € € € Pµ¥Þ45ÔîØÎ¦©UûÞ~ôèZm46~¶Z­¹[VžóxÀçL‚ à¹@Óú†ºÙ¦i#l:zLJ~Ñ¡ishïa6Wõ\‘– € € € PÞ†Ë:ÎÕiîžmÚøíOV³:¯{gÕµæÅgïÊÔ–½¥ß45>6ê\ÃqÿÈÈH%''+--픫Õçô˜ã¨æXËËä8þ§äNSUÓ^»ú$O¦ à±À#.-¶Öwÿh£K—v04ÀÚ`Õ]”ç@@@@Àp¯€‘••¥˜˜ŸNÈ£‚»OgàÁU÷‚»ûõ:]-þ*M_^«{ã¦[«6 ð·Nz à­ÀÿséíOZ¶Î¥ Ï+,¼»—¡á@@@@ÿð—‚»GKÊÞ±J .´¾>Ôž|ÿ~1Dï¦aÓÀó~¯‹ߤç×ß¡?mô¿$ˆ*EÀ½êÝWÛ4w´M­ ¾ÇÍsèÉE}±ûœÌU)ñ1 € € €¶€G÷{\ƒ¶¾žÕ·9 Bv¾+pUóaºµÍ#zÉÚLõóýÿðÝ@‰ ª\ <ÌÐ}lšgÞÛ46ôøB‡&,phë·Þ«üå € € €,`­Æ~îÃÒ¤¨Q„µ]*U'ЭÁÕªÒP³6¥êpî^%4»£ê‚adðy!†nëm¨OCü×¥§Þr(ºž”t¹©.-=ú³ÏçH€ € € € à;T|ç]‰‡-kwÑo»½¦U{é­/ÿX°Æ»‡Ò ª©@h°¡›/65'Õ¦ÞM=¿Ä©Ô—óõŸ/ÕT„´@@@@ "(¸W„*}V¸@Tæ?_»ÿ÷EÁl÷cŽ£>& €€ÿ ºñBS³°éºî¦fýŸS÷½”¯mqÊéd¹ÿÃd€ € € €@Õ ”²à.{XÕÌ蜨i¯£‘]_Q°ªô Ãt䨷øŽœUÀf3tM¼Up¿ß¦—˜šÿ‰S)ÓZ‘á”ÃAáý¬xÜD@@@3 x´†ûɧ3´ì½¥Ú,?yÑó³Z-uuŸÎ õü Z"pV»¬¡þ¬÷¾~^Ï­¤{㦫qÍÖg}†› €À Ó4”gèòΆ>ÝæÒ¢UN½¶Bº­—©>Öu»5#ž@@@ðT Ô÷q=íû×íâÒuh#÷_Ãp¥,†aè¦Ø±Š k®)†jXÇçÔ¶n²tɳ PÍÜÿŽ\ÒÞýe곯œzc¥Óšõ.Ýz©©«» ±Sx¯f?¤‹ € € €€W¥,¸{5!P)—FPÝFš½y¬nnýz4*Ã/‡*%bA_¸ )÷WF–K ÿé,ør/;Ó·»¡° ï¾øÎˆ @@@_(eÁ=NçŒS{¯—”i'–€÷•W˜qtŒì¥º¼¢™#u(w¯ú¶H ÌDÉ *\ ®…¡¸6mû®°ðþ¦µÜÌÍ™ºáCµÂ(¼Wø `@@@üP Ô÷þIƒÔ¹”Où¡ !û±@Óðv?_/eÞ¯9ßhPÛ?ÈfÚý8#BGªh×ÔÐÄÁ6íøÞ*¼[KÍ Iwªß…†úõ0U§&…÷ª|7Œ € € €€¯ ˜¥ ([y9¥{‚ÖT…@ÝÐFÓmž~:¾_Ó2FèhÞ‘ªƒ1@ €bzl MÏ·éûÃÒð©½òw‡qP–¤‚ € € €e(eÁ½,Cñ,•+TK÷vž®ú¡M5yÃÖ3{*7FC€hehÜolz1Ŧlë—Ð÷¼èÐôúáG ïùÂI @@@RPp/MýOÀfiP»'ßàZMZŸ¤oŽlö¿$ˆ|R q=Ccmšy¿M.«Ö~ït‡¦,uh÷A ï>ù @@@Jð¨àžwlwQ(G”W A1å-зÅÝ;V/f¤(óÀ'åÝ=ý!€@5ˆªmèþëmzu”M5C¤Q³úó»eý@á½ÿX: € € €@5ðhûÓ–W?¬3ê˜"Õˆ½'«éŠÿ§}~ÃëU'¤¡^Ùü[]ì~õj2Ðÿ“"𺵠ÝsM{¹ô—;õЇº¶2t륦ÚD³¹ªÏ¼(A@@@ <*¸×mw­RÚU`t@% ´®s¾Fw§™÷iÎ7êoÍz7 þУ’"dðwˆ†îºÂ¦[.qiéZ—~?ß¡vM ÝÞÛ,øîïù? € € €œY€Jã™m¸ j¶ÔØøùúú§ š½y¬Ž;r4SÒBª¨jÙ/35o´Mc M|Ó¡‡ç:”‘ÅR3Uù^@@@Š à^‘ºôí³áÁ‘Õu¶\rjêçÕ}üÏÆJ` àß¡Á†5ÛÝÔ\«ð~i{CÏýÅ¡1¯äë¿_9ý;1¢G@@@_ Ppÿ ª‹@°-TÃ;NVLD'MZŸ¤Žî¬.©“'T@p¡~=LͶ6W½¦›©éËœ9#_ŸnuÊåbÖ{¼†D@@@ Ü(¸—;)ú“€{ýömÆëò¦ƒ5eÃmÿq?…O¬ à‡A6C×v7õòH›nºÈZrf¹S#¦;ôI¦S'…w?|¥„Œ € € €@±€G›¦·æpÜë…6Ö¬M©ºµÍ#:¿áuš)i!€€¯ØLCWt1Ô'ÎÐê-.-ZíÔk+¤Û{™J°®¹ ó € € € à_Üýë}m ÄÕï£ûãhæ¦tøØ^]Õ|XŽF× €@¡€aêÕÑýeê?_:õÆJ§^ÿDx©©«º ¶Sxçg@@@(§‚{¾ïß§öÔOG”ìÑꫜýûe¯¥ÐrÅ_P‰ÓÜë¹í6_/eÞ§ý9ßh`›ßËfòì¿o”Èð/ Ï3åþÚðµ»ðîÒ‚:5ÀÚpµowCîÍW9@@@@À·ʸ†{¾2—NUîz š¨}\œzöì­žCÿ¦|åjá• fï¢'ß^o}â@À?"Úè·Ý^/(¸ÏÈ©ÜüŸý#p¢D€èÖÊÔ³Clzl Mëv¸tׇ­rêç\Öx˜—L" € € €)P†‚{¾>|òjÅ%¦jÉ/i"C ¯Dº¿eh€î KY¨Ã¿lÇg|T †=ÂZ^f¦Âƒëjò†;u8w¯FJX Èí›z*ɦ?Z__ìviˆUxŸ¿Â¡#G)¼ò{'7@@@ÿðºà¾Õóê;ÁÚÝ­èHHž¨gFÇ~Šp U×£‹îZßf ÖïÞÞqò3gø¸@i×íÓÔ)ò2MZŸ¤ïþ÷…GLx ¨­£ M¸Í¦ç†ÙôÝAihºC¯þáCÙÞõ“ € € €€ xYpÏÖ»“Æg®-WûGÐD‰)ÓÀÐïn±é…d›~´V»ºû‡^ZæÐþŸ(¼ä ')@@@¿ð®àž›¥ÕEëÈ$<³F)=¢ ÏÉ;V pb›ÉÐØ~š³d|áõŒOµ7»¸ 'ø@ÏÆý5´Ãsš·u¼þµçm¿‰›@@ 0¢# íoÓŒûlÊwH)Óšú¾C{QxÌ7NV € € €þ"à]Á]y:Q7Ø·Ã9shVÔf‰¶ífûÔs‚ÑÀ'ÚÕë©Ô®³õ»féý¯_ËEaË'_A!PÔ1ôÀ 6½ò€M¡vé™=÷‡víãß§jôc@ª € € €>$à]Á=ïdûöŸ»€V£AÑqªvbîûÉ>8CÀ_¢kµÑØøÚrhµæn§<çq 8@ €ê…J¾Ö¦Ù£lŠ —ÆÎvèéÅíøžÂ{¿vRC@@ðAï îá‘ê^´?ê„1“µ«„Äò‹¯åë“7}j©†õ(¸Ópâ—µC¢4ºëËÿY/n¼G?çýä—y4ž@횆†^iÓÜT›b¢ Í¡?¼áÐÖo)¼ÞÛ&#@@@_ð®à®]>¸h+ÔŒ4µèóˆÖî9e¦{DˆÜ‹Èäîߦ¹Ü¢¾i+ sOì«ó¬™wø»@HP %wžªèšm4i}’öç|ëï)?@­0Cƒ/75o´M›zr‘C¾îЦ]Þè5“  € € €€ Ö:ÔÞý·ïüco­)%&§«¿bEÆiwoÏÑ-±¡§]ãÃÙ"##•œœ¬´´´³7än• üã›ÙZþíkJî”®–µ»TY ŒœIàxžKËÖ¹ôö§N5¨­‚b||¬—¿s?Ó \G@@@  ÃPVV–bbb*p”²wíýÛŠÕäCë4±h¢ûé¡dü¢Ø§kvSl?‰O"pUóaºµÍ#z)ó~}¾ÿ’i €@ Û %ö4 Öx¿¢‹©ÿê´6XÍךmN6€¤M. € € €U.à}ÁÝzÝx=¶}‰²ŽlTJè*O–¨(n ®ÖˆÎ/jÑ—ÔŠo_¯¨aè(“€=ÈÐuç›zù›{Xøœº÷%‡VnrÊéôîÞÊ#€ € € `Þ/)SD~n®rò¤ðð egç(,<\l‘ZT).±¤L)°| éþ£ßX3ÝïS»ºë–6ãd6ˆŠ@’ÜEöÕ[\Z´Ú©cÖÿý¾­—©„Άl6£ä¸Š € € €@ ø’2Ùš{G¹“¼cff1qPh¨Ulw¯Ñd}?Ylß¿v¦úXm;æ*»¸5'ž@Tæ?_»ÿ·M³6¥ê˜ãhà%IF 0¦i¨w'SÓFéî«Mýõ3§†½àÐÿuêx>3ÞæE“ € € €@¥ x¹¤Œ]Ê.ÜÕ“zæ’ZáN)ãKʯ´Ü*¨i¯£‘]^V°ªô ÃtäØ*‰ƒA@ÒôlkjÊ=AJ½ÑÔŠL§†¦;´dS¹Ç)¼—Æ‘¶ € € €Õ[Àã_¶-|D_Ù¢–…`;—~_2=Uý—],Ñòˆ–µUa¾ÄV\D ì¶ íðg½÷õózný`Ý7Mk¶¤ÉT >Ö”ûkÓ.—ÞXé,øúÍŦµö»¡š¡,5 ¯´@@@ÊIÀã‚ûÑ[”±bɯkæ+´ÄÓBzb'5ôxÄrÊn¨"÷’K7ÅŽUTXsMÙ0TÃ:>§¶u{TQ4 ‹”N SŒ¡?ÞaÓ—»]ZhÞßú—Sý­Vû]h(¼…÷ÒiÒ@@@ ºx\þnÖíbËd‰âââ¬ïÊ8¥È^xíìd-û דÜ*÷ ïT'K£¨nH#ÍÞ$Ý©.°~¡ØÓTZÞýüõ> € € €@9 x\pêõ°\®‡‹†?¬©]ê)Õ*º'¤¯ÓòQñåÝ!X#{é.¯hFæHÊÝ«¾-R+A²A€hÙÐÐ#lúî€Ko®rj¸µ¹êÕÝ ¹—›©Aá=àH@@@À#/7M­«ë'ÏÐèädõoQÛ£¾Q~®rsó•Ÿ›­ÃÙ¹Ÿ. –^ ix;Ÿ¯ ûÿ®×·>*‡3¯ôð PÅMëzð&›¦°é˜õÏXò‹½ðW‡öfsÕ*~5  € € à†Ë:JG®–Ïœªí“BB<}ú˜ŽÕ¾D¥ôñùeer·-TXûÁVbIZwäuŇŸ9Çý™jò³Ï*mþ «Qœâ2´Â½ÜNB’æ<ñ é{æ‡=¸©dëiii´¦‰?ääÿO¯nþ­õ#Ö ÑŽÏ«†ýl›ûCFĈÕYààWÁúî}îÒÅí ¼Ô”»(Ï € € €@y ¸÷KÌÊÊRLLLyv[î}yYpÏÖÌ>á®1—æˆKס£T·4ÏTAÛUOöQï îä­‚û{g,¸o[8FíO9k„ ã—胧ûyýK îgåõÛ›g¾Þür¢²ŽdèÞ¸éªí·¹8 àøñg—ÞýÔ©Ö¹t~kC·Z…÷V(¼óÓ € € P>þRp÷rI»wqožZº#ñú +Ý#•Û:?[™N-*¶Ÿ}èüoŸ^lO­Å¯ÔÊe 4ú”=1W¤%jâ‡{ÎÞw«€Í ÒàvßàZMZŸ¤o²·T;FÀ¨SÓа«lš“jSÓHiÜ<‡&¾éл]•(Ù € € € p/ î¡ê7yŽ9¢œœœ_}¹¯ïÎÚª§+¡xðD}Èû™ÞÅÝ”û‰{yœ'•rGÖÒq}S=áß §Ÿl—A³æ/)Åp‡µaʼnõt¬uÞÓ‡üb™œ õ¸ëakø¢#ãS}}âß8]à‚†×ëžNS´à‹ Z¹ûÓoò ðS!Özî½Ì‚Â{÷XCi‹zhN¾6|íôÓŒ@@@s ”¡à~îÎ ZÔí¡‡Ç%6ž5[>Wx¶«Û¸t=“ž®ôôš1ã%kµœì/õÞ‰z{Â¥jZ‚Eh]qÊÒ2öšp mꜯÑ]çiù·¯é/;&Éim¨Ê‚@ˆÝÐM™KÍ\ÞÉTúR§R_Î×Ú/œÖæÑÌz„wL € € €'‚NžVÜY“ÎñÅçŸùÊI¨z ¥^Åáä+dÙ8ÍÏ(¾ðë“ð.úýŒ‰ê²íÂZ¶Q‰Åôìzï”Ió¾—÷¯ÓâJÕ 4ªÙRcãçkfæš½y¬îlŸ¦`[I¿Í©Ú8ðFÀdèú ]ohy†K/ÿÝ©yË¥Û{›º¤½!ÓdƒUo\y@@@À·*¡àž¯OÞXä[YŸ5šœ³Þ-¼ª>)©Ï[î×Ü“U\oOì¯áglÌ Šƒ#5ªëlÍÛ:N/l¼[ɦ*<¸^ñ}N@°Ù ]ÕÍÐ] ­ÜìÒ+zÍú«±Û¬åg.ïdÈ}Ÿ@@@ðºà~xW¦¾Ü{ÔšÝmWI³·íִ?÷ií»Ï*uʉõW:¨~˜¿Rywîžµš˜ÔSi'R¶›ó§ßˆz»g~´RÁ¬öá'ëíÏhÒú$Ý7] j´€(÷ŒöË;ºÌ*²ÿ{›K‹V9õzQáÝ]Œwψç@@@@Àß¼,¸gëõ~qJ=Û²+%H$<ÓW±^ŽXBw¾u)w–N}B‰ãfWúÇYÒŽrûi(|8§€i˜Ðf¼¢Âškò†»4¼ãój]§û9Ÿ£ ào†aèbkI™‹Û›Z·ÝY0ã}Á?¥—˜ºÆZ~ƽ< € € €þ"Piåï„Ñ ôÎÃ'WJ÷ sÇ™­õo¿¤¡Æé´ß?$Œ×ÊùÔ+ºlkp»7”Û¼y³.\xîPŠZ\~ù劎Žö¸= }Wàò¦ƒU/´±fmJÕÀ6ª{þ¾,‘!€eèÞÚ”û+3Ë¥…ÖR3îåf~s±©ëÏ7BὌ¼<Ž € €ø”À[o½¥üü|ŸŠ©<‚ñ²à®Ûß]§N»~”ݽvÌÙŽàšjÞªƒb¢ÊVx>ÛUv/—ž½º…Ʋ|Œ”¨ÿIÃû´“—¸§¥ãt:µmÛ6¹==Ú¶mKÁÝS,?hW¿îk ™›СcßëªæÃü jBD¼èÜÂPZ ›¾ø®°ðþÖj§nêiêÆ Õ £ðî½,O"€ € €¾#ðî»ï*77×w*§H kµ«œú n²5·„†ìxš¨uGÞS|‰+ÂÖÜ;êièü“iŸ³R 饺'/•ù,22RÉÉÉJKK+s_tàßsvë¥Ìû[;^·Z³ÝmfyüJÇ¿Mˆª‡À×{ 7WÝðµK7^`(Ñ*¾×©Iá½z¼}²D@@ ÜK’fee)&&ƧILŸŽÎ‡ƒËœ;ê”b{²Vfåèér.¶ûpú„V‘aMôÛn¯k_Î.ÍÈ©ÜüŸ« †D*_ U#CÞjÓäá6íûI>Õ¡YÿçÐÁ#̨ü·Áˆ € € €gðhŠìámkµvÏÏ >[OžÜ³G«w¯òYjÅ“á*¬MþÍ.žÚž¨•‡fªWyNk¯°ÀéØßjØ#¬åefjá4ÅÚLuDÜ4Õ ièïi? à‘@³(CÝlÓ÷‡\Zd-3sÏ‹]ÑÅÐ-Ö« ë0ãÝ#D!€ € €T¨€G÷¯¾©§-Tî]Pqé:´±]¹.¹â] e{*ßWZ~JŸ¼>Uÿ>ËzCÇŽ5Р‡†(6—±?…ÓJ2íº³}šÞÿúMZŸ¤”Î/ªi­¶•4:à €U/иž¡Ñýl|™K‹ÿåÔ}/9tiC·^jªI$…÷ªCD€ € €T_ îÕ—§äÌsö~©Œâ[K4!µ`Á÷â+¿>IÐÕ£)¸ÿÚ…+e¸±ÕŠ k¦>®!žQûz—”¥;žEüN ª¶¡û®³éöÞ.½ó©S£f9táy†Z…÷ )¼ûÝ %`@@@ <*¸w¸cŽ2rd·—%ã<Ù#šúÙìöwKU~^iš¨Lt¥ŽöÕF gãþÖ’24gËCê×*U—DßRmr'Q@à„@ÝZ†î¾ÚfÚ]ú˧šëP\ C·õ2Õ&šÂû '¾#€ € €T¼€á²ŽŠ†¼ˆŒŒTrr²ÒÒÒ¼í‚çªÀžÿ}¥—2ïÓ… û醖#åÞµ™¨®?çºôþ\zÏ*¾Ÿ×ÄšñnÞ;6çßÅêúó@Þ € € îzWVV–bbb|:!f¸Ÿ3ƒülíØú¹6ï<,[[«?®Zu›*¦]ÅF• @_¨jÍnïm¨OCü×¥§;Ô¬¾a-=c¨KKÓ—B%@@@(cÁ=_Û>œ®ûú¦êŒ[ª&ŽÖ’ ÖrñÑFG:ø–@í(î:W³·<¨i“uO§tÕ´×ö­ ‰¨DÐ`C7_lè† ýßz—žÏ©záN ºÌÔm(¼Wâ«`(@@@ Ú”á¿mæjé#ÝÕþlÅv7ã’)JìÞD}žüP¹Õ†•D¨ Jéü‚ՌդõI:ó]Õ¨ €€ ºñBS¯Ž²éÚxS3–95rF¾þµÅ)VÖó¡E( € € €@x]pßóáD%¦e$$ל%Ë´fÍ­Y¹L fX÷ãŠokÅ„¾šøáž“8C 0 ›n;ï1]Ôø&=oÝwþ´±BÆ¡S@Àß‚l†®± î³FÚô›‹M½þ‰S#¦;´"Ã)‡“-müí}/ € € à‹^nšº_Ïvi qõö8ÍY÷‘†ÄG•˜ß®U3Õ¢÷ˆ¢{ã••÷´bʸM‰èE6M Ð[IimØ÷w½ñåD jûuº²’Fe@À?ܳÛ?ÝêÒ›«œúÙú3<÷æªWt1ä.Ìs € € €ø–@`ošjmÊøiÑäöä‹ÎXlw¿’˜^)ÊZ²K-Ó¬O[t0ǺÆ>ª¾õÓJ4+ЭÁÕªÒ@/o­Ã¹ß+¡Ù›+‰!€¥pÿ?k—tp™úì+§ÞXéÔ‚J.1uM7CÁv ï¥5¥= € € PݼZR&ÿ‡ï´³H.¾s“s6lZ§¨ÍN}w(ÿœíi€å'ЪvWý¶ÛkZµg‘Þúòi9]Žò뜞@po¢úüð íoê_Ö¬÷!é½û©S¹ÇYj&@^1i € € €•"àUÁ=(¢¡Z–&<û‰Æ:”cMqç@JˆªÑ\cãçk÷ÿ¶Ìv?æ8Z©ã3 à/]ZšúÓ]6=6ЦÏwºtׇ޴f¾ÿœKáÝ_Þ!q"€ € €U)àUÁ]AÅtMŸ½Bçš³¾åÓÌ¢ׄõdªò…3võ¨i¯£‘]^–Ý Qú†a:rì@õÅ s@à훚8ئ?ÞaÓWß[3Þ­ÂûkË:r”Âû9è¸ € €Tkï îámtkR¡[Æ”DÝòäÛÚ•]RÙ=[k>¢î#æ!wPí°jíMòT©€Ý¢¡þ¬6u/ÐsëëûŸwTi< Žøº@ëÆFÁl÷ç†Ùôýai¨µÔÌ+wèP6…w_wć € €T…€á²oÎßµTö‰§=š˜<^}âÏS}kûw;6jÁ„)*Ú[µ ÝÄwë±>ѧ=dz DFF*99YiiîMg9(?Õ»ßÒû;_аŽÏ©mÝå×1=!€,°ç K‹V;µz‹KWt1 6XªÍæªüÊI @@|DÀ0 eee)&&ÆG"*9 ¯ îîîö¬š©¾½GœVT/y))}¥æŒê¥ 35àz‰ÜKdáb9 l>¸J¯m¯›[?¬ú•S¯tƒ¾À¾]Zü/§–g¸Ô«£¡[/5]Â{à¿y2D@@ªð—‚»wKÊ©F÷JÑÆ#YZœ>Zq§JŸò!!i¢>ÞzH¯Sl?Uˆs|B cd¯‚uÝ—~®eY3}"&‚@üA AC÷_oÓË#mª"=0Ó¡?¿ëЮ}^ýá ?¤LŒ € € €”i†ûéýçjÿžt$Ç® ìÚóõ÷2#¢T¿N-Õ­ËF©§[yþ‰îž[ÑÒ{ù{õRæýjV«½µ}\6óäÆÈÞ÷Ê“ €@õpo¦ú—;õ×Ï\êÚÊÐÀ^¦Üë¿s € € €”@µ˜á.eký‡sõHJŠÞÞ–§¨èÅÆ6ÐWï?­v]»è¼VѪW/BF—}¸ÍÚiŒ|R nh#é6O?ß§é÷*'?Û'ã$(@ÀW"jºë ›æŽ¶©UCC¾îÐã Úú-3Þ}õ € € PÞ/)“¿KÏö‰P÷¾C•6k–öÍ/ˆoÿªçÕ}ð”Óc͘¥¾íëin&E¼Óaø„€ï„ÕÒ½§«^h´ž_§åîñàˆðš¡†n¿ÌÔ<«ðÞ9ÆÐ“‹ÿšCYÞýä& € € P&¯ îë§§jÜŠ“c‡l‡š«¿ÍW|1!ù¥O,þ<4u¡˜ç^ÌÁ >'`3ƒ4¸ÝDÅ7¸F“Ö'é›ì->#!€þ lè–KLÍMµé¢¶FÁúîc_Í׺íNŸ@@@¼òê¹ümš™º¤èÑd­Ù®Ñ¡Ö 3kõÞü¢Ë ÏhÑ̇e}ìÖ¨¿z»Û¯X¦Ù)bIw¯ÔyJèÛb„ê‡5Ó‹“ug»?ªSýË*mlBI Øn¨_C×oè£Ï]šö7§j†:u{oSµ3ä^ƒ@@@ p¼›ážsT?ŒÿøñÂb»õ9û«µ*.Ãßݯ ØînvÁÕý‹ZïÔ×ûr‹Îù†¾,pAÃëuO§)šÿÅcZ¹û _•Ø@Ÿ²º¶»©—°©OkÉ™åNÝû’CŸd:åt²ÜŒÏ¿@D@@<ð®àn—‹ˆ©sâLújõòâa/ëÑ¢ø<´Ew%|ÊÐ×rНs‚¾-ЦÎùÝuž–ûšþ²c’œ.–Bðí7Ft àë6ÓÐ]L͸ϦÁÖZïoÿË©äiýcƒS…w_ć € €œKÀ»‚»Õkñö§Vñ½ð8¬Þ;1¿}´âc¬%fŠŽÜ¬u*\i&Ní…¸ÌwðF5[jlü|íøqfo~PÇü•м6‡µ(ª@IDATBDp/%Ó«£©Géž«M}°Î©aSúÛgNϧðîã¯ð@@@3 xYp·ÏpñìBíÉ—v,ýóÉMT“/QëâÕá³õ×É“‹h©†õNâÏ7@À§ƒ#5ªë«rÉ¡6Þ­ìã‡|*>‚AüY G[S“ïÒèDSÿÜìÒÐt‡þòo§rSx÷ç÷Jì € € P=¼+¸‡vVòÄ„B±ù#ÔÄÚ¬ubZ±àÄ—)HùÊ\:S)}"4`VFὄ>juršâöœ €€ï ÛÂ4¼ãd5ï¨ç×'ißÑ,ßš@?èÖÊÔ³Clzd€Mëv¸4dŠC‹V9õs.…w?z„Š € €Õ\À»‚»…Öë¡éW‚^BºFô‰²näèÓ)#4kÅÉ6sÒ‡o¤zò*g à/¦aj@›ñº¬é`MÞp—µÌÌz 8@¿èØÜÐSI6=i}}±Û*¼[3Þç¯p(û(…w¿y‰Š € €ÕV xá—R „¶ÓÓëöéÊù34ç½ukº7ì~«?èWEõ¸¤‰zñ©‡Ôë”uÝK= €€Ï\nÜë…6ÖÌM£4°Í£êÞ°¯ÏÄF  €@ ´‰64á6›²~péMk¦»»ð~ýù†n¾ÈTZF ¤I € € €@@ .먨Œòs³•gWÝpÖm÷Ö822RÉÉÉJK;¹d·}ñå-°ëÈ&«èþ€šÞ¡«š+ïîé@à︴hµSŸnuéÊ®†n¹ØTTm ï§qŠ € €,`†²²²ãÓYz?Ãý”´ò³÷këçë”ù­µ‘bp°‚[ßê5ÔyíÛ©u ‹¶ŸBÅ)%ÑIc»Í×K™÷ê@ηºÕšín3Ë埕€r"@ <šÖ74¶¿MI—»ô–Ux1Ý¡Ë:ºõRSêRx/cú@@@Ê*P¶îù{´ôù'”8nÖ™ãˆKÒ‚ÿ A½bÏ܆;g`†ûi¸áCGóŽèåM©²ÛB5¬Ãs ªéCÑ  ˜¸ôö§Ný}ƒKµ34Ð*¼7‹¢ð˜o›¬@@@À_f¸{½iªòwè{“³ÛÝ?ó5¸wkuóvÁ:ïüh €@à Ô°Gèþ.³T3¨¶¦X›©þxì‡ÀK’Œ@ˆŒ0”r­M¯Ž²)ÒúƒÂ1¯:ôôb‡¾Þ[a«ú˜á € € €¾'àuÁ}íó÷èÔUÅ’'jñÇk´u{–¶oÏÐÊe 4>)®8ãŒ)ôàÂmÅŸ9AÀ2íº«ÃŸÔ1ò2MZŸ¤Ýÿû2°$@ÀGêÔ44ôJ›æ¦ÚcÍpÿÝ<‡þð†C_|GáÝG_a!€ € €@ x·¤Ln¦î‹Óü˜8-X÷‘ÅG•È´ýB]Ù}°2 îŽÖö¼ÉŠe‰ç­JºÈ’2%©pÍ×þýý_ôÞŽIÒᵯw‰¯‡K| €@@ äs鯟¹ôî¿jÕÈÐí½MuŠa©™€zÉ$ƒ € €@5ì%eòòŠ—‡Iš3ÿŒÅv÷{Фw/úØim¬X Hj&pQã›4ÔZË}î–ßéÓ=ïT³ìI¨Z°C¬õÜ玶éÂ6†žyÇ¡‡æäkýgÕÆè € € €@5ðn®¹]²– -8.íÞæœLŋτËz”ª@»z=•Úu¶^ʼOs÷膖#åþM$ €@儨 %ö4tÝù†þñ¹KSßwªvMgÁŒ÷çü›\9¯Q@@@ š x·†{žŠg¸¯_—uN²¼Z'f¸gËz”ª‰@t­6z0~¶Z¥y[§<çñj’9i"€¾#`rÝM½ú€M7^`}ÿ‡S÷Ïphå&§œNÖy÷7E$ € € ÞÜÃ;èÖ¤Âôg ý–ïÉ?³Ev¦þ<®h{Õľ:ïÄÔø3?Á Ú! 4ºë\åägkÚÆdýœ÷SeG* €€ÿØl†®ìjjæ}6ÝÖËÔ›«œJ™îÐGŸ;åpPx÷Ÿ7I¤ € € àËÜs³ëðáS¾²¥¾.(Êk‰®hÒ]Ͼ½J{²s ®åççêðþ]Z»t¦úGÄiJᎩZð§AªëËĆ"TC)_P£š±z~ýÖ^ßUÈ8tŠ pnÓ4Ô»“©i#l~¥©÷?sjø }ð_§òò)¼Ÿ[ € € €À™ —uœù¶ûN¶fö‰ÐˆgoåÑݤÿgïNäªÊôÿ?UÕÕû¾%é,}ïe“-¸ ÁE%( “dÄ™tÈàF@‚ŽËøùè Ybè!„ÙÈÚ[º“ô^õ;çÞªî®^ÒN/µ|¯s©ª[w9÷s{ yòæ=÷¨æáe„îÂrw*((ÐÒ¥KµbEèo űìŠ@4 <¹ý~­Ýñ––Ý­ÉæäX@F_ÀN¨úËçz{·4¡PšXèÑ„³š÷ãÍëøÉö„gA@@FKÀÎ ¸uëV•––ŽÖtÝÁMš: S÷²SEs/Ù„‰$ðáI—«0u‚VU\¥ÏÏúwWô¡Dº}îˆJ…Ó¼²ku}P;ª‚ÚY-í4¯Ö™×ꀪê¥BÓp‚ âMãíkQA|T>T… € €£"0€À=Kç­xL)oTrò1Œ±¥EÉ“N¦ºý9x8¾ø#²½ÝïÛp½j›vkÑÄKâåÖ¸@ ¦ ²=²ëqS#o£¥5¨÷jÜ~g•´igÐô~wƒùö€[ï†ð¶2Þ­·Uñ©É„ñ‘’|B@@x@à.•œt¾.=)Þ)¸?I©9Çé†ãÒªÊ+UÕ´CŸšþuy=šVb$‡Éµ@Œ@²i'3eŒÌÚ3@¯i0Á{—ªø§ÍÜ=;«ÚkæÈÎÏ UÅ›ðÝVÇO UÇåHö¯ƒ² € € €ñ&0 ÀýØnºM»6½¨ÇZ­'ôiý÷íç+õØNÈÑ 'Eé“tãñk´zõ¦Úý:]:÷¥øÒãäî¸ @ 1ò³<²kù”Èûµ°î WÅ›5[võL¥ 祖6Û>2„·¼Ý–žB)É'@@ˆ%a ÜkwUê/?ª•ËoUÇ|«‹NS£Ñ!p¥ÆŠÀð d&çéš?ÕÛþEw­¿\ËçÿHÙ)¦’@ ¦üI•ˬ=ôºƒ}âwV› ~ƒ âÚS'åf„'m¬Ž/6Uñ^oÏsÅ4ƒG@@¸ÒÀ½­v—^üËãZ³r¹Vw¤ì]̪™4µ‹o@ $à÷¥è²¹ßÕ£ïü@ß[w±®,_¥qÓðAˆSÜLrM»™ù¥‘z[{P»mU¼ ám%ü;{‚zîu÷}S«©ŠÏ áÓ·f¤Fž'NÙ¸-@@ˆcÜÛjUùâSztÍ*ÝÚkÊî*,¹þ]|Éb&M †ˆÀhØ^¾Ÿœv£ŠR'jå?.Õ—æ}_3óN¡pM@QHò™>ïE¦Â½¨g€^Ø Þw8ýâƒz~£ù\púlÓÌNÖjÛÒ„Cxû~L®ä£*~”ž&—E@@ 1¸7i[åßõÇ_®Ñò«û”[lBöË?{¾N_0[yô‘éÓ‰/@ Sà´ñŸ1ÿ¾§Ÿ½~ƒþiúM:iìù_ò@ a²Ó=š;If ãÛmU|mgUüvÈ¿°É†ñÒ¡&©ÄVŘ ÞNØÚ%ÏJ‹2„·Áü8óËW{N@@@`0 Ü÷¿ü ÝpËÅZÓ[_v{ÕEKt×Kõñ…‡ôÏsÎuÃxÿ`†Ã1 €€+01k޾ºðý¤ò*U5îÔçgý›i À¿Xøù@¸€­bŸ3Qf ÐÛAí5´îtÚÓ¸¯ÛìVÅ×–Æu­Šwªãm«)'#ò< {"€ € €@¢ (pßñò¯{„íå&d¿ð¢OëÓç®Ù%¡Jö¦uŸ(rÜ' »@^êX}åø‡œö2«*®ÔóïTZRÖ°_— €Ä·€íën[Í”ä{Ô}¶CMnðî„ñ&eKP¾Ð{f2×Tóç¾NU|—~¢iSczÛž@@PàîOép•ߦÖ|M KhÌÎ ¯@ZR¦®,û±~¹ù6ý`Ýteù*å›ï, € ‡@FªG³Lɬñ‘zÀTÅï? ¹“¶ºUñëÞ¶¯Õ’Æš ZÝñfÒWÛ+Þé/åfFžg8ÆÌ9@@@ z¸K ]F\.UܪÆßjZÉ,Õ=W-Ñ9þ­\~«ÖvÙÞùv‘n¹ë ]¸ø\-, M¬Úùeœ½kSSS›’’’œu¨nŽÀ}¨$9O¼ ì9ô®~Ry¥Ž+ú°.˜zƒì¿tY@ˆªzÓ¢ÆLØêñ&„ßiyóZU/fÛ0Þöˆw_'ÚWÓ®¦0›ÿÆÃ³ç@@úHˆÀ½óö›´­ò=öËt]×–3;HåKt×·nÒUçGÕ{Ó¦_(mÎÅfôKôjýÃZØmÎØ®·Õ´¿R?¿ó;‘­vÊ붯,×—–œ£’c,ñ'pïªÍ{"ê[ªuoåÕÊK§/ÎY!¿/%r>!€ G-­n¯ø÷º„ð6˜ßiªâÍœ®N¼ ãÝI[Ý@ÞVŧ&ÆÇÑ·‚ €$¬@‚î]žsÓ~ÓræMË™;{¶œ)¿K5¯]«h¯uÿË·ÎÖ·ÚšýÅ&p´ÏÀ½v݃Ê?á².7ßýíõª¨¿SeGì»Ñý3{w>#)ÐÒÞ¨7~] ­ÕZ:ÿne%›YèX@H0š·*Þ†ïá~‡ ã÷ò3Ý*x§¾Ku|‘é!ÏßK°n@ˆaX ܱþº—'”Z¤…ç\ꬷ™–3zü!­Z¾¢–3½?š›ÚTùçBa{?iÛ¤¯w ÛË—ê‘;.Ròž¿jÕeá;+U~ÕûUÿðçu ™{?ák[ Ù—¦+æß©ÿÙr‡~°n‰®,_¥âôɉÂÝ#€$œ€hÕ®åS"o½¥-¨Ý5!üæ]A=]áVÅ·µwVŇ[ÔØö4vòV;,  € €½À1õpøåšôöËÏ赓uÁ9³£l"Õ&=}ïwõ«ç_Õê5u»¥¾+Ü7ýb™æ\¼ÚÝ¿ü6myõ›šþ㋆uZ–}‚BßêŠz]:È2w*Ü»=>"pgv®ÑŸ¶Ý§+æÝ©i¹ °'_!€ €@ÝA7x·•ðáªxûº§NÊËp«âmøám«[ïµ³º² € € 0‰[áÞ+tª¦tަõúÝholÕ†U·juÅÑŒc¿~G8N—~ó»[:Ãv{š¬…úÆc×kõâ•ÎIzb£ ÜO:š °/ BଠKL?÷Ý»áZ]4ã_t˜sqA@ 1r3=Ê5ífæ—FèmínU¼Ä›5ïì ê¹×m(/5µšªxÓ½-Â;¯¡ªøŒÔÈó$†"w‰ € €@¤@¸&;rkB}òëø›ïÒæ7©JQJÊ=¿êf­9R_»I _~‡Îì(mï„+=å<•k¥ìnkÿ¸^µ7õ½ë;GÏ;bW`AÑÙÊI)Òjº×4ïÖ‡']»7ÃÈ@$Ÿ™xµHfí 8äVÅ»ñA=¿1¨Uí©•²ÓM®ˆ…ð6“+ù¨Š…'É%@@FC€ÀÝÄì§þZޡߦ”'ޏ7¼»±£'ý¢‹O‘ùýHÏ%¯T7[\~íóz·a™òhäÞÓ‰- ƒÀäì2Ýpüú§ò*U5îÔgf|ÃüFŸÝ 5§DH0œ rL»™y“"Ãøv[oB÷Õn%üöýA½ð†ûþP³T’ß­*>4ykVZäyŒ“ÛE@ˆC¨µ±Ç–îüþÎ-Ù©æw½-IÅš¹Ø|á´…oùÛ·, 0‚…iLè¾F÷m¸Î´˜¹F—ÏýžR“úøÿ×—B@ |¦*Þ™xÕT´kVä64ºÁ»ÆõÒ&[%Ð.3™kFj—ªøPo{ŵUñæœ, € €Äšû žXÍþ}G)4wvK—Œ~{³  …@º?[_^°Zlú¦Vþã‹Z^þc妌ŠSs@ €­bŸ3Qf ÐÛAí5´:íiL{GÈÿm³ ã¥úÃÒ8[ áí« âm¨ŸyžƒÝ@@÷A0gM;K×—K+M¿˜…eãqA‘HòúõŹÿ¥Çßù¡¾¿n‰–—ýXã3gŽÔå¹ €ô!`ûºÛV3%ùØí?͇š"«â_ÙÔ£/ôž©ŠO5•,N5}—Þò6 ·ýçY@@M÷Aè·íyÑ Ûí¡ë*ß“Êf÷{–Á¶” zá…tûí·÷{ð]t‘¦M›þÈ+ó¦^#Ûfæîõ—ëÒ¹ßÑœüSqA@(ÈHõhÖÓfBd€0Uñû„ªâM%¼­Že‹­Ž¨îœV4áJx·:ÞTÅ›‰\s3#Ï¥·Í°@@„øîw¿«ÖÖÁ¦¦ÑKEà>ˆg“”žÓqÔÞó÷]ûXÌüP¡%K]û¾‡·ôõðáÃÚ·¯³MÇ57w^¹¿}ùD8eÜ'•—2Vl¼I‹§^¯SK>•H·Ï½"€ ó^S?6Ïëy½oFäínê½PoÛÓ¬{'¨ßÿÍíŸä“iInQã†ðL‹[ŸœD)É'@@`döï߯–––‘¹Ø^…Àý±[÷ŽÚ´P= ÞÒ΄©æ‹OÓ 3!Ô`¯×«}èCZ±bÅ`çè&0;ÿ]wÜÏô“Ê/«ºi—>1åjy<üF»@ˆ9ôf”Ȭ‘ÿ]ƒÚo«âM¿ÃöŠ7Uñëßµ¯Õ”ƘZ¾ÛJxç5ô>?+ò<1€@@(øÎw¾sT#¼ë®»ŽjÿÑÚ¹GN(fB`˜R’Òµ¬ì‡úõ[·ëë.ѕ嫜‰U‡ù²œ@b@ (Ç#»?5r°Í­n¯ø÷BaüÆíAýß?ÜmfNמUñ¦:~¼iWcÃ}@@ø pä3Î*û’žºíWúà­n²¾ââ3Ô³Ëz¹{àKÊä58 †_Àëñé³3¿©'·ßoB÷%ZZv·&g—ÿ…¹ €Ĥ@Ši'3u¬ÌÚ3@¯i°ñn›šæõÏëmïø€ö™ò¦gB¸5Mèu¢©Ž·ÕòÌ'“? @èU€À½W–ðÆ#U¦'éìo>¦'R¾ªsovzË„r_Ë—è±_Ý­óK!Ž„áÑ)ðáI—« u¼VU\¥‹gý‡}0:ʨ@@ jìD«v-Ÿ9Ä–¶ v×ÈLÚ궨ټ+¨§+Ü`¾­]N|8Œ·!¼}o«âÓÌD°, € €±%@ÜãyeéÒGƒº´ÇöÞ6d霛îUë•ÿ¦Šõ›´ïP‹Ù)YÅ“g«|v‰ÀíÍŒmD¯ÀÂâÊövÿé†ëUÓ´K‹&^½ƒed € 3ÉI•ˬ=ôÚƒnïö‹jm¥ýО:)/ÃTŇzÄ;A|¡[%_d¦ñÚY]Y@@¢N€LxIRV‰ž^2gâ 0ÚÓrŽ×WŽH?©¼JUM;ô©é_—×ãíaq}@ˆS¼Lò2¥²É‘z«­Š¯µµº•ðoï ê™ îûæVSŸ/Ù~|(„ó©‘ç‰S6n @ˆZ÷¨}4 FK 8½T7¿F«7\«ûLµûesïP²/m´†Ãu@@ ü¦*~R‘ÌÚ3@?pÈ ÞmoÛÔüec¨*ÞôÙéUñáÞ¾ŽÉ•|TÅ'àO·Œ €#-@à>Òâ\bB 39O×,ø©Þô/Z¹þ2-Ÿÿ#e§˜2@@`”r2<Ê1ífæMŠ ãÛÛCUñÕ6€—¶ï ê…7Ü÷‡›¥q¦*¾kïö‹—2Ó"Ï3Ê·Çå@@˜ péÇÇà@`8ü¾SÝþ]=úÎô½uëÊòU—1m8/ɹ@@A ø|fÂUÛbÆT´kVäiÝàÝmQÔK›‚úmu@»Ìd®©¶7¼{\8„·çk«âÍ9Y@@.@à>p+öDðx<úä´U˜:A+ÿq©¾4ïûš™wbJpË € ËY¦Š}ÎD™52@oµ×öŠUÅÛ×—ß´­j¤†ÆPU|Çô‹WÇ»¡~vzäybÙ†±#€ €C)@à>”šœ âVàôñ)?µD?{ý3‘êÍ:qìyq{¯Ü €$Ž€íë^bªÛKL¨~âÌÈû>ÔªŠwÂø þ¶9¨ß…ªâSývÒV7„·}æíû1¹¦*>OJñÆGJò @I€À=‘ž6÷ŠÇ$0¯àt]½à>ÝSyµª›ÞÓ¹“—Óù8@ˆfŒTfM0Ýi&DèS¿ï€©Šw&m•3q«­ŠßS'Õ4HiÉ6ˆ— ßݶ4Ù¦*Þ„úös~–”l&„eA@âU€À=^Ÿ,÷…Ã"01k޾ºðý¤ò*'tÿÜÌ[åóš/@@ A¼¦*ÞV²Ûý}3"oÚ†ñ6xß[ë¾î1¯•[ƒzr½Ûº¦Þ´©)Ê1džªáíë{®Ðç\3¬=?  € «î±úä7Œš@^êX}åø‡œö2«*®Òó ´$S®Å‚ €$¸€ ËKòM‹šüÞCó–¶ vUË„òno_7ï2}]@{L/ùæ6i¼9Þ†ùc̤­á*ù1¡jùLÓ‹ž@ˆf÷h~:Œ ¢V -)SW–ýX¿Ü|›~°î º²|•éñ>.jÇËÀ@@h°íd&‘Y{Îmßø÷L ¿×ñ6€ßUÔº·M@_PµiWcÛž&Àwæ“éï"ñO@5÷Q£ç 붕̒ÙßÒ[ïÕ÷×]¬åe?ÒĬ¹±~[Œ@5Û7~æx™µ÷@~ÿSoZÖØV5¶uÍæ÷‚zîu7œ¯9(e¤„úÇwkUc[ÖØþñ~úÇڳ堀$Š{¢‘²¸w@†N€À}è,9$°À‰c?¡¼”1úÙÆõ±æ«tÆøÏ&°·Ž €Œ¼€Ïö7ífJ z†ñv4-­¦]MMä„®o¾g?›þñ¦Z¾Õô·ýç¾ñ¡‰\»Nèj«ïY@@þÜûâ{@`€3òÞ¯ë{P?©¼JÕMïé‚©7Èãá7fäc7@@`Xl÷)¦ü”#ôßiûLJ*âwVõªé¿Ûö¯—¼^3¡« ôm{š±&zµŸm0oûÓ³ € €îü €C(06cªn\øˆî­¼Z÷oüª¾0ûvù}¦™(  € €@T Ø öY¦ü¬#ô·­jlËÊ¿iúÇ?»Áí)_c&tÍJ³ÕõÒ¸<ÀçF¶®)0ýã“|òQýÀà@"÷!‚ä4 €@X ;¹@×w¿ÜøuÝýÚ—´lþ•™lÊžX@@bV Ü?¾L=ƒsÛ?Þ ãMžÔõ•-n0¿Û„ô›lE¼[ßµMM¸JÞöçoFÆìG@ B€À=‚ƒ €ÀÐ$ûÒtÅü;õ»-ßÑ÷×]¬+ËW©8}òМœ³ € €D•€íoÛÍŒï£|³íoÛÕ„&tµUò›vÚjyÓ?Þòí·¼ àÇÙv5¦J~l¨JÞõôªÇÍ`@8¢ûyø¼€×ãÕ…3¾®‚Ôñºó_ÔóîÔ´Ü…ƒ?!G"€ €Ĥ@Šé?u¬ÌÚ³:ÞÞPCcP»L oƒxÀï¬ ê•·Ü@¾ÊôO ÷ïÖ®ÆNðZ˜-¥&÷~Þ˜ÄbÐ €ĸ{Œ?@†Ñ/°hâ%Ê7¡û½®ÕE3ÿU'Ÿýƒf„ € €#&•fúÇO0ýã'ô ΃Á ö°á{xB× ÞØÔ3•n8_{PÊÍ´íjB}ãM…¼;‘«[%oûÇûè?bÏ’ !€ @àÎÏ 0 ŠÎVNJ‘VW^£š¦]úð¤ËGàª\@@ Ölo÷b¦ÛU“{òííAÙ>ñ]ÛÕüý-ƇÚÕ õïÞ¦ÆVÇÛ>‡þñ±þ#Âø@¢L€À=ÊÃAø˜œ]¦®Ñ=•W©ªq§>3ãòyù×pü>qî @~[½>¡PfíÆÛ«7µ˜v55¦BÞLè®’߸Ã~8¼šù^¾ñáÞyµ}äM?ù±æ5=¥÷óÿq@bS€¤'6Ÿ£F(L› Ž_£û6\gZÌ\£Ëç~O©I¦¬ˆ@@a°ýÝÔ?¾þpg ¿·NÚ¾?¨¿™þñ{M ¿ßôO6©ÖmSã¾Ú ÞòE9’íOÏ‚ €î¼CFD ÝŸ­//X­G6}S+×_ªåe?Rnʘ¹6A@@ «@vºGÙéÒì>úÇï;îïVÉo4ý㟮p«åëLÿø<Û?¾KE¼[)ïVÇçÛþñ^ù®Þ¼Gˆ÷øÆÜ!D¡@’ׯ/Îý/=þÎõýuKLèþcÏœ…#eH € €‰*`ûÇ1}Þm5{y/m¦üÓ?>ܮƾþm³ÝpÚ×n¶ÇFVÅÛp>\-Ÿ›Aß +›@b\€À=Æ ÃGØ8oê5²mfî^¹.ûÍÉ?5¶oˆÑ#€ €$Œ@R?ýã›CíjꂦE æÍëëÛí¯ÙÊù@ÀôÏï àm?ÎVˇ&tM£|Âü,q£ €@< ¸ÇÓÓä^@ &N÷I奌Õ¿¦ÅÓnЩãþ)&ïƒA#€ € ÐUÀæÓÆÉ¬½W²×t+ä÷š ÞVÊo³ýã7Û`> *Ó?>Õ/•˜@>ÀÛv5Nży-Ê6ýåéß•›÷ €Q"@à%‚a €@b ÌÎ?E×w¿~RùeU7îÔ'¦\#ûWxY@@ˆW¼LÓ~ÎÄž¿î ‚Τ­N»šPuü†mAýù57œ?pH²=âÃüXÛúÆñãB¡<ýããõ§†ûB¢_€À=úŸ#D(1=Ü¿ºð7toÚ¥%³¿%Ûë@@DðšÉVÃýãLéy÷­mnðnÛÔØêx[%ÿò›æ½©Ž·ík·ØV5fíRåíkýã{¢²@`H܇„‘“ €C#“R¬¯÷sÝ¿ñ«úÑkKµtþ]J÷›¿/Ë‚ € €þ$&ɬ=«ãíN‡MÿøÝ5‘ºnØf?»ýãí>]ûÅÛ`>ÐåH©½Ÿ×Ç‚ €À‘ܤÃw €À(¤$¥kYÙõëÍÿ©ï¯[¢+ËW9«ŽÂP¸$ € €1)ÞOÿøš3‘k]g ¿uoP/½éò¶|fªmQãNè:ÖNäj&tµ¯vb×BÈ'›ÀŸ@ÞÜ{Sa 0Ê^OŸu«žÜ~¿~`B÷¥ewkrvù(ŠË#€ € ùY§|oýãÛMÿøª&|7mjvÛv5µAUšþñO®wCúpÿøpßuRW»-?S²-qX@S€À=1Ÿ;w1"ðáI—« u¼VU\¥‹gý‡}0FFÎ0@@ˆMŸío«ÚM›™ÞúÇ·´Ú^ñnu|¸JþES¿×´«±Û›lÿx{|—ªø®Ÿ³Ó ãcó'ƒQ#€ p˜{!€£&°°ø£²½ÝºázÕ˜ÉTM¼dÔÆÂ…@@Htd¿G“LÿøI}ô?ÔÔYïTÈ›JùŠ­¶bÞô7¼×êß%·¯±Ŧ™v8, €±+@à»ÏŽ‘#€@ LË9^_9þ!ý¤ò*U5íÔ§¦ß,¯ÇüJ@@¢JÀN¸:}œÌÚ{pnûÇï1­jlËš½æõÓ?þ…Mn oûÇg¥Ù^ñ¶JÞTÚ‡^íg[q_”-Ù cY@¢W€À=zŸ #C"ŠÓKuãñk´zõºÏT»_6÷%û̯ÆY@@@ fÂýãçNêœÛþñûmÿxÓ7>ܶæµwƒú?ÎÛ¾þ°T`B÷po'qíÚ®¦ Kòxzž7fp( îqð¹HÌä<]³à§zhÓ7´rýeZ^öce'$wŠ € €@ Øþñ6@·Õí½-Ͷ¼È5ÀÛ*ùÞp«ãíöÖ6©¸KU|÷*ù,úÇ÷ÆÊ6@`H܇”““!€Ã/à÷¥èò¹ßÓ£ïü@ß_w±®,[¥±S‡ÿÂ\@@FU Åô/-–Y{ä6v¶«qÚÖ˜JùõïÚŠyÓ?ÞTÎ'™®”á@¿³J¾³}MjrïçÕ›æâ €@Œ ¸ÇØc¸ €€°Mô“ÓnTaêSé~©ÀÏÌ;@@H`Ì4Ó?Þtœ^Ò38ƒªi°ÕðnËš½æõíÝAýÕTÈï5|•ù.Ûö7öcz™Ðµ(Çö¾žçM`nnèU€À½W6"€±!púø‹”—:N?{ýg"ÕÇžg” € € 0¢¶hÇö·ë¼ÞúÇ·*øðd®öu½é¿gYM8ß`úÇšcíä­½MêšOÿø}ž\ ¢W€À=zŸ #C$0¿à ]½`µî©¼FÕMïéÜÉËt;!€ € €aŸ©^—/³ö^ÅÞÔ4½ãÝêxÀï5íj¶ìvÛÕØí­í¶2ÞTÈ›êxçÕó¶½ýl^³Lõ= G° ÃüŸÌÿ9ÿ°¯½}Ÿ#ü}µKø³=ÁpÛq­Ðõº^·ã»ÐõûGø˜ðkx¬]?Û› o·¯]Ïe?Ú%|¿½nx¿#Þ'|î®× Ã9>tý#«·cs êX×Ãü}{ɨ_Ü£þ1@@ ‰YsuãÂ5&tÿ²ºnæ­òyýýÈ € € €Àl÷#õo8ìVÂï1A|8˜ÿÇ;v‚WÓ?Þò~“@uð&˜O1¿] Šöòá€/z¿nãuÝm›¹¡Þî©GðºáÞöÊûïë\]½»Ž­ëö¾ŽíØ~”÷ßö†‡h1aÃ^C¯]?ÛKØXÖn³Kø»îŸíNáýœ]CŸÃÇ„_ÃûtýÜ×±áktÝ7¼mÀãpîÛ‘Îeo.<¾ð=„?æûŸ/|þ#£Ûxê:u®ÙDZ~Ÿý"6÷ØxNŒèW ß´–ùÊñ?7íenÔªŠ«ô‰)Wkrv¹ùlDzú=; € € €ƒÈJ÷(+]šÑGÿøjÛ?¾Öð¦u à[Ú‚N è5¿] ‘öMøw/Û:Ã8;®ðvûÚõs×ÔÙú‡Ý­û¾Ý?w=6|ý®Ûº^§û±Ý?‡o |]ç|æáÏç2÷ê|ÙyOákvîã¾ç±=ï)|lÇ9“ôvÝžÇv§=´ëùœa†¾ë¾o÷Ïκ‡w<«®çrNÝǹÂûù“œ+Ú]Yˆø¢óGZ›¢ò{T>… N -)KW–ýXOl»W½q‹šÛk~Á™*+#ïýJñ¥' w‰ € € €ô!@àÞ ›@"¼Ÿfåä¬θY{½ë´žùÓöûtÿƯ™í';•ïóòOSNJqäÁ|B@@@@€À=2·ˆ ‡ÀØŒ)›q…>Rz…¶Ôª¢z­Sýþ»-ßѸŒéNß÷ùgª$sÆp\žs"€ € € €Q'@à>T¤­I ­ÎÙüiYJEv¨d9Ä€@fržN÷OÎÚhÑ›5/ª²ú­ª¸Òéó^^øA§ú}ZÎB%yý1pG @@@8zbá£7‹8bÛ_~«•«WiåšµÛ—\núÆ—TVq @ îüÞdÍ/<ÓYíÍn­¯t&]µ•ï5M»4·àt§ú}Nþ”áω{n@@@GÀ4KâÜîÐÞéËw_¢“¯[sÄ“ÞóÒ>-;©èˆûéË‚‚-]ºT+V¬8Òn|‡Ä„@mÓÓ÷ýi§úýë5%»Ü©|Ÿo&^-L›÷À @@@@`ä<¶nݪÒÒÒ‘¿øQ\‘òë£ÀêºkCåƒaû¢¥wèú‹Þ'mE+/»Yáz÷å'ß ÷×?¬…Y]æ= ˜y©cuæ„Ï;ksÛa½^óÓ÷}­žØz¯2ýyZPdZϘð½4»ÌiE“˜JÜ5 € € €Īû ž\›þzÿG^ÿH…îü|YèóÙ:ÿ³ŸÒ·>6]·:©û=ÿÖÝZ¸0¯cÞ €H)IéZXüQg ÛõvÝ:§òý¡MßPc[ƒÊ 9mifåžìì‹ € € € íÞh`tޝQÛÞ­ m±>{^8lmJ¦/\}ÇПþû»ïyƒ ÐSÀëñiFÞûõOÓ¿¦;éuÃñ©(½TÞþ€nyá,ÝSyµþºë·²-iX@@@@h Â}PO¦MªX¯ó±ûÒXs¸cÓ©s'v¼ç  €@ÿÅé“õáI—;ë¡Ö:Óvæ§úýÿ{û{“>Åi;SV¸Hã3gö2ö@@@@FH€À}PÐyš±¨\Zk«Ü×êŒkïÕÖû–©4Õ=Ùþu¿ÐE—­î8óÔI4pïÀà  p”þ\<îgm ´êÍÚ—œ¾ï÷T~Ù9SyáÙN?-÷ù½ÉGyvvG@@@†NÀ4ËÐ.ÎTû².É?YkºÜò’¥×+}ïÓZýX¸ÝŒ´øŽ§ôÛ›ÎÖ`ÿd£  @K—.ÕŠ+º\‰· €V`{ÃF'|¯¬~FU;47ÿ4ÙÊ÷9y§*3™¹3ø)A@@@ ^<¶nݪÒÒÒ¨¾%÷cx<»þx‰ÆŸk"wSì®ÎŒ=âŒÏÕuú1d>îœ|@ú¨kÞ«Šª§Mÿ¬Þ>°N¥ÙóÝÖ3g™~ð“ú<Ž/@@@@ úb%pláuô?aá®§¿ã„íå&l¯pÂör-Yz¶©pÍT¸¯u®nsø3òè±­/ëüp¿™a§GU 7eŒÎÿ9gmn?¬ÕÏ;}ߟÜþ3¥%ekAáMõûYšœ]&;I+  € € € 0ÔT¸F´©R—¤•w´“Y|Çzà†s”ú㋦]/ë¶%'k…›»K×?¡Ö;ÏT[™¼¼<ç¯Iœxâ‰é5×\£²²²ïÏŽ €@< ‚½sàNøn'_µ“°Úà½ÌT¾ÏÊ;Y©Iñ|ûÜ € € €Q)põÕW«¥¥eÀc»ï¾ûb¢¥ î~¤;6l|¡#l×â{ôðMç¨ë´¨©%'éöÿyNóÏÐcö°•ҖكÔ.,,Ôܹs;ÐÏ»¬¬®£égg¾Fâ\Àëñjº™PÕ®Ÿœv£öޮתžÒÓ;ÒÏ߸E3rßç„ïó ÎP^êØ8×àö@@@ˆ9s樵µ5:3„£ Â}˜ •÷*»|¹säâ{*ôè²ÞªÉ›ôàiºÌIÜë¥úGuÒ rpz¸âq 0@C­´¡úYÓ÷ý½Yû¢ŠÒJ;ªßÇgÎ’íÇ‚ € € €£/@÷Ñ#2‚úæ¾þ¦¯í#2,.‚ 0 ŽN{¾³¶ZMèþ²À¯ÞpÚƒm¦ïûÙN?=ç}òûRpFvA@@@Dd““D&3÷Þ%K_{ÝZwÙÃZØ­z½iÓã¡êv³ùÙšÙíûäö@¨ðyýš[pš³~Fÿ¢ o8}ßÿÎÝÚ׸UsóOsZÏÌÉÿ€²’ó£nü @@@F_€À}Ï «üCºÅ·Â9vNÈ–~óÒ¿ë£'”ÊßX«k©Ë_×qæ¥7DyŸxƒ  ³æÈ®›|¥4ï7mgÖêÕ}OèW›¿íl·“®ÚÉW‹Ó'ÇÂí0F@@@z¸¹¡òAÓÇý²þ^t—ö=}­Šúß³×=èáÞ+ @QhioÔÆš¿:}ß7Ö<¯Ô¤ •ÛÖ3&€Ÿ’½@>/–=j‡ #€ € €Ä­=ÜãöѺ7–Uv©·NÓw¯»Z·>VÑëÝ.¹ã1Ý}ÓùT·÷ªÃF@ 6’}i:®èCÎônýkÚ`&]ýïÍÿ¡ú–¼ŸéT¾ÏÊ;EiI™±y“Œ@@@%@…û Ø"jØõ¶ÖozKµ[¤–%çOÔœã¨4/5rÇA|¢Â}h‚Œ’@UãNUT=í´ŸÙÖðº¦å,tÂ÷ùg(?µd”FÅe@@@ˆ}*Ücÿø²J¦ét³² €$¶@aÚ=ñ Îz¸µ^ªŸ3ë3zÜL¼j¿³mg曾ï3çÈþB@@@âK€F³ñõ<¹@(H÷gëıŸpÖö@«Þª{E•Õkuÿë7ª5Ðl*ß9üÌÜå÷¥Dɨ € € €‹û±èq, €ðyýšг~z†´óà›Î¤«غJ÷þªf›~ï¶ú}nÁéÊN.ÀÙ@@@¢Q€À=Ÿ cBˆk ™³d×s'/S}s•©|Fë÷?©ß¼µÂÙnÛΔ,ÒØŒ)qíÀÍ!€ € € oîñöD¹@˜ÈN)ÔJ.tÖ–ö&mª}Á©~¿{çåJö¦©Ü¶ž1ëÔìãäóòŸí˜z¸ @@@ áø{Â=rn@ Z’}©&`?ÛYƒÁ ¶ÖW8}ß½ù?u eŸæœaÖ³4'ÿT¥%eEëm0.@@@V€À=a=7Ž ÍGSr8ëùS¯Wuã{ª¨zZÏïúµÖlú¦¦æç´™gú¾¦Mˆæ[al € € €$Œ{Âî¬í6m9ðŠÓ÷ý7©¥ý° ßÏ6ëYš™{¢l›@@@÷‘qæ* € ‹€HuVÞÉÎzጯk×Á·Låû3úãÖ{õÀ¡¯9Ûmø>/ÿtÙ ZY@@@@`ø܇ϖ3#€ 0â%™3d×–þ³ZªÊ÷Šªµúí–ÿRIÆ Ó÷ý,§ú}\ÆôD@@@ ÞÜãý s € +•\ SK>嬭íÍÚTû¢Sýþ£×–*É›¬rÛzÆðÓrŽ—ÏëOX'n@@@¡ p*I΃ €@ ø})Ne»m/ µ­¡ÒT¿?k*ßïPmÓnÍ+8Ý ßçä@éþì(¾†† € € €@ô ¸Gï³ad € ‹€ÇãÑäìrg=oê5ªiÚ%Ûvæ…Ý¿Ó#oþ›¦d/pÂùy Ò©¬@IDATg¨(mâ°Œ“"€ € € îñøT¹'@ŽB ?µDgM¸ØYÛjcÍóNï÷'¶þD9)Å}ß'eÍ—×ã=Š3³+ € € €‰%@àžXÏ›»E@àˆiI™:¡øg Ûµ¥îUm¨~V?ã5µ2áû™Nõû¬¼“•ìK;â¹ø@@@D pO´'Îý"€ 0@¯Ç§™y':ë?MÿšvzÛ©|ÿ¿í?Óƒ¿îl·“®Úþï¶ž@@@D pOôŸî@ ŒË˜&»~¤ôKjh©ÑëÕÏ©²z­~÷öw56}ª;)« àK2gðŒì† € € €@| ¸Ç×óän@¬ä|<îgm ´èÍÚ—œê÷UW9}ÞË ÏÖ|¾OÏ=AI^ÿˆŒ‰‹ € € € 0Úî£ý¸> €1.à÷&›pý gµ·²½þu§òýÑ·¿§ê¦÷47ÿ4§ú}ŽyÍðçÄøÝ2|@@@ú pïÛ†o@@`“²çÉ®Ÿrµj›ö8áûË{~¯_¼ù*Ížo&^=Ë„ógª8½tgç@@@¢W€À=zŸ #C@ æòRÇêŒñŸsÖ¦¶Cz£æ¯Nÿ§m÷);¹À©|·­g&g—;­hbþ†¹@@@„ pOèÇÏÍ#€ 0r©I:¾ø#ζëÿpú¾¯Ùô¯:ÜVïT½—,Òìü“•âK¹q%@@@†H€À}ˆ 9  € \Àëñ™ Uß笟œþUí;¼U¯U=­§wþ\?ãëš™û~Í/´­gÎPnʘŸ˜=@@@E÷QÄçÒ € à §OÖ‡']Zë´¡úY§úýÑ·¿oz½O6}ß9íg&d΂ @@@¨ pÚGÃÀ@HL ®N»ØYÛ­Ú\û²éûþŒî­¼Ú ‡ï3L|’ן˜HÜ5 € € €@T ¸GåcaP € `l >·à4g½Hÿª Ê÷ß¿³Rû·knþiNï÷y§Ëõ, € € €Œ¦ûhêsm@8*‰Yse×M¹JuÍ{ðý•}Ðoþ–&eÍsÚΔœeÚДÕyÙ@@@¡ p EÎ €#.`'S=}üEÎÚÜ~XoÔüÕðÏêÏÛïWZR¶Ê Mßw¾OÉY ;I+  € € €Ã-@à>Üœ@†] Å—®ãŠ>ì¬`@ïXïô}ÿÅ›ÿ®ƒ­µNÛ™²Â³4;ï¥&e ûx¸ € € €@b ¸'æsç®@ˆ[¯Ç«i¹ õ‚i7hÿáíª¨^«gv>¢‡Þø†¦çžàT¾Ï/8Sy©cãÖC@@y÷‘7çŠ € 0‚Eé“ôÁô/ꃿ¨C­ôzõsNõ»xµ0m’ ßÏtz¿ÛÞð, € € €‹û±èq, €Ä”@†?G'Ž=ÏYÛ­z«îïÎÄ«÷møŠÁöŽIWgä(¿79¦îÁ"€ € €Œ¾ûè?F€ €£ äõkNþ©Îú}C;6™Ê÷gõÿoý‘ömÜêô{·}ßçæŸ®¬äüQ!—D@@ˆ5÷X{bŒ@†E`BÖlÙõÜÉËt y¿Óvfݾ?é×›ow¶—œe&_=Kc3¦ Ëõ9) € € €@ì ¸Çþ3ä@@`ˆrRŠtZɧµ¥½QoÔ¼høµzjÇÏ•š”¡ò‚ENû™©9ÇËëñ ñÕ9 € € €@¬ ¸Çê“cÜ € 0"ɾ4-(:ÛYÁ€¶ÖW8}ßµùÛªo©Ò¼‚ÓÍÄ«‹4Û´§IKÊ‘1q@@@è pÎç¨@@ ¼¯¦æ笋§]¯ý;Lø¾VÏíúo=¼é_5ÍT¼Û¾ïó ÎT~jIÞCB@@N÷áÔåÜ € ×EiuöÄ/8ëáÖzm¬ù‹Sýþø;?T Ümøn«ß'fÍ•Çã‰k n@@@@"pç§@t¶Þ7æãÎÚhÕ[u¯:}ß¶ñFµZLðn*ßM?+÷$ù})CpEN € € mîÑöD €ļ€Ïë7=ÝOvÖOϸE»n6áû3úãÖ{ôÀá¯ivÞÉNå»íÿž•\ó÷Ë € € €¸îü$ € €Ã,P’9SvýhéRÕ7W9áûkUOé7o­0Ûg8á»m?3.cÚ0„Ó#€ € € §ûpêrn@@ ›@vJ¡>Pr¡³¶´7éÍÚ¾ï?|í %{ÓT^¸Èi?3ÕLÀêóòKµn||D@@¢Z€ßÅEõãap € ÏɾT3±ª ØÍ µ­¡Ò ß³e…êš÷inþiÎÄ«só? ´¤¬x¦àÞ@@@¸ p‹ÇÈM € €@¬ x<MÎ.wÖó¦^«ªÆÚ`ú¾¿°ëôȦ[55ç8Í/8Ó©~/Hë·Ëø@@@¸ pËÇÊM!€ €@¬ ¦MÐY–8kc[ƒ6V?ïô~ÿÃÖUÊMëï¶ï{iÖ|Ù°ž@@@`ôÜGÿ0@@àˆ¶Ì cÎuÖö@›¶xÕT¿?«7Þ¬–@cGåû¬¼“eÛÔ° € € €ŒŽûè¸sU@@`Pv"ÕYy'9맦ߤ݇¶8}ßÿoûO~¦ùÎV¾ÏÏ?Cv‚V@@@‘ p9k®„ € ¹À¸Œé²ëGJ¯PCKµ©|Î àÿgË—>Ý ßË ÎRIæŒ!¿6'D@@ˆ pôà € ³YÉ:eÜ'µµ½YoÖ¾dú¾?«W,“ߛ⶞1ÕïÓsNÏëÙûdà € € €@´ ¸Gë“a\ € €À1ø}&`/<ÓYƒÁoj{ÃëΤ«¿Ûò]Õ6ïÑœü8¯ÎÍ?Méþìc¸‡"€ € €„Üü"€ €q*àñxTš=ßY?1åjÕ4í2mgžÕK{Õ/ÞüwMÎ.sÂ÷Ùù§ª u<¯ÆéÏ·… € €Ã/@à>dÆmjhh”ÚÚÔ¦$eåe™² € €Ñ'ŸZ¢3'|ÎYÛêš¿š~­žÚñsÕ·ìW†?Wy)ã”—:F¹)cÍ{wÍMµ¯c”“\lZÒð+è{²Œ@@F[€ß)ó¨ÕÓþHß¾ìV­8×"ÝñØ]ºáü2‚÷> € €@4 ¤%ejañGÕŽ«=Ðæ´œ±mgj›ö¨Î¼V7½§-u¯„¶ïUS[ƒrRŠM?¦#ŒÏ3a|×p>39_^7šn•± € € €Ã.@à~,ÄM›ô“æhEEo'Y«›—ë‘[ÓË·Ÿ¯ÔÞva € e¶r½0m‚³ö5´–ö&Ó–f·Æ;Á¼ åß;¸YªŸs·5íU[°5Æ›P¾[o+åóM=½ãûf; € €Īû Ÿ\›þxÛE]ÂörÝñ›;uîü\Uš×‹o]㜹bÅb­¾°F×.Ìô•8@ˆ&d_ªÆfLqÖ¾Æe[ÕØ^ñ6¯3•ò5Í»õnýz­3ïk›÷ê@Ë>yäU~/a¼ÛÂfœ©˜/VjRF_—`; € € uîƒ|$mÛþ s;JÛ鉭Ð9¥n{Ù7ÖÂ9…šóé•ÎÙöÛ—uÕÂsh-3HkC@ذ­jÆgÎtÖ¾F_ßRí„ñn•ün§…ͦšÜÞ„òõ-UJñe8}ãmïöõ”O5=æÍ6ÛÚÆïMîëlG@@FT€À}ܯþêþŽ#oybMGØÞ8û‚eZ¢•²uîÿ»Y ·Ÿ#jÜÃ:¼"€ €Rvr³NÒ¼^9Á€4ïs{Ç›6áö5Û6˜p~¯óùPk­2ýy‘a¼ä5ÈÛ>óÙÉ…LòÚ«0@@@`¨Ü%º_/ÿñ±Ð‘Kõ…•ô×µìU» î#ÛÖ˜–5Nïò6œg’×¾„ÙŽ € €a÷°ÄQ¼6mݤp}{ÅŠïèc+Ö*”¿wžeå -W¹îyê÷ZvviçvÞ!€ €Œ¨@²/Mã2¦9k_>ÔZׯ;½špþíºW;ªämk¯'©3„µ¬qBz§…Í3ÉëÓs>½¯K°@@@€À}¹µµÁ9ªÜü³ÂDíkÝ7*_´D'ÏhÐêÕq¼–p²Ù©^Ëʲq%A@ ®ì:!kv¯— ƒÎ$®á0>\)¿ûЧ¥Mé1ß`&µ“ÅÚ¾³‡¼ÛǶ­±Uò6”·Uù, € € ŸîÇð\+̱NÖ^±DO¼ñ3»È9Ûÿ«R+>U®[Ceï˯û…>ÿô2¹6‡"€ €£(`û»Û>ðv•ÊzI ØnÚÖ˜É\CmkÂáüÖú Ê»“¾n= Ìä|å§ŒsøÎ¶5no?ÛI^½_¯×`# € €D·€ÇTë£{ˆÑ7º†Ê{•]¾<4°rýfË«ºpZ·?»hxYdŸj=³X/Õ?ª“‘¸çææ*//O3fÌ0Ä·¿ýmxâ‰ÞŸ@@FF 5Ðby7|ïì)oBzÈ› Þnk 4)'¹¸³}So+åǸ}æÍç,Ú³ € € Ë矾ššš| O>ù¤¶nݪÒÒènßÝ-%ðý±cX`ñUúh÷°Ý~—5W,– u—ì_öz½Z¸p¡.¹ä’ðû}öº~o€@@8ð{“Uœ^ê¬}ÝbsÛaÕ4ïꨔ·!üö†×UQõ”Ó¾¦Îô“*à¶®éãí䮡*yój[ÚØö6, € €D«ÀÒ¥KÕÖÖ6àáÙÀ=÷A<¥¬ÉÇÉdé§ö~Š4M:a‘Ù)ÔW¦÷úÝjÿúòÌ™3uÁô»/; € €ľ@JRºÆ%M7“¼Nïóf¶Ô†Â÷=Ϋ­Ž«îïï´ì— ÷óLëšpÛÛCÞö’w?Û–6Ųʲ € € 0ŸøÄ'Fã²Ã~M÷Áû»Ô«?¶M5æ=»ÅÔꕵa{ë`®Ã1 € €ô"™œgzÁçibÖœ^¾•ÜI^÷w𶟼]ß;ø¦Ó¶Æ¾·“¼¦ûsB•ñn…¼ÆÛÖ5nPŸ“\$“¼öjÌF@@z pïM¥¿m©sµd©)^_mw\¡ÛñÝûùÙGÕ¾üKÝÎÛª©=ùˆýù€ € €ÀP ¸“¼›I^‹59»¼×Ó¶ÚÜI^Ca¼3Ù«é/ÿÎtõmõ¦_|¡ÊwVÊQ¾iYãVÌÛ~òf’Wo¯×`# € €‰&@à>¨'žªO|åiõeÎÑ«/6•EUOèß.;KÅi­zãÏhɹ×uœù¶ÿ¸LEŸxƒ € €Àè ø¼I*Hï¬}¦¥½É©ˆ¯ Mèj+ã÷~GoÔ¼ÐQ)o'‚µíiÜò]+å;ßgøsûºÛ@@ˆ+÷A>ÎÔÙ—ê¥{žÒÉË×8gX}ݹZÝ™±wœµü–ÇôµÓ‰Û;@xƒ € 3ɾT3ÁëdgíkÐmͯf’׿½•ñÛê+µ¾ùIçsÙî1ÿ Wć+åm@o߇·§&eôu ¶#€ € 3îÇð¨NZö°¶Ì8MÿüÁå wézº[yI·}þ$ÜU…÷ € €ñ$–”©´Ì™*1k_‹íïò]*å߬{Yuæ³­š·“¼&{Ó:&xíÆ»Õócä÷¥ôu ¶#€ € dÁÇø¦½LO·~^oWlÔ¶ºCRK‹”1^eÇ•©ˆ¾íǨËá € €ñ `û¼ÛuRÖÜ^o' è@ó¾=åw4¼ªšß­ƒ­µ²­ilE|~—Êx'Œ7Ÿí«;É+¿Åé™ € €#"À¯F‡‚9)KÓž¤iCq.Î € €@‚ ØIWV3&8Ÿ¢½Þ}{ Õ­’·“¼†*å«›ÞÓ–¯šÏ»ïšL{›l;Ék(€ï­RÞÿvRY@@†C€À}8T9' € € ©€ÏëWaÚgíëÄ-íê:Á«mW³ëà[ÚPý\h’×½²Á½Û7~LDù®•òþœ¾.Áv@@Ž(@à~D¾D@@XHö¥ilÆgík̇[ëÝ65&Œ÷·~½Ö9ýä÷šÖ6f’W¯Ï¶5NÕ¼i_“’”Þ×%ØŽ € Àî üð¹u@@M ÝŸ-»Žïc’×`0¨†ÖšŽ0ÞVÉÛ–5›j^p‚ú:ÈhÞ¯T3Yl^Š©’7á{n×6æs^ê8å¤ËïMN4^î@Hx÷„ÿ@@¶¿{¶éón×IšÞñ¶;¡»Ƈyû~{ÃÎïu‚ùCf’×L^0Þ†óù)ãL[›1&”/’×TÓ³ € €Ä{üïüP맇|¸}­Œ»îÕŽ*y[Eïóú^òáJyÛCÞé-ïô“wûÌÛ eY@@†_€À}ø¹ € € 0( Žì:!kv¯ÇÛI^ë[ªœêxƇ+åwÚâVÏ›Êyû}š3É«;Á«ÛCÞVÊ›ÕVÏÛ‰_Ík’ îY@@ŽM€ÀýØü8@@5;É«|Õ®RY¯ãh´é@˾Ž0ÞVËÛp~k}…Ê›ó‡M%}fr~¨R>ÜCÞònoÃùìd;É«·×k°@@À pç'@@ˆcŸ7Iù©%ÎÚ×m¶¶7‡Âw7Œ·•ò{oÕ›µ/©¦Éôµ%Фº‡[Ö„ÛÖä›0>ÇTÈg'˜jü<Ùþõ, € €@¢ ¸'ê“ç¾@@@€ß—¢âôRgí ¥±í Sn[c«äwÜ¨Šª§Ìö}N뚦öƒJOÊ1á{¡Àgu¼8Û2M Ÿ“Rì¼Ï0ûÙ? `A@âI€_ÝÄÓÓä^@@@a°}àÓ’¦k\Æô>¯Ðh5íkö;á{CKµyu×ZS%¿­¾Rî¶*g{K QYþ|'|Ï2Õñ6¤¿ÚjùÎ÷…æºÙ´³éS/@@ šÜ£éi0@@@ †|fâÕþÚׄo϶±©3½å;Cø*ç½meóVÝ+ÛZ«eƒ|ÛCÞ á»‡óá Þ„ôþ¥û³Ã—à@q÷'ç‚ € € €¶MQÚDgíO£¹í° ç÷†Bx[5ï†óï|S›Z^UÒWéPk­ :½æÝ*yÛÚÆ®ù&¬ïÚæÆ¼7á|JRz—æ{@@à¨ÜŠ‹@@@FZÀãc’¦hLú”~/}¨µÎ äm;›Ì»¯ÕNK›Îm&œo;`ÚÔø”›\ÜѾ¦k›,Ò»a½© 7á¼ý@@ ?÷þ„ø@@@ f2ü¹²ë‘zÍÛ› ƒjh­éh]®š·¯¶­M¸Õmis¸õ€ ÜSMå¼;ák÷óá Þö¤Ï4A½ß›3^ @†V€À}h=9 € € €@ x<SÁnûÁh¼fqÄ`{Gw"X·¥ çwÜÜYQoÂùƶ¥'å„Îmûˇ[Ù¸×r'‡u[ÚØ?ðyùmùñù@à¿ì1öÀ. € € €ÀÈ 8­gRÆ(׬ý-v‚×-ûC­lÜ–66¤¯mÚmÚÚlµ¹1ÛM8ßÒÞhÚÕØþò}OëôÎd°9¦Ž·¿Ëó= €Œ²û(?. € € ?>¯_ù©%ÎÚß]µ´7…ªãm0ßY5o[Úl©{ÕÝf‚yû]{ ­#˜ï»¥[EŸîÏîïÒ| €Ã$@à>L°œ@@@# $›¾ð…iœõHûÙïšÛ›Êù}¡€ÞNëñÝ[Úl©QÐü¯cÂ×PK›®!½ÓæÆTÍÛ}ì„´, € 0tîCgÉ™@@@Œ'MVqúä~ϨµÎón æíë¶ú×ݪyS1o[ÚØý|ž$¼9=çímÜ>ó]z·Ây¿/¥ßk³ €‰.@àžè?Ü? € € €@\ ØÉXí:.cÚï+ ê`kMpÞ¶°ÙgÚÚØÐ¾!ÔÒæpë%ûÒBá|׉`íİnµ|¶ æí{»&™Ö:, €$¢{">uî@@@ á<OG@>^3è¶w´±q‚øP½}nkã†óÕjlkPzR¶Ó²¦³Z>Ì»á|V¨jÞþÁ€ÏK4qD|¾Dˆ)þ«S‹Á"€ € € 0ò^O9)ÅÎÚßÕÛ­Nëš®ÁÚ`¾¶iik³Á÷nKû}K{£2ýù}´´ UÒ‡Âùt޼o—ç{@FU€À}Tù¹8 € € €ñ%`ÛÉä§ŽsÖþ½©—p¾JûoÓÛuë:ZÚ4˜É`Û-íkB­kÜÉamÎ;-mÜ>ÝŸÝߥù@a pVNŠ € € €ý $ûRU˜6ÁYûÛ·±í [o*ãmo+äÝ–6o™×‰`íä°vµ‹Ƈ[Ù„_#[ÚØ}ì„´, € •ûPIr@@@6´¤LÙµ8}r¿×8d&yliã†ôÛê_w·‡&ƒ=ÔZ'Ÿ'É™ 6+Ù¶¶±òáp>²¥ýÞNË‚ €À‘ܤÃw € € € s¦ß»]ÇeL;âØƒÁ ¶Újy·2Þ­š·á|µÞ6mmœïl%}•›?ŗ1-m:ƒùΖ6ámYæ{ÛZ‡@ ñÜï™sÇ € € € `<ÓÞäý-`»ć[ÙØPÞõö󮃦­©šw&„5ÛÛ”ž”Ý%”ï½jÞôþ\ù¼Ä3ýùó= +ü=VžãD@@@Qðz|ÊI)vÖþÑhu‚x7”w+äíûÚ¦=ÚV¿¡Ëd°Õjio4¡{^hBØ®•ó¡ö6f2ØìÐ$±6œ÷z¼ý]žï@FQ€À}ñ¹4 € € €ÄŸ€m'“Ÿ:ÎYû»»–ö¦^Ãùý¦¥Í;ÖuTÑÛÀ¾=ئL¿í5ß5˜½w‚y[IïöžO÷g÷wi¾G÷a@å” € € € €À@’}©*L›à¬ýíߨv°£mMÏ–6/u÷ö;»„{Êw}uªåCá|x{jRF—æ{@ ¸ŠÝ@@@@ÑHKÊ”]‹Ó'÷;ŒCf’W7”ïlic{Îo«=¢¥MCK™à5¹£mM8„·¯Îû.-mìgû, €} ¸÷mÃ7 € € € €@L døsLoø͘zÄñ‚j­ …óî$°á þÆí-mµÖ)Å—ê7 ä“m‹Óʦ[Õ¼ˆÖ¶ÖaAM€À=Ñž8÷‹ € € ðÿÚ»ਮ;Ïã?ÔØj,pFT<²3à5Â#Ê;;x¶å¬’ b'Ù€pLe"Q©S‰Y±ÉÈ[VP2kP9 › Z3Žƒ¨E¥‚”…TŒÊ+WÕîþ÷éÿA‚Ö$¬VpÜzäÞAåÆMŸ>èŽ Â[£æ{¯_V×ÕsÁ”6Öˆúnõùz5+Óeç­òC£æ­çœ™ŸT–5búÝæù.e™gÇô™wh‡@Ä àžø÷ˆ"€ € € €q˜>-S³gÎó?îÔßÍaRÚ\V÷“Ö¦]öÿÑå?–÷†yø®êúÍ>‘3¦9M~Ž À› ¼ ÈûÁ |dp>¤·Òád›‰dCÛÖóŒéÎ;5ã €À” pŸ2Z F@@@ÒSÀJ'““õIÿc´7¯ûƒô^ þª È{L@þª È[ùÀóÇ&­Íå¾÷üÛþã&X Ú[Ïý7®ù«sLËÒÝŽÎû@Ð>ÀQï Ž¬ ê[#íCûgfÎmÓ9°¸Û¬ € € € €ÄKÀaF«ÏÉú“ W]ˆ·FÑ÷ùGÓ‚÷VÊ›oW0piyÕðz3Ú>4ê>âÙ™™=ìþPßÜöY@ }¸§Ï½¦§ € € € €@Ê „F×O´£7¬´8&g½¬ ć¶ý)qÌè{+=Nä(ü>{T¾•.çc šÿ23º;2UN0hH“3|0ß Ú;­´:£ò322&Ú-®G) à>ÅÀ € € € |ÓMZœ{fÞ'Mp.×Àd³=·퇦Ìé½vÙ?â>¼züæà MÏÈÔ]þT9‰fGJ‡aïöONRgZÆôä»!´$ àž$7Šf"€ € € €$Ÿ@`²Ù¹š­¹j¼p·rØGä‡}yÀä¸7#ë)t†ŽÎÿX7}šæÜÏ–sºI‰cç²ñÃÏ#¥Ì Œ¼¿KÖ—, -@À=Úƒ-@@@@NÀ•îšq¯ÿ1‘ÆÝ¼©«vàÞJ{Ê÷ Þ÷xÿ ?Ü8k&¯´lûÌ$·V›îÊœm‚öÑ©oBA|`Þ,4Â>ú9”RÇJÄ‚@ªpO•;I?@@@@¸ƒÀ´ŒiÊ6ùä­ÇD+pmࣈ48áà}ä$µö`õÃûMÐÞçñ_;p³_šfRå˜À}Ä„´VhûP ?ô<ô¸cúóÿL„k pçO@@@@Æ$`îïž‘£»•3¦ë†ž<88¨k¾^¯=áìU3²>¥Ðé½~Yû:íóüÇ#Fß_¿Ùg÷&Hï ê­ÑôÑ)s#êÃ)s²‚)u†îŸ1Ý9´™l#0jâD@@@@˜LŒŒ ÿèvk„ûD+p¤ä°7£î#‚øVðÞʃ¹ï=s®u,zT¾µ}ýFŸ¿V°>”«>jÚé&}N0ï}ôñÈý ¾¸·úÇ’^ÜÓë~Ó[@@@@RNÀ lÏr¸ü‰vÎŒ& Äï3£ò{¼]þ€þpÁûþ×4¨›&hoFÙI•Úå°m}¥Ì±÷Ö/ X’C€€{rÜ'Z‰ € € € €1°ÝÖc¢KhBÚáž#GãØÿG;UŽ5 ¿Ï?*?RÇ Üß¼1lÐþvÁ|+xï?oÊŸ9}–¢Û‰ö‹ëo/@Àýö>E@@@@Æ,àO=cÝšà\®VÐ}hÐ>< ßš€6:§÷Úe;…NähüÐq+po–Ï2iqœþ@|tŽûð~+=Nðï´GéßíÜOŸFXy¤?dF’a? € € € € gkdºõ˜­¹jÉÀ~3zÞÊ[xÖMÀ~H.ûË#縷®½1è“cZ–ÿWV>”Ó~è³?%ޏ·ƒõÖD¶í@ºœ»4}šcB}JÄ‹ ¸'â]¡M € € € € €À$ 8¦Ï”õp͸wB¥ܼn‚ö&å/:XßµíQ÷mrÜ[×ûLà~fD@>:xÊ[ûAú 5:†p!öxªºzõª.\¸0žK¹ÒXÀív«®®N ,HcºŽcxíµ×ôãÿXõõõc¹Œs@ Íöï߯óçÏëûßÿ~šKÐ}‹À¿øEUVVê‘GËeœ‹ "à˜6C´Ïž`àþÆÍ&œ ¥Å±FÞ‚ø‘û?ìÿÀ¿_’ÇãI…‘›AÀ}d›ññyåéNegMŒøÆº~ýúøÛ• –o¿ý6¯iyçé4ãøøãõÎ;®D´¸r劺ººÒ²ïtÆ/`}QwíÚµñÀ• V:™»gäèn匪?O >§›7oŽêÜxž4-ž•§dÝÞv•š@»Ëå’kù‹êIÉNÒ)@@@@@¡܇ŠLhÛ«ƒeùÚ*ãþ™šØøöPA<#€ € € € €$º÷I¼Cç_®Ðz;Ún îÄÂ) @@@@@ ¡¸OÒíñuѾ´s’J£@@@@@d à>)w¬SÕkŠÔ6)eQ € € € € €@2 pŸ„»vâÙÚŒ¶ïh8¤òI(“"@@@@@’K€€ûï×¥5zl{³¿”üŠãzfÍú<Á2¹@@@@@ ù¸Oäžõ´èm –P¡WªVJÞkòL¤L®E@@@@HJîã¾mÕm\¡†àõÎlW^f`#{Üer! € € € € €@² pçk¯û¶6£íŻ۴nQV ¤Ep÷³|.C@@@@H.ŒA³$W“ãßZOÇA¹¯4¤xŸúö?­`¸]òuhƒc±ê­£EæØáˆc+ÆôoVV–úûûÇtÍôéÓ5mߥŒ “H17nø_222R¬gt¦JÀzKxóæMYï#X@Ñ X¯ÖÂçÑŠqX|^áï,3ryŒË[o½¥Å‹ñªØžL‚ÛJ“½¶³¿þy¸ õÇTõ‰ÓºböÌ2kïì Û­3þ—ʶœ–._Óüo?Ò“‹Æžlæ—¿ü¥ÚÚÚ¬ÒF½Ì›7O³fY­aA@@@@O ³³Sc îr¹”———xÒ"F¸ÍfûžµÊßÊÞ>š+¤­Ýz¦ gt's € € € € €@Ò 0Â}·lÖŸª¤ü~ÝëtsuŸNVïT³ÿˆ[å+¤+}Z4êa°Ø… € € € €¤Œ#Ü'ýVúT·Ö˜Pur¸Ozó(@@@@@`J˜YsÒYûÂ%öö+b+¼Ÿ5@@@@@” à>Å·”D2S Lñ € € € € €@‚pŸÊášÊÂ)@@@@@ ‘ÈážHwƒ¶ € € € € €$­#Ü“öÖÑp@@@@@D àžHwƒ¶ € € € € €$­÷¤½u4@@@@@ ‘¸'ÒÝ - € € € € €I+@À=io G@@@@H$î‰t7h  € € € € €@Ò pOÚ[GÃ@@@@@I€€{"Ý Ú‚ € € € € ´Ü“öÖÑp@@@@@DÈL¤ÆÐ@Iðyåõe*S}ò 8”“5ÉP¤ž€O^¯/Ø­Leeñv1õî1=B`ê¼L5Ng¶2y™zpj@@ ­|òxú$ŸO>ñÈÎ1ï7¨ÿŒpO ›q§¦x;*##Ã<6è”çNgsÒYàRûQmÛP¨ ‡Ó|Ð]¦'–»4ÇåTFáÕ8ŸÎ4ôFðt¶¨vÛ-Íp˜× ëµÃz8´tm©êš:ÌY@`tíu¥rº\r™Ç‹m=£»ˆ³@ mΩцÒRmÙ²e„G©9^£oÚÐQµ@šêžU¡ùÌb½ÏpÍ™£9s\rdªæH{Â|fÉ4˨ûĉq8ñl¡ÛÞlÚP¤ÖÞÃ*ÈŽks¨T ãà-^¿ó¶­sW4èÕçÖˆñî·eâ i#ài¯“+ãíû[´[—jîíÏâ(¤¹€5Hȹx½­°«µ[› rìmV@–šB­ØjÅ6n·餉{,'îq;$Ž!^Þm[¾XÕm#w;ßÄ:Z ÖÁ÷‘ïQâñyÔ~´6lOœfÑH<ßù—£ƒíîr:v\Ǩ¼(ÜÞæê"Uí ï` ÒWÀסoGÛ‹´ëP£Ž™×Šâü°KÃ&}÷`Gx›5@`¨€ï¼*"‚íC³HýóïCÁö|åçÿî“.@ÀðéhÕW"‚íùÚqè˜Úδê@U±}V›‰uì=ÿ_×%Rz‡KÀ«¦=?ÔK¿kÕÞúH@Q ¼vðÅðy%ûÔ½çi…Æ”­\õeý—=µbS½ÿœê­õÚ²êF«†ÅXC -ºŽÒÞPÏÝU:÷j¥ò‚?)\µN_]½EùÁ_ÍìýŸ¿ÖÖ-²_WB—ñŒ˜$ª:ºý ºýoìpBºuñ€‚{×>5m.€¸£€¯óU­¶‡¶»ÕxáU­ZøÐ²¤r¿ B‹¿xòÓ—[ôÍ‚UqÍéÎ÷;ÞÒx0 7_ÜN°=^üÔ‹@R ôèæÐh‘bµî ÛÝÉÔò¯=#û»ß¶ßë_˜")ï4F`2®œmµ‹;´¯Â¶‡v.YW®ŠÐ†kf\߸†šÁ3$ž@×Ñꈉ×>Z„ "རÖ`:÷ßLFÑ HtÖ—~f7±¢±Þ¶‡v.2óN…bm¿zÛü–&¾ #Üãë›Úúó­»´ã²LŽå™š9ó#ýîÅ­ª¿Mž¢ÛÆ!HÏÛ:Š·»ÿR— =ëA=nRË„~8ÃÏ4Óáƒ>"p{?ê žàÖ§æ ÷ÖЧ+¡"Ì©LžÂàlKM*^½=°Y¼K ùÿT´ÉþíŒ}+ €€÷ýQè7üŸÊ 0 Kj9zå(ÑSŸÉ½õšÌEÚ?ЧŸø?¬dÆ}¾ºá>UÝÚhöÄA K+×mÖJ»fŸf6p·9XA[²—ê»»«´´£[Îû>ç¡ç´‡þ?eJ¸µö €@š ¬üÛ½ÿ•nózàÐ}ÃLLÖ~ð…pÊ™ï•3Í|è.ÜIà’j¿ò¸ßùçëXíf-hØp§‹8Ži*0pÍþ_Oý\5{õûÓïËúúßåzP…_.ÖW¿¼Rs‰V¥é_ÝF`ï»j .̯øÏZ¨Kj:øŠ~óú)]¹fΟu¯ þýgôן/Tîp‡)rªwñ6Õ“V~ߤ•DA ªY*,­TáˆÝ»¤ºo—Ø#JT´V \ñr €@j df+wAÄ‹·KG_ù­º¯_Ö뇪 ¡Ÿ×¹Õ°íóq-’š7^!¼§j¿¡²à‡àò†WTh&iïOÞþÐr˜Z ­¿³+غ~½½XiVCÃ^•­/RÙýZ³(âýÉ3ÙDôð^è°ãmÕ5úlusð‹þƒÕÚ¤|í>vD¥… "Äg•îñq§V@ ¦Þ®m+œ§{C3iß¾(ÞÂÆô6PI!àyëe­6€×o, Ûóí.*ךàÄDIщS.àiߣeeÁŸÎ•Põš¼)¯“ @ ¹zƒ™•óƒï/ÜŪ¨ªRy±;¢c *Z\¤¦K$²‹@a´¼n^5L°=øò‘o^?JJLÎ\{iÓ¦ÇjO{¼3¸KÜí›Â  ‚f¤ê‘šR9ç¯ùØ^v» §1b{°‚—’/wð¬d}Qg6Š´tÛQy#NeÒXÀÛ®oço ˜ÉÚ´Ž_À¤ñŸ]G`t=úÝOƒ_ÒµµiGã 6í×s••z~“zÏS‰]P³ÿî«Ìc{°‚ÁO%æãI±Ï\Ôióú±gÏa t·©*â;»Meã>i*wþ^@”ðèÔË5Zꜯ¢­“–¹+tüý>mN€ŸX¥$;B ²—<­Óƒ§ÕtzP}ÝÔ¸ËúèøuL[õjýSGüGŒ¤3]@ É•äëй}Zµh®­‘™³D• 'euonÔ[qþÈBwûö°‚¤ˆ€¯S5O,ÔÖˆí2ÿëÙ}ìúzá"ñŸ"÷™n ¬œZµyŽ{ÿ¨Ç¶F¤þõYó ™‚ÔN °ž·Tñ}þ±¬ÒéÌœS³¬_ÓÎõvÓ_ª,SÇýfïœÏéG•kHgg˰‚@z ää.™êaÄ%3oµv™‘ª¹!þ¨Ì© 2 âˆæÄN è›úOyÃD5²ÒZqoþˆÆ» [Ó0-öÂ5Ný›eæÛº†¨‘‡#œ;õ»Gz…›úš©@`ÒÚë6kc}¨Ø¿°K+™ä0Â3 èû@¿¾'mþÕyžÓ°_Îõ}t1|eDªˆðNÖ@ ­œŸÔ—«Êu·ätÞš2¦ïÝ“ÚYxqq—kŧ¤¾{û…^Z¹ÑYÒ\ÀšhÙœû¡¼á‚ž_³àVïY½fGÕîÓì[_bn½†= ÚŽˆ/ú:eÞ~ ó‹¹ýßæp°ÝúqL<îñÔ§n@`2|çõ3;Ú^¤ãÝ{´2g2+ ,H9ç'ôé”ÿsm[™~~jƒJ †¾ptê…’­v× 1¹!X@ ½2sµ®òy­AÁ×QgÜ¿òLµJ—b*v#¶;w6hÛšÍ gaP´ì­´ç‡PùçôQ«´ý¡ãØY©ØL+e~4g–j=wð)íY=DOË?†ÓêºÿB1·Œ]N WxéŠ!6U!€S)à»xVMüv­^óŽ<ËPÿ<­ûÎÓÊã3p„«¤™@fžžÚW¬êà—u›–ÍÑG ­úÆùfÔˆG§O¨¦¤H{s¦œr}nÙЀ|š™Ñ]¸£@ß@¿}Nÿ€ÉíNfÛƒÒY {ñgÌ; i§…Ð\¦y¼:ùýb-]0Oò¼¯ÿýB™¾´Ý? ÀÏt ô ~ã—àÒ] KŸß²Oڻѱwýbér£¾·ñ?hžs@g~³OÅ«Ël¤ª¿ÛxË—yöÁ­d š%FuQÍ„<ª[ëÒFÿÿ{ŠÔÚ{Xqþ¶fBÝáb˜tÏ©Z¹–…ÿ'sç Ü:Ùۤ弖ܙŠ3Heóë˜mËPµT¹³ûZ»õô-#àG>Ÿ# ž‘i#v™×ͼn¤ç½F`K-µš·âΟYŠwŸÔþÒåÔÀ.HW–=´b“CwX†|3/U‹™—*Þã § Û:v&¸Ñ±¿A4¸øÆœ¤l¾"2¡Å¥ÍTŠ `F¹?×ú¾Tؘü¢*¼ÐG°}D! €ÀHLû0’ ûHO¹Ë7«ûL£ÊÍ܆Ã/EÚwüÁöáqØ‹@Z ,/ݯsÇvk¤—Š'ÕšÁvë&1Â=­ÿTé< € ðtuèŸÛÞVÏõš1ãº4#G =¬E¹¤‘ +±† €“!ÐcÞw¼}þ’® èêõëÊ™ÿ Z’7Ìdˆ“Qe €@Êø<:ßö–:?¼*™×Ý5_KY¢¹ 4>™€{ÊüµÑ@@@@@x R&žúÔ € € € € 2ÜSæVÒ@@@@@x p§>u#€ € € € €¤Œ÷”¹•t@@@@@ žÜã©OÝ € € € € €)#@À=en%A@@@@ˆ§÷xêS7 € € € € €@ÊpO™[IG@@@@@â)@À=žúÔ € € € € 2ÜSæVÒ@@@@@x p§>u#€ € € € €¤Œ÷”¹•t@@@@@ žÜã©OÝ € € € € €)#@À=en%A@@@@ˆ§÷xêS7 € € € € €@ÊpO™[IG@@@@@â)@À=žúÔ € € € € A›Ý ñIDAT2ÜSæVÒ@@@@@x p§>u#€ € € € €¤Œ÷”¹•t@@@@@ žÜã©OÝ € € € € €)#@À=en%A@@@@ˆ§÷xêS7 € € € € €@Êd¦LOè € € .àëéЫÇÞ”fÌSK¯_¿®9ÿ• ÍUOG“þÏ¿ª_wkÕמԂ¬1•D'ûÔ~ôçú}§G÷>ò×zrynµ¦"€ €¤«@Æ YÒµóô@@X xNÕʵ¬l|Uºw«·©Tgk µ¬¬Ù”áÖÉÞ&-Ï_q •ç” ]ËäïéŽV5=SðM¦ € €R†¿@@b%à˜9þš®ôËg®vÌœ,Ã%ÇøKKü+Mç잦ì(þÄ¿ ´@@`l¤”›g#€ € 0nì%_W÷Å/øçv!™Yê}ãôÀã[ý»ÜUÇô‹ò?—Ïk…×#—,å˜Í÷"w±Ž € € %@À=¡nA@HmLåÌ{K³çζ÷¹fߣœlZEª˜ûªÔ\ñ¤f·è € €@ R&…o.]C@HñÎïÓ,õ¨å`Ö.UFF†y,UáÚRí9rJÞ¨®_Ò‘=5zöÙgUw¢K¾žSª)]«¥Ö5êØö]RS]J×®UáÒ¥ZjV™µ›t)ºÐè:N¨v[©ÿš@[2´´p­¶ÕT{WT Q×y:O¨fËs]¡ ÍÃÔUs°E=ÝufĆiãѺgµv©Õçðcí–ZêºM##Š`@@©`ÒÔ©P¥L@@Æ àiß#Wþ&ÿE»ZuxóÈ„¶ïÙ üMõw,ݽ㸙hteà$Ø^¤û©áÀ.…‹mÐ꾡SÖ}çFÛ‹*v«ñøq5Ú­w¸ží«¿«öˆÁçžöºè`{~±vìÞ­ªÈ‹Â—‡©#ÿ5lÏ/ªÐ†c:ÖxHUÅáN•=V¦–ˆ6ÞR ;@@˜"r¸O,Å"€ € 0õn:ó =¹ÈŸn–u_“{ÛgUTÝl6ÚôzÇE­ÊÍõ ýc…¥ÛÚŠÕxæhÕ¢p>ù–ÚJ{Ôx~ùýæ‡ë47øiaÍ—‹TûäB•5X¥Ô«êà3:\ºÄ_ä¹þg럊†sznM^p{¥V=¹NUú—Z¿×OïÑ5+wŽp¼G+7Ï“Ü jxnM0m}©¾^¼Gó Œø·O²V¼oéÐÞàžüúíágü#ó­=…«žÔ†FÚ7¨ål–]‚—ð„ € €ÀT 0Â}ª…)@@)(9ð“p°Ý_G–žxê)»¶æ7?°×C+mÊWÃûû¢‚íòuèg[ýÑtsZ‰^жû¯Ë\ ÍûOÚ#Ý^j6Ùã˽yš­¥D_}"l³f~-øwá‘çŽàn_g³^ Ugç/ÙÁöÀ ¹+KÕ¶;<®>TšLÀÞ¸Þö½1bÞ:gùW¿¥ªŠ UTTéÓ³öe¬ € € +F¸ÇJšz@@˜T·ŠW pKýv-.{-b¥¤ROäF ðž;¥ÐÀqÈåó¨ÇLG¼Ô™ù =dÖýqòæ&½íÙ¬åÙÒÜ•›uzpsà,ŸOžžyz¯èƒ.éâù7T³±>¢òÀjÏ¿vØ9äK*¿¨ð8ûð©K¾°YîM ¼ó¡ÝÎÙ©îT¾ó´*vÿVÿÅr=¼præ.WåsËCgóŒ € €@Ì¢ßiǼz*D@@ñ ¸t×8ÞÍüY «KD¥×.‡·6i¾s˜t.á3ük¡ÑêÖ†çü ýCÍßkëÞаõ!'Ù|÷£öž‚?›g¯G­dßÎ;:™§mUÚ»z{pO³ª7™Gp+ß]¢¯³X_ýüJÍõ§® ]È3 € €± ¥Llœ©@@Äè·©G/ÎO=l§‹‰>2ÒV¯•ÝÅ¿t5ÕÈõÀcÃÛÝÅÅÁt3ÑåÜïþ{ÿ@ôHúè3oÝZ°ªRÝçŽkGä ±ÁÓÚš÷ªìKižs­š.­Ü[kb € €c à>v3®@@@ ¥úÞ}3*ÆôªhÇqõöõª»»û–Go_ŸúüWµÌ¤“‘ï¼þîñ­¶…»|—Ž·ÓÅî^õ ªiÿ~½r Ä>Zy§ùçvJ™Ð¾áží|íCæä­Ô3ÏÖ içûçZÕp`—ʋ¹â­Ä7÷UrÇ& € €À” ŒãG¨SÞ&*@@@ 8fçÚµ5´¿+GÖJeß’’Å££µ?Ôë™Sg?ªïl^%]<«³¡+‹÷©áù§Í4©ÑK×{ööû—šõ@ú™Ã¿zS› VÚÇB+=¯ÿÆþ ´Ï×uBÕ/4ªO÷hõ·þV+s³•›W 5ÖcÝfU?¢¢ŠyßÏþÁ?ÁjNèbž@@ˆ#Üc€L € €$²@VÞ£*5°~½^éð†¶ìçž–}Z]¶]Û·›ÇëÝýÙê+%nÿºûÓy·Û}]Gõ½­ÍÁ2L(>˜ø=ûSŸ¶SÊ4oÿžšºìj‚+]úÉ÷Â#çCGû>xCÛ««U]½U¯´] í¶Ÿ³ÍÈ÷Uö@÷ðä±ö ¬ € € 0Åܧ˜â@@H|*Hý²~ñgU×r^^““ÅçóèÔ‘ÍYQfwc×–Õþ‰W3}]zqo  nÎëNœ—Çë•×sI-GjõÄüÕÑæþ+ëõú[—ük™¹ŸÑ³v„¿YÏß #í]þ0ÞKíªÝ0_vœÞ®UÊþd8P¿sõjÕ6u(ôÕ€×Ó©—ŸÝ¨­m òW<,F·Gొ € î1a¦@@â+0R>ôP«­ûïÚ]ÚjÖÆÈéÈÃáÒ²¢ðhswÕ1}³ ÊÎyT•vŠvsÍcÈåtÊéš§EeÁö@¹›–ÍÓ†ƒf#Sk¶·Ê¾Tõ*ÊŸ/GF†œóòUVjÇçÜUz¡*0¢^& |Ùã‹åÌXª¥KÍu®…úÒö@šÉ­ç·XikX@@ˆ­÷ØzS € €·˜yûòÍ–>Ìuö¹Ý<œ=3˜×å–Óçªt¯Ží ‡Á‡žRq U¿®,4áòÐ’¥'|A»Kì<.¡þç’]ÇÔÝwNU‡ÛÞû(pNNöô¶©ª(ê’à†[»]¬Ýieå/ÔÕÆ6µGµû/v—ëØ¹Î®\ö!€ € 0µƒf™Ú*(@@’IÀ×Ó¥¶7;tñêu͘q—îÉÍÕý ó”sËDªá^õt¶ëÍó—4àpè®{æêÓ. ŸïëÑùN“÷=Ó©9÷Í3ûÃ!{“´F]mê¸pQ¦6åÌ_ ‡›|ð‘§„«±×|=j}ã´Þí¶Ú8ÃíŸ~:_ù‹r#¾°Og@@˜p 3• € € € € €¤º)eRýÓ?@@@@@˜p 3• € € € € €¤º÷T¿Ãô@@@@@ &ÜcÂL% € € € € €©.@À=Õï0ýC@@@@ˆ‰÷˜0S  € € € € €@ª pOõ;Lÿ@@@@@b"@À=&ÌT‚ € € € € êÜSýÓ?@@@@@˜p 3• € € € € €¤º÷T¿Ãô@@@@@ &ÿ½·/„˜ÇäûIEND®B`‚concurrent-ruby-1.0.5/doc/images/tvar/ruby-scalability.png000066400000000000000000002743631305460430400236470ustar00rootroot00000000000000‰PNG  IHDRÜ„»8óÄ/iCCPICC Profile(c``2ptqre``ÈÍ+) rwRˆˆŒR`¿ÀÀÁÀÍ Ì`Ì`˜\\ààÃyùy© |»ÆÀ¹¬ 2 UŽ +¹ ¨¨ê¥¤'300ÙÙå%@qÆ9@¶HR6˜½Ä. rвùÒ!ì+ v„ýÄ.z¨æ H}:˜ÍÄb'AØ2 vIjÈ^çü‚Ê¢ÌôŒ#Ç”ü¤T…àÊâ’ÔÜbϼäü¢‚ü¢Ä’Ô Zˆû@º! A!¦ahii¡ ¥"ŠˆqŸÁáË(v!†°(¹´¨ Êcd2f` ÄG˜1G‚Á)Ë„˜I/Ãþ©15C}†}sïPoì%¬´ pHYs.#.#x¥?v@IDATxìÝ \×7þŸ)(š€A£æÁ4hÐóÔk«u1/&^MòèÚxÙ®6­’44-ø¤]ÅÝ6ŸÕîb«‹é®â?MÁnŠÁmªM½î?ŦL Ö…Ôkž@#DØD6 4‚B;Ï™{ïÌœ¹wî\Þôwýà;/gÎùΙ3gÎÌœ§ˆø¡(@ P€ (@ P€ (@ P`P× ji.L P€ (@ P€ (@ P€ €[€ îÌ (@ P€ (@ P€ (@(°Á= ˆ ‚ (@ P€ (@ P€ (Àwæ P€ (@ P€ (@ P€ @ØàDA P€ (@ P€ (@ P€`ƒ;ó(@ P€ (@ P€ (@ P lp"ƒ (@ P€ (@ P€ (@ °Áy€ (@ P€ (@ P€ (6¸G‘AP€ (@ P€ (@ P€ ØàÎ<@ P€ (@ P€ (@ P€ˆ‚Ü£€È (@ P€ (@ P€ (@ P€lpg (@ P€ (@ P€ (@ DA€ îQ@d (@ P€ (@ P€ (@6¸3P€ (@ P€ (@ P€ ¢ À÷( 2 P€ (@ P€ (@ P€ Ü™(@ P€ (@ P€ (@ P€Q`ƒ{(@ P€ (@ P€ (@ P€ îÌ (@ P€ (@ P€ (@(°Á= ˆ ‚ (@ P€ (@ P€ (Àwæ P€ (@ P€ (@ P€ @ØàDA P€ (@ P€ (@ P€`ƒ;ó(@ P€ (@ P€ (@ P lp"ƒ (@ P€ (@ P€ (@ °Áy€ (@ P€ (@ P€ (6¸G‘AP€ (@ P€ (@ P€ ØàÎ<@ P€ (@ P€ (@ P€ˆ‚Ü£€È (@ P€ (@ P€ (@ P€lpg (@ P€ (@ P€ (@ DA€ îQ@d (@ P€ (@ P€ (@6¸3P€ (@ P€ (@ P€ ¢ À÷( 2 P€ (@ P€ (@ P€ @ (@ \kÝ­uøyéAû¿V"%PÆ‘bÆÁAô¶¢òÿ? ±YGmYc]F"Í\4"@Ç®ˆ†™û;Pút1*Þ¾õгúÿükRG¦i?{¯üþƒ€Çµ+ü£ØánƧ?·©Iâ¬ì8lÚ0lˆQ» áY)êU¢° Vݸ"â?cÆl¤Ü>I‰!*¤µéÄüæ­‹˜0õ3øÒÚ4„r°<ÁÊGõ¬‘§±³¡ÎWþ —qV~emÈzߨNþ0EN«k««»í®@u¸~œ­ü%~¯VÄÓŒO¯ÀÒÔDõ‡ß§éÄ1¼ñº·„_w+Ç¿Är(0º~(@ \3=JEa–"Já6¥°¢qÄTj íÞøÙ•š®ÁE£«¶POkAmGØŠƒåø®Åî5µÔHëèSÚë•úúz¥ñ "…½Á>¥<Ϧû¸ó…½P ¬Ô¥ÚCåÀÓ û;%KÊ{yåB&¥¾,CŠ_žz‰Ah9…ÞìJYmÛ€Öµ…¤¥¹¶B9ì¬VjkÊ•òêzÅoiÛö5ö”sŽ"ŪÈfõtæe’½°Öoº{D_½©NœrÅH¥¼H›R •·9aÔ½Õ¥m·Ö_äq˜¸vFü4Qià‡ À°œ=ðu¬Ø\*­Ëެ<;RnšNÁ~§Ë;Í…Í+æ5Ø”f}·„HÔc'Ìô†™€ØÁ†;A!¼;”ôÙ-BÅmªãnž³U"$qò…3O¦Y†9b#ûñ‹]Ú6q´Û1{ÁMz`¼8ðØöþùVd:°³ÓÈ®²—±}åú wŽuâ¥5òkFÙ£±g¤|Z  MÇjÚÄþ3-ôìC1Gl,´½(nÐ;‘UÛñócÛ¨sìæEüÓÚMþÃ*~£{œ«$‹6»KÔtAZ ›f}“!åÃÙC³a}×ñïPedÄŽõ†â80a£sãË¿€täÝ> ±A&ô¼ûv•îˆoþ7¿¥IžÚÉŽ£t¿zü öqà›?Óµ‡Þ&ìþÒäzª¯Æ‚¶Ôüæ)¤ù=ÜŸýÃ:w±’¿é¡€O™‡>÷P>°w»{dU¥ Ý›ú…ÑÛX“ÂÞ_¡å)ñ¤¡oÞO׃·ã iƒ«I¸þ¢Ç Àµ$à[$]KigZ)@kI ó¶e–ê)Î+«Åöõ õº$° ÿÔT‰ï|aö{O<7/ye’õ¥®Ù«ÿ% ŠOÁÍ¡,ãoÇ?.ã¢K™)ón6ÄrZ£ç¨l비´Øf”àÕƒùUèµÉžïxd¾Ü†/÷›ÇÆÄtáÇ-NDÜç/”7þi €Ïlˆ‹OÄÄ›3oƒ;J†3ϬÜØØz ÏêçDvd>j^ñýrTãÈ“w¢¿×Ha_O7ÚÎ×âéÌUØ«í?yÿŽG*¯ÎèÞ¦_#×·ªêYœhyk×Ò1B[uxWk4@Ì–/Ñ o$¸¶áŠã@0#:v €ßZúºõ#Š\¯"{~¸Wœü‚Šúˆ‚ŠflZ<=ýžò=&&ýÝpâÈ86kÍ[N¬˜õuÔvÄB-êêÁ޳Á¦E=e#`¼vŒì…hvfaJ_½¢¿ë=¼òün¬ËõÖo«rñ\u&¶-‹Ýò@Ø 3Jc4¶s¸É—.<ZD.× éØÜrc»ÍŒ©çQZ%*A®½X2}"š•¦s¥îºlP³¤½ß\ywÒü»!žœuß°gš{Ã|­ñßßs¯TøÄ|/NµìBJŠyÆÎóoxÂQç¶§#@¯3>aŽ%¬¿øQq(D@+}ƒÌÂI ƾ@·¨pi7fØò*°S4¶û~S–£øÕZ\JXÏ©K-.vÉÚ ¥ïcîwøE~bÊR<&þÂû$béÚõð›;Ní™Öû™ ÎFFÛ'~’ÞÀîX±DÍøÄióÅaºh`×>ÓgNCÀ®T“W@tK÷ͽ"G:_kEÚJë“‘ù.ÈŒG±xΟµ4™¾ã®w¼‰qF~Š‹‹C|âJì)/GåÌUž½ªJ¼Ý½)ðS cëÇéCÿja~"ž’Y#îÄâ'¸€Ñ^؉ÁçåÔ1.0Ç aFvìÛIfxWœûFQc»©¸§ˆ‹ÃñÒÍbd|ª(׊Ñam[çm¼*Å·~ôMTêO®¨;Λæó_AòjØiK˜€)ñâkÞ*žÅ±öɃ(ÿðVíò4¤V½ùîÈ4¸‹ç»,ë‚a't,Ì anç¾($1~~6”¾lX>z ^'U³ºâG°h£çLÆ^PÇõr¦CÜቄ½°•aÔWzÏB¦÷*§¤O=–æ^õ?ß9«rE`»ð\å)ϵãGßÚì^IIáú=õ7m>VŠ‹j›>ÄYmó1?UnHïÄÉr5}æK å'š±>Å|sÊùӕÿÙWŠwté¿‚:–°þÜS)@³ÀuæŸüE Pà*0jH˜½Ð\3¥8Þ‡èhÛóq¢¡­Wûáý/c<²é ÆaÜ8íoÙ²'š:}æõülo8}[³±|Á}™ËÓ±uß!œm-ú‘|úÛÅfû-^¦º@[¿7={+UžE°Ðb»ÑTY,–5â1nA:v:á·œú’§ââbì+>‚_¿øv¢òP±˜ŽœhSÅ‹ŒŽÀŽ­ß÷^¸Î—ÿ»wï@qåïQw¤;vïÆŽÐ ì–J±üŽÝؽC]F 3œO/êŽã‘åÚvñ|/d+ŽÕµšP_ÈT¼õ #~ÏáÀ‘†C§ J¦åƒþzF•ˆÕOè j·2ÖëS»“Ñî&ò6<è×Ði¾ê<{Ìí¹c÷!´ö +w>VóÂ8,çM­ybRWoK ò‰4Þíužxï>pBä¬~÷6vç‘åéÙ(>VÀÑ*"" ±©yPÍ“;ö`Y^¿xÙáví±<¸ê»OùÔ597‹ýÅj•Ò¸^ñBâÝÙézY –# –?âÞ­KÈËœþö:oyÄ´Žq –ckñ1´úf¸þê¾vè”y?Ñ¢ÝrâØÅ<Å•’U;ŽíS÷cQöµŠ-£®s‡§œS·Ë±¾ì­Å¨“V¨–+û„û÷÷xÔ{ð~²+xY Å!ø·‘†­èqÙ'Òˆ‹ð->Þà ¢·EÄ{+Ò—{òÏG¶îwÆ™aš*¸Ë´GDÞ/kU—1ÊpQænñ_&x=SÛ…Áî-Ùbý¢ ×ö¡²¡Ýbñè§K^ÉÀâîövh’£ðË„Ða?v…Œðn­ˆó¸)a>?Ô—`Ç™¿ËÔÊvžÛwÅûŠÅÓ1Fþ‹hÿëˆnÙn<¹ä}$Î_‹ç«EoÈÞOUîÓ¨Ó¾õ ØqöípÁ¢ÎSy`·¨·¤»÷?­Ìßw¨í™¥ð-" 7òãP輪G:Ô@W¨€e_~XŸIºþÖSž²{Ǿc°<¾ˆòð»>¶•V²™ñè]r‹:¬^çǬôlµÎ«o|ïºýó€)u Bs÷²b™ãvøÔ¹ÅúEù+[LëñùÑÙpL¯O9ë£ ºJ9 ÛTƒÝGDÝȼ°¼ìqwz}ÓÉvž!^܉S‡Ä9„8þxÎ!R‡qŒ1ÇSÿ%Æ÷6ÐÛ!žŽxþÉåÆì½QënÄÏŸ¾Y_,Ø€Q¥ÍCŽ·±]?eå×!Þÿàþ¨y´Oëñ=ž'>³ãKzC¿65Üïi¸sƒQ™|½®Ù¼`ç›xÞ}À[FÞx”­ñ9Ÿé†«\»Ý H¿ïvo8âØZ¬Ö=và€¨3ôwÖ¹ëeî<þÈw¾Ç’Hê/‘[=Qj?{;|ê†ê9Ú¾ˆê·f&þ¢FÀµÓ]=SJ \Ë]®"E¹ž¿Œ"%Ø+{Ú—K¼ìÓåR.ÈoôëiT B¼43Ïi~qbM¡üÒKã%@z\DœòË›M›ÆU¤-ãPjå7 ‰%ehiôm/P𥷙Òhu¼-O©—ÖèeA–q“^"e//7’~ËéT‡m•J‘d˜_mµ%Ä »¤yJ䈙¤¤}ÍŠèÝØÆiµç9½/n’^æ;_$/ÓWߥ”èëöÙfú<Ò@Gµþ’YˆN‹,ßéiz©^†Rëófªä+c›B±;Ì/‹ õÂ>99½ÀJM¢)mYJ½”ÕɃ‹·]ÉÊ0Ç[Î_¶ü ã…Y=µú¾â›6ß8ÕXåA5¶ÖŸ¶ê=ŸÙóÕ—w(ùÒK‹\ÒŽäDc¹±¬wc8Oi”·õÊœæ ãEÉF¸ò¾aWËûTW­âðîvÓKµÈK/ –_*,íç6ñ6q¾«»˜×kW*¼/l«)´ýÂ{AtÀ|(ÅżnsœyùJ†´­ÌóŠx¶i6Há“Nчåþ¶,#ÝSú”j½l7ÇK‹‡=¿Üüº¨§K‹êàâÖöwù…оû£f!ëÇÈ0Â4Ê9Ÿ<Ñ1Âë$­/¬4k¼¾»jïÿÚË#ÞźŒ4G^¶‹¶tü çå­ÍJž´j•ÉÊ]åbÀ—±Úv)»í‡Ò1¸ïB¨:C)7˜áY .Ü0C’‡œ—Õa9ÿÈ*Š"ÃD·!_:)¿PZ~Édm¡Ã[.ûìÞËËÇJsžð¿ü;ïp½‘)Íž<`Lˆ¹ÒQ£ÇåuÊÃ…Õæò×X£1ÔV¯›Ä®Æ1$§_ ×)W Åôê|ã˜åžæ›Fé·/uXÛÎÆ1ÁºÜ×–³T›â6 }J޾ªÇ4s(=âE¦ÚúJ|+hæYõ_Æq7_¹ UŒ}\Ïsúúm~–¦EÃøÑQ#•—Y‡MÇF¹–_Q¯”çiÛIÔ©å*XKÊCÒ4y»Ùìæú‹Øß:DüŒrÕ³ï„WÀ±U]WˆºÄy«OÖ C³P€£A£!Œ(@¡è©/Ñ+™îʦ͡””+õÍmF#]ÐHt(Ez£ªZi¶)y…%ŠÓY¢äHÃ➥Z­©‰O_c™i޼"¥¼ºZ)?\¤d™–ÉP\R#›Q9—o{”ÃYreÝ¡.Wª+Ê•¢ü,ózŠ\žˆÿв´¬=K)*;ì·2Êô ­uÅr¼tbènŒ„…99J^N†Q‰µg(yy9J¡¸ q¡Â8ùAŽÓß_nl¶½8âI¨89ÌÒ'¶MAY¹R[[£”˜m< Š=Jyaž’#â§xÀ¿œ‚ò'¶:®> ŸœÊÛLŸÁg G)“â›ãô?a¬/3âmË)7 ._i'%²WèF9Y7¸÷)Í5J¾”¯m>'ƒ‹·9¾öŒ<¥¨¤HÉ1í“Òɲ”'Fq"dºfSÊ\ÞÕg þiÞveõžר/ÄI¶Ï ½VW­tÑO=wä)%N§RV˜cäC1Þhô޼Ìér™Ë9[FR^S«ÔT”)Y¦.£œ’v¬·­”¿å†ÉXßDù——Ÿ/ö}#ÿº§yóp›ë°(ò” »‘3rÔ}±PñRj\–ßó¡U\lJA‘ÑâêÈÉW òsŒ2Jm¤ÈÒÊ#)Ízã…§Ì/+)ôk´?,5úyÁ\ˆ­™¶³#§@9,¶ažÖ æÉãŽ"qÑRûD=]ž€£—`Û;Äq@IÄeBaZûGzŒðn+ÿ`iö.èKmtÌÇFßüŸ'ögc—8^`ÿ+ó¤Ùا´<®~å_ X™ózèùÕ†(#ÏæöÞd YyÊ‘`ÇY§òB¨c°©¡LÝ7Ô:ÛaÅYV¨_ ô¤S\–ØBZ *ÜŽCaäÕ@[Ä=^ò„£$D½Ä|¬Ð·‰ž7<~²“¶n¹L5¶½9Ohù)« H9¬Ö_MÇ(úMRœMÇ’™÷(¢Ûz½ÌT—eÎ ¥¢ü°’oºð.5¢j‰òý–.*Ãfn4–ó²šNs}ì‚q1]«‹ú¦1Œíl”IFzìYùJI™ïñɦ”{/Nû&!Üß5Vû¦´°¼½ ÊÊ”QvØíŠ]ü9YJaYµ¢_wö.'/“SV«×G¥‹ûùž¦x­îªÞ1è鎥Q».®ÐØmJ…¨Æµ•çéy¥@º‰Âtîç.\IÛÑ¿å<-æSk†ÆvóËé¿ äØÚ×l\ñœ[–)ÕÊá¢að­ä¹ã Ÿ°ˆ»Ñ¥ö÷ä®z£q_>Ñ‘+Ê’½²¬.ØQk>Á/ól1¿åx©â*¯[é3î,qHä>À|±AS£ÔØœQ"Ý=¥N´ø˜2Õm#ÕÊÅüªå;~¥†Æ@ñ³XGðQòÉ©¹‘-ÐrmòEéB‡g~q×Ôpmœ{¦>_yöƒŒÂr¿«@ñõÍG'g6›ÍøÓ%½û˜h ð¹±J‰N¼mJ‰t2%N³”"éä;¯Ü{ÿ•”'=w`ŠÆö£‘H=©)“ïò”pßñmÆÓ Ú ¸˜Ç|”eº€æ B4ˆHÛÔQ¨Þo|zF¸û·È‘—9]¦‹‚ŽÂjÓ¾.öÓS úÝt’•iÿÕ£'åï` îYæmÞQ#]`ðiä0ò‚ØÿÍ»«¾V«9šâ*¥A-çìùÚÓ,j(RY«æOq‡¿t¡¥O\à®{Êo=}RšÝÓ²”ZÓµ™.q<ÑÊo±¬táвŒwjêëy¯¨Æ|Ÿ`s…t'Ÿ(õ'Z¢ž.•#:qA¸Û;H9kä(‘#[Dò¬ü|Œðñ;Íj¶ ò1Ò-çÿî¿b=Fš=ù8’²]­‹Oh…Ó@¯Þi”¥ú~(YéãTƒ Û?Ø´©¼¶å”™U>O+Èõ‹PÑ 7ÌãP¨ô«Ó}$O G©ilV}þꕚòŸ8Ä“e!oà0V*—©F]Ü'`ë7Õ«Ú”½þ*òœv÷±g9 È\ âXk*~Eôå'cŒxé2ÉÊ廾Í*Ôc‡é‡¶r½ÁÓ®³¥xÉi –—ÍyR}ÂLNùüAk¸6Ç?¼_}ÍN=¾ª™oL Å·AØsä=þiÇAqqËiªù8ÙJ†é)É<Å}Ûˆ~aCœÓÈI /úsÉuaùŽyé)-Ò:ö|ãIù|B.'äóÏÓyJy½YÌØnæz½uù-¢?Àc«±(åæ8(âÉfí DÑ=ß~`ÆQ À(`îâHÃ(p-Äaíž”Ї-ý>.8÷ïÅæL–Øæ !vèë¸Rêï²ÿ±g³¾T~E–šÞº‡5ß4­<ó¾{Þ©)‹½};gá˦èË{â±ðNo§ƒbDÈWŠÆMÅ=¢/õ“µåËH‘ß$ÆÅÏ™ÑÝLðèOQ{Ù‘6câÂÇ îðÑ~âg/¾¥z ßèù—¥á86ähi/Eùi¹ïâNüFï»\Ì÷àœÑP·ÍF}žüêÛÆÜ¹eÒÒMkzç©Bi…·ÿà@ñÓCºiw¥Û«ô_qºSZWë)<[¥ý΃ca¢öÃý|eË+ÇÁM+áCeZOÐUUp¹\ÆŸïÌçßFƒÔ'±:9ñÎ*{¥É;ß4|åÉ'ôµ×¼íÙ÷ôb aR/Ní[‹{sµ~<í8\ÿ*Ö§Fþ6ä†_?ï}a ¸T´e•þò­˜äû º›ò~öã¨)O«}ª:±QÛ¦ö<³)M›Ùý—²OêEÈ‹h퉼ÌémølÔ’h+À7-5úmu¯% ›Öêù®*÷4ùôWkŠTD?²PÿÃÇtuÑÄ´¯@4äy>®Z¼+u÷ÛwÙ;^ô”z©GŽÖw~¼mô΃DSY›Qò ÖÎ7ö©˜¤exT‹çÅ|úõÄ© ú{0ï†ñX»«D·ÄÞŸÀ%¥Ï7%MâÚæÏ(yÙiæ%'/¢QÊ»X)^=#ZhÑIWtâÁöRθL¦¦e|âa"†"H³i9ÿVù?Zûï Ëvÿèú™ý™å~㎶­MïÉø‰^^gáù§Ö›U1É¢,«¶Ç8Ÿ¯’êkFLü,¢nDÇ¡@i4¢ÆÐ^,™3 sæÌñù›‡%«2±_+\DHmÅ0½[2ŒÐCÍRöÂ.¤™* ÓðØöëþØ_Š3Ê¿š‹*£¤ë¿ñžOýi_þ&òóò——Û'‡zóvÒÚ¶ ¯iïËè>r혩"ˆj©ko5.xAZk«=/€¿¶ßáà+ÌíœUöc¬M5Ž?â5ÅxðÑGõ@«Þô¯ÃèƒôâèN‡ßÂ’¯›ŽÇÚ¢}]^U›·nÏ€x* 9zFÌê„cž•íZ!Ù?­‡~ˆªr¢T¼ Þý±å ¦-ÉâÇ©å‹%ų(E;&%±··W¼Ågz–ñ"îI×örjêÛÜó÷·œ¯iõ|ìîó¤3i6x“TuäexÞFÓ‹7^ÑÞ—¬ºk–w)ó—èÎ %X™*×-ÍóÈ¿¬Êouú@­}FNÇ¤Ž‹òª€iw"¯¤@l£<ä§ßŽP9ݼ0Q€£A€ î£a+0 À0 $bå¦=Pz:àª.GQAÄ£Ýëvaׯ˜’~À{ׇ+zÍßÕw™KÜ$=ˆÆzD¿ïxáqOÅ|šhè=£(âI¢bÌéGwg;Z[PwêŽÚ‡'2K-ÖhT²žQŸJBñcóÑßÛööV4œ­Ã‰ÊãØ÷íÍú @…P˜½Â§Î3§ÍñUï…ñ{B ¥£9>w?ò¸`Ù µâU˜ÞOû)<£<:¶àî$sã¹6›ñ-o›,¬»ÓºÂ|Ç]÷è‹|Ðú‘>”êWéRü¦™ó¦cÉfõ4ÐóɯqŠÞÈÛñ’­íäM\ Z=_ R|OÚG3ôßÛK_‘^. ôghp¤ß‹˶6Š õâï|f¢œ¯Ã+súúôB Y¹k,O¶?+ôÍtˆRc·½ð«HõÛUå-ø¢bÈ‹ºjxö‚/Á÷ò¦Ä{Íô HЧë¤é€gFî_lQ®ÄÝ!½`Û'HÓOqÁ§\Ë7â¤ÉTñÂNtÊݽ¸Éf4èTž:o AýtE).ƒØÞrÂ_&È¡–÷¥#“ÇÅL¯åÿhí¿ƒ)ÛƒÅSžÖÓ9´ÇÐÞÆ:è{Œc!ú»Íû‹ØwÄ}©ªÄÛFñ§GÕ×":áì8¤Gjˆ^{½!ºk/Ý\å{‡‡º†øEبß8aäcß•Ø|âdÌÐÛ ÛDõ¥ß‡pâl:»EqZ¶í܉;·a¥Uüôe=ÉwÙõznÕË£îs§Ý Ä¢tE~¾x™½» ùEœiQk¤ýpýêEo(Y¸oî@ê >‘ëÉXå{t2׬ê0¾¡Xýîmzë´ÆQ„GÌWˆ½‹tâÕg½u!q®RP^¥ò vnÛ†=+ÑÕX!.+jŸ*¬øû_uó¸T;ЀݎyÈu_4qaÕ?EOñZý$apñ|Ro—@ãª^z yi+-/>ZFßÛð"r½7u©gæ«î_.òÔEÏ"S§Â%îú×?ûŸÁéZ‹¥‰ž1Í'ËõIwÜ~³>,ÄMKÁ|­]·÷¬‘¯Ã,sÎþ‡±Ž…ó}•µ5ÅbÊlõB'!ÆÉ¢6}`ß z³áÀ–æR qÁSu¹OmL üñ[Ú± ³-w—8|êNq‘EÜÝ)JN¼×Ñ…ñVÜà l€ò‰Nº¢—(nïÁ– !-£tŒê<.—ßW¶‡´ôÎðþÛµú¬ñ ~{Œ>m }—þ`,ê܈™=ÇIc¤ÿ,ü-¢ntŽCþ)2ÆžÚ¯Çä¾>—cÛ‡?œ«ÃOwoÀ^ïág»ã;XÝs -ˬ ë4)aB€ce f.ÐŽ%¢üà §ø2`ó˜l-ÏÇþUÛ½V‰ê’øóþ²Ù³ðøøòç—bZiIúÖŠèŠvfTyÛ–â½ÓÞc¦m%Ö?jÑíûőхª3mX“܇ê½Þ~ÖjÌ cþ©÷“€ë­¾³Eü»/=] /U÷Ex«ú8Ï@")où£}13šlž+>e9~ØX†ýs6xfßÿ" ×HOLÄ eárñç¬h>¶3×]«Èqnu_|o8´ó6¨5|éãOú­rŠ'kpÔç)?i.Ó`üÜÅî'ÉÔ£¬ëÅÿDçÎ{¥†í Øï0Òp‡¨“©wç«õ›*Ñâ¾æÎs¨ÔB˸slCÇÂOéuTmöÈ¿~lMIߊ|Û~l÷f·ªÒ]Pÿ<²òGÆ£_ÆÒ0ïÀ<î\‚JÞá>”º ›ý8[W‡:õïl‹qdž7v1¢>95 k7íÄ™¾6ˆ¾)õxŸ{Gœø‰“ýæ©*ow$úZ+w#aν–íöŒ ýn›À!HSú[°{yîÝ`ÑØnwÍx»›‘–ˆ`Ð8…›:ñú–ĬâdêKzûQîîB¡[êNÆ/-M½yÛtž=fÒL ª6jy>÷,š¥ Fí{â'?­——áÚeqHó·ˆN¸áÅ(ªs%LÇÜ”qSG*Rõ?ñ;%i+×cÏKõâíã„ëœH{¸ŸPEM}Æ80ˆò/ÖºüŒyòÊmèh¬Fx;ºïÇUµ›×Ý‹éÓ¥®O|ç’'áÁ ÞnSÄ“Low‹óo2¶ÕŸCJ² «½³WÖ4 ·½^oÜÏû«Ï¸è ‡?‚ÃÕØ«]@>2äþ\|¢•˜”ìÎ7¾íÚl1)« Þ!äý|€Bå1goÃÏàP×oËǷ׈z{ëq<¬5¶Û²à¬mDs}ò¼á:7/Á1÷SÚz‚|ËOå©Û­Å…WÔÖwõ“±ÊÔˆÇ=zhoÕ¢©A½|âùd­Z¸Q=XÖ»|è¯A[EYÛj;P]V‡qúé]¥ ûwmƽâB}úî¡£Á9(@Q'À÷Q·I! P ê=o#cÑ",RÿlÏ[öõ©¯3FôMùݽÁ°êø)tÆÆ¶Úÿg€>ôúÑÙÞ.ºyi»öЧQ›ð+rõ`í9…¨v5¢­£ =} *Ä eá7Â4Ýé½kX ÒŽÂÃÕh¼Ð†.q§Šr¦>¯W4õ•ú LpB„žõ>+&Sƒ»ˆÛ‚5_ÓcXæ|ýÝ¿3º“ÉÊÀãÆ}>¿yÛ$øMÕGt¿û¦Þ‡r°óG}aHÆÚ"íD² åo´¢åõ_'_{п[(ç«!IfüL}ÿQûxqŸ†h¼³PÛÕ‡ú2q7²÷³yI~dý—‹;ÎK·{o!©Ë+Ýé¢Pþ]ìÈ ûŸù^Ö\¨9ì}tâuÖwX÷‹µühoÝ%Èù:Ì2§ùD™Ô­”uãDŒÞ:®¥#Ìë.½çñªÑ¾¦^;ß¶”€÷s_º¬5l%àÆwÏ©æ¯>§=×î@Å…tut Ã÷¯KDy®þÚ´hˆ|GQ\†«L÷¥Q|Œ²ý7Ú9I¼cDïöMÔ:ê¦aëíÇk­ÈqT‹zN—ÿþ"öµþãÙg~‰Ea\Ǫp‘Ôð Ui‰I•n`ºc¬VÖ|úU«ÑÆ8q‡{ Ï¥B—ƒ5OLYŠ'÷]AváBc-œe…È1µJ:Í]ŸЬÇýéÞ©Nœª:W¼™lõ½©b|î÷vóçªy /¿Rí׎û%y‡GçWƒ³D¯ßf¥[vY§Å¼¿¿ê_àÏD$)'ý—ëÆO¿³Á=ºàéîuw¿ÿ¶·ë@Í«ÅX³0EÜÔ´;¥ C/¾Öè”å˜x,I×ênNü¤ø j¼óe9ÒÌèqs±J›µò0ž-=®‡x_Ú,}xhylIÄÒõOâèEÔ. ¶Ú‰Âü£.-"í̽G|Þ44ia¨ @4ØàMM†E ŒNøÛ ÝØGC¨›[û®èž¶³7 õvÑ£xC~ǧ–âÖß`Êôé˜.þ–ýè úÛÎáœ6-£Î=›°t~ ¦%Æ#ÎÛÖúž>‡6g€ï~üß×´*¦ eõ¿Ä¦µK‘’4MÄÍÛÊ#ú‡¿`imô«'­××râ½²Ž þfkËGû;.u™xŒÒªëÅð³C/èîùâñOoÊ‚¯VÞ6ÎrÏ]âKœ{U° fM¶˜cdFÙV~U_ñ‹%O‹w/jàÚñð©ú4m ºùJ 5ºßýÍ¢qZ ²ë²û‰’‘ŒwaíÜ]}¤®ÿž¸÷KûìÅ×ÿ%ü»…ÚO5úý}îÜ”ìM›°IþËÎÆ“Oí0.|U=ƒÞ»¸f.ºG[1ž}é }XøÍö)îòcúôe8Ýy™3KZÇÑßxùq÷Û(×ÛÛg㦉r İÕþ/]ó™; ?Ãh%‹ÂZ„¸«î­]ÉP œú»‚¥c"’æz :ÑŒø_]Ÿ˜ˆDŸ¿‰m¯á©ü§Ü/_О 1­0 ?FO\†­L#Lj¨ì¿QÈ!ÁƒèÄÜUúq9ë` ë@!tž@‘¶ŠÛo¼Ì™85Y¿ª*w—ÿ¾.VYwèiýÎQ{Á¢^üëƒÞXá,?©ß•è›5ÿ›FÙâíÁÿ,ÅǃdˆCpbW‰¹Òr¬XïrŽ|£o¯^®Ç1óû/˜^¨ë™Ð‰û»Uؾk»ûïý>‹–1=„Á Œp\äã@´Ê9LKš±qŒðþk™æL˜$·Iáô¶âÀ–e0Þõnƒ3ç/‡¤«¸”ÅF)¥ðBC¯Ï Úзj³Ø_¶‹¿Ó~Ó­F U¸Vë²2¯Z.ñHë§Kqú-s°¿åˆ÷E—ÁVQŠüù—M¢üÓY¶¼Ì€}ÆÔ¼çý7DY¸ »våâ—ÿ»…âÅï+µªŸÑ·M°„ˆFû¹þ/º¶­…ÍûÂÌióïÖÓZ@އï к6‡Å÷0mg÷š[](ÓNlpg²÷Ž‹hÉ£öŠÊ¦o5D~jÿ6ãæ‚Ñw}ÐàZñã¬Íî`Kþé+úyάŋ=«r>ÓòJzßÕÞzƒ¹I7yæ ãÿ¸9KÜ/sUûßwÜßkñ9‹´&ßý€)D÷29vXÌjšo`?äúË@­=xã¹\‘Ïw!W\¹¸à‘x,]µÒ+êküP€cK€ îck{1¶ À€âðÅ8l,Yš‰)Ë·àHeZE÷ žnZPWy[ÒàØ¥ßН=8×½ÜÒ/5fÝ‹GöG{¯x4³»Ç÷ec‰~§Ñ÷xL+žwW¨ŸªíßÅMèîíEow;NÛ‡g®’±Ô!¹Vê^Lú/‹ÓÞߢÁ?ÿš:»Ñ+Âko:…}ÙbÅvý–8_­µ¬H‹ÓcÜ»,ÇêšÐÙىΖSØúàìÒ*±âÎÝeÞiåƒÔš3¯V¡®©â½Z¦Ïü7è®î ".ö|ñ²³ •|9ˆ¬üæ}„Ú7¤gÛxFõŠÇ߷ܳĸã:çIÜ™¨Ï> ±ú‰m#x†ò3—YÞáÝ|5°ä—f>ŒÝûöa÷îÝÞ¿غe+vlIG¬د'ÅŽ§¿éih ñVS?ÿq”{Wg>¼­ê@°OûI”j3daÍb«+!Úô,ý‚qÁÁ¹ñE¸ï#›¶¯=Î!öÃÓ³q¼¡ÝýhwkÃqd/»×h/t@½o+â2'é~Ñ¥Ö!öõ)žuxbÖ‹S¶`ÑF=!ÈɸÓ3IÜí¦7±‰þõŽ#híîF{ËYغÖÓ7«–¼!ø~áW§D9¬•C°‚(©–+[Š+Ñ*ÊÝnµ ?´³ÚKÍ€Â<‡ah±¾ä¿Ìv7¸'‰Ä¿ÜrH”áj#b?º[ë°;} 6jE¸½ŽTß‹ªpÔHÄEÛºòq`°e‚U˜Ö$cã3Ðý×:Ñ›9ïØçS¾oÉNǸ‰3‘©öÓìýd””ŠK†} Ö ó;ÙR—{æý%œj‚¨r‰2³uÇvcÊOCŸ`á–U–ÇKÿ• U¸þk’Ç„ŸWå¥"ÖÖ".¬ž5šíb¥a6.ÊÄ‘ºVwv¶òÖÎZ'Õ<¬OÜ"ìÌ]‚ì}ÇÐäî2±uG¶bŽTþå>~W€…ÕÑ3¿ùv½n¸wÕ*ì«ýª{×ÒÛÝ‚#;2õ—˜Û–x/쉅g’Ú(ªÖ·ÄÇsë3l«ï6º`™6_oÄ׎¤é÷Ýá™?Œÿµ- —sa,6¨YZ]Õú6´¯½Ó¿B)ôøy÷²ª6cú#»qª©UìWýèíTMÓ±D¿9(çÁöð–cO{¶A–Ò1+~ög½.ªD]'ĹÖÙGðHÚ"ý©‚¿ºK­å„ù‰™…|zà´ç/3¶›LLòbãÝHÞñ9öAÓ!-ñ \ر5Ÿ^¢å¶]X“],žÂÖs:ZêŽ ó^­{Rnÿ¤^[‹8®\€!… P€׈@ýáEµaÿå”Õ›dç…\6çp£w™åpVøëRã•á]Ÿ«(û‡RÛå ®§ñpÈu›Ó–¥Ô÷(J—«(Ìå2”š#¹VqP§ZŽï©UÄå÷z…µF Òx-nö"—1Ý=Ô¡ˆnÌMq,Q#áÇU’e C]Ÿ8Ÿò—£¸¼žîàEüÄýõþñŽpÝBY)ÑÓ`l³°ƒé¨VijR\3W@‚èæ«pã~>ÒÒ‘¡”7ˉºxËqÓóŸ”÷ k¥Œ­&¸Ëȯj>qIyÖÄU¢í"OåWXÌá3ªÇ¥ç+5ü"-ÓõÔ+â%¹Òv¶ÎSûŒð"+sÄr"mâ¼Ô¼›M§s¦q9eæý°:ßnš®í¯¦ou²‰ÜîýHƺ»6Íýx¿p9|Ö'ö9»˜Â1~Xnkurˆ¸å¿ü`¹ÿÊq7Û™LT׬Êuc]æ² £&œ²Ø®T\2@ÔÓå±Џ,¥4hvžãÀÀËy{›Ã pŒÉè1ÂòØæaÿËùļ½õY,å‘î¿óX·ÿ¨.¿c°fè;£°Z‘r©'Hi;›Ê1>àq6Ø4¥M)ʱï‰ýÏ.Êd9.¡-†&ÜpÊ&ÍÓ¿ä¿ULÇ)¹Üµ˜UÕQ[h”©Ž"¡çý´UøÔ/›ecøy"C>~ÊÜ–þÇ%q,ó«×‰2SO¬–è ßÊMÇÃüŠ ¦™k äcaŽéxìž1P¥ñ¾Û9Tž ˜wL1³þQ!»}ÓbµD[”O|êZ¼Õ«Åq}õЏt!òœM)—YÞ9šËóü賞,Ÿú‡hà¡ÆÃæ:~Auà^‘g“ÖmSœñ“!¦òJŠB í¬þ2 c«ØG}ëh6Qo“·‡:lϯ–bÇA P`¬ðwQ‚ñC \©k÷ £±âfÄ {V>*ê;°g}ªi¾”µ;q¡ºÄï‘SÏL”T7cÏZ­»’8¬ýa3в´;LA!«°=zæêT×{¹gŠ uÙaÜÉ—²V¬»H¿ãÇš=å\iô9|$=Œ•noÊ/uÔo€•æ„#®ŽƒH“ïüÖïŠ2â .b7µcPm®ø„X#丅Ø^æ½›H{Ù÷yÈD¬Ìæ±`µt§Œ¶X¨ïù£±¼Ðä£?~*¶ç” ¹gækõ PO¯ï„HZApã )ŸØó31?à ®ÑÍWAbå3)L ›ù%hë;ˆ•¦>3oè«ÃVŸ×ÝQ“; ~×Ç/D¡S4}{?ÎÅ8«ÝP¤Ô¿»q¶Â¸+|Ë:ï£Òút‹¸yØ õ¹ùjíÏLq©ØÙ׌ñx³ÕÇ‘S„Æ®žn^¼3DV戅DÚŠ»Q(å'ˆÁ¸/ÕŽ"µœZ?ß…¥Û~ŽÃ–£ …µ(/…¦H‚¼X€ý^žE6o»ù_ÜîWõù ú²Æ@l¬Ž´­–AÆ¢úi1}¬6 …¯²ç¡¤P*£´ñâ[-Ç»Š×šî®µ.#Ä´lÑïp9äM#%úÀÍGMÛKXnzÊ(|ãHÒ5Ôq1ö>‘€ÇA” ÃëÓ!ÌÛr`LjðýMi6mØ`?Ìqèþ(Ï[³1-SgX×SŒyD³šÝ¼‚2¸.táথwŒ†a¥o9dï°ß´iÈ>Ø…ŠBŸ[[¥EóÊjñҶ妸„¶X¸ò•cPNK°¼j,á?æË~µ'N’ºèO*ý{]§g’xºêç®2XU{mYE¨­uêÓäh‹^Í<‡ZþYoƒüÃ.Ì^¨EA|Ê3WKå¦u‹c™q0S+v¨}¹/öЙ;÷`Ò"<®‚í¸{¾ñ¾uúí÷¥ëKØòþ—EW$Òl;ë°ª¾ ÿ}^ÿIþczñþ{½£íXœêé‹Þ>cÌ´´Mè¨/G€jˆ˜Ñs.s0;ÍXÈb¨î™'Ü] ÙòŸÆJÓ1Ë3sòÊmhs‰õ8tlQ†dápÍûÔ?,‚÷•¼ø©~ïÀ}Ÿ ¼Ñ?»jƒ±¼è2èsñSóê ï\ñºÒ·…y»«¿ èØ*öÑWÅ6‘ë.SFrŠ*àܶÔH‡(@1#0N½20fbˈR€ˆ’@gkÞt½w;þˆñãÇãoÀŒ[f!uîL‹ö¥ˆ€x¤¹©þþpITÙDûò¤É7cNJ’é¤OŽf§èšáͦvô‰™¯¿qnŸ›ŠD­Aµ¿M-@ÌDL™1]Œ±îÞNœ=ó&Ú?îë¾Ón½©ÉFKywk Úzú11A¼€qZ¢EœzÑÒðþ«ýcwßÍ×'¥`aªù„CŽ{4†ûE mâYÛØ‰¢7üøDý¥±ZØ-Ƕˆîöºf•5ŠÊ¸vÑB›#‚o·Ï8ÿÁ±]¯àWnÀ§|ó%£BÕ³F5_ cJÇj¼£IÔÝÞ„sïüÁ]€ÄNš,ÞË0S¼PY+,Öa™£† :¿QbOÀ•?^Á ŸœÏ.šñ®Á€µË«ææ÷qI½X7)³æ$#Tq0°úÑÞ*úæ|m¥½@IDATåbŒúRÄø éV´gèÆѽ˜çep%è9ú˜ Š·Þü/|(® Ä^? )wÌCÒ€púÑÚàBCs›{Û\Ÿx#’ĶII2Êñh§&px×`Ç– Á ˜æ1rŒÈþ0Íc|Bg+\o6 ícõ¸~=nLJÂìY)F=j€éªp­¢3 ¼jЀlj.[.àý.õÆŽX$L…ä$sCb° {ÛEù÷ÎûøøŠ¨;âF¤|f¡(ÿ‚-a=m æý¢ì­}㌨¯«Û_ÏÄ1í¶Ûm°‰ºkÙu†xìÈoç𨞽-ÎM®ˆcÚÇW® qæ\Ü1ßÿSþ!öâlåË8e<,[Ó½þ3_¥cBÕ_rlíGËÙZœùý»¸"òùx±MÆÏ¸ ¶ÏØX׸Jé™, Œ16¸± ÆèR€¸º:±oùl®RSå@m×Q,ÀIÜÕeÂÔP€#+ 5¸‹>Õ;*³#qÞÈ&€k§(@ P€ FP`´]A ®š †K@½[ꃾI¸øòoc»x:¸ íõ¸ P lV–æâŒ (@ P€ €à9³(@ ³@7~úð,dºïj×VmÇ?~=xŸ‘Úœü¦(0l¦~ë‡m­\(@ P€ (0†øÒÔ1¼ñu P€cU ë¢9æå?ÆÒ‘èÂØ þ¢(àè:ï…8ý4¡(@ P€ (ûp‹³R€ @t:[ðÞÅKïfÄÔÙ6${“ctVÉP(@ „-ÐÝÞŠnµ€ŠGÒ4¾X"l8ÎH P€ (@ € îÌ (@ P€ (@ P€ (@(°K™( 2 P€ (@ P€ (@ P€ Ü™(@ P€ (@ P€ (@ P€Q`ƒ{(@ P€ (@ P€ (@ P€ îÌ (@ P€ (@ P€ (@(°Á= ˆ ‚ (@ P€ (@ P€ (Àwæ P€ (@ P€ (@ P€ @ØàDA P€ (@ P€ (@ P€`ƒ;ó(@ P€ (@ P€ (@ P lp"ƒ (@ P€ (@ P€ (@ °Áy€ (@ P€ (@ P€ (6¸G‘AP€ (@ P€ (@ P€ ØàÎ<@ P€ (@ P€ (@ P€ˆ‚Ü£€È (@ P€ (@ P€ (@ P€lpg (@ P€ (@ P€ (@ DA€ îQ@d (@ P€ (@ P€ (@6¸3P€ (@ P€ (@ P€ ¢ À÷( 2 P€ (@ P€ (@ P€ Ü™(@ P€ (@ P€ (@ P€Qˆ‰B×Lý½½è÷¦6&.Ä»f6=J P€ (@ P€ (@ P ¤ÛŒCuãÔ‘<ý̳(­rIsÛ•Ÿ‹-¿ˆÔi0ö6`÷æï£iÒM˜$…&^ºôÜòÀÿÁ¶µ©òhS€ (@ P€ (@ P€ À(§ˆÏ(ŽßG­™‚ÌÒàÑ(¬iæ´iÁgÒ¦vžÀò)÷¢JûàÛ^X‹ÊM Låh P€ (@ P€ (@ P€mÜš=Ú¢>ôñi:òSc»#§ú4:Þü 6ï‚v¿ûæ%{Š‘:NÝï½¥7¶Ûl6ë\.Ìœk=c)@ P€ (@ P€ (@ P`T ð÷€›¥;ÌÄvo«z~y#¶­L1æî¬Ã–e‹°×;½°¶›&Ó µVîÀÌÛÅTjºŽ"->ÀŒM P€ (@ P€ (@ P€cJàº1ÛáŒl÷»¨ÕnaÏr"OnlW㑸9Ûr"ŽÑÅsµžel‹ðI6¶GìÇ(@ P€ (@ P€ (@ ŒV6¸Ü2“p‡·Ç[Ê-°ê{§—.m=¡¿¯;ï™4û“˜n=ÇR€ (@ P€ (@ P€ À°jGƒÉ‚(ÇÏGþ«mÈ؄þ+]Ê<½c¿>þ¦ÉõáÀ}¸ø÷¶ùø6=°Σµ¸ÐÕ%IÀÜ%Ë‘ñè—±45̰^§P€ (@ P€ (@ P€ À0 °÷À[ëŽã¥†t5ƳÛ÷ê/Mµç•ã—;W"ä;S{Ï⑉6”†X§#߉ƒÛÖ€=΄€âd P€ (@ P€ (@ P€£H€ îaoŒnì[€ÍZ¿îÒr‡/ôamR tŸBzÂ8Ųjo5jP9y¸}JªD~•¦-¿g¶-—Æp (@ P€ (@ P€ F³ûp`ë$Øl°Ù½»{—£°næ"ké R÷¹WÜíêŒ.Gê»ܳÛ¶íA¥Ò…ŠÂ,= ×ö8ÒÒ¯ÿæ(@ P€ (@ P€ (@ ŒnÞá>íÓß‹–ú—±3cökw¼g”¡çàúàÝÊôv¢åBz.õaƼT$úÝß#Ù‹°ÎhVY=Š×§$†HJJÂûï¿Ѳ&Lˆh~ÎL \þóŸqÝu¼þzulM¦‚C+Àòbh}:®&–WÓÖdZ(0´,/†Ö—¡S`4 \¾|9¢è©mï¼ón½õÖˆ–î™Ùà>ñöJ,Ÿ¾ÂÛŒ5]G‘6Ȏ׻Ï#Á¶Ñ+Ga-ŽnZ8 Ž7_ùÊW0}úô°—Ÿ={6ÝÂÖ⌸:.]º„o}ë[xæ™g®Ž1 À äääà»ßý.‡t= œÛúÓŸðo|?üáñ‰O|bl'†±§†\ 77û·‹3f ùº¸ P`t ¨çŠ¢„©§žz gΜMírdØà`ã´ßY«¶‹©v8›‰5ÉV¯DíÅô‰ÈT;e‡µ¢Á}aÐ÷~ô»{‰‰AŒßÝ히ô6ÀÄy™îƒmp ГjþO Œ”À‡~è¾0wåÊ•‘Š×K Œ!o¼o½õ–ûIº1mF•f¾¾>Œ?jý"66v˜×ÎÕQ€cM`æÌ™xùå—1wîܱuÆ—fõã±ÐÞÉ>dŒ‹o×z§T¡áýžsu£­+À$¿ÑÝ¢q>Ö]áŒÝŠ¿éžÍ5¯ëSfÜ4Iæ(@ P€ (@ P€ (@ Œn6¸Ø>SgÍÖ§ä>íD§þËh9^„Ü*ïoûrÌÖînïíFkK ZÄ_§å»TwáùíF@ÚPç |'s¿ö Ü=Gæ(@ P€ (@ P€ (@kIàÊŸzq®ó4޽SŒ)gƒ{€í”üàW‘¡M+ÍÄ”ôݨké]Âô£³½ Çöe{»œñÌ”óÄjh½™žÝïÀÌY³0KüýøŒÖT¥YZˆÈ½w:v9…öî^¦x kݤO¹îÞiÔ¹ÄKX?Ÿ ß=P€ (@ P€ (@ P€¸:Ô>Ýßÿø¼ü^)þ¿ß} ¹¯ÝƒÃ»ÐÿgÑnøÝ½([tñÇÍÇ÷œy(uìòÌáÌÅ"ñgùÉ(Áöµ)Ƥ 3õá8©Ë”µßC¡c?6{[Õs×-uˆY¨Ù·V½Æës€ (@ P€ (@ P€ Àøèr?ªCCÇIœ½ø²¸‘}RïÄ_Üü¾ú?€ëcoô¦ðÉ1‘R6¸ÙLÉkvâBÍíxbI¦qç¹i~òËöãÛëÓL㱌¾×'˜æŸ†MG;pû¾|¬Ú¼×4EûaÏ)AÉ®Ç`ùŽVm&~S€ (@ P€ (@ P€ƒj71-]gQßyR4²¿Ž.ǬR§Ü‰œOþn¾Þèê{ &lp±Õ’ÒÃQå¯ÑP÷;¼ýN'Æß0WÄ ‰·Ì§m©H´L}¬Šø³þ$bå¦=P²¶£áÜÛhÿð úú>ÆÑ!ÍÜù 2÷µ[»q,(@ P€ (@ P€ (0ÖÔnbÔFõoûï?<…ioußÅþÐmƒÛoü |â:©›±–@ŸøZ4ûÌÁŸB © —Š¿(bÄ%"u~R£$ƒ¢(@ P€ (@ P€ (0Òr71o^|ŵ›˜ÏNÌû¾ÔMÌHÇ4úëgƒ{ôM"(@ P€ (@ P€ (@kF X71›?™9滉‰dC²Á=-ÎK P€ (@ P€ (@ Pà¸Öº‰‰ds³Á=-ÎK P€ (@ P€ (@ Pàøèr;?ª/:=‰k­›˜H67Ü#ÑcóÞpà c,ÆŒ.(0Üñññ8yòäp¯–ë£ƨ@ee%¦M›6FcÏhS€Ã%ƒßþö·P¿ù¡(Jà—¿ü%n½õÖP³q:(0Á»‰yLtsÛ°Çj,´wŽ·ÿ+Ã.ùÀ¸qãÐÜÜŒäää!_W@ P€ (@ P€ (@ Œ}÷?~ 'Q/îbûÃßbÚÄ[¡¾ìtÞ”»pûO\;b‰+í¼å`IJWL P€ (@ P€ (@ P`äu³púJ<:o'®½qä"7F×Ì÷1ºáí!ènÁñ_ÆÇ®\Á ·Ý…• “B®°éÄ1¼ñà^ìWpÛ²ÏcaRœw¹nÔUVáÏô@]f̘”Ûç")Q[ÖËïÂË Û±>ÕÔòmš§Ûõ’§±Ýf\îÖpÄÉ]ZÅÆb¦i‰Ð?ªöoĬs¡ù¥'‘,í© ³Å²îU$@^Eè9(@ P€ (@ P€ ÀÕ.àî&æÃÿ}±¿Ž7/V»ÔçL^µ›˜GR¿Æ'^í#š>©oDãÁ•S`T üë±3¢Á=-`OyÖ3ÍÛØpFu‚½ÍÎ,LéïA¿ÏŒý]ïá•çwc]n©gJU.ž«ÎĶåÓ|æäO P€ (@ P€ (@ ˆ‘ÿÔ‹–®³¨/;mèx\:Ù“àS‰Kð™ëqK|*™†Q€ îÈÍUMõ¦õª\'ZžLC²UDw2Ïï·œ‹ùñ°¸c>1kŸ<ˆò/`Õ.O4Uo¾ËwkIŽ¥(@ P€ (@ P€פ€ÜM̹O㦉ŸDjâ`71#ŸØà>òÛ€1åž›Öw¡ª!¥úw˜Þ©u'ãéIF¤F°NY—õhyì²/? xÜä ¦(@ P€ (@ P€¸æ|»‰ùĸÑÿúçØMÌ(Ì lp……Q-6ä—l@Uf®ûe§Ï{K4¸ûw+sJëNää{÷:€¾¾Ëza´Ïëór€ (@ P€ (@ P`ì °›˜±» Ùà>v·c>ä.|ÒVŠt»hp½»Xv+#º“ù…ÚŒúÉú"Zð öz~þ_t)üÓ‰Cù›õY$MÖ‡9@ P€ (@ P€ (pu °›˜«c»²ÁýêØŽLÅ \ž4 «ÍÀæªR±†]8~6Ùóne:k_Â~ïºó¾Iï—‡Ž‰ó ÞjjÁM~¯LíÃÎÕà'»3±ßÓ}»+ ÙŸO &ç (@ P€ (@ P€Sì&fLm®°#Ë÷°©8ãµ(p¹/)®IWÜçþN4¸/uC4˜Ÿúé³Þa;w‰Wªþ›÷gЯ½X2'ä}ðî*ÚŠ‘jñnÕ Ás"(@ P€ (@ P€ À¨`71£n“ I„Øà>$¬ ôªèë’îD È=ÇTmMyK‘¢î9½õ(ÛëíNÆñ(ˆ†ñsQNøk¯7`ùšÔ(‡Êà(@ P€ (@ P€ †C€ÝÄ ‡òèZÜG×ö`lF@¿ˆÑ4¬Ú’ÜLõ.÷½xѵ›&¢óL¹÷¾w ç«v„}#º=µ?^É¢1_4ç{?±ˆU»”©ÃOwoÀ^o—2ÛßÁꞣXvàZxá}·®Y¥·7¼™¯ò¹nX·“¿þõ«<•L(@ P€ (@ P€C)Ðuù8÷áiÔwžÄ[Oàºq1˜{ãç°púJ<’ú}Ü0>q(WϰGÜGÁF`F¿À<Ñ­ŒM4¯«÷³?{ä Ñà¾\t'Sæ¸_X*º“ ÷“0sSR`ôo,˜’’Š´û±ó¼/_uÂu® ¥~ã¹?49+ J¿zQŸØ¹s‰@ P€ (@ P€ "èûÓe4w¹Ü ì ¯ãƒKç1{ò¤&Þ‰e37à–xö\èU03ܯ‚È$ ½@LÒR¦7#O P€ (@ P€ (@±-`î&æ?qÓÄObžè‡ÝÄŒííz­Æž î×ê–gº)@ P€ (@ P€ (0ì&fйÊa`ƒû°QsE (@ P€ (@ P€¸öØM̵·Í¯å³ÁýZÞúL;(@ P€ (@ P€ †@à¿?nÂï;_G}ÇIœûÝÄ 1ƒ¥lp¥†ÑŠ\ õl%Nþ¾C,8w¥/G’7w÷¶ÖᥓïãÇôÊà†˜=7sS’xÎȦt7áÈÏOàâeà3} iIQ 9²xpn P€ (@ P€ (0„Á»‰ÙøñS‡pí š£G€ î£g[0&ƒèÆ‘ŒØìR±£¦K4¸Ç{|ëÈ·àØ\AèvU” {yrËXÏÚ}îE¬ËÜìžX°ØÁwk&Ž¥(@ P€ (@ P`Œ °›˜1¶ÁÝa`ƒû°QsEC-0[¬ÁÝàž€Xie±fJ¿Â¬ÂƳðQE3žl£{ì}…¼·]§à(@ P€ (@ P€cP€ÝÄŒÁÆ(»܇œ+Iш¾iñôô÷ûD£¼ù ¾ï:”z§ä®x™Ê6Ló™“?)@ P€ (@ P€ Àµ àßMÌ8Ü~ã_`áô•ÈHe71×B`#`ƒ{äf\b ÄÝ8qññ–}´'.]‹ƒÊáš¹Ês£ÂeL^¼Ù+SüÖŸ»žCÛ„ ¸|y:Öû1¤°Ï'Ž¡(@ P€ (@ P ¨@ nbÖܶsnüb¯tyN¤Ìlp7{ð×5/Ю.¡O칈Ÿån‡ÚoŸð Eƒ{7œßÝ€íê»Yí…øºEƒ{¦Í¢/y—¹Ä_Aê_݉TÑêÞóþilÜžëY³m¾°òI¿nm:kÈܾÝ3£ ßfc»Ç‚ÿS€ (@ P€ (T@î&¦¾ã5÷¼ì&&('R "6¸GÄřǺÀ„ØàY¾³îgج6š»?³qÓDï ¸Õ]»=!N¿ïÝ;Ñó• ýœ€ k±g¡èkM¿ ëû= ¹vaÞŸFÏÁõˆŸÿòm±]½ ÞU†×[þk’Í!žr>«­ ù÷€ßÝôúDP€ (@ P€ (pM ôýù Îô;4tž»‰ùìÝ `•Õ÷ñß½YIHBBˆ@Ø $²¸ 7,j¬b µb;@mG´ÓBqF¦¥}¥:yÅéÌ«tZ:-u¦j;PE– XµŠb@Â*ˆÙ³B.$!Û}ÏóÜl@’ÜÜå{gâ}î³s>ÏÕê/‡ÿ ꯃ÷’À…)ž—¥ºJ`ÛÎ=:›hM½°•¥Ú¶öWš¹°67‡çün®†tðß!O¬Ø¢~dRm ?C_™~­2f{:³r¦þøÃûôоº÷±YZýïÒÚ’4š£{'°¬k[ € € € `•‰ÙWô¾ Ù?ÐÓ› …ý5ÒÔa§L ß :_ ƒãÄÎï0- p%ËgNVC¤Þ–¼£—Jiá„všój£°Ýs}|ú#Ê^¶Jó=Eã_Y³G=ž®‘w? 4¸[±úÊßlÖ¿šÀ½.V/ÎÙP?†´Ej ådÚñ0¸@@@ÀpUjñGÚkÏb÷”‰?I齦iVÊÞ3pËHðqw@t¯‹6¿­}OL±kªwT–ͽ¥ÉR3iY*ÍîöœõOk¡}§è±LižUÞfó/MY™ÇêËÊl­¡œÌc3&tT÷¸ € € €ø‰ebüäAÑÍ  pÊǼƒ^ôj¶æŽSYeýr¨ SåSRæ½ÿÑÌùÏ{p6/Öc+¦k“™mÞÙ¯ÐÞƒ”f±÷C‡ój›‹×­=aÂv«?VY™ÏLY3ãÞ”“ù}}9™Eš–^WY¾ö²6¾­:ø¯ªªi°hãåuúˆø‰“h~ËÁ @@@°ÊÄX‹œ~Z¼¥¾LLjÂõ”‰ñÁgE—‚[€À=¸Ÿ¿_¾ªø röŸQ¥ ȇ§Q|ãooUžö{ª²Øcj.BN1LÉC𠩇(%}’&õ•†>à Ý7oÝ'—ÒëKm«Jç[>¡…£ ½íÙ-ºþ¼!·Ü§L=/k’ûÊßlÐ &pmTN&óÙ,%ןݾîañªv_Tо}·òû«ÂC¢ü~ @@@ pêÊÄì)zÏ®ÅnÌ*sMïéšiÊÄÄR&&p6# (Æ‘e@ ŒÁš€K+gÕl;TOÓ;E;4%¾ÑËÎhOýÇÞŠ «ÿpÁÆùÊ–ÃåÆ!·Ž¹ÔòÙn]~Hï5 ü©ßŒkæo·²s:V{Vl\Cà®ø úæ,3É}¥9hÊÊl/~LÑkVÕßï›÷­ßnïÆ­jlmï ¸@@@:D ¥21™ýV¿î#:¤n‚+ÐLعrwÚ#Ð0ƒºï¥§ô½Œåa=é(O¥÷9Ú[ù’§ÌÍe®â0 € € €t¼@KebRL¨Þ¯ûˆŽo”;"€€ü%ï$pÐ/«¿|”¿C‡åúðÅNžoß3kY¶V=~%s:´gÜ @@@àh\&æ³ÓÙêÙ­ŸFÆ_++`—ÁÌõàø0Ê.ð—¼³Õór»Ø“æ23þà)Eu;©gæxÂvk±Ô¿ÿa{}. € € €@¸*Šôiñí+þ@{‹Þ—[5J‰Ÿl—‰™™òcņ÷ì‚^Ñ$øƒ»?<%útå;ÿKÓ-”j2Ÿý‘¦4Sç=è€0 € € €(ÐR™˜›ûÍ¢LLZs+]€À=П0ãóKÊÊóö;ëYýâñ)îã € € €´[ ¹21÷ žO™˜v«r!¸ó@ÀbR¿¦½9™faV³²jTO¥¥$‹¿Y}ðAÑ%@@@¿ LŒß<*:Š€_ áùõã£ó+¯”1Ô ØçËÀ@@@:]€21NL Є{(ìB@@@ð?ÊÄøß3£Çš{ =Qƃ € € €‰@ã21ûŠ>Pª•?Y½îÔÌK‘$ |E€ÀÝWžý@@@@hQ€21-òp|@€ÀÝB`tÁ¥m›6ëó")<¼ùU˜C½{ÒáÃÔ7>²ùÛrÄuP¯ýá]ž—ÆÝý7šÔ·µ÷5}^gú|¶BÝ_§ié}ÛÒê%纨õ[˜ý ºîÞ©êËß]—±@@@¶ P&¦­bœ])@$Ø•úÔ¶k¾wK–6·aL™s^ÔŠes•ÜÚ|¼™{»¬Ñ³çÛGŸÕúÀÝêóž>§=»åŠ÷«éù–@¦¶”˜À=¦™³@@@š¸¤LŒ»J) ×R&¦Y1 €€/ ¸ûÒÓð羄…éê6öóòyxàŒr7,Pò•|Ã"ê[novßSaõ÷`@@@¼'PUS©ÏÏl×¾â÷µ×Ôa?UzHƒãÆidüuº¹ß,]=\‡Ã{¢%@à ®$漂f¹4 2—)wõ%T•©ê¢V•Õ_~ÿœX¸ÒsdóBýæÙzzjÒEgzácÌpýèÕßéaSR&adŸ+npÐôiEìÃæ> êC~ÅžÜ@@@ p¬ZìŸoÑ_¿¦ýŪg·~&`¿V÷ ž¯¡q i˜\¸ Œ Q€À=ŸjW)6B 1‘ŠQóÍãã5cÁoµöô1ݹÔS€fó®#¸·å+¯)3Ò”òŠ2E˜^ € € € p©€ÛíÖa×.½âÚž·Á„ìWëú«fè«Ã+6"ñÒ Øƒø¡@[ÒI?]î’Ë·zóW”j÷ØF§ÿðeýrÃA)n¬¾óø=ŠotÌÞ,?¬—_ø½šR¯èqMra¨æÒÁM/ë¹þCËWçx®NËÒ³ ÿ^ßzhŠù%@ãW±6½üŠ¸Î«gj–fLI¶æoû“V¬Ù!õ¿Yß}äZåüé—zéW¿×–C…öñžƒ&ëÁGçêë÷¤_ð+…â}›ôÊ_ÈÜMY_Ÿá©M_eúû¯¿ÑQÓß~·CMºtaÖÃᆲ߼}P½®×ãs§^pÏüëôâÏ_Ôâå«:nƳìÇ‹5ç¢öN` @@@ß((;ª­§Öè´‡8B5.év-Èø%E ðNÒ@ ƒæ·‹îº·ñ!«¶Ynn®’“=!r§w­|›¾Ö-Cv¡˜ÌU²iîEáö…=pm{A±ž…N3—ekÓãéö Û^¸Wó­pÙZxt“&]˜«ñu˲‹ôxz¼\;_RlÚ¼ hêSÚ"í}ï¥ÔÝÓõ¡¦ÆN¶zÍ|ÖôaA]¦š>l¶û0gV¡–¯¬ î/ºgÚ’Ê~zªê~kµí…†ëêûîÚ¦{c3dÈ,̺iÁ¤‹îâÒ Scåin™Š6=^ÿK†m/}MólÑ‹®©ý8ëEå®0‹ÎÖu é³Ø‹ € € €€×J* •“¿Q5!{Qùq¥%fjBï»4<~¢×ûBƒ ^Ï;ÛÉælçu\†@ó¦¤L˯b½¼Ä¶[çíWzXD]Ûô2¦H­¿¨©Ì9zñw¯êÅ%sŽæ,ÕÈÇ^VyÝžF ½Æ6š(Q·üëæú°=sÖ"½¸âE=‘Uw±”³ø½y¸¡J}Ãuúnj¹×(²éÂî±õSü#êÃûªÃ¯5 ÛÓ´hÙï´ñzõÅEJ«ëÂÊyšýÛê>ñŽ € € €@— TT—é“ü?ë»æëG[¾¤]Eïè¶ê™ë6ifÊÂö.}:4ŽÞ`n¬·¤ƒ©Õ;´çàa%^²dj¥ lѯž›­åÖrû5GsïR÷¡CÞŸX±EÿüȤÚðz†¾2ýZ%dÌöÜ{åLýñ‡÷é¡‹JÑ4ßpšVlyKLª]Ôõ‘û”òµ[5¯vÖû–½yº'ùÒ21Í߯uGö®k(!3kí[zfZmûS¦jÆ}wêÞ^7Ú³æ7¯zOÅæOÄ·î¶œ… € € €@‡ Ô¸kôù™í¦dÌÊÎ[«>QCì™ì³R~¢n¡uSÐ:´In†ø´»O?íÜóš<ôùVu~cÞKJi4»¼UµtÒœW…ížãÓQö²Uµ¥j¤WÖìÑCµ%lZº•ulÎï~ß¶Û''éë 3»§„Í–ý'¥i¸WÊUßµ¨¢B³]¸[{“®Õ¢Ï*õÈiu‹®nõg² € € €€wNž;d‡ì[Nþ¯Âœ‘&dŸ®§&ü¯"¯òNhðQw}0ÁÒ­¿~°OSïIé°á.›{K}Y–Æ7MËzTi¦6¼]ýroê/ÌÒ£w_Ú·ÊúãR}5˜Fû:b3®gïúÛ,Ÿ9RÖ.Ò7gÞ©Ii£•Ü7^“Y ‹«Á×_À € € € P\~R; ÞÒ_ÿAç*‹56Éü ð1?Wÿ˜ÔNh["€þ)@àîŸÏÍ·{¹DÙ¿xHq••j§Ãf•”Ù¦ÿyn¦ž¯-)³8ëš^¶Jé‘;¤ÐÞƒìÚçVà~èp^«kºêz«/o÷‰Cî}JKÒ–kqíz­›W.•õãy¥i΢ohÖÃ_Õ””F3ßÛÑÚ†í5ª®iÇ…xÉàÞèçÀ‘1$@@@ ýeUgµ»ð/f6û}v&[© 7èîÁ§Ñ=o’ÓÒþs%  îú`»tX±½4lÈúÅB÷eÈMº5] )OÑ3ëü€KécZY×­!Áo|ÛVl7\س[t+Î÷Ö)U:ßTS¡Éz:»H7¿ò ý˳ µº6x÷œš£åKçÛ?YϾ£U ¦4u‡VíÛuØ­ÊêVð'u {À?eˆ € €­¨®©ÒÓ›ýu³ê[ö ö‰½ïÒ££~¦ˆ¨ÖÜ‚s@  pÚG߉/¹Ì½CSô7Ïfêù…žiî%•U—¹ ápîÖ÷>4±ÖÌWºìœŽÕžçC{ù!½×°>ê…# ×”‡Ø?®âã:°ëc½÷öfýrñóžÒ8æìÕ oÔk–iFrûþˆÀwïe6Â…è|B@@‚WàèÙOµõäëúðÔŸÔ=,Þ^üôŸ&­QlDbð¢0r@ ͤ“m¼ §#ÐF¨¸«/s…™ñÞD=—Ò3 ‹‰6uƒ÷Þ? ¹cÌ ú‹^‡ßý£j«ØHMÜø¢ó;åcSí6úE@C›åz÷×/híþÓê1TKëj ÏyZ7÷õâï™ÂÂjÙ¯ž§ûüšŽ»\Ê?¼S¿~j†²ž¯ëXãqÄhôä´ÚKuÏÜ—´¯¸¼ös¹o{M³o\Xû9MÃû·²þ}ã&ØF@@*Êš í*ø‹Vìþ¾žþà6}œ÷¦&õÉÒ3×mÖ×SªÔž7¶Õ7‚Á"€@g x1yì¬!p_Ÿh4“»5ýé7aª9Í3[}ù+ÑOJQ’Ù“2}¶2µ²vÖ÷j=ÑòŒö‹Û²ãëœåÊÊX~ñ!óy–¶üt†W;oˆý›8½#vEŽÑœ%fD‹=å_6/~@W/nâÆuùº}(TSŸü¿J[z‹ý †œåó4Òü¤¥¥)'ç€>sÉÏ5Í›¿@h¢ëìB@@ðM·Û­Ã®]öâ§[O­QBd_Mì}·ö”º‡7üùkßì=½BüS€îþùÜ|¯×f&wïº^ÅÖm4ÿÞ-ªÑ‚+fæ÷o+öœœ4UÈù²š¸4m΋ÊÎ^]¬n2|X£iñ‹^|QO\^×Þ(k‰rŠ~«IüûDÃìó˜ØFuÝënÜ07½‰ÞÔîª?×|®ß¾pÆù”§ÿ W59"-Û˜­µÏšcVŽÞØÍ8¼·w­æ4ËÅaû/nÔê§§4ß7Ž € € €¥€U—}mîKú§-Óôë= îŒÒ÷Óÿ[?¸æUMíÿ0a{P~+4xKÀa~ÛéöVc´ã=«æZnn®’“/¬þí½\iKå¦ìÊ1,9cn¦Øž•Ü÷ »ùLÙ•}{ôEþ9É̼î;Dé)}›?ÝKGÊMiœÜÜ“*5} ‹ŠÕÀ¡ÉйìŸ1©ÒáÙÚñéU„‡+¼¢Bá½+m\šú^þb/Œf@@@ºZÀUQ¨ùõ¾Yü´°ü¨Ò§jBï»4<~bWwö@𗼓À½C·ïÝÄ_¾€¾'G@@@ðŠê2í)zÏ^üt_Ñ;\·Bö±&lq6ú“Üþ1z‰´(à/yçeç×¶8J"€ € € €xM Æ]£ÏÏl·Cöì¼µê5DûÜ¥Y)?Q·ÐÖþÉp¯u—†@  pºG΀@@@@ÀßNž;d/~ºåäj…9#L¹˜ézjÂí…Pým,ôd÷@~ºŒ @@@üVàôùSú$ÿÏv]ö³E›t«æŽù7 ˆIõÛ1Ñq@ ÐÜý 3>@@@ðòªsÚUø¶™Í¾FŸÉVj ºkÐw4ºçMr:BüftV÷`}òŒ@@@|B º¦JNoµë²’ÿ–ú›ìÍ⧦þL¡Q>ÑG: Ð:÷Ö9q € € € СGÏ~ª­'_×G§^WtX²ß­Å“ÞP\DR‡¶ÃÍ@¼'@àî=kZB@@@ ((;ªíùôÁ‰ÿUeM¹Æ%ݦ¿ûŸêÛ}XË0|@ 0Üã92 @@@ðQÒÊål²g²qí±ë±ÏºP#®—ÃáðÑ^Ó-@ö¸·Gk@@@@ªj*µ¯è}».û®Âw48nœ&÷¹Wßó ‰háJ!€ø³»??=úŽ € € €>%[’c‡ì[O½©„È«ìºì {JÝÃã}ªŸt@ sÜ;Ç•»"€ € € €@œ*=¤myëµåä*9äÔø¤Ûõ½ôß©WTr0L@:÷: Þ@@@@V ¸* µ#£]—Ý ÜÓ§jÖˆkXü„VÞÓ@Q€À=Ÿ*cB@@@¨¨.מ¢wí’1ûжhxüDÝÜo–¶‡:Ã:¼=nˆ àî]ú̪T^^UÛƒPEFò8ºôqÐ8 € € € Ô¸kôù™m&d_cÊÆ¬SŸè!šÐ{ºfšÙìQa±ÍG@` áí‚o€ëð‡ZñÒÏõË¥+•Ó¨ý´¬9zòñ'5kjŠx0`ØD@@@ÀË'Ï2!ûë¦.ûju VzÒ4-šð³j_/÷„æ@üIÀá6/ê°¿÷Õµó׊M›Ýò0²^TÞª¹Jjù¬:åææ*9™ZZ„â  € € €µ§ÏŸÒö¼ úÀ,~jÕh—t«&ö¾[ƒâÆb„ ÐÅþ’w2‘Ú›_”ª}úÞa{––½:O£»é­ß=«¥+k绯ž§|ù&½ôPŠ7{G[ € € €@yÕ9í*|Û,~ú†šÒ1© 7è®AßÖèž7Éé :Œ peîWæ×¦«¿óª–×]‘¹DŸ½ù´†DzvLö¾zç“J›ù¼½cùnÐOMà_w>ï € € € Ð!Õ5U:pz«½øé'oi@÷TS—ý.}#õ_Õ!mp@à p÷âs/<]ßÚ«+Õ‡íu;Ç<ô„™À}©µ#6‚:îu0¼#€ € € ÐG]ûìý#S›=:¬‡].fñÄ×Ñ«îÎ-@™®7¿§Ï”Ô6—©þ Mý®£J…u2§VÕmóŽ € € €í(,;¦mùëµåÄ*¯.Uz¯;ôwc¡¾Ý‡·ë~\„ €@KM¥¾-ϱ+˜òÝÕ:ö`‘*¦Þ1—ÞhçË?o(93¬§º]z {@@@@à2¥•%Ê)Ød겿®#®=v=öÃjDüµ¦.»ó2Ws@ö ¸·ß®íW†Æ¨or£¤½ü¸ÖýñmUhëª_êùÕµ‹¦*S«ŸºKµåÝÛÞW € € € dU5•ÚWô¾²ï.|WƒãÆirŸ{5oÌ¿+<„ÿ²¯ÃEºL€À½Ëè%מ×tçÌùzf¶Mèžõ„îIæ_Á°‰ € € €@“¹%9v]ö­§ÞTÏȾöâ§ {J1á MžÏN@:S€À½3u/wï°X¥™ÿë™–£Íöävë/&t_¥±O­Õ‡ÏLc–ûå 9Ž € € ty¥¹ÊÎ[§O®¶ÇnÕeÿ^úJõŠt @À·nóò­.goÊ‹ëíß>£;ç/¯X±·D¤4*ASäò‡CPrròåO®=#,,¬Õçr" € € €ÞpUé“ü?Û³ÙO–ÒØÄ©šØûn ‹ŸàÍnÐ €@ TVV¶éNáááÊÍÍmSÞÙ¦:èd÷‚ì¨Û¼ûܽºq¡ç7ôY˲µêñôvÝÚ ÜÛú:w¢¢Úzç#€ € € Ð)ÕåÚSô®>:ù†>-Þ¢áñí}Lb¦BLëtnŠxI ::Z¥¥¥mjÍwJÊ´é‘^ÁÉU‡õÜíµp³”¹hµ6ÑCA.Q@IDATL]öéš•òcE™Ò¬¼@CàôéÓmˆ5ÃÝ^Me¾þÐoÿëcÙI½oÂvëµyM®\ÏHñžüµìL^Ã爆ÍölY%b(Ó9®A@@ð¶ÀÉsŸÛåb><ù'E„D)£×4ýàš×Ô³ÛÕÞî í!€xA PsKw/|yì&º%*ÕlØÅbræë•m_ÓÜô‹#÷Ãúùœ…õ=š:nPý6 € € €šÀ™óyfûzm9¹J%…Ÿt›¾1ê_4(nl  •ñ €‰»·tè=¼b––Î^i·8/#AgVgëooOSŒ\:¼ã]=7'KËsê:ô„¦g\È×ã@@@ÿ8_Uª…›õÑ©7tДŽIM¸Aw úŽyŸ¢'1…>Uz P'À¢©uÞx¯:¨§2†ji}¨Þ|£+²‹ôÈ%3à›?ÿâ#Ö¢©þ°ˆÀÅýæ3 € € €@à T×TéÀé­&d]; 6j@÷TS—ý.¥›²1‘¡Ñ7`F„ Ðáþ’wò«ãô-ÜÐÌr&û˜F/~L3—ÚÅe.99-k‰–/û¾&%G^rŒ € € €ø“ÀQ×>».»5›½{X;d¿gâ|õˆèíO௠€´Z€î­¦êØ]Ç÷铜ý*®Wxx…¯)£•Ò·cÊÈøËo|:V•»!€ € €tµ@aÙ1mË_¯M]örS>&½×šÔ'KWwÞÕ]£}@?𗼓î]ô%‹é›¢)æ‡ € € €þ.PZYb—ŠÙjf²qíÑèž7éþ¡ 5"þZ9NýG@ Õî­¦âD@@@¨¨ª©Ô¾¢÷íºì» ßÕà¸qšÜçËš7æßB™Ô:'Þ@‚K€À=¸ž7£E@@@àŠrKrìºìŸzS ‘}íºì [¤˜ðžWt_.F@ Üá)2@@@:Q ¯4WÙyëL]ö?É­eôš¦ï¦ÿV½£ub«Ü@ÿ p÷¿gF@@@ètWE‘>Éÿ³=›ýdé!K¼E3GüHC{\#ká:^ € p©û¥&ìA@@@ (*ªËµ»ð²¯Ñ§Å[4<~¢2û}Mc3ê J €@[ÜۢŹ € € €˜@»FŸŸÙf?}CÛó6¨Oô`S—}ºf¥üXQa±6Z†ƒ €@ç ¸w®/wG@@@À'NžûÜ.óÑ©×æŒÔ5½îÔÂk^Qb·~>Ù_:… €€?¸ûÃS¢ € € €t€À™óyÚ–·Þ,~ºZg*ò5>év=šú3 ŠÛwç € @àÎw@@@8_UªœÂÍölöƒ¦t̨„)š>èÛJ5ï!Nb~ô @  ø_Ö.@§I@@@:S Æ]­ýÅ™ºì¯kGÁF 螪 }î¶g³G†FwfÓÜ@  pêÇÏà@@@Ià¨kŸ²|j¢Ãz˜ÅOïÒ=ç«GDï@&cA@ÀgÜ}öÑÐ1@@@./PT~\ÙyëL]öU*«:§Œ^Óôí±Ëuu÷á—¿˜3@@ CÜ;”“›!€ € € Ðù¥•%v©˜­§ÞÐ×I¼Y÷]¨ñ×Êépv~h@š po’… € € €ø–@UM¥öýÕ^ütwá»7N“û|YóÆü\á!Ý|«³ô@  pÒϰ@@@üC ·$G|ÔyS ‘}íºì [¤˜ðžþ1z‰ €@ ¸ÑÃf¨ € € €þ!WzØìkM]ö?É­».û“ã«>уücô@  pÒϰ@@@|KàlE±¶çoÐG§^שÒ\K¼E3GüHC{\#‡Ãá[¥7 € Ф{“,ìD@@@ ó*«ÏkWá_L]ö5ú´x‹†ÇOÒÔ~k´Y5ÌÞù @èP÷åäf € € €´,àv»uðL¶™Éþ†¶çm0ebÛuÙg¦,QtX\Ës@|Z€ÀݧC@@ç>³g²o5A{˜3R×ôºS ¯yE‰ÝúÊ €A/@àô_@@@:KàÌù|mË[gÏf?}þ¤Æ'Ý®GS¦Aqc;«Iî‹ €](@àÞ…ø4 € € xç«J•S¸ÙÌfÔŽÙ¦Q Sô¥ó”jÞCœügxà=qF„ €@ƒÿKß`Á € € €í¨qW›EO?´Cöœ‚Mêß}¤&ô¹[³SÿYÝB»·ëž\„ €þ'@àîÏŒ#€ € €øˆÀQ×>S.æu}|jYð´‡YüônÝ=áqÅGöñ‘Ò @ð¦»7µi @@@ÀïŠÊO(;o­><¹ZeUg•Ñkšû’úuá÷cc € peîWæÇÕ € € €A PVåÒ'ùoٳٸö(-1S÷] ñ×ÊépCD@Ö¸·F‰s@@@‚N º¦R{Šþj×eß]ø®Ç×µ}îÓ·Æü»ÂCºF@Ë ¸_Þˆ3@@@‚HàЙ&d_c—Iˆ¼ÊÔe¿K3†-RlxÏ R`¨ € Ð÷ö¨q  € € €@@ ä—~¡­yk´õäëªvWëšÞwêÉñÿ¥>уjœ @:W€À½s}¹; € € €€ œ­(Ööü v]öS¥‡4.ñV=”²DCã2äp8|´×t @|Y€ÀÝ—Ÿ}C@@èPÊêóÚUø»ḑÅ[4<~’¦ö{X£oV˜3¼CÛâf € |îÁ÷Ì1 € € Tn·[ŸÉ¶?Ýž·Á.cÕeŸif³G‡Å•ƒE@Î pï\_îŽ € € ÐE'Î}fÏdßzê 3{=ÂÔeŸ®…×¼¢Änýº¨G4‹ €.@àèO˜ñ!€ € €A$Pr¾@ç½iíÅçO(=é=šú3 ŠD @ºJ€À½«äi@@@ CÎW—*§`³>:ùº>/Ù®Q Sô¥ó”špƒBœaÒ7A@Z#@àÞ%ÎA@@ð)wµ>-þЮ˞S°IýcReÕetÔÏÔ-´»Oõ•Î € €@ð¸ϳf¤ € € €€ß qíµCv«lLth;d¿{ÂãŠìã÷cc € àÿîþÿ  € € ÐEå'ôñ)«.ûë*­*QF¯;õ­1ÿafµ èq38@ð?wÿ{fô@@x²*—>ÉK™ýˆkÒ3ußÐ?INGHÀŸ"€ €€ ¸ûçs£× € € €@À T×TjOÑ_í’1» ßÕà¸ñº¶Ï}š7æçЉ ¸ñ2 @<÷À{¦Œ@@ð+Cgv˜}²óÖ*!²¯©Ë>]3†þ@±‰~5:‹ €¸ó@@@ðº@~Ù{&ûÖSoÈšÙ~ ÙŸÿ_ê=Øë}¡A@@ £Ü;J’û € € €´(p®ò´™Å¾ÎÚO•Ò¸Ä[õЈih\†G‹×r@ðwxJô@@ðSÊêóÚUø³øéÚ_ü¡†›EO§ö{X£oV˜3ÜOGE·@@¦Ü›va/ € € €@;Ün·>;“mÏdÿ$ÿÏê5ÈÔe¿K³R–(:¬G;ïÊe € €€ï ¸ûþ3¢‡ € € €€_?»_Ûò7裓¯+Äj‡ìßÏø%uëïý§“ € €À• ¸_© ×#€ € €A,pâÜAmÏ[o—Œ©ª©Ðؤ©šúœÅ b†Ž €Á*@à¬Ožq#€ € €í°<Ý–·AŸZ£òê³JKœª™¦\ ‹Ÿ¶”Ë@@ `ÜæQ2@@@ óòËŽ˜}²Ÿ­×W:„ € àî¾ñè € €ø€ÀѳŸj{Þz²¯•U£}\Ò­ztÔÏ406ÍzG@@|]€ÀÝןýC@@N8~ö€¶ç¯×Ç&d¯ª©ÐØÄ[ôðÈ¥7®SÛåæ € €'@àxÏ”!€ € €ÀeNžû¼¾&{yõY²ßª™#–hH\ºÇe®æ0 € €M ¸7íÂ^@@0¼Òæ&û:»\̹ÊÓJKºEÿG íq©Ñî °Ñ2@@® pï uÚD@@¯X!û'ù¶ËŸ* ”–8U÷ý†ÇO$d÷Ê @@ ¸܃ëy3Z@@^ ¿ìˆ²oÏÛ Âòc&dÏÔ—‡|W#â'›=$àÇÏ@(r¹å4ȨºZ “ùç´Li¯†÷ÆÛžc”ýò§çK_F÷`|êŒ@@(,;¦í’1ye_hLÏ›5}з•­BœügO€=n†ƒ~*àv»õE¾´çˆ[»»•“ë–«Ì3˜·d«îÝÚnëË ä#ÃÂúºð¾qhom7þ\wÎÅïÍcõÉs®£þ—ÍÛxÿÅÛ?·¶mëë× ×¶® ç{®müùâ¶ë>7wNÃøš;×ÚßÔ±æö[m[Ï?ÔünÜzþÖ{]êÞ/¿9nà…€ ðož>ö@è € €´N ¸ü¤ Ùß25Ù×ÉZuLâMº#yŽR®7!»™&É @ Kª«Ýúü”ìp}×ní4»¢¦öwht²C_žìÔà>í MÏ•»íP¶qH_Ö[ïÖ«ñgë¼æÎm¼ÿâmë—ß§îsãsëöÕ½[]hêxSûê¯15Þn8÷¢>ÔÔç1¨»¦ñ{Ç¿¡­Æ÷·úÖпºsÞ¯tüV(oý©‡ÆmZcºÜËúÓ¡æ§© ßÎæÍ}ëÂûº÷æÎm¼¿~ÛtÀÚ®ÿ\¿ÖÿòãÒk›º_C?Ÿošk¢íºs/ßë76uã®{o|ÿº}¿×ŸÓìøëîëh¡ÍÙµ4¦ ]îùûÊqw_yô@@.+pæ|ž)cf²ç¯Óñ³û•ÚsŠníÿ¨y¿AaN3­‘ €@— œ¯tkÿ1°›pÝšÁnÍd‹’®OêÐì[œê—hE†WþŠŽì˜û\¾'Þjçò=áŒë!•UòüÀœzÁçF¿Ì¨ ñ[ü…A3¿Phí/`šû…C]ÛuïÍõA-ö·¿€é´ñ×™_Ô‡‹¼:küò“Eî Üþ^e @@|P ä|§\Lþzqí13ØoPf¿Y•p£ÂB"|°Çt ³ení=ê ×w›}ÿq©o‚ Ø8tÛ8‡¾›åTÏXëàø6xw”3åÚªùïýßgï›7´èXlþx‡¼Üýà!ÑE@@‚MÀUQ¨œ‚ͦ&ûzåºr42þ:Méû F÷¼Iá!‘ÁÆÁx@Ÿ°8µ‚ukûn3ƒÝªÇn•„±ÊÃ̸Îi¿wïF é‹N €@— ¸w= #€ € €@cs•§ÍLöMÚnBöÏÏ|¢ñ“uíU÷jΘeŠ15 x!€xUàDQC¸n…ì%RJ?S}€ôÛv-öˆ0v¯>CŸ p÷ùGD@@\ÒÊ3“Ý„ìùôÙél ‹Ÿ  ½ïÒ7Fý«"C£wàŒ ð1STú°™±nÕ^·f±ç˜N«Ì¢•u œÞ‘îÔð¾RH»=:ºƒ>&@àîc„î € € èeU.í,xÛ,|º^Š·jh Oº]¤>«n¡1>|Ƈø„@e•[Ÿ§DŒ Ù­ì¦&öSf”©Áþà§ö’¬ZÙ¼@Z/@àÞz+ÎD@@v ”UÕîÂwìšìŸoÑà¸qßë=œòŒ¢ÂbÛyW.Ch­@Ùy·öóÔ^ßõ…´÷ˆ[‰æ¿VÀ~}ªCߺөÞñ„ë­õä<@ 9÷ædØ € €W$p¾ªT»‹Þ5!û:í-z_cÓ”nBö™)?RtX+º7#€´,PRêÖ3kÝš¹n•‰ùü¤Ô?ɳÀéôkúÁ §zD°·¬ÈQ@ íîm7ã @@hF ¢ºL{ŠÞ³g²[aû€î©&dŸ¦‡?­˜ð„f®b7 €À• ”x‚u+\·BöEÒЫ<ûÌ›v™˜¨ö+uæz@àrî—â8 € €´(PQ]nÏ`ßnj²ï*ü‹®î>BéIÓ4cØ"ņ÷lñZ"€´OàhAmÀnÂõfÓ³åRJ?‡F›1ßþ’S#úIá¡ìíÓå*@ ýîí·ãJ@@‚V ²¦BûL™+d·@í=Df&û—‡|Oq¦f/@¨®qëÐ)Ù¥aììf»µ–ijOÀž5É©!}$§“€½Ãй ÐN÷vÂq € €Á&PUS)kÁÓmyë•S°I½£Ú ŸÞ=h¾â#MÒà @ C**ÝÚ¼6`73Ø­Zì1Ý<åa2†:ôõ©NSp½C°¹  ÐÁî Êí@@$j²ï?ý‘²ï(بÄÈþ&d¿]Ó}[ ‘¦80/@+8WîÖ¾£¦4ŒUÝüXaûUñ²ë®ß’æÐ÷8•KÀ~ÅÐÜð‚»i@@¨®©ÒÓÛåb>Éÿ³™½~•©É~‡dü^‰ÝLQ`^ €W$P|Ö3kÝØÍìõ/ò¤A½MÀnê¯ßS£8EÀ~EÈ\Œt‘{ÁÓ, € €¾$Pã®ÖÁÓÛ”¿NVÈždBöÛõ½ô—•5À—ºJ_@¿8Ulf®[‹›ÖÎ`/(‘†_mꯛ¼~ãV§FšZì‘áì~÷`é0 Є{(ìB@@ jÜ5úüÌv»\Ìöü êÖîÉþäøÿ2õÙcD:\Àí63Öó=õ×ëöó•²CõÑfûãÖW !`ïp|nˆø€»<º€ € €€·¬ èPɲ¯Ó¶üõŠ Ñx3“ýñq¿ÔUÑC¼Õ ÚAF ªÚ­ƒ'LÀ^;ƒ}·™Å&¥š²0Vi˜¯Üà´ËÅ8ìóÐ Ђ{ 8B@@ ¬ý°k§=“}[Þz…‡DÚ!ûci/ª_÷0DÆ€xM ¼Â­OY‹›zf±ï5‹&ÄÈׯKqhÎNõM \÷Ú¡!@ÀÇÜ}ìÐ@@:Jà‹’Ýö,vk6»Ój‡ìsǼ þ1©Õ÷A^ÀUj8=â©Á¾ËÌ^·f³÷K4»)sg†C îw*¾;{À  ÐJ÷VBÙ§U•«¼*T¡*“«2Lñ1‘m¹šs@@èt#®½ÚnJÅd›ÝšÙ>>é6}cÔ¿*9vt§·M €@ ”¸µÛ”‡±ÂuëçX‘4ô*Ï ö¯ÞèÔ(S&&:’€=ž5c@:C€À½ªù;×éÿ>÷œ–®ÜlÎNSfZŽ6ç˜ÍÌYZñ£ê‘)m¨uY¾OÏÍÿ?:•¨¨fÚ.--P¿ÛþAOÏHiæ v#€ € Ð pììþÚr1kUå®Ô8²?2òY ŠÛp[ €M +¬ ×kCö3礔~¦þº™Áþ­;övx{“xìD¸DÀaf½¸/ÙËŽz}/?©‘3Ÿ¯ÿÜÔFæ¢Õzó™{ÔªùîÅïjj²¢û–^™Ë²µéñô–Niñ˜µKnn®’““[<ƒ € €þ)pâÜgvÈnÍd?_]jBö[•ÞkšÇŽ óùç3¥× Ðù55fáèSžN­ÅMsÌÌÿ×-p:Ê„ìÖlö'{ç? Z@Ú&à/y'3Ü[x®U_»0lÏ|B¯þã}ê]qD|q¦ž_í¹xóÒ,-¹ñ˜ž™Ö·…»y¹Žî©ÛÓÒÒš>?'GW[KšóB@@ ‘À©ÒCµ!ûZ•V•h\â­úêˆÒи BöFNl"€uUn8îYÜÔ*cýD›Ùr£MY˜qƒšy³Sɽ×ë¼xG¸r÷ ?xù?ŽÎY¡¢—Q|íž)Ó¾¢¿yi¶&Ï[iïYºp¥žœ¶@I W4¹åÊϫݟ¥åï­Ò$³’9/@@šÈ+Í55Ù7Ø5Ù]…›x‹ö”†õ˜`Bu6wû@ (=ïÖÞÚN­ìŸ“z÷ð,pzÓh‡þî.§’â؃òËÁ @/ ¸7 ]¬í›ë ¿ÌRö²†°ÝsI¨&}}f™ÀÝŽÜsÞ×ç.)é2zálÏåiê™s›í@@Z ¿ìˆ¶çm°?-*?¡±I·è¾!ß×ðø‰&d è±38@ -§ÏšYë&`·Âõ]föz®)3°·g{Öd§Æ˜1±Qìm1å\@+ poÎϵ_«êòöÌ4¬©í‘ÃtK–´²¶´Ìå‹À”ëÓm‡<-ê¯^͵Í~@@ (,;¦Oòÿ¬ìüu*,;ª1‰™º{Ðã?ÙÔæ_Ûƒî Á€@ IS§= œZ¥av™=ïŒ4ÜTwµj¯}ªS£L©˜Èpö&ñ؉ àþͽ9昱úÇ—hì¾"u4LM†é®ZU¶[·©lî^õû+Ux*Çó)&O«~ýc­^•­c%%f_¬†MžªYUSR.W˜¦þ†l € €ø±€5{Ý Ù·å­W^Y®Æô¼Y_ø˜FÆ_kBö&ÿ ÔGK×@¶ ¸Ýn}‘/»îº®ï4?efÓþ;X¿e¬ÓÛÃB ØÛ&ËÙ €)à0ÿfÖãæÕv|ýzî­š½¼6@ÏZ¡’U¨Å*1å;õµniž4-4˜µdµ~ûô=-ß«…ë­Cþ²jïe†Áa@@ àNŸ?eBö·LȾN'ÎÔ¨ž7*£×™pƒB Ùîy3 h½@uµ[Ÿ4{my+d5U´¬N­ìÖû S.Æé$`o½*g"€#à/y'3ÜÛñ+?þ¡–Ìš¬¥u%gÌ=VüôþËä•¥2eÞíWšù«ÕÏzb‘†'”ióâçUw»Õ‹³tƒ6jÇÓS='óW@@¿8s>_; ¬}ƒŽžÝ«Q StKÿG”jBö°¿GÚ+p¾Ò,jzÔª½.»<ÌS‹=¾»gÓIÃúÆmN]Ý“p½½¾\‡ Ð5Ìpo‹{ùqýé…)káò ®Z¶1WOM¾`_S\ÛžSlÆBÏ¡¬gµ÷· ”R?%Þ¥M/|O·Ìo¸÷«¹•š‘ܾ߉øËo|šrb € ®ŠBíÈߨmùëuصË×Ó“î°g´‡‡4µ@P Œš1 €Í œ-sË Õ­™ëÖ§Ÿ— Ô=ûh3ƒÝZà4!†€½yAŽ €Á-à/y'{«¾§.m{íÿiö íYéõ—d.Ò;+kJßVþSy±+RYi¥zLQü%Yz•^››¡jËÔÌùÝ^½ôPJ}smÙ°¾€¯½öš®ºêªV_6yòdóGóœ­>Ÿ@@.8[Qlf²oÔöü :T²C)¦»²N¼I!QžÌ'@ À KÜžúëµ œ-”†ô© Ø­21æ§{7öÿ0<@ Y-[¶¨¦¦¦Ùã¸þúë•››«ääËO|¾øZo~&p¿œvÕa=wû@-¬«÷bŸŸ¥7þTߘš¢K2óËÝï2Ç];_RlÚ¡‰½Ö—<2²•¿hÓµÖcx5ûúC×;¿;ý¸f¯¬kgŽÞÉ]¦)ÉíîÒ¯ïÕìÕÖý)×ýŒšúù[¾h½™U§Ï; € ÐÕeUgµ«ð/&d_§ýÅiHt»\Ì×GþTQa±]Ý=ÚG:U ²ÊÔ\?!í´f¯›ŸÝ&d2óŬ²0c:4ó&§$Iþ†t*7Gj÷æÕAýª>mÏÒ;E/iJk§µ—»tüT‘*ͽc{'+þ’Œ~©~ÿî“Z0ÅüÛHãWñ»úÁì†ESo»~hã£l#€ €xYà|U©'dÏ_§}E[4(n¬²ÏJù‰¢Ãâ¼ÜšC¼'PvÞ­}GÝž€ý éS³dþ±g•‡¹i´CßžîTïþ1ÓÐ{j´„ €€UÛ„W“Uy´©Ñ‘·û‚>(/o´çÂÍóç{é¡ï?¢!&\ß¹FSfÍ‘V{õ…7ö’^Ý¢ÙwŒU|7éXΚŸñ€ì ðÖ­gýNw%óx.Tæ € ÐùÕeÚ]ø®²ÍLö½ÅUrÌhS“}š¾:ü‡êÞÚßOZ@:RàÌ9·öñì»Í öC§¤æ?[G›ìYͧ8Õ#š€½#͹ €@` è6ó\ËNîWNý±ÕZ<¿> ¯ß{áF¦n¸+âêúC‘aõ›2ã'Z–µ\u·ZøÀd-l8Ühk޶¼ð.™ßè 6@@:N ¢º\{ŠÞÓö¼õÚ]ô®úui/|úàðPLxÏŽkˆ;!€>"ÆSÆ*c•‡9Y, ëë™ÁþðT§Föw˜’1ì>ò¸è €€ ¸7󰪬z0mz]­ºl=,¢¡öº)i×蕤ÇWiø KtçüçíoØÌ|b…V,}Dí.ßp+¶@@Z¨¬©Ð^²oËÛ`ÊÆ¼­«£‡Û3Ùïº@q•þká>BüAàH¾ Øk7µBösæp[¡º5ƒ}ê]N0óÆÂB ØýáYÒG@ßp¸ÍË·» ½+/Ö¾û•ºB••çT¡x 3VC’:f^»µPMnn®’“›Zš5@M € pªšJS‹ý}mË_¯o«Oô`OºÝžÍÞ#¢÷e®æ0 àÕ5n}~Röâ¦Ö§VÐî4YºµÀ©UƒÝúlþ‘ç´vòB@ÀOü%ï$p÷“/T[»é/_À¶Ž‹ó@@¶ T[!{ñmÏß œ‚MJê6À^øt|¯;”yU[oÇù €€Ï TTºõé1°×Î`·j±Ç™?xm‡ëµ!{¿DÂuŸ{pt@ Mþ’wRR¦M•“@@üA º¦JûOd×dßQ°ÑëWÛ³Øf¼¢žÝÖÛñ‡±ÐG@àbsåžNíÙëfûRßϧ·sèÉ,§c Ø/vã3 €Þ p÷†2m € €tº@»ZNlj²¯×Ž‚·Ô#¼—¬YìßËøo3«½§·O €@g ¹< ›ÖÍ`?’/ îã™ÁþÀõN2%bbº°w–?÷E@ -îmÑâ\@@Ÿ¨q×èà™m&d_§OòßRLx‚©É~‡¾;þ7ê5ЧúJg@Ö œ(òÔ]ßmf¯[ œº¤”~Ö§Ò7owj¤ÙŽ '`o­'ç!€ àMwojÓ € €À ¸Ýf1À3ÛͧëL]ö?+*4Ö®É>ܯìEP¯¸n€xQÀúgZnžgÓݦ»°WT™Nû{7½#Ý©á}¥v/>šB@ Ýîí¦ãB@@o ØTIŽ Ù×Û%c"B¢ìšìßI{I}»÷V7h¸bªjSsý¸d…ëV vë="ÌSf”YàôÁ)N ì%Y ÃñB@ÿ p÷¿gF@@ È-Ùi/|jí¡Ž0»&û·Æü»úŤEÿ(¯pkïQ¬›p}×Ò>³ëYàôúT‡æNsêªÂuÿ~Êô@÷ ¶@@|@à מúÝêÎø¤Ûõ·£—i@LªôŽ. €- ””ºµÇš½^;ƒýó“Ò€$S"Æ,l:ý‡~p¿S=º°·¬ÈQ@üW€ÀÝŸ=G@Fà¨kŸ].f{ÞzU¹+í}vê?k`였#AÀÈ?ã) c•‡±BöãE²k®[åafÞìTª©ÅIÀ˜OŸQ!€ p©û¥&ìA@ð‚Àñ³ûMȾÁÔd_§ŠêrKºM\jBö4j{ÁŸ&@ }G <µ×ëf°—”J#k8ýö—œÑO %`oŸ.W!€ àÿîþÿ  € à7'ά-³N¥U.3“ý6=4âG—NÈî7O‘Ž"<Õ5n2%aêÂuëÝzY³×G›Ÿ¬IN î#…8 ؃ç[ÁH@hY€À½eŽ"€ €\¡À©ÒCfûm7 Ÿº*ŠÌLö[õà°§5¤G†œçÞË@ލ¨rkÿ1°×–‡±j±Çt3 œšúëCúúT§ú'®wœ8wB@ ðÜï™2"@@ ËòK¿¨¯É~º"OcoÕýChX &déòþÑ@À8WîÖÞ# œî?.]ï ØoIshþÝN%ŰómA@Ö ¸·ÞŠ3@@Z((;jf±[5Ù׫¨ü˜ ÙoQÖïjx‰¦ÜÿÚÙ‡@ÀK§Ï6„ëVy˜/ò¤A½=ûý×9íR1±Qì^z4ƒ €@@ ð_>ùX € à¢òµ!û:å—}¡´Ä©ºkÐw”?Ù„ìaÞé­ €Íœ*vkgmy«LLA‰4üj‡Æ$K߸Õi/vNÀÞ »@@ îí@ã@@ ˜ŠËOê“ü?Û%cNžû\coÒÉó”’pB Ùƒù«ÁØèR·ÛÌXÏ—'`7áún3ƒ½¼Bv¨>ÆÔ`¿c¼SÃúJ¡!ì]ú h@ pðÌð@@ލ®©Ô'þW[óÖèøÙýÕóFÝ6àQL¸AaÎðŽh‚{ €m¨®vë³µ» ×­€=Üüî¨Ö v‡¾rƒÓ.ãp°· –“@@àŠܯˆ‹@@ÀØY°Y<ø3%FöSf¿¯)Õ„ìá!‘?pFˆ>%P^á֧Ǭ1Òn3ƒ}ïQ·bLýu°_ŸâМ;œê›@¸îSÎ € „îAøÐ2 € Ðcf&û?{Ng*ò5cè̬ö)­¹Œs@p•¹µÇÌZ·j°[³×šÙìý= œ~釾ŸÓîì‚ÍM@@ ÃÜ;Œ’!€ €!àª(ÔúÃÿ©ì¼75-y®nèû³*ÿÚO—Q à»…%ní2Áºµ¸©õs¬Hz•gûWotÚ¥b¢# Ø}÷ Ò3@°ø/'¾ € €¶@•©Óþ×ã¯êÍÜÿ§ ½§ë鉯+*,@ SŽ6„ëVÐ~úœYà´ŸC£Mýõo}É©”«¥ð0öNÁç¦ € ÐiîFË@@ÿØ]ø®^=°T}¢é»é¿QoóÎ è(š·Ò3ØÍ.{ÖºUƒýî‰N 1³ÙCœìeÎ}@@ kÜ»ÆV@@Ÿ8êÚ§?|ö¬ÎVžÖƒÃÿQ#®ó‰~Ñ ðoÊ*·ö7{my˜=GÜŠ6k-[áúøÁ}-Ó©I„ëþý”é= €4%@àþÿÙ»ø¨Ê{ãÏLK€a KÀ” PÄ€¥âBÅðVªµ h[)öJ[´RÔV°Ö X‹U@‘E‚"V…(¸€JP@CHØ‘È@’9÷ÌL6d›L&aNæ7~BÎÌœóž÷ý¾s/ôÉ›ÿ{6^C@ª¹@ÎɃzÇ,}õ¶cÖi*»-¤ššá!€@e 9nh«ªg~m1¿Ò̰½iϧ×u¶éá›íjÒ€€½²üi@G€À=p悞 € €•.ï<¥O÷Ì7Ãö™Jh–dÖi_JöJWçT/Wy˜Y’kÕº+\w…ì‡r¤öÑR§V6ÝÞÛ®Žæ÷úuØ«×Ì3@ðF€ÀÝ%ÎA@ªÀ¦ƒká¶¿*ºNý¦Û\5©S FÅ@ ²Nœ4ôýW¸.}gnnºu·¡Z5<áº+X¿¹‡§þzh{eÏí#€ €@à ¸þÑC@@ B;s7»ë´; ŽiØ¥Ö¥‘ j‹@ z ìÏ6JV¯»V±ï2W³·nâ Øv…Mco±›åb׫÷§€Ñ!€ €€¯î¾Êq € àGOÐòÌJ=¸R7¶ýµz7¿Í¬Ónð^Ó=¨J׿¦ÛöÉ]Æ®»¾ò ¤¸–6u278õs›.maSx öªœî… €Ö p·îÜÑs@@ଧ Z½çM}°ó_êÕ|ˆžHxWµBëžõ\^Dà8r̪×_O3Ãö&õ=«×¯lgÓ=‰vµŽ’l6öàúd0Z@ð—€_÷‡CùùÊ7{VKáá~mÞ_c¦@@ Ú lÌZá.Ó*¢“~×ýM5®Õ²ÚŽ•!€Àù\››î0ËÁ¸66-^½~8·tsÓ;®ñlnZ¯6áúù%y@ð^ ‰¸C;6­Óg)ë“•)Z“œ¢Ô3î¯Ä=uÃ5}Õ·ïuê­ð3Îá@@Š dælríÎSº§ãÓjßàÊŠ6Éõ `1ãÏæ¦›ÍÍM]!»ksÓÚ5%ׯ¦Ì¯[®²«]3)„ÍM-6³t@¬$`3ÌG¹:\¥•oÍÐSÃ')¥\ºNNÒô5òöE”ûZ.(€ëW@333SžË8@,&íØ¯å;fè»C«tSÛ‡Ô³Ù`ê´[lé.¾ ì;|ú榻J1E››ºBöËÌìQõY½î«/×!€ €@` X%ï,Wàž¾r¦è?æìA{|¢’â[¨iíÚî™8qâGíIÍPJê™ëÞ¥DÍXþ’î»!NXbX3`½±Ê0ÀØè €–8U˜§wÏÓŠ]³uuôíÐú…‡Ö±Lÿé(”Oà”¹¹iºYoý»FI‰˜§¹zݵ¹©{»ÔÍMˇÊÙ € `)«ä^ záÑîš0§Ì$ŽÒôûoUbB¼Ú´h¢ˆsÔk/päêÀžL¥®MÑÜÓœ²Ëâ'jÍì‰Jˆa½{Y¿Zåè—ÁÒ €A$àúåÄo²>ÔâôgÕ¦^¼_ò¨ÕjD àÈ.ÚÜ´¸þú63loÚÀ³¹iq‰˜VÙÜ48> Œ@\VÉ;/¸;6hp­îJ.š×gë‘ÑIêéÓLg¥¯Ö/þM㦵?]‡7Ž•o­ùÔ… ¸È*À ˜ ‰ €€Ÿ2ŽnÔÂm•+t¿­ÝcŠmÐÍO-Ó \L׿¦™NßÜ4û˜gÅz§VE!»¹’=‚ÍM/æ4qo@¸ÈVÉ;/\Ñ%´¾:¹0'ÏÕߺC±‘¾ä|öQ±}4öù>õø&½ùü8\S“²2çã=@zÃŽ}z/ó%m9ü¹niû°š%¹Ww= XTÀµ¹©kCSÏêu¹ë„{‚uWy˜¤»bÙÜÔ¢³K·@@ Ø.¼Â=Ø…,:~«üÄÇ¢¼t@*8YxB)»^×Êݯ«OôsŸj†xöË©’pð‹À^ssÓâÒ0›Íì{Imš–ì®1lnêjA@j,`•¼³bËÕÏ3¹ÙÊv(44\‘‘Ôh?o!€ €§ ¸JÆl8ð¾Y§ý9µkÐ]¿¿r†7?íž €@` ¸67MÛ{zy§ksS÷Ʀ6õ½Ñ®KÍmj†Ùsô @@ B ÜsµáýEZøöêöÈsº=άhüߩûði¥‹¥åóÿªâ¨Ô^ŠÂ € p¦À¶#ëµxÛ³²Ûìºÿ²¿«mý.gžÄ+ 0‡sˬ^ße(}¿Ô¬hsÓž—ÚôËëíjÙ˜p=`&ŒŽ € €•,à{I™‚zf@MHñôpúúÃÛ-RY«ŸQ“k'œµÛ³SstogV»ŸÇÏ/ZåW,ü] @ p…úrÿ;Zº}š:6¼Z÷X¬ú5›¹ ÃGÀÿÇò mu­^7ƒu׿¦ßï1Tϵ¹ik›{ƒÓÛz›››6esSÿËÓ" € €ÀOl†ùøé‹Þ<_ýd?];)嬧N^q@Oô‹Ô¦¥¯èÅic4«ø´Äé:°rlIm÷³^Ì‹~°ÙlÊÌÌTLLŒ_Ú£@(Ÿ@ú‘ šŸöÕ ­«ÛbSëz—•¯ÎFs ì>h–‡q‡ëž}ßaésÏa׿¦ͯËÌ ½a››ž7@@ X%ï,Y‡^^ã>¿{IvÔ”ÔŸ\i†êcúE™/æêó²a»ùÊìé# ÛÂÅS@¨^NìÐÛéÏiïñ4%]òˆº5ùyõ £A ŠN𛛦™››zV¯{‚vW”ç Öͯþ]ÌÍM£¥aìU<5Ü@@à,^ÓNÓÓëèú934{ÉzwM÷¦ÝïÐ';#T1Y/>õ;õ)S×ý,}á%@@À²'òsôѮ볽 Õ¯Õ/ôËNÏ),¤¦eÇCǸX]››–Y½žannÝȳzýêŽ6=0À®×/Öüp_@@ó xURfà ƒÕ}œ4yÆÝt}oÅÇFŸ¾ŸãŽ\忇)2‚ºíç ª´—­ò+•@à €T‘€«NûšýÉzgût]Þ¨¯ni;Võj6®¢»s¬-PXèÙÜ´ìêõܼÒÍM]¥aâZÚT'œ€ÝÚ3Mï@@Š X%ïsé»GLÔýÓtuBÅP[¦,^¥[åXéÜ@?: ôÅþ·õnÆ?Ô¥qÝÜö!EÔ0wqä@ d-. ãùžñ£ÌÍLO_½Íæ¦Aü aè € €€¬’wV p?,{ïV­ýø½ý¯W4+åÌô=>i”üåCºoPg¯6\=½už•WÀ*ÀòŽ‹ó@¨j­‡×hAÚÓjP³‰†´{L-êv¨ê.p?.º€ksÓíf î.³ÓS&æ¸Cî M;µò„ìlnzѧ‰ € €ÕZÀ*y§ß÷²³éÈÞ¡u«S´xÁkš6§Lá™øé:¼q¬"ËžÌq¥XåX)ƒ§Q@ü °ïø6-Þö¬:vëÖØß(¾q??´JXC ÷„¹j}wqýué‡=†"ëzÊÃ×_oÓD²Û)c¥— € €€õ¬’w†VuxdŒz%&)®×MzüécÚ•¶^ g¿¤e£U«2nH› € €€ŸŽÊv×i_»©Äܯ¾-†)Ôæ§ÖiÀ0 C»zV¯oÙeè;óëÇ#žÍM/kmSR‚ksS»¸®ÞìÑ#@@@¨`àž« ï/Ò·¿P·GžÓíqæø ´aÞïÔ}ø´Ò±ÆÒòù‹ôtkÛKQ8B@@(tæë³} µ,ã%um2@O\µTukðo—@š#úâ׿¦®ë›w…ìæJöТÍM]«×tµ«››ú›V@@‚NÀ÷’2;ôÌ€6šPT1fúúÃÛ-RY«ŸQ“k'œrvjŽîíì åyT¶€U~Å¢²h@o¶þ̬Ó>E ã5$öwŠ®ÛÞ›Ë8K¸67u×^7W®»V°gšµØ[6>}sÓæ Y½n‰É¤“ € €@ X%ïôy…û†—Æ•„í®y®éÞ Õ¡e³JÃöÄQS5¸Ñç7%ÙýQ9nž’Vަ†{ÿCG@ öûA‹Ì:íGNþèÚ/oÜ7ºG_(·@¹¹iú~¹ƒuWÈî ØOœôlnêZ½~o›{£ÓÚ5 ØËË € €x!à[à^°U3ÇyBti”Öì™®„èp)w­–Ì)ºkâTÍŸù˜¢Ì§]› Öµ®óS–+#× ÜYäîÅÔp  €T–@î©ÃzÇL­?°\?oý€®mq—B¨Ó^YÜ´[‰9®ÍMÍP½8\ÿa¯ÔÐÜÜÔ®wicÓÝ×ÚcþƒœÍM+qh@@2¾îy'dþ&ªû1qÅ=a»ù,7m­Jbøû¹Ãv×I= 6ÿt½“¡íêa†ó<@@*(0ë´ºw¾–gÎЕMo4ë´¿£:aõ«¸Üß\››îrmnº³´DÌ£Rû枀}pO»¹¹©M ØÜÔ7`®B@@À¾îaRñ"õ˜ÅGRÚ§+KºÔ7¡MÉqx›îa>›£Tm?˜'Ÿ—àp€ €U"ðí¡UZ˜öW5©£Gº¾¦fu.©’ûr|pmnú}Ñæ¦®U쮯0ó_ï®Õë®`}`wssS3l ¥<Œ¯Æ\‡ € €€¿| ÜÍ^ä÷Ä ß=l}´¤x}ûxu‹) Õ™ëͰÝõˆW\³ZžÓù@¨ݹ[Í:íS•›Xw´\]Swå”_àÀ‘Ò•ë®1;H­Ìr0®pýºÎ6=x£]Í" ×Ë/Ë € €T€{XÉ ÷1ÏÌÓ-³G+ï½gK7QuµÚ•´œ«wŸ¾hDmÕ´ai_uÃäN € l9§™¥cþOßd}¨bÆèšè¡fö’ ã 0÷æ¦ûÌò0E+×]ßóNy67uì÷]oÓ¥-mbsÓ›8ºƒ € €À|û_á5jr¢æLJ1ëÄŒQ ó«ìcò}ªmZúŠ^œ6F³ÌÓÜÄ~º¤´MÙK8F@ü"ï<¥Õ{ÞÔwÌR¦·¸ë´×«ç—¶i_Ž7KÂìö”…ùάÁžfnnÚÈüX^f†ëW\bÓ°¾vµfsS_y¹@@€°™›/>õƱU'tÔ”ÔŸ\8]VŽ57LÍÕÌ~õ4¦8l7O›š£{;“¸ÿD¬RžÚl6eff*&&¦RÚ§Q@Q õàJ³|Ì3j^;V·¶û­šÖnˆÝ¤OÕ\ÀõÏëYžÕëÅ+س\››F—Ö_wÕaoP‡ò0Õü£Àð@@ü(`•¼Ó·î.¨ð8=½þ€®Ÿ3C³—¬w×toÚýýqâ03l?ý?b²^|êwêS¦®ûégð @ð]`gîfwö¼‚\ÝÝáŠkØË÷Ƹr äôlnºeWQ‰s%{MsŸ£ŽfI˜N­mºéJ»b›±¹i9Y9@@K ø¾ÂÝ‹á8rÍ ÊÂAÝv/¸üzŠU~âã×AÓ €@Ð =™¥÷2_RêÁÝØæWº:úvÙm!AçÀ€«VàÇìÒÍM·¸675W³»ÊÁ¸V­»ê¯»¾š²¹iÕN wC@¨öVÉ;/¼Â½ ]x@ Æ?§_ êV²Yª73¡ÈseíŽ,­üÏÓzaG¢Þ|zÎuš7÷á@.S…}²gž>Üùoõl–¤I ï¨V(eë‚ëSP5£Í/0”¾ÿôÍMOæ—nnzÿssÓ6ÕªIy˜ª™î‚ € €@` \8pÏ;¨5))JIé® JÔÔ¹Öˆ!}ícB^½Cï½5SOŒ™"Où÷æÊ#pìO ½C@ €¾ÉúP‹·=«–u;êwÝæ)ªvëê]±ºÀ׿¦æªõâÚë®ÍM£ê{V¯w‹µiÄužÍM]«kx € € €?ð¢¤LÒW¾¢úQ™ýO5bâ ¼ýzumc–Œ9nïÈÞ«´o¿ÒòÅÿÖ„iÉ¥}ˆ¥åóÿªâ"K_ãÈ/Vù ¿ –F@‚B 3g“»Nû©Â< i÷˜.LŠq3ÈÊp:K77-Ùæx67-. ã*SŸÍM+oh@@/¬’wz¸رW _˜ ¡æœAŸ˜¤ž]Úªeóæªn.ÒI9Žî׾ݻ´qÍ¥x–²ŸvÝĹk4qXB¹JÔœÖOÎ+`•àyÁ› €˜ÙŽýî:íßZ¥›Ú>¤^͇˜uÚíØ PnE››nÞé)³ÕÜÜ´V ¹k®×_m.…†°z½Ü¸\€ € €@% X%ïô>p/sìݤÿ¼ø„ÆL)³R½˜£¦ÎÕ#Ü¡¸Èó¯Š/G“œz«|ÏÒu^B@À-àZÉž²{ŽVìú®n~›Ä<`Öi¯‹^ ì/ÚÜ´xõú.׿¦M<»k»+doÚ€pÝkPND@@à" X%ï,wà^lê0k±¯[¢åË–hÙ¬ä¢zìÅï–ùŸ¨ýnPÒ-Õ·wgEùXû½L‹z!`• Cá@ 0 C_g} ·ÓŸSLÄåû5®Õ2Èny\››nÛ'wýõïÌì®=¿ÀS{ݳz]îÍMÃk°—×–ó@@«ä>î§#(7;W¹y9ÊÏw½¦Úµk)<¼–""HØO·ªšgVùVwA°Š@ÆÑî:í…F»N{ûWZ¥ëô³ŠŽóllZ²¹©¶71+–­½Þ:Jrý›ˆ € €X_À*y§Ÿêº„*"2Òýeý©c € PÕ‡û´,ãEmÍþB7·}X Í’¨Ó^Õ“À÷smnºÃ,S\fóNC‡•nnzÇ5vwy˜zµ ×xé € €A!à§À=(¬$ €øYàdá ­Üõš»Vû5ÑC5éªwU3´¶ŸïBsVpmnêÚÐtó.OÈî:®]ÓSƵ‚ý–«ìŠmÆæ¦V›Wú‹ € €@0¸Ã,3F@LÀU§}ý÷Ì:íWlý®šÐ}¾Õj`½¤;U%°ï°§6SÞÞr> €´@VÞ.½³}º2r6ê–¶ãÔ£éMÔièó®s?ì1´ø §Öo3Ô©µgsÓë:ÛÕ!Zlnê!g!€ € €@øœ”ÚI“ü¥†Þ’¨¸èˆÒÛDvÓ½O¼®Ä­Ôfàóõ\È7¿¸—q„ €ÀE8žTÿÝ1Kkö'ëúV÷êþ˧)Ì^ã"õ†ÛVDàÀCo¯qꃯ õ¼Ô¦é„¨ec‚öŠ˜r- € € p!÷l-{h¨¦œQ)&^ã§>¢» P÷¸h¯ñ°’žå”q€ €G ÐY ÏÍÍP—eþSñõ¿=–¨^ÍÆ§3ܵB»zÊÆ¬úÎPßËmšñ`ˆ¢ê´W•‹@@@/Η‰Ÿ·‰šJßN?UcîºMWwU„—-6é~·Ìî cj¦VµJÛâ@ªV`ËáϵhÛ_Q£±ŠŸ¥–ì­Rµ3àŸ»¥ï3´Ð¬Ï¾.ÍЀ®6½òpˆÔ%h÷.­ € € €Þ ø\Ã}ëû¯ê“S5d@wE…{™²{×'Îòƒ€Ujùa¨4 à£À¾ãéZ¼íYÌÛ©¤ØGuEÔõ>¶ÄeSàû݆Þ\íÔæ]†nºÒ¦!½ìª[‹ ýbÎ ÷F@@ÿ X%ï´û6ô\­™û¼Æ$õÔ£ÿÙrÁ&²ÖÎT?›M¶{^5+¶ó@@‹)p<ÿˆ¦MÕ´¯¡‘WéW%¶_Ì ññÞ3œzlv&Ï/TÇV6ýg|ˆþ§_a»ž\† € €øCÀÇ¥éfö\OwoôMÉc”âêmê:\ ¯ËÎøc€´ €Bg¾>Ý»@ïeþŸ°ÿLÿkí5ÊÔˆ*à ÃЗ?šû‰S¹yÒ­=íº¡»M5BYÑð“G@@@ (¼Ü·Î{\wþk³ÚÖó¸d${¾'¿4Nƒ—½xV²%«36Y=뼈 €~øîÐj³NûTEÖl®±W¼¢u;øù4W™…NCŸn64Ï Ú]ÛzÛÕ¿‹M!v‚öÊt§m@@@ ¼^î'nVjJò™™yjŠ’½ Ò“.WS¯ïXÞ¡Xó|‡Ã¡P³~^v®Â""E9|kÎ#½FU`ï±Ì ýYeŸÜ§ÁföøÆýµ«ôë,ù†V¦zj´G˜›ÌïkWŸËÌ2}f©> € € €'àuüݪko³÷ÉŠ7¿§*µLÈîyíüƒkÛï>=ùø ?ÿiÁñnÁ^½ÿÊ+zæ¥IJq9&&J)î¢;1y¶þ4þ^ÅF£D¨ÜS‡µQ>Ä*?ññip\„ pšÀîÜ­Z”þŒrNÔ­í~«Ë]{Úû< \¬£†Þ6W³»ÊÇ$t°i˜Y£½ec‚öÀ1z† € €KÀ*y§WÙwƲߪÿ8Oñ©krôX‚´läµî’2原®ÃǪ4b.×Õ–?9{û·%aûˆ©§…í®Á…F÷ÓߌWòPÏJ÷”¯wù¸[‹ €\P çÔ!½—ñO}sð#Ý3J}¢ï2ë´{õWûÛæ„ÊØsÈТÏúä[C}/·é¥_…˜µÚ Ú+WÖ@@@Ê(÷ÿ*wï·¦š*¿sÕíŸ,)RmJŽË´¸¼KÉÓz%G € P*ï<¥U»çé¿;ÿ¥MoÔW½£:a”x+ Ü£íû -üÌ©µ?úyW›^~(D #ÚwÆè € € P>¯÷N·¿¤5 GÍ–k«C|„ûÃf§êŠý'fþgVšñ⑯°Æ—íêvP§;ÿW“÷uÑaÕR‡úîŸ\œá¶ù“%¯å”q€ €€G`cÖ -NVÍj_¢G»¾¦fu.Æ?ì1ôæj§¾Ýaè¦6½:>DµÚ-0ut@@(—€W5ÜËÕ"'û,½áU5ì>²äú©9ÝÙóŽ’½<°JM#/‡Ãi €@Ð ìÌÝìÞõxþÝû[ujtMЛX 5ÓÐÜÚuÐPR‚]ƒ®²©VM‚v+Ì}D@@À°JÞéÕ ÷À¢­Ž½qhí¼Éê9|JéàFÌÕ0ÃöÒF8B°ºÀÑ“YZ–ñ¢6úجÓ>F×D¥N{€OªaZ—fíŸ8uÄÜ`~H/»v·«F(A{€OÝC@@*,àUàž½u­Öî=®½]X´®í'¯nZÑ{Yäú½–êÏ#“4+µL‡“¦+sö0ù¶¶½L;"€XV ¿ð¤RvÏÑG»f+¡Ù wöÚaìîÈZè4ôùOÐîtJ·õ¶ëú.6…„´ò¼Ñ7@@@ÀŸ^eßLÔÀq)¿oütÞÔuÜ‹{7è…?Ô„Ó’viüì5šro‚‹O¬À÷W^yE 6ôº…‡zH¡¡^}$¼n“@Ê/ðõôvúsŠ®ÛA¿í6GMj·)#\Qeù†>ÞdèUNÕ6ÿ¿ûZ»®½Ì&ׯ;ò@@@8»À?ÿùOåç{·;èÙ[ÌWIW/¼ìXùŒÚôŸpÚ“ÆÏÖ_¡¸(ÿMIZZš""¼_'ït-Çã pÑ2s6¹ë´; kØ¥“×°çEë 7¾°€ã”¡¿14ßÜ 5ª¾4ú».µ_øBÎ@@@Ж-[têÔ©j'áÕ¦©ŽìJÛ§°°ŠŒ?_aõZ*6:²"XþÚÜ 3U¯û˜Òq$NÔª—§>±þu±Ê&¥!€Á+pääz׬Óþݡպ©Íƒê}›ì¶à ð‘wzï+C‹>wªmS›†_g×å1¬fði£{ € € `q«ä^-§ŒQgÿæÁŸ^»Ÿ»A– ÛGÍX¥é£ûø¥|Œ=â2@‹(pª0O+w½¦•»_S¯f·jRÂ;ªêýo&]Ä®å­7ôΗN-]kè23`jDˆÚE´å‡A#€ € €çð*pÏNß ¯ÍMSÃÌ’:Ñ]{ɵ;}Ã2_*ߣF´z%Äí¦©éÿ©9Eb‰S×hæè„òùq6 €@µ0 C¼¯%Ûÿ®Vu;éwÝÞPTíÖÕblÕqYG -YãÔû õhoÓßî Që(‚öê8׌ @@¨¨€W{ƲߪѦ©S×äè13'^6òZK-çíÝ›¦Ž ÒMS ”¶!­lßzá…Oäp”¾tÚÑÉ“jrõ0ÝÛ/ö´—y‚ `mŒ£µhÛT8O鞸¿¨CäUÖP5îýÞCfÙ˜/œJI5tíå6½4&DM# Ú«ñ”34@@@ Â^îeïî®ã¦šÊ¾Êñ…ò´cMJÉi)Ó&©ôYÉ˧$N¿É ÜO{‰' €8ìØgÖiA[¡›Ú>¤^͇˜uÚÙ`3§3ãGC ?sjÍ÷†~v…Mÿz8D #Úq®è € € h^înIkŽš}¯­ñžÚ²Ãf§êŠý'fþgVšñâanšÚø’ ]Ýîâqèd=/˜ÊœR¯f™'"€XRàdá ­Øùª>Þ3WW7¿]O$¼kÖi¯kɱT÷NoÝmh´§fºéJ›^¢ˆÚíÕ}Þ € € àO›YGÖðgƒ´VÙµ70´è à×_¯ë~\¦äíÏ«m½.û¨×jéÿÑb…6™û›«Ú¾ßPR‚]ƒlª]“ ½Â°4€ € €øQÀ*y§W+Ü/äR›¥-߬צ]‡¥5Tã”ù­aSuè§v1QA»Iê…Üx@ z ¤Ù`ÖiF†ùßÈNSÕ®Á•Õs Õº4§æ}âÔá\éÖ^výñ.»j„´[|Zé> € € pQ*¸ìÕÒ¿ÿYIf{ñ#4÷Å?iX6ÿ<7ï €TCy{´4cº¶ùJ7·}X Í’¨Ó`ëtúl‹¡7V9uª@º½·Ý]§=$„ =À¦Šî € € €–ð½¤LAºk§)^;~ü}úüíòT€÷ò"NóYÀ*¿báó¹ GÁq}´k¶VíyC}¢ïÔ€Ö÷«fhíê!])(4”²É,cíá5¤¡WÛuíe6Ùíí|:@@@+X%ïôy…ûÚ¿?pZØž8j²¼s€.ifn£š£½i›´|îTM™“ꞯÔiCõÛ[4sXœæ>"€ pA§áÔ—û—ºWµ·«ß]¿¿r†G_ð:N¨:“ù†>øÚÐ[Ÿ:ÕÈü©ÿìêg¯ºp'@@@ ðm…»c“9nªxÍ]ÿ‘†u‹:+\Ö†yº¾ûpyb÷ñÚ–ÿ¼b}ŽùÏz ^<‹€U~âs–®ó ` 4³lÌb³N»Íf×mí&(¶~WKô;X:yÜahùzC ?wªM›†õµ+¾ «Ùƒeþ' € €T?«ä¾Eßùù2÷s?FÌžsΰÝuBT·aZ¼à[µê*>“¡ƒyR,ueÜvü `=ƒy»•¼ýyeݨ[.««šÞb†î¹2“GzçK§’׺¬µM“‡…¨C æ'Pæ‡~ € € €Õ]À·À=L%µØ¯éÞþ‚FõJŠÏD˜åfx € `=¼‚cúpç¿ôéÞêÛânˆ{R5C¨Ó(3y(ÇÐÛkœîUí=ÚÛôÜ/Cc®lç € € €@U ø¸ç«d…û†õ™Rçó×eϯ;Ñ“k…{®ÌKy € `§Q¨5û–èÝŒ¨Cd‚&^¹H‘áÍ,ÓÿêÞÑ}‡ -2ËÆ¬L5Ü› ¾8:DÍ´W÷yg| € € €@  ø¸GtÒ#¤ä9Ò¬‘¿×ª_ô9šÊݤg'¸Âvó‘4P('ã±àO@€ø>{Y§ýY…ÙÃõÀåÓÕ¶~—€ïs°tpÇC >sê‹­†®¿Â¦— Q£zíÁ2ÿŒ@@T¯6Muäf+¯ ÌBkI{«aÇáE/Ækê‚5âç=®‚‡r³Ô_¼¯)Ic”\tÖÜ-9Gâ^F²Ò­²‰@¥Ð0 P'v¸ë´ïÌýNƒ.¯+›ÜHö xúóÒï÷˜Aû§NmÌ0tã•6ÝÖÛ®zµ ÚýiL[ € € €@ X%ïô"pÏÕÌ~õ4&ÅÌ#fèðë£釦hâüVùž¼‹T­À‰üýwçËúbßb]×r„®ou¯j„˜?dæqѾÝaèÍÕNmÛg()Á®AWÙT'œ ý¢O @@@ªHÀ*yç9êÀT’RêÉJj˜f@ð]ÀU§ýs3d_–ñ¢:6¼Z÷X¬5›úÞ WúM`ý6§æ~âTÖQiH/»ž¸Ó®šaí~¦!@@@¿ x¸Gè–)ɪ¹å˜jÔ¨À½ORÖ=YÝ^B.Eð¿À–ß»ë´× ­«1ÿ©˜z—ûÿ&´X.§Óp×fŸ·Ê©“æn뮲1?3ë´‡†´— ’“@@@ª\À‹À]ŠN¤{ª¼oÜ@JøñD†–¤ÿ]{Ž}¯¤KQ÷¦+í^4ì@A¡¡O¾5ô†´×0ÿ…2ôj»ú^n“ÝNÐî g!€ € €\l¯÷ wrÇ<ÙÚ˜¬&NÕž•)ºÂ Ò €¾ ¸ê´/ß1Ck÷/UÿVÿ£_vzNa!5}kŒ«ü"p*ßЇßšon†ÚÈÜ[ý¾ŸÙÕ+Îî—¶i@@@ª¨`àîЦÕëûl³\Ì9z]ìC“úŒ¶»)ŸkW®¹bÞüÓ<@¨JBg>Û·@ïeþŸ.oÔWèñ¶ê׌ªÊ.p¯Ÿœ8ihùzC ?sªU”M ²«k,AûO˜xŠ € € `! î{5sp Iön´ññRjªæÝùœ… €€¿6úT‹ÓŸQݰ†z0~†ZGtòWÓ´ãƒ@Î Cï|ihÉZ§:¶´éOw‡èRó;@@@¬.àsà¾éÕ ^‡í.$WØ>qî“ênu2ú `}ÇÓÝ¢fåíp×iïÚd€Uº^-ûy8×ÐÛkœzï+CÝÛÙôì½!jÓ” ½ZN6ƒB@@‚TÀÇßÛÞ«%ÏÏ)"KÔìUÛt`Ûr(z%~òrí9p@[VÍUR ìd=2¬sÉ3@¨,ãùG´ mŠžÿújß ‡þpU²Û+KûÂíîÏ6ôÏe…ºÿ…:z\úÇè=>”°ýÂrœ € € `5ß÷ÜýZo®Xw=Æ'ÏÖ½}b{ƒšê‰×™Ý££¢×g˜îY®D÷™“ôÀ kÝGü €@e:óõñî9š¼öå:ô¿fÐ> æ>…ÙϵÓHeô‚6‹vfúÛ’BýzF¡læBöY…èÑÁ!ŠnȪöb#¾#€ € €T/ßw³{ñ¾§qm–ˆÔ®ï9LII“¹7ªû}ƒ^^0Þ}œ<.Y;Š^ç €þøöÐ*ýeÝm<¸RwyYÃâþ¬z5ùó´å¥@Ú^CO¿U¨ß¼R¨È:ҿdžèÁCÔ¸A»—„œ† € € `QŸk¸Ÿm¼-¯èg¾l²U ÌP¾¨õ&—´-:}³ö›I|LqZ¶Fx @rì=öƒ¹!ês:”·[ƒc£.QýËq5§úSໆæ¯vê‡=†%Ø5n]u ÙýiL[ € € €-à[àž¯’ìË—oÖèÎ îQ†Ö®Y4Ú•J; ÅFŸ9xsq<@*,{ê°ÞË|I¼¯Ÿµ¾O×u¡P;ËTÖ‡ÖosêUNýxDºµ§Ý¬ÏnWx ‚v(¹@@@À⾕”‰h¯ÁE;¤&Oè©{žœ§M{Šhߣh“ÔT üó¦äÒø©ëµñ±Nzup-4«ÊxñŠWªù_ñc¢¶å?­XßÖÕ7Âw/læît™™™Š‰‰ñâlNA¬!jÖg{ÛsjÞB·µû¢ëv°FÇ«Q/ }ü­¡7ÍÒ1¡æío¿ÚnþvM!vV´W£if( € € €@À X%ïô9úŽì6Z™+NªMÿqnüFá®oáJš4Ã,ã^Ä— Û¥©«!l¸*B_`wîV-JFGOÐ3hïÜ81ð;]Ízx*ßÐGÍíŸ:Ý¡ÞÛß®Þq6¹þÁÃ@@@<>¯p/tdiëæýjÔ©³¢Ü¡»Yß=}¥¦üæMÉh«Qñ9Z³§½žœþ”uŽ*¹ŒƒÊ°ÊO|*WÖ@Àê9§iYÆ‹ú&ë#ý<æõmq·¹’š:íU9¯y' -_oháçNµl$ÝÙÇ®îí|«HW•ýæ^ € € €ÕKÀ*ygÅ÷ê5oÕf4VùVp‚~ÈwžÒÇ»çèÃÿÖ•MêÆ6ªnH¿ÞƒÆÎ/›gè/ -YãT\K›î¾Ö®Ž­XÍ~~5ÞE@@¨,«ä>—”©,8ÚEno²>Ô’ô¿+ªVk=ÒõU5¯Ó.¸Aªxô‡s=!û²¯ uµé¯¿Ñ%ÍÚ«x¸ € € €€E¼ ܳ·®ÕÚ½ÇU£¢ƒ ‹Öµ}âäÕM+z/®G°”À®ÜÍZ´íË?¬¡í×eúXªÿVïìG -2ËÆ¬0ë´÷îhÓ £BÔ¢A»Õç•þ#€ € €T­€WÙwÆ5p\JÅ{?]‡7Ɖ¢§¤@ º=™¥w2^з‡>Ñ 1£Õ'úN³N»W=U‚‹:Ž]Y†|æÔg[ õ‹·iƃ!ŠªOÐ~Q'…›#€ € €XV€DòSGÇ@k äžÔÊݯiÅ®WÕ£éÍzâªwT'¬¾µe¡ÞoÛgè­OÚnh`w›^y8D ê´[h é* € € €@ x¸wºg¶RóV‘ä+¬^KV·W„k@j"°þÀûJ6ë´»ê³?ÚuŽšÕi[MFøÃزËЫœú~¡AWÙ5öf»êÖ"hü™£‡ € € €Vð*pŒQgêÀXa>é# Ð;r¾5ë´OU^A®î¾ôêØðê€îouêÜ×éNÍ3ƒö}‡¥[{ÙõøP»Âk´W§9f, € € €_À«À½ÂÝÜ1O¶6åĩڳò1EW¸A@°’À‘“?êí/hóáO5°Í]Ý|(uÚ«` ÃКï ÍûÄ©céöÞv èjSX(A{ðs @@@ ¨`àîЦÕëûìSªq¼5j(õ3lw=R>×®\):Âó”?@ª·À©Â<³Fû”²ûuõl6Ø]§½vX½ê=è]a¡¡UßzsµÓÝ›;®±ëºÎ6ó‡í0=t@@@  T pß«™ƒ[hL²w:ññRjª*XÞ»{q €ÀÅp­¬^à=%oŸ¦–uãôÛnsÕ¤v›‹Û© ¸û©C+6šoíõkKÿ“hWïŽ6ÙlíA0ý @@@ |Ü7½:Áë°Ý5NWØ>qî“꣦  €•&qt£Y§ýr:4üÒ'×°g¥Ý‹†=ŽS†–¯7´ðs§š›{®{njûkõn>Dv[HUÝ>(ïs,ÏÐ;ë -YãTûh›þ04DZ³š=(? @@@ |[þ–»_ëÍë®ÇøäÙº·O¬¢boÐCS“ܯ52+ºGGE)®Ï0-ܳ\‰îW'éÖºø@ úœ,<¡e/êéuCT¿f”&%¼£k¢‡¶Wâg34û£BÝ;½Péû =}OˆžAØ^‰ä4 € € €€W¾îaRñ¾§qm–ܨv}ÏaJJšÌ½QÝÐèôò‚ñîãäqÉÚQô:ß@¬-àªÓ¾vÿRM^{‹öOÓcWÎ×­±¿Q­Ðâ¿!¬=¾@ìý#†þoy¡îÿG¡™ÑN»?Dÿ{gˆb›³ª=ç‹>!€ € €Ÿ€%eÎÕòŠ~æf™”­:P`†òE­7¹¤mÑ›µß bÈbÎÈ« €€EÒlТôgät觨CäUé¹5»¹û YŸý3§Vo6”ØÙ¦ÿûUˆš4 d·ælÒk@@@ê,à[àž¯’ìË—oÖèÎ n£ÐÚ5‹¬V*í€}&¹8ž €€Eåí1ë´?¯mG¾ÒÍmVÏæ·š¥c|ûe)‹Ti··ï7ôÖ§N}µÍÐ Ýlú×Ã!ЬKÐ^¥“ÀÍ@@@(‡€o)ID{ á¹Kò„žºçÉyڴסˆö=ä©âžªž§l÷)YZ4ó•’.™Y=@‹ œ,8¡w¶¿ ¿~5TÂ[šuÚ—©wôm„í•4›wúÓ¼BM|­P-I³Ç…èþ„í•ÄM³ € € €øMÀfÖà5|i-{ÃL5ì>¦äÒø©ëµñ±Nzup-4«ÊxñŠWªù_ñc¢¶å?­XßÖÕ7Âw/l6›233ãÅÙœ‚œ]Ài8Í:íÉz'ãÅÖ捻KQãZ-Ï~2¯VXàëíNÍ_mhg–¡!½ìº¹‡Má5XÑ^aX@@@°¼€UòNŸ£ïÈn£•¹â¤Úô瞬Fá®oáJš4Ã,ã^Ä— Û¥©«!l·üG› €@°¤™eco{Æ®M¿ìô¬Ú5¸2X†^¥ãto>û½¡7V9uô„t[o»&·«F(A{•N7C@@@À>¯p/¹·#K[7ïW£NåÝÍúîé+5å7hJF[ŠÏÑš=íõäô§4¨sTÉeT®€U~âS¹ ´Ž¾ÌÛ­%éSFÎFÝÒv¬®j6ˆÒ1¾@^àšB§¡Õßy‚vש·_mW?sCÔ‚ö Ðñ6 € € €@ X%ï¬xà^«­ë×éÛ]RïÁý]´f¾ k“Þû"Km»tUç˜È ü\Ü![åxq•¸;”È+8¦v¼¬O÷.е-îÖ€Ö÷©fhí²§pìüC+6z6C­cþ úŽk캦“M®ÿ¿Í@@@Î.`•¼Óç’2®ag­§;{WŠÛ QkrÌÀ=Â’·+EIIžr3ñ£¦kñsc[ôžç þDWö/ö-Ö²ŒÕ¾AMì±P ã¡kÕªŽS†Þß`hágN53ý«íêÑÞ·½Ë« ƒA@@@  ø¸g¯}AMzzuÇ¡s²¤Î§v³ÖiÍáוÀb÷s:ñ PÕ»r·hîÖ'bÓ}—?onŒÚµª»PíïwÜaè/ -YãTls›~{ˆ.a5{µŸxˆ € € ”>.­ËÒëË„íI“µ"u©º”YÁÑén­Y>CI%¬s4êÅÕ%Ï8@¸x…Î-Ïœ¡l¼_×´¸S¿í6°ÝÏÓq䘡WWêÓ •¶ÏÐS÷„è/æa»Ÿ¡i@@@ð­†{îZ ®×SÉ®ŒZ ¼™·«h¿Ô3‡V®'»·Ó¤T×[•i<­˜3Ïâ? X¥¦‘Ÿ‡Ms à…À¾ãéz}ËT#¤–FÄ=©ÆµZzq§x+uÔТÏúðC=/µé®>vµŠbE»·~œ‡ € € €ÀÙ¬’wúVR&¬¾Úzú蟟;lw«‡fM×$wù™ÍÚŸ+Å”Y 6<^C𿀫Vû§{çë]³V{ÿV¿07E}€:ýȼç¡f}öÕߺ®³M/ QÓH‚v?Ó € € €/à[à®|(ZAÉѹjÕ¯WòVXÉ €U%•·KsÌUí…Fí:GÍêÿØ´ªzP}ï³}¿¡·>uj]š¡ºÙôòC!jAÐ^}gœ‘!€ € € pnß÷ü|ýXÔæ+¯¯Ð¨nç))cž·ñƒ%%=È/9â@ *Öì[¢ÅéϪOô]º©íƒ²ÛBªâ¶Õþ[všoí›wºå*›~}cˆ"j´Wû‰g€ € € €œGÀ·À=¢­š»¡&›EÜS§ Õš­—'Ý¥ØÈŸTr/ÈÖê9“uí8wµw)¾Ÿ:PNæ<ÓÁ[ €€ÿ²û5gë:–Xc¯ø·ZÖ½ÔqK3œzs•¡Y†níiׄ!vÕªIÐÄ †Ž € € €@‰€o›¦š—;ÒªV»¡% ¹âGè¦ÄÎjV_ÚŸ±IS¦Í9íý©k豄¨Ó^ãIåXeÊ=­"€Àúïë­žRB³$%]2^!v zUäSa†¾üÁЫœÊ>.ÝÞÛ®Ÿwµ©FA{E\¹@@@o¬’wú¸» v¬|AmúóÊdÔìõšyo7¯Î夊 XåXñ‘Ò”È9yPoüðg8±C÷tü‹ÚÔë\ömŽË)Pè4ôéfÃ\ÑîTSºãj»úÅÛBÐ^NJNGû|:Â@IDAT@@@ BVÉ;íeL¿±2r¶iÁÔñŠ?GC‰£¦jÕ¶Âösøð2 à/M?ÖÓ_ QýQúý• Û+›_`远zàÅB-0ë´ëk×ÌCô³®vÂö ¸r) € € €Õ] B+ÜOÃ)p(ëÀ:”'5mR[9N¨^“ŠŒð­Lüimó¤ÜVù‰O¹Æ p†Àñü#šo–Ù™ûFÄ=©v ®<ã^ðNÀqÊ Ú¿6´ð3§¢Ìòhwõ±ëªúÙ´w7æ,@@@8¯€UòNÿ¥á¡áŠŠŽ‘«B»Ã‘«Z-ÌÝQý×úy±yVתvW ™¸È^šxå"Õ ­¬÷q‡¡w×z{S—4µé±!!ê܆²1Båb@@@‚P Ü‘xVúZ}²ú:Ù\·Ü7HÑeZpìX­ÉãÒ”äÔÊø¤Qzdì#º·_\Ék €TL ¯à˜–nŸ&Wà~OÜSêØðêŠ5¤W=nhÉZ§ÞýÒpìOQûh‚ö ý80l@@@*,PŽ’2Yš÷ø>%¥è¦‰Z“³R æBv×#wÓ<Õ‹îyr–?GÌX¯×G³iêYh*å%«üŠE¥ žF¨æ[¯ÑÜïŸPLDg »ôOªV¯šØÿÃ;˜chñçNwù˜„6Ýi–މiBÐîiZD@@@À?VÉ;ˬO?ßÀ³õê=M4rNÙs•y²WÓ~¶Ç'&I)É*^ë>gLw%]Ÿ§ÛcÃË\Ç! €€·§ ó´,ãŸúòÇwuW‡'Ô%ª¿·—r^‘ÀÞÞúìŸ|k¨ïå6ýsLˆšE´óA@@@ÿxµ\öê—O ÛÇOÕò5óÕ©hu»cëšT¦?ÓWejãÊ%ÚhähÅô%ï<ùÊç%Ç €x/~ôkMYw›öŸØ®Ç{,&l÷žÎ}f憞YT¨‡g*1EÏ#Ôoìß5õ•9š`.uOò޶Nî§8/îZÒ  €@ ä;O郳´jÏ| mÿ{]Ùô¦ Ö(ÿпßmhþ§NmÚaèæ6Í¢zµYÑ^~I®@@@@o.};6+yVQSI3ô»Ÿ„ífõv­ÿ´´Ö̃ƒ{üä¾QºmÂ(Mîj$CGóÌoE+ãr"O@ÊìÌݬ׷<®†áÑæªöEª_³I™w9<Ÿ@j†So®6”a®lÜÓ®ßÞjWíšíç3ã=@@@¨¸À…wó¹E÷IØ[‘?½gÁ}Q’·Rïög¦éMâŠWÄ'kmZ¶ºÑÊO[å9 ´…έØõ}´k¶njó ú¶´åø—?8õÆ*§™qÝÖÛ®?ÝmW0‚öò:r> € € €ø&àUà^¡ŸÌ?ã.ŽT¼^I½Ôæ,{¢:¶—–¤9£^@(Ø{,M¯oýƒÂCëjB÷ùjT«EÉ{œ]Àé4ôéfÃ\ÑîÔ©ièÕvõïbShAûÙÅx@@@*KÀ«À½x…»jš;Íýä±gí'%¯$ Œ?kµ˜ÐVÓÍsƹÏk\Û«[–´É  NÃiÖiCïe¾¤Ÿµ¾O×·)›Àø|s_Phheª¡·Ìí®¿žîìcWŸN6Ùí¸Ï÷@@@@ ò¼H¿ÃJBôäùŸ+{tç2eerµú­’õíê×£íY{º6ù•¢×“×¢d½üYÏåE@ ØœØá^Õî÷o»ÍU“Úm‚ \ã=™oè¿ -üÜ©Æõ¤Ø•p©½\mp2 € € € PN(Â;*iTÑ­SÆè÷¯nùûîGÖêÙ™\ôD#tMû3k³çn˜©SR‹Nj«úµŠÏç; ܆aè³½ õ܆aŠ‹ì¥Gºþ‡°ý<‰ãÏjö{§ê‹ï ýf°]¿/”°ýsê“o ]{™M/ŽQó†íåBäd@@@¸(^î®ÞE' Óë‡é¥ì,9Š ¹GDEɳ®½´ÿaº+))BM;uÖMIwjP«¬Ku8B`ؘµÂ Ûÿ¤îMêþËžWXHÍ`d8ï˜wðÔh_cÖgÐÕ¦™¿17E%h?/o"€ € € €@@ x]R& zMg.(`•_±¸à@8‹ ;•­ùiOiWîÝ÷”bt³øˆüßýöš¿Ú©ÔLC7÷°ipO»ê×!h÷¿4-"€ € € `]«äåZánÝé ç €@Õ l9ü™^ßòujÔG{,TÍÚU߉¾ã&3`Ó ÚÓ÷ºÕ ÙlWp‚öž2º† € € € p¿o#€åÈ+ÈÕ´¿ê‡#_ê:NQ\Ã^åm¢ZŸ¿.Í©7W9uà¨t{oûÿ³w'àQÕ÷ÞÀ3CXE­¨àŽ(¸rµ­Z±vµo«¶V»ØEm¯u¹‹ÖõZ»XmßV»x-­uÜ7ºÑV÷­Å*Z ˆ.¸  D!dÎ;’Ä2If’ÏA{‘/á @€ @€í¸·KQ´&°ªfEüqþ/cÖÓã˜Ï±›Mh­h¯:^S“ÄŒ§Öí}sâ ÚÚ-é´ ½W]&K€ @€z‰€À½—,´i ÐyóÞšSÊÏ÷ Ú1Î{ *Û¤ó:+‘–WW%ñ×&q˃Ù–»ÉÿëMÇ~;§"ÿ'^ @€ @€ž* pï©+k^tº@Uͪ˜¾ðŠxèÕ[ã¨ÏŠ}¶øD§÷Yì¬X•ÄŸÿ‘ÄmgcÛá©8}b:öÜ>]ìÃ6> @€ @€@AîaÔ½M`áò§crùÙ±Yÿmâì}o‹!ý6ëmMæ[±"‰ifcÚcIì¶M*÷A¨™½µ»Ù› Ù!@€ @€z¼€À½Ç/±  PHšlUÜùâïbÆË“ãSÛø|!›/¹¶–V¬¹›}ú¬$Æï”ŠK¾’‰í¶´—ÜB0 @€ P{A5B€@oxå¹1ùÙ³kŸÑþ}oŽaýßצÝâ__–Ä͹ç³ÏÌ} êcRñ‹2±Õ¦‚ö±$@€ @€z€À½×,µ‰ °¡Ù¤&îyyjüeá¯ãc#OˆC¶þR¯ýðÏ'qÓÙx¸<‰C÷LÅßÊÄðízm©G€ @€ô,{ÏZO³!@ À¯¯˜Ÿ»«ýÜH§Òñ?{_Ãn[àJ£¹y‹’¸áþl<9?‰O+OÉÄ&ƒí¥±zFI€ @€t•€À½«¤õC€@I $I.º9~?ÿ²˜»£ýc#¿Qº—Ô$ 0ا® ÚóûÄýÓqúÄt ê/h/­& @€ @€( pï‹jJtL`ÉÊWbJù¹QY³"Nßëšxß ;Ö` ÖþÇsÙÚ;Ú_[ñÙ¤ãÜ£ÓÑ¿¯ ½—Ò  @€ @€.¸w!¶®(~G_û}Ü:ï’8`«#ã°Q'G&Ý{¾MÖÞÕÿìš;ÚWTFu@:Ý#e}íÅå! @€ P ½'I*mc @ hÞZõz\7ç‚XVùZ|{I±Íà1E;ÖB¬¦&‰™O­ù0Ôt:âs¹ ý ÝS¹_6Ú m­= @€ @ g Ü{öúšmøç‹æ~/ÆoqX|c÷Ë¢,Ý· µJ¿H6›ÄÏ$ñ»»²±ñ ˆãMÇþ»¤"•´—þêš @€ Ð÷îP×'E!P±zi.h¿0½û\œ8ö±ýÆ{ŸºbÌÉÆ•wf£_îOÿ8,ãwÊÝÚîE€ @€ Ð!{‡øT&@ Tž^r_L-??Ænvpœµï-Ñ73 T§Ò®qÿó…5Aûꪈ/”ŽƒÇº£½]€  @€ @€Ö! p_ŽSô<UËãæç~Ï¿ýx|eÌűËÐýzÞ$[˜Ñ³/%ñÛ¿ÕÄÒwÖ<£ý£{¥"íí-H9D€ @€Øpû†Û©I€@‰ <³ä˜:çcçMÆÇYão‹}6*±´¸s^Iâš»³ñââ$Žú`:ŸŠ>Ïho¿¤ @€ @€õ Ü×o¤%.°ªzEü~þ¥ñÄâ»â˜].ˆÝ7=¨Äg´þáÏ=‰ëïÍÆìIüûûÓqÁ1éè[&h_¿œ @€ @€ ¸o¸š”€ÀsËþSæœ[o4:Î{ *Û¸F½áC|eI7Ü—Gæ$qø~©8}b&ô´o¸¨š @€ @€¶ ÜÛn¥$%$°º¦2¦/ø¿xäµ;âèΉ½6ÿh ¾ýC}ã­$nz 3ŸJâû¤âªS3±ÑA{û%Õ @€ @€l¸€À}ÃíÔ$@ H,Ÿ×>{Nl1p»Úgµé»i‘Ž´ãÃZZ‘Ä­eã/'qȸT\ùíLl²‘ ½ã²Z @€ @€´_@àÞN³ÊòëbÀ®Çæj³–O޽·»¸äÔÄó7‹­T]±âÍØú#çÄyGŽn¥„ô$P­Š¿½øÛ¸÷å©qøö§Å·:²¥b=âXÅŠ$n{$¿4‰욊+¾•‰á Ú{Äâš @€ P²÷v.Ýßoþm]ŠvÖ¬+¾rqüeÒ”˜¹žÚv;=Î[O§ X+ðrEy\[~Näïfÿξ·ÄÐþ[®=Ùƒ¶V¬Jâ%qËƒÙØk‡TüâÄLl5LÐÞƒ–ØT @€ @€¸·uñª+â©»®ŠƒÎ__T¾î+^~¦!l7n\Ë…gÏŽýÊZ>ç(M²IMÜýÒ5qç‹WÆ'Fž¶ùb“ó=egUUÓg%q}îQGoŠŸ|5#7´÷”õ5 @€ @ gÜ׹ޕ1ã×?Ž˜“¦L[gɶž¬XüF]щ1é;b¿ö>’¦­)G ¼öî 19wW{Ÿtß8cŸc³[÷¸YWU'qדILž™m‡§âûÇeb§­í=n¡Mˆ @€è÷u.cU<}ùù1iö: µëä’çf­)?nŸØFØÞ.;… Ô d“lÜÿÊñ§¿Œoó•øÈ¶_‹t*]ºG¼×d“¸÷é$®¹;Ãrß+Î>*»´÷ˆÅ5  @€ @ Ç Ü×¹´e±×™—ÅÅoFô~ѯßÛñÀågÆ” à+cÎãó×ô¸Ý6±ù:ûv’–Þ\ùrL)?7Vg+ã?÷š[Ú¾¥b%{,I’x¨<‰«îÊÆ ~§|:ûìØ³~™P²‹cà @€ @€õÜ× Ô?üÂ)q`C™êè7½#{U,y½.­üFÜqõ÷bÚ³â•åËs= ‰ö?$ŽûÒ1qàèá =Ú @`­ÀïÞ·?ÿ“8hÄ1µÏkϤ{Ö·°Yó²qåÙÈÝÜ_>$î&h_»ú¶ @€ @€Å/гҪN÷^Ù±*Äõ‚Ÿrf5¥is3gN‹I/œ“Ï;<¦G-²É @€ @€½B@àÞ•Ë\µ"*êú—{Ïßë~ÜigÅÎÃVÆÌó/™uç¦?1ˆ»ãÉó©;â@ï˜õúô¸é¹Ä~[NŒ“Æþ*÷©e=ãÙ—’¸:÷ŒöEK“øÜéøÄÞ©Èdí=fM„ @€èu÷.\òŠçîúÜgO¼8ž|FŒ®»ý¼ó.Œ?ÿïøð©“jG4ûüÇ-_ªŠ#GZ¢.\"]‘@þnöëç|7^_1¿6hßnã=ŠhtÊó¯&1õÞlä÷#?˜ŽOÿ[:úö´wLUm @€ @€@÷ Hs»p ùF,˜÷ÙX¹¢*¶Øut m¢?89åWq󿉣&­yÎûÎËîþèŒ+¯¼2† Öæž|òÉѧO“Aµ¹®‚ )ðÔ›3ãº9ÄÃãÇ\}3ý Ù|·µõÒâ$®»/³æ%qÄþé8ã3éèßWÐÞm ¢c @€ @ Û~õ«_EUUU·õßYKW;K¶¥vû‘; méLݱ>ñ±“¿1é¤Úý×ß\±Ž²ë?õÜsÏÅàÁm|6›]£JèDw«Þ®}|Ì‚å³ã«c~; ߉½u]Ó¯-Kâ†û³ñÀ3I¶o*®:5ƒú Ú»nôD€ @€›À³Ï>«W¯.¶aux<÷¶§ê¨®Î—ï“»“¼åzeeýZ>±Gô£ÅÈ‘#7 ¦*º^àé%÷å!sAŒúþ8kß[£ŸA]?ˆ÷¸dy7=˜»žHâÐ=Sqå·3±ñ A{™5G€ @€” À/ùËvú7¿ùM»ÊwWáVbßîNOî·"®>bH_û÷³bAòÃh) _ðÈà [l6°aÛž*°²ú˜öÂÏâ©7ï‰/ìòÝØmÓK~ªo¿›ÄmgãOâ ÝRñ›“31l° ½äÖ @€ @€ë¸¯hƒNWVÄ¢×—Fþ DC¶Cßóøé‹âÆûO3Þ´ùe÷ÇwŽ_ó¡©ùùàŽMÏÛ#ÐÃæ,{4¦–Ÿ#‡ŒsÆßˆ”ô ß­LbÚ£kÂöÛ)—Ÿ”‰-† ÚKzQ ž @€ Ðt;Ê*ÚF§&MŒ£FŨÜ×ož\VWkpxÜ -œyÐæqÉ-ÆâŠÊÜcf*cáã·ÄÊÚà󥎛Ÿé÷! `6z”Àêš•qÛ¼ÇÕÏœŸÙñŒøÚnÿ¯¤ÃöÊÕIÜúP6¾rYM<ÿj—~=g|VØÞ£.Z“!@€ @€´A@¢Û¤vé7¢¡Jÿ²†ÍØáÈïÇe'Å©u©ú™Gíg®=Ýhë„xäç_ˆ÷Üߨ„M¥*ðÂÛOÄäòsbó#ãìñ·Æà¾›–êTbuuûgSïÉÆö[¦ââ/gjßKvBN€ @€ Ð!ûó nµfY¿µÏ^oú¨Ãã”;–ÆÎ?¿0>qê¥-ÖŸpÚUqÕE_‰‘Òö},]ªìêøëÂIqÿ+7Ægw<3þmËO•ìdjj’˜1;‰kgfc‹M"Îÿ|&vÝÆ£cJvA œ @€ P T’{¨-Í´G rY”?77¿µ:ªªÞÕ14v»Gì0¼0I{*•Š ÄÈ‘-}4k{ª,Ž ¼TñL\ûì9±I¿-âØÑß­}ïx«]ßB6›ÄÏ$qõŒllœû½Ú—IÇžÛ{2Wׯ„  @€ @€Þ&P*y§;Ü»ëÊì?4FÝ/FwWÿú%Ð5Ùê¸û¥«ã®Ü×a£þ#>´õ1]Ðkçtñèœlüî®lôÉD|í#éøà®‚öΑÖ* @€ @ tvFN ¨^}w^L~öÜè›gìsCl6`ë¢okƒ{â…5AûÊÕÇ”Ž cS‘ÿª @€ @€æ÷æ"ö è@6ÉÆ}¯\^ðñ‘m¿‡ns|IÔO/Ì=:æîšX¼<âó¦ã£{¥"“´wèâP™ @€ ÐÃî=|M@W ,^ñbL.?'²IMü×ÞSb‹Ûue÷ékî+IL½7ó^Mâè¦ã°ñ©ÜcdíÁÕ @€ @ ‡ Ü{ø›®ÈöòC¯ÞÓ^øY<âØøø¨#Ê=켄^ ßX´ÏžŸÄ¿¿?g•Ž~e‚öZBC%@€ @€t»€À½Û—À”¶ÀÒÊWcjùùñnÕ²8uÏ«bÄF;—Ô„-Iâúû³ñHyŸþ·Tœvx&ö´—Ô", @€ @ HîE²†A {íqë¼Åûß÷™øôvßÎ=㼬d¦±øí$nÌí3ŸJâã{§âw§fbðA{É,  @€ @€ŠP@à^„‹bHŠ]`ùª7㺹Ä›+_ŒoŽû¿5dl±¹a|o½“ÄÍfã/'1al*~ûíL ÝHÐÞdƒ @€ @`ƒîL§"Þ)ðÄâ»â†¹ÆÞÃ?_óÿ¢,Ó¯$ *V&qûÃÙ˜öhŠ+¾•‰á ÚKbñ ’ @€ P"÷Y(Ã$ÐÝïV½7Îý~¼Xñ¯øún?7Ù·»‡Ô¦þW®Jâ÷%qKî®ö½¶OÅ/NÈÄV› ÚÛ„§ @€ @€@»îíâR˜@ïxêÍ™q}î®ö݆gí{kôë3°è!VW%1}VîQïËÆÎ#Rñãã31j A{Ñ/œ @€ @€JX@à^‹gè:[`euEÜñüOã_Kî/Žþ~ì:ìƒÝe‡Û¯®Iâ®'’˜|O6¶Ù,ß=6»äw/ @€ @€- pïlaí(Qò¥ÄÔ9çÅöïg¿-– )ê™Ôd“¸ïé$®™‘ÍrCýÎg31v” ½¨Íà @€ @€=L@àÞÃÔttT`UÍŠøÃ ¿ˆÇߘŸÛùüØcø!m²Së'I—'qÕÝÙè_ñÍO¤c¿]ÒÚ§Æ  @€ @€´$ poIÅ1½Tàù·)åçÆ–ƒvÌÝÕ~{lÔwhQKÌš—ßݕꚈ/œŽƒv´õ‚ @€ @ ‡ Ü{ø›¶TÕ¬Šé ÿ/zõ¶8rÇ3cß-kKµn+óôÂ$®¼³&Þ~7☃Òñá=R‘N{|L·-ˆŽ  @€ @€jî.½\àÅåÿŠkËÏŽMûˆ³ö½56î7¼hEÊ_Î=£=÷蘗—$qôéøä>©ÈdíE»`F€ @€èe÷^¶à¦K ^ &[{ñw1óåÉñéí¾Žø\ý©¢{áµ$¦Þ“½”Ä‘HÇwMGß>‚ö¢[("@€ @€ôr{/¿L¿w ,z繘\~N è38¾³ïM1¬ÿVE ñò›I\wo6þ>/‰#öKÇÿ|&ýû Ú‹r± Š @€ @ î.½H ›ÔäîhŸ]8)>6ò„8dë/E*U|öëo%qÃ}Ù¸ï_I|j|*®>5ƒúß8{Ñ¥cª @€ @€m¸·I=Aà rwµŸ[;•ÿÞûºØ|àÈ¢›ÖÒŠ$nz w>‘Ä¡{¦âÊS2±É A{Ñ-” @€ @€´( po‘ÅA=G I’x`ÑMñ‡ù?¯½£ý£#¿éT¦¨&¸|E·>”?þ=‰wKůÿ#› ´Õ"  @€ @€Àzîë%R€@é ,­\SÊÏ‹•ÕqÚžWÇVíTT“y·2‰ß?š ÛÎÆøRñ«“2±åPA{Q-’Á @€ @€´Y@àÞf* ”–À£¯M‹[çý8Øê¨8lÔ·"“.+š T®NâOÿHâÆû³±ûÈTüôk™Øv¸ ½hÈ@ @€ @€6H@à¾Al*(^·W½×͹ òw·Ÿ<î×±íÝŠf°UÕIüõŸI\wo6¶Û"?üR&v|Ÿ ½hÈ@ @€ @€:$ pïŸÊŠKàŸoü-n|îû±ïæ‡Å×w¿4ÊÒ}‹b€5Ù$fÌNbòÌll¾qĹGgb̶‚ö¢Xƒ @€ @€(˜€À½`”"Ð}ï¬^7Ìý^¼òNy|c·Kc‡Möî¾Á4ê¹ö[ŸIâ껳1x@Ä釧c¯ÒJØ$@€ @€ Ðsî=g-ͤ— <¹xFÜ8÷»لøÎø[¢_f`QH<67WÝ•TîFö¯šŽŽ´Å @€ @€@§ Ü;VÃ:W`EÕò¸íùÇœeÄ—výQŒ¶çvØÆÖŸœŸßå‚öw+#¾ð¡tL›Ê…îÓF>Å @€ @€JX@à^‹gè½WàÙ¥ÆÔòÿ6Ù7Î[ è3¸Û1þõb×Ü]¯¿ñùƒÒñѽR‘I Ú»}a € @€ @ Ëî]F­#XU½"¦½pi<ñæqÌÎÿ›{ŒÌÁo´ƒ-Ì[”Ä”{²17÷~ôé8lßT”õ´wUu @€ @€¸—à¢rï˜÷Ö?bJùy±õF£ãœñ·Ç ²MºbáIL½7OÎOâ3ïOÇYG¥£_™ ½[Eç @€ @€Ý* pïV~X¿@UͪøÓ‚_Å#¯ÝGítvì³ùÇ×_©K¼º4‰ëîËÆÃåI|úßRqê§31¨¿ ½É5M€ @€ P"÷Y(Ãì –?•»«ýœØlÀ¶qö¾·Å~›uě˓¸ñþl̘ÄÇöNÅïNÉÄ‚ön[ @€ @€€À½è–Ä€DÔd«â¯ ÷¾r]¾ýiñÁ­Žì6–·ÞMâ–³1}VMÅoNÎİÁ‚ön[ @€ @€­€À½h—ÆÀz«À+ïÌÉÏž{FûÐ8sß›cXÿ÷u Å;+“¸ý‘lÜñHïŠË¿™‰-6´wËbè” @€ @ $î%±LÙ²IMÜýÒ5qç‹WÆ'G}3>4âØH¥º>à®\ÄïKâæÜ]í{m—ŠË¾‘‰­7ëúqô†57G @€ @€ž% pïYëi6%*ðúŠù¹»ÚωLªOüÏÞ×ÇðÛvùLVW%1ýñ$®Ï} êÎ[¥ââ/gbû-í]¾:$@€ @€(Y{É.÷$Iâ¾W®?-øUºÍñqè¶_t*Ý¥S«®Iâ®'“˜23#6MÅwÉÄ.[ Ú»ttF€ @€ Ð#î=bM¢Þ\ùrL)?/V׬ŒÓ÷º6Þ7h‡.F6›Ä½O'qm.hºQÄŸIǸíº6ìïÒ ëŒ @€ @€@' Ü;XóZxèÕÛâŽçø||bäI‘IwÝÿŠù»ê.OâšÙ(ËDœøñtì¿‹ ½¥urŒ @€ @€@{º.åkϨ”%ÐCÞZõzL-ÿßÈ¿{I±Íà1]:ÓYó²qÕÝÙX]qìÁé8h·T·|0k—NZg @€ @€ºH@àÞEк!ð×ÿ7?wQì¿åÄ8aìÏ£,Ý·ËPž^˜ÄUwÕÄÒw"Ž9(‡î‘ŠtÚsÚ»ltD€ @€ Ð+î½b™M²;*V/‰æ^¯¾û|œ8ö±ýÆ{vÙpæ¼¼æÑ1/.Nâs¦ãû¤¢OFÐÞe  # @€ @€^% pïUËm²]-ðÄâ;ãÆ¹?ˆ=‡_ÞõGÑ73 K†0ÿõ$¦Ü“½˜Ä‘HÇǤ£o™ ½KðuB€ @€ Ðkî½véM¼3VT-[ç]Ͻõ÷øÊ˜‹c—¡ûufw m¿²$‰ëîÍÆcÏ%qÄ~éøï#Ò1 Ÿ ½È @€ @€N¸w"®¦{§À¿–Ü×͹ F}œ5þ¶Ðg£N‡xã­$n¸?÷>Äaû¦âªS2±ÑA{§Ãë€ @€ @€@#{# ›:"PYýnÜñÂOã©7gÆ1»\»ozPGškSÝ¥IÜü`6þöϤöƒP¯üv&6ÙHÐÞ&<… @€ @€X@à^`PÍõNç–ý=&—Ÿ£†Œ³Ç߃Ê6îTˆŠIÜòP6þø÷$“Š+¾•‰á Ú;]ã @€ @€Ö# p_ÓÖ%°º¦2þ8ÿñ÷×ÿGïtNìµùG×U¼ÃçV¬JbÚ#IÜöp6öÙ1¿81[ ´wV @€ @€ p/¢&z§Àü·Ÿ¬½«}ËÛ×>«}HßM; bUUÊÝÍ~ãÙ³M*~òÕLŒÜ\ÐÞià&@€ @€ °÷ @S¥w Tg«bú‚+âE7Æ;üW¼ÿ}ÿÞi UÕIíóÙ§Þ›Q¹€ýûÇeb§­í®a @€ @€¸wOÕÞ'ðrEy\[~NlÜw³øÎ¾·ÄÐþ[v BM6‰™³“˜<3›oqöQ™Ø}¤ ½S°5J€ @€ @ @÷Aj¦g Ôd«ã®—®Š»_º&>µÝÄA#Žé” 'I<“Ä53²1¨_Ä·?•Ž}wJwJ_%@€ @€ @ °÷Âzj­ ¼öî ¹»ÚÏŽ¾éþqÆ>7Äf¶î”Y>67WßÜÍíqü‡ÓñÁ1‚öNÖ( @€ @€N¸w¬fK_ ›dãÞ—§Æô…WÄG·ýz²Í—#*|>{~6~wW6*VF|áCé˜06é´ÇÇ”þd @€ @€½M@àÞÛVÜ|Û$°xåK1¥üܨήŽÿÜkrl9hû6ÕkO¡g_JjïhuYŸ?0Û+™Œ ½=†Ê @€ @€(&{1­†±…Àƒ‹n‰i/\o}l|lÛoD&]ØÿMžu͇¡Î]”ÄQLÇaãÓÑ· ½(ß  @€ @€t@ °Ib¢*îXVùZLs~,_½$NÙã·±õàÑÒK‹“˜rO6þùBŸy:¾sd:ú÷´Yc @€ @€ºQ@àÞøº.Ç^ûCÜ:ïâøÀû>‡mwrôI—lp¯åsݽÙx¨<‰OOÅ)ŸÎÄ þ‚ö‚kˆ @€ @€@‘Ü‹d! £{òw³_?ç»ñúŠùñÍq—Ǩ!ã 6%Ë“¸áþl̘Ô>ŸýÊogbãA‚ö‚kˆ @€ @€@‘ Ü‹lA §ëžX|gÜ8÷û±÷æ‹ãÇ\}3ý ÒùÛï&qóƒÙ˜>+‰ƒÇ¦â7'gbØ`A{Ap5B€ @€ @ ˆîE¼8†Ö9ïV½7=÷ƒX°|v|uÌOb§¡ã ÒÑ»•IÜþp6îx4‰ýwIÅå'eb‹¡‚ö‚àj„ @€ @€@ ÜK`‘ ±pO¿yo\?÷»±Û°ã¬}oþ}u¸ñÊÕIüá±5wµï±]*.ýz&¶ÞLÐÞaX  @€ @€(1{‰-˜án˜ÀÊêwâöçÏ,y ŽÝå³éÖP£Z««“ÚÇÆÜp_6vÚ*?úr&¶ßRÐÞˆÈ& @€ @€^% pïUËÝ;';gÙ#1µüüØ~ã½âìñ·ÅÀ²!‚¨©IâÎ'“˜zO6Þ7,ç>»n#hïªÊ @€ @€z€€À½,¢)´,°ºfeüþ…ËbÖ‰Ïí|nì9üЖ ¶ñh6›Ä}ÿJâÚ™ÙØx`Ä‘Ž=·O·±¶b @€ @€ôt{O_á^:¿Þ~"&—Ÿ[ Ú©ö®öÁ}‡uHâáòl\}w6úd"Nøh:ö-hï¨Ê @€ @€z €À½.jožRUvuL_py<¸èÖøÌŽÿûmyx‡8~MоruıJLJvOE*åñ1BU™ @€ @€@¸÷Ð…íÓz©â™¸öÙsbhÿ-ã¬ñ·Ä&ý¶Ø`†§&¹;Úkbñò5Aû‡÷HE&-hß`P  @€ @€ô{/Xäž>ÅšluüíÅßÆÌ—§ÄáÛŒ8zƒ§<÷•$&çžÑþÂëI|þÀt|bŸTî12‚ö U‘ @€ @€@/¸÷¢Åî‰S}õÝyµwµ÷Ï Œ3÷¹160bƒ¦¹ð5A{þÎö#?˜Žs?—Ž~e‚ö ÂT‰ @€ @€@/¸÷Ò…/õig“lÌ|éÚøë‹¿‰<1&lýÅ z¶ú¢%IL½7ÍMbâþéøÏ#Ò1°Ÿ ½Ô¯ã'@€ @€ Ð÷îP×g‡¯x1&—ŸùÐý¿öž[ Ü®Ýí-~;‰ëïËÆ½O'ñÉ}Sñ»S21x  ½Ý* @€ @€ Ð po °QìI’Äý‹nŒ?ÎÿE|x›/ÇG¶ýZ¤S™v {Ù;IÜô@6þöÏ$ò„úÛogbèF‚öv!*L€ @€ @€@‹÷Y,6¥•¯ÆÔòóâݪ·âÔ=¯ŠíÜ®!V¬LâÖ‡²ñ‡Ç’8`L*®øV&†o,ho¢Â @€ @€¬S@à¾N'‹Aà‘WïˆÛŸÿI°ÕÑñÉQߌLº¬ÍÃZ¹*‰;Mâ¶\ؾώ©øÅ ™ØjSA{›$@€ @€ @ Í÷6S)ØÕo¯Z×Ϲ Þ¬|)¾5îŠ9d÷6auUüGîñ1÷gc×mRñãã31j A{›$@€ @€ @ Ý÷v“©Ð¿ñ׸é¹Äø->_Ûí§Q–éצn«k’Úç³O½7#‡§â»Çfb—‚ö6á)D€ @€ @€@‡îâS¹Ðï¬^V´¿XñL|}·ŸÅŽ›ìÓ¦.j²IÜóT“gfc³!ßùl&ÆŽ´· O! @€ @€ " p/£F !ðÔ›3ãú¹ÆØM'ÄYûÞýú \o³I’ăÏ&qÍŒlôÏ=Úý?KÇøÒë­§ @€ @€ - p/´¨öÚ-°²º"nwIÌYöH|qôb×ahSÍÍÖíÕ5_>$Œ´· N! @€ @€:E@àÞ)¬m«@ùÒ‡cêœóc§MöÍÝÕ~k ,Ë=f=¯Ùó³qÕÝÙxû݈cNÇ„±©H§=>f=lN @€ @€ ÐÉ÷NÖ|Ë«jVÄ´çO,¾3>¿Ëù1n³CZ.Øèè³/%qmîÑ1//I☃Òñ±½R‘ÉÚÙ$@€ @€ @ î݈ß[»ž÷Ö¬˜R~^l3x×8{üí±Qß¡ë¤xáµ\Оû0Ô9/'qÔéøîøtôí#h_'š“ @€ @€t¹€À½ËÉ{o‡U5«â ~¾6-ŽÜñÌØw‹ÃÖ‰ñò›IL¹'³žOâ3ïOÇw>›Žþ}íëDs’ @€ @€n¸w}ïêxáò§crù9±iÿµÏj߸ßðV^_–Äu÷eãÁg“øôøT\uJ&6 hoÌ  @€ @€ŠB@à^ËÐsQ“­Š¿,œ÷½r}LÜþôøÀVŸmu²K+’¸áþlÜýdRû|öß~;› ´· æ @€ @€E% p/ªåèYƒYôÎܸ6wWû >Ç™ûÞÃúoÕâ—¯Hâæ³ñç$ñ¡ÝSñëÿÈÄfCí-b9H€ @€ @€@Ñ Ü‹viJw`Ù¤&î~隸óÅ+ã“£¾ñ…H¥Þ ¿[™ÄígãŽG“ØoçTüê¤Ll9ô½åJWÂÈ  @€ @€èM÷Þ´Ú]0×7V,È=«ýÜÚžþ{ïëbó#ßÓkåê$þðØš»ÚÇJÅO¿–‰m‡ Úßå @€ @€%% p/©å*ÞÁ&I÷¾r]üyÁåqè6_C·=>Ò©t“WU'1}Öšç´ï°e*~ø¥Lìø>A{$; @€ @€”¬€À½d—®x¾då+1eÎyQYýNœ¶çÕ±ÕF;5\MMwå>uê½ÙÚGÆœ{t&Æl+ho‚d‡ @€ @€’¸—üvïZtkÜñÂÏrÏiÿ|||䉑I—5 ¨ö®÷§“˜<3ƒDœvx:öÞ¡é]ï …m @€ @€ @ Äî%¾€Ý5ü·W½×͹ –V.Š“÷˜ÛÓd(”gãšÙ܇¥F|ã£éØ´ ½  @€ @€zœ€À½Ç-içOè¯ÿ)n~îG±ÿ–ãë»_eé¾ þóùl\ Úß­Œ8îàt|h÷T.t÷ø˜  @€ @€ôX{]ÚÂO¬bõÒ¸qî÷â•wæÄ c;l¼WC'ÿz1‰k×ߊøÂ‡Òqèž©Üãeí @6 @€ @€èñ÷¿Ä…™à“‹ï® Û÷þ‘øâøD¿ÌÀÚ†ç-JâÚÜ3Ú罚ÄçLÇ'öIEYA{aÔµB€ @€ @€@) ÜKiµºa¬+ª–Ç-ó~Ͻõ÷øÒ®?ŠÑÃö¯ÅÂ7Ö|êS “8òé8çètô+´wÃé’ @€ @€"¸ÉBã0žYò@í£Žöþ8{üí1 ÏFñêÒ$¦Ü“Çæ&1q¿Tœ>1ƒú Ú‹qýŒ‰ @€ @€®¸w­wIô¶ªzEÜþüOâ©%÷Äçw>?Ænvp,~;‰ßÜW÷>Ô>6æÊS21d  ½$Ô  @€ @€èt—ô¢“uTÆu'î©T*Žøõãë(×5§ž{ëqÑ?>+ª—çîj¿-¶ð¡˜ô—š8éòšÜ‡ FüæäL|ý£Âö®Y ½ @€ @€ PJîpïîÕZöPüvÒì5£XÕ}ƒY]S˜ÿóøÇ늣v:;vüѸå¾lüþ±š8`L*.ÿf&¶ØÄíÝ·Bz&@€ @€ @ ØîݸB‹žŠ«Î<=fvãò]/X>;&?{nl>pdœ>îÖ˜ñÏaqÑÃ5±Ï©¸ì™Øz3A{7/‘î  @€ @€({/RåÂqáoŒg™Óênlïâ!4tW­Šé þ/XtS|zä±øåOÅ)WdcôÖI\üåLl¿¥ ½Ë @€ @€Ö# p_P¡OW-y:.š4©ÐͶ»½—ß™“»«ýìÔgxŒïóǸâ¦b›áI|÷˜Lì²µ ½Ý * @€ @€ Ðëî]| ”mºW\vñeýs÷ë• §Ç™Më²Qd“š¸óÅ+ã®'Ǩš‹ãOü[,qÆgÒ1n;Ÿ¡Ûe ¡# @€ @€zœ€À½‹—´ÿÈã”3l赺¼_—;?wWû9±äµýbéü¿ÅʾeñÍO¦ãßv´7,ˆ  @€ @€l €À}á UmeÕªB5Õj;Ù$÷¼<%nžõD¬xégÑ/µi|åt0&©”ÇÇ´ ç @€ @€Ú! poV)}såËñó&ÇÜg&FßìQñ¥ ýâq©H§í¥¸žÆL€ @€ @€@ñ Ü‹wm:<²?Ï}8fLIå·âËŠO쓉>A{‡a5@€ @€ @€î- ô„C©t:OìñòM±Ûß¿oý®*®Ë=>&ÉM.É¿×5Ú?âßÿ=2ee‘»ý=òõóïõ_÷o¿§l®ÝÆço¿§l³~jËæê·Ôg}ݤº:Rýû7é£þ\m½ºúûm¼Ý¤l³þkÏåë{ @€ @€fI’ÿuîµ®÷fçšÔiv®¥vš”oÞW+õ›Ôi¥Lm_uçš”oOëj»¾uõÑJýdõêH ¹gÞæ[©}¯}üm£ýÚsÍö‘›?^ÿUW¿ñ~C[Íêw{µ“õ½[à«_ýj¬ZÕùÛîje{W‹wUÙl|á©ÿŽ-ûæ–xôŽ‘ÊÿÁ–ûjxÏÏ¿j÷sÛù÷¤¢"jòóçê¾’V¶óçkÿν§úôÉÝE_ËÖž_WÝü¹ü˜êÊ4®Ûx»y;Q×Wm½ü˜õѼìºÎÕÖÏϵ-¯ÜÊ©Ûö‹ˆüàu¿¨hWÐ_ÿ˺úë6Þ^ß/ ò?04.ßx»v\9¯Tß¾­Ï¥•ñ7o§ñ~ãí&ýç×7÷ œÆço7ŸKí~£þ›Ÿ_gÝ\_©ü/‹ZðkW;-ùµåQ†´A ög§üŸùWþ½þ«Ñ~“¤…óµuj«·\¿þ|þ½«úKjjjÿ¼ïªþò\]9¿úþú¬ë?¿_ûÕh?©ªZó³qý¹ü{£óË÷t¯ìÊ•95ÓoæPoÒÊ{“ÿš—ilÚü\nÿ=®ÍË4«ßb_ÍʼgÝš·Ù|¿Yý&}4;׸í|3ùý&å×Óv}ý&uÖÕGݹ&åÛÓǺڮog]}¬§~í¸ÖU¦Ù¹çѬL½Q‹¶¹ ·Û^ù¿»ä_ëzovî=ózê7)ß¼l³¶ëÇѤN+ejËÖkR¾=}4n»þïùùúùõ«ÿj´ßd­[8_¿Î ×Pãë Yù†2Ú¯¯_ßw[ûk¨}–E«7.IDAT—o«³_ù›ûõ[û˅Ɔ¹í&k‘?×ì|ý~m¹uœÏ—k(“ŸS}ÙfíéoÍÿà VÍ|ê½ëý:ä•¿†3™5WX[ŸÏåòÄšúÿ_믷Ü{þFáÚW³÷ëÖ-úÿ Ü‹~‰6l€ùiþåÏcäÈ‘Ö@/­•¿ƒ>ÿ˃6…÷ùoíü…A“_äêç÷óArþ7úmê³Ñ/jh¼ßÊv“võUûƒA®N“1å÷sõuÞs®QùúÏ7Þ®uÉ}SÌÿ¥³v»Y?µe[ñ«ï»¥zMÎÕÕoÜoãí&e›õ_{®Qÿµ}å÷[{å¿Áç~\oxŸ/WÿË“üC­l·ÚN]ýÆõZ-[×v“²¹úMöÛ:†|¿-½Z2iéX¾nKÇ[8ÖðƒkóþZ(ÛÖ6k›ê`ýÇÕÖ6Û1ÿçÔJý6©•ú-öÕÒœ P¿Ící¤þ[šk›ÇT€ù·ÔKÇZSößÒ˜ÖtßÂ÷¿–Ö*,ÿ• WêÕ«ŸG³ýÚ9çµr>ß^ƒK}ÝVÊ7´ÕÊù†¶Öq¾¡Ì:Æ“/³ætÝ|×Ñ^Øš·WgTÛP!þSÿ}:ÿ^ÿ•o·~»î|[þÂ×P¦…úõíuè/„õcªk¿·õ—¿±¡ög©F¾mõÌû½Wþçü8ͯöºÉí7Œ½îzì³õÖk~.ªÛ¯/×ø½‰M}›Íß›ÕoR§Ù¹Æmç›Éï7)¿ž¶ëë7©³®>škR¯¾¯feêûXïØZ©ß¤üzä¿Gmh­ÔkÒG+ejû¬;פ|ý¸ëß[©_[§•sMæ³®>ÖS½}4«ßâ<š•i<¶ÆåkojÊÏÙ‹@²+V¬)™ÿ¸þ+$·ÝêÏuçÊ4Ú¯m£…ý†¶ò}´p¾¡­uœo(ÓJýÚ¾ë겿T.`®ý35ßv+ã+Tõíª½Úv è•ÿ~Ó£´àQþêÚm0h4þæí7߯÷k¸êÖ«¡­VÖ/_~Ïü ®ë8Ÿ?׸¿VÒ‹üh‹ê%p/ªå0˜îÈß­ŸÚh£î†þ»Q ñ/jƒøº_24óþ káÜzƒþº:µ 4ûE@ã>jÿPÉ6­ôQ{¾¾­fí´i ù?зÝؼþ/å¶þRÑøxKe[:–¯ÓÒñ¶k¥~›ÇÔJý6©õ[S;ê·8¦Ôoq\ôoq¬-µÙÊøÛ<¦Vêw´ÿ–ê·8¦.ì¿¥1å»oéx‹cm‡Km¶x¬®ÿÚ_èåÛ¯ÿªW£ýÚ15Úo(›?VßÎzÎçë4Ì­¾l£ú mæÚëQýåþRÙ0ï5ZþK€ôPt>dô"@ ÝÉÔ©í®ÓîÝ¡®OŠV ÿK—ü«T~kZ´F€ @€è…¹ƒæE€ @€ @€tT@àÞQAõ  @€ @€ @€@N@à^L—Aîæ½ @€ @€ @ 4<ý›×mðØsŸ}xb7B÷ @€ @€ ÐQw¸wTP} @€ @€ ¸»  @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸» @€ @€ @€@î@Ô @€ @€¸÷àk ¢¢¢ÏÎÔ(„@þûÄž{îYˆ¦´A€@/Øÿýã7Þè35E:"P]]»í¶[äß½ °> &ÄÂ… ×WÌyÔ ”BÞ)po×ÅZ•••%óƒc6›m×ì&@ ÷ ÔÔÔÄ3Ï<Óû&nÆl@yyyÉü´AT‰‚$IRûóEþÝ‹ë˜;wn¬^½z}Åœ'@€@­@)ä}¬Õú*?×üì’8é¢)k ›ž~R|í¸ÇVíQ¬,KNýAzñç¢ïkÆåÇŸ_š_ã¾5>–OþB´%s¯xù™†°}ܸq-÷>{vŒèWÖò9G  @€ @€ @ (îëX–ò›~“êÏ»0æÍ:/v¨;$Žüìaqâ}ÖœŸrlÜzƧã+m¸Í½bqýMŒIÜûµ%¥¯ƒw @€ @€(ZšÚêÒ,Žß_Ü·ÇÍ·U¶×U¼wœ=í´†Ú×NoÛ‡.ynÖš:ãö‰m„í ~6 @€ @€ Pê÷ÖVpYyüevÝÉqLJÖÜÚÞ¤ôÈ÷:ê 3ó/OIJ&g[Ú©Œ9Ï_sb»mbó–Š8F€ @€ @€%)à‘2­,[ÅüµÏZŸpìûcxK冎ŒÃrÇksù™ÄüŠcè:ïZ¯Š%¯×¥øƒßˆ;®þ^L»cV¼²|y®•!±Óþ‡Äq_:&Ýbo-À1 @€ @€({+ QÖè3K‡ôÔr©>›ÇÎs§¦åOWDUË¥Ö­\Ô–Íšrf5eí©üÖÌ™ÓbÒE§ÆÄ §ÅäóoÓ‡°6mÁ @€ @€t—€GÊ´"¿´áÃM#¶Øl`+¥šn”Ñ7=Q¿Wµ"˯yÕ?Šæ¸ÓΊ /<-&ԗɽO;bð½ŽØ$@€ @€ @€b¸·²Bƒw88N«KÅ÷;¢•Rí;\ñܽkn†ÏU›=ñâxvy“öÃ8?ŌdyÜ}Ù Î>ÿÃqËÂê†} @€ @€ PÜ)ÓÊúT¿öp\Z÷¸õÇŸz%bìèVJ®=¼¾GÊ óX0ï³±rEUl±ëèÚDprʯâæ=GMZÓñ΋#G®¿ßµ#hºµÇ{4=°ž½²ÆÏÑYOY§ è9ÕÕÕÑ·oßž3!3!@ Óòß/FŽ©TªÓúÐ0=C ÿ}bРVÍÙ3¦hH ¦¦&ÆŒãç‹yj†@) TU­/M}ïlJ!¿lù¾w ½÷HŸ7LþõŠ ÛÍ7V5ëÍ«û‘; m¨ñÞ>ñ±“¿1é¤ÚS¯¿Ùz¿ï­ÛôȤI“béÒ¥M®goÛm·tÚ?zX“Ó @€ @€tP`áÂ…‘$I›[2dHì°Ãm.ß]îmŸöø Q{Ç{°*ž‹éõ‚:ñ€Ø©ÿú«ŽÜa¹WŸèóžÆÖÔ-+ë·¾FÚtþßøF›Ê)D€ @€ @€…p;s+Žƒwú@WnÒñleýÎÚ÷eÏ<ÐðLö ‡ìƒ×žja«"®>¢,w|þëìXØB‰ü¡<Üp¦­ÖÚPÁ @€ @€t›€À½5úþ»ÆÄ†Ï0—ÜPÞ¬ä¢øÍY§6ûÜ„1 ÛQY‹rÿ$"ÿÏ"–µÔG\7Þ¿xmùú­e÷ÇwŽŸT¿ùàŽ Û6 @€ @€ @ ¸î­®OþyêW4œrü®qöu÷ǢŋcñÂÇã’#FÄ™3ëNO¸"Ž»öþö§&MŒ£FŨÜ×ož\VWhpx\C‚g´y\rË£±¸¢2÷˜™ÊXøø-q݃î˜ã¦Æ§F¶òÜ™†QÙ @€ @€ @€bHåLßö'Ó˨»lÕ1ã{Ÿ_Ÿ¬·Ôñ¸˜¶`VÞ(ê×_Œq'M©-|Ù¬¥qÊÞõ”º8~~Äæqjýsß[j®öØ ñÈÒ_Ç~õÕZ-ç @€ @€‹€;Ü×¹}âó¦Åô‹×Þ™Þ¤ø¸ãbÚ³÷4 ÛóçËú l(Öô#P‡Ç)w,é—Öp¾ùƄӮŠ+…íÍ]ì @€ @€ @ ØÜáÞÆª®X³Ÿ(7Þ]«Ñ765:ÆÞ*6ø¡/•Ë¢ü¹¹±ø­ÕQUõn¬Ž¡±ÓØ=b‡áýÛ8"Å @€ @€ @ ˜îÅ´ÆB€ @€ @€%+à‘2%»tN€ @€ @€Å$ p/¦Õ0 @€ @€(Y{É. @€ @€ @€@1 Ü‹i5Œ… @€ @€JV@à^²Kgà @€ @€ PL÷bZ c!@€ @€ @€’¸—ìÒ8 @€ @€“€À½˜VÃX @€ @€ @ dú”ìÈ œ *PYY}ú÷‰•Ë*¢lðÐÈmz @ EêÜ÷‹êº3}ú÷ß.ZdræÕ•Q±²*¢l@ öƒFsû @€@›ª£¢beDuuîï%}bðÐÁEõw?jóB–nÁÊòëbÀ®Çæ&p\ÌZ>9ö\ºs1r ,P½(þrå•qÉåçÇÌÙ¹¶'Lˆ˜9³¶“ã.¼*.8í+±ƒïF×R¨ˆGo¹*~yù•1¥öFý<ÆÅ ž§ŸttŒîGËzï4¨|*N0.&å»,–>yJ mVÄ.½Oàùß_üéùØlàÀV&¿"Þ\±CœsÙ1º+E&@  ,‹Wÿ2¾|.Ãh2ë qñ´Ëâ?[Á{*ɽšŒÏN¸ÿ{‡ÄAçç/ɹÀý{[a"°¹¿øžžû‹ï¥ë¬>!¦Íûs¾ƒŸn×Éä$/°,®þâ°8~ʺ'zÙ#oÄ)û _w!g è…•q݉âØÚ´=7ý‰WÄò;N ¿Óï…—‚)h&ðè%‡Äþg6ÍšÉíNŒGrYÆ~¾i¼—ƽI ²<ÎÞo׸(³`+¯qgM‹Gxxtw‚áî­,P8\]Oýåçua{˜‘I P0Êøý©MÃöÓ.»9î{侘zÙiz™wüq,jtÄ&½Oàù[¾Ó$lŸxÚe1ýî»sß/Ίq8NÝÿÜ(¯ltÀ&rÏßrÖÚ°=/² òñÄCõaû¸7®å¯ˆ-¢ ½\ :þráç…íãââ›ïŽÙÏΊ©×`3û¢‰1éñe ûݵá÷î’ï´~+cƯ7>0+&M™Ö¬w¸7±K ÷ ,ž{lþá¨ÿÅðU³–ÆWö^û»«͈#G|8ê¿‹\xßqÞîZí½Œ™÷nEñ½=FÄùuß0.œ>/ÎûøkI–=§¼O\Zwþ²Ü÷“S}?Y[нQ záïcŸQ~æ¨5˜»Ã}†;Ü{ãõ`Κ ,ÌýŒ1ªögŒ —ÍŠ§ìÝô´=Ô äž(Ëý<±æ5!¦/øs||äÚûØËo9=v=jÍ¿ßwÖô˜õÃwë£eÜáÞã.ݪx:÷,æ÷†í=n¢&D€@–½ðtÃ_|»bv“°=ßlŸ­‰ÿwóÚ;Ýgþó¥ô¦*%-PñR̪ÿíÜ Óâ¬Æa{~bC÷ŽÓÎ[ûý¢¤çjðX`a\tx³°½À=hލ\Òð3Ƅݷ,á‰:-0ëÆß5tqÖô)MÂöü‰ÑGœ˜ûäÊ5¯Ùš›û÷3ÝûòÉVÝëß ½—Å^g^¿¹çõ‹~ýÞŽ.?3¦ÔÿE¹zÔ$¥'0ÿÞ;=~ü¨†íÆ#vߣawHÖ zŸÀÀ“{nÌ´ÜÏãvغÅ;EªcEïc1cÖ+pÿ÷Žoø×1O»9^xÔz>;f½M*@€@øÿíÝPÛç}Çñw`C2äbrÃËpJ’á\ ™¹žÝöÈ&9ËìµE¬ç¶WŒ3³®È—ë¾mæð‚»âž]“í|i ä:¸bèòg9Ë·/`Åig.ƒÔ ,ƹÔ4ƒVé°Ñû!¤Ÿ$#pd+£·r2Ïïù=~ÏK:EúêÑóL_ù…ù‹Ú{3ÒWÑÈ DW`\=gý¿¿/Õe,l>![-3SzÁ3w*!æk¸p_øÝá9IÊ/*S¾9 Öµp79H €€W࡯>¥š_åjBÉzp}øßýI‡©å2S$@ îR¶ªæÍ19&>T¢åž…Ã7–”yî¨'Dé“ë“–!âN`ü\­¹—TNU·¤i_Ü)0`XJ`æÃ«æé±¾—TÛЮŸ]¸âÝæÁby@¶¯ëk_ÉW‘+Ó‰q)0ý¾:}Û=äTý…6k\m¯ê·útunÞÏ]µísé‹_°)#°ÊLL©XÃ=¦üËѹ[Í…•x¿b ÷å§VƒÀd_³6䕘C©ïwɱ5Å<&ñ-0ÚwV¯MÈué-ýàȳæUVc½Ä׌õWÈûÜø~=±˜ìQᆾ™«Už9¦,OŸ “óæóXÃ=–}#°bš÷)§äÔM®Ç.ç`‹ ²ù,r(N#°j¦‡Ú”¼e¯o|VYÕeüî–£úŽ3rØ2Ã\Ö<Öp_Vn:CVºÀ´zÚ‡ÛUܪ"‚í+ýãúXF·^)Ù­’½{UlŸ»€'¿ùÁöe|$è •)`Lø)ñÛ¥ÖÁ#ÊòÍN%\¶21® X ̸|«,çk×ÍݬŪª©QE±uþØû¯Sö-vuŽ{׉Ê'‰ñ"033ÿZ1ÿJaÛ}/9ÆkFi©#Õ9~عY ±^Á]"à/ÏNƉÜD`´Ïø&87Y;ö”´×érS‘ø€ !…’Åø`œcõ½ÓõÌ}Vþò¦<™†âX` ùo}¿®•æ6f/ÊöýæeF!˜:‹ã' CGÀ+0©7à[“¹¿_'Ú5ÛÙ¢cÕÕz¦¥S®á•šR]ÚùÔkâuÃ!@\ ÌmOéýÒ_¬öÁ1]0^3Nkf¢_5AßÓ(o yÏ ,î±P§O@` Lö©Ö‘«Myv5m°\Ñt^S§Ë”Éš‰+èÑâRX )ÚßrÁxƒ{A³ÆÆD—ûÛUj¼ó5>+·~ÙŸzU„ÜWÂãÄ5 °ünã'ß9%¾=Š›ô‚ckà"’ï |oYgì"à â[ UûÚ/kxxPƒ—'thWvGJ–Mßn ä5þXüÁxB NúûËÃMÚ•f $¤nUµó¼Ì¹î]íz7Æ“Ü £˜ @ þF:kµygeÈÀíMúîábe³;Qˆ  F !I™[w©á]Lß9¿–â©—táù"mç§1aÀÈB`u \|ý¥ÀOu¨æ“tÕȹ˸ø?ÏÊ\©ÙùC•¼ ýúCýéßÿ£ö°6sÀq$š‘©Ô%Æ›µ[uƬÕrïbÍÿ«ß¿”aíº%À8…@<ØŸÔŸùת oÊC*4"îNßgƒÏÅ MÀ=èt‰¬w_Ch°ÝZ¥îþNùYK½í] WÎ5 €Àr Œœ=ªÍ»]Zå¼üš 2Ãl‰šöY=a¼ÁíZ!op—Ó‡¾@ ¸.–^?þlðqpºKÏÎow–uð»Á'H#€@ x<ó‹Ä$$,šJ–ÅG  ¤l~Ä;{Ý÷Q#l¿ûƒ<ã:gøíT©ô±e/öªö±uHà €+@Àݧ'ó˜RZß­:G>FL à¸ú^¯/Ù¥¡¦ÂÜUÇ\þüEx¸ë÷l*­¸O“Ã-3¥óF~þc°UU;¤«SÊ^ÏGÒx}¾0îøp4{ÂÌ©p^Ö3™ A¦/ê?ÍÛ=Zî¥ea-r@`µ $ÍWwŽhÂßÂÓN꿺Áö¹ÄÄòÆ»›XêÓ7 #KÿÞ`þ¬Ûzâ¼Ûct%t‹+]`ãæûÌK¬|Ωolß¿àçß#gëUékµé¾…ï€Í6H €ÀêÈ*(SCÁbãó¨ù]#à><³?¡ãÇöóEÿbTä#gÏ>ëÔaãõ#°"ó<@Ocµ|»BHŸ×ýD°âì™Ápð $=¤bce§÷Ḏµ=¡†¢ìžÉž}ù¬>ãÏ#¼\…<< €ñ àÑž‹þêu<ùM/¶ ѵkJÿ\‘öÛ²uH!€@Üd>þW*–oíåS%ÚàSoÝ7”³)EîÉûQ­ìåæÇaU<ùùù¸Áb  °„ÀTàœëšæŽ’9¤@ ÎR¶<¦ cÌÞ•§ºÊ•¾oZçÿ¡X¹™é’ûŠþí¹r}ùˆ9½]­ŽÇE+Ξ$ S I_8Ø$5–xs÷n1öi×·JþDéÉ3|£IÅ»ËÍÒ5ß.Yðžyr™kfÛ2õE71p«¹Ð¢ïÿ§ìêuÖ¶Ë:E ·lðÏF :³XÒZ׫βm‹&V¹ÀÈ™ÃÚl?~óQ7i¢eá ø›W¤¬~ Ï%Öz¹:a~¾ú!Æ{N*}G H8š*®?¯~‘ŠÂq(ÐÓ°O;œZrä9UNõ+ˆù—ú¿³äUrr• i_e(ÃAà¦u-Â͇,!› Ýb·TC;V ³à˜®œoònV~9ªi=¯©‚íá}ÈE߇„ÔåV@Úö2M ¶«ÂØç0üÍ®¦îËÛÃã‹@Ü lw´h¸£^‹½dTŸGzW@°}îa†{Ü==0 € p«n õý\ïýbRkw­®_—R³ÎÉV*¿ó¾UTê!€ ÷“£CzïÒ¸®ÏÌè·ÆŒÔMè¡­Yü&îŸ FÀãÖ¥þw5ò¿•÷ÉÝ›´õ‘­J[AóŒ ¸‡yÜÈB@@@@@ R–”‰TŒò € € € € €„ à…,@@@@@" à©å@@@@@#@À= Y € € € € €D*@À=R1Ê#€ € € € € F€€{²@@@@@ˆT€€{¤b”G@@@@@ Œ÷0(d!€ € € € € ©÷HÅ( € € € € €@îaPÈB@@@@@ RQ@@@@@0Üà… € € € € €@¤Ü#£< € € € € €a¸‡A! @@@@@H¸G*Fy@@@@@ÂpƒB € € € € €‘ pTŒò € € € € €„ à…,@@@@@" à©å@@@@@#@À= Y € € € € €D*@À=R1Ê#€ € € € € F€€{²@@@@@ˆT€€{¤b”G@@@@@ Œ@B˜<²@@@`™<“Cz­ãiíÚˆz¾~ýº6<üDze'¨³Í©‹îkÚøÈµg{FDíÜI…=ãzéÕŸÉ­Úõ—{”™t']=׊ € °šÖÌ·Õ<@Ɔ € €À àî;)K^ù­]ªµ^.ç#²[v¨ËhÁz¢W‡¶ÝZ[w@­¾“6å•{Gªó®NmO¹.šKD@ˆ –”‰‹‡™A"€ €¬xÄu·~‰W¯É“˜¨M¾,«|Æwâ:s¤J¼u5j"€ € u–”‰:) "€ € ¹@ÊÖ¯kbìKòWMH’ëíïëþ•Þ\kM‡þµâä™)eœKRª.×$ € €1 àtºD@@`¡@‚RÓÒd§¤­7ó,ë?¡Ô”T)Ü*Óf1 € € #–”‰<Ý"€ € ðQf>J¡ʤXå=§£ŽBå®Y£5s÷\›‡Ô7~cd~\gjuôèQ5Ÿ•g²OµþzûšIƒnžqu6×ÊQX([n®r»­Ð¡“mZÐlPµñ¡s:yØá­ã½ãzrm…:|²M£!=Õrë\[­öÙlFY›lÆÝq°VçF&•˜rWP¹ÐäøÀYï¸ýý̽P'Ïô鯑‡Öä@@Û`ÓÔÛ7¤@@>6÷@ƒ,9¼íÛëzuºl‘ÍP§û´/9O§nz%vuV¾2½»G6ßf«Ê±*§¿Kýþ6ŒÍX':Ær5’Çà—lzt‰öíjþíÊ ]@¾çä>í(_úªjÚ/«zW¦¿W£³Õ>¾Y•sû¢.y³«×uZÛ|3þûö)ïÀ}×ër“C™üÎwIUN"€ €ܺ3ÜoÝŽš € €¬p«jê[ÕZWtN}ó™³ã ÍV5lÏ œ’Å—ž¸!Øn׉¦—ål­“Ý,îÔîû¿¡¾  ëžKm!Áv{U½Ú»»Õþr½J­fEÙý”Ìéçn5—„Û‹«N¨¾®FAU•})ÏÈ+AÁöUÕµª£»C/×WÉÒ©*y¾oA]2@@ˆ–÷hIÒ € €+HÀZåÔÄl§ªE**;&×àËfà¹ÿÇoi4̵zÓýÅjÓìì¬fOÏÏnï9YmÎlÏ©hÕØÌiÚ¿GEe:=sYufÔý”jÚÌ–‡Ïµ›é*ç°NshW~¾víq¨¡Ó¥ÖR(Ü­}kç¸ûÚTbNR·Ê9èR˱Cr”U«sæŠê‹Í&Cƒgæqqû:VV$[¾M{Çta¬Ûüb ëô›š4K’@@@ ºÜ£ëIk € €¬ ½PSà] Æ1)Ù_ÐA`¼¿WïÍD÷—é7BòÎ+MÚ•í_oÆ8ãÒ?WúƒÙ¥zñé"¥/É’©²–óf@Ûùb—ÐÞ˜õi_¿T_{<Ëßïoж}Æp—½¹ý´åy³\MÇ‹*ÈÚ!6!CŽz;̂Fb&hµù»&®Ÿ’Ò>£ª¦ªª©RMáƒJ=Ë € €Q~«µFi@@b'`­ù’²¼ÓÝ~u>À}Ã5–VëñŒÐŠÓÃ}jô³o“ÅãÖ¤ÛãÏñþMNø¤2RÞ°|W§Þs—i»'OË/Ó…Ù²ù²Ü““r»®êƒÆ5vémÕ¦²ûÚS§ù*=a üûJ(i›þ¦Æ˜ù~$t÷õïñ—PãÞ-ºØ^¥¿Þ»[ÛsVfFª¶ï?¤íf  € €|<¡ï¦?ž>h@@–QÀ’~÷-õfßö‡ ÝòÔ˜9þá¯m9hSòü®Ì…©à`¾ûÒ9}¿öŸTÙèŸ%¿°¼™ãþ@?óÇÛí™Ú`žMܽÞšaeVMN£Žøêw:®¹ûü-G¥U_Wñ_S~ðìý­ € €Àí °¤ÌíùQ@@•'pí/éZè,ø¹V’ï}8ì.‹÷à2–w™¿vÖÊrÿ£aƒíÖâbsMy³-#R´€Œ™}cb¬3LðÞXÚ¦ºwBÝ­'d¬Tã«Ú¯ÆãåztKº kÏÝØÇ € €DM€€{Ô(i@@Õ'0õþ;óKÅC³Ÿè–kÊ¥‰‰‰w×Ô”¦¼÷×”75÷\Ò·wVš ÖŠ:u÷klÂ¥©™Yu¶´èÕÖRó¼7aDêÍ¥å]F¡gÍ£M…‹ìœšªü¢C:}aV®‰+êívª®¦"$°ï¬|T¯ŒL›m‘@@@ šÜ£©I[ € €¬2Äõ戜ï+1)E©©©7ÜôÓÆ§õôÓÆ½ñ?¼rÏØE]ô×,n’ó™2åoÍRZjŠ’| [ŽþÒ,1_2å^Ù¬¾J]/êíqÁÇÕþÃSÁFzZçškuøðaÕ6÷xûOIÍжü•U?c¬#ï’³Êß°4zuê†ú"€ € îÑq¤@@V¥@RÖ§UáÙ©½zuháìðÉž&í.?¢#GŒû[ó¥SÐWKçƒÜÖ³,ã=«oUú7>5¦Ä{~OÕƒ;üëÁté;õþžÍ¿ãM2«™¹Szû‡•:~ü¸*Kœºbæû)Êß½Ë`,LH’B@@ šÜ£©I[ € €¬:L9‚–~Ù»åÏÕÜsIÓÆz/[}gjµaG¹9꺃»½¯&xFõ|ã|@½ëÈ·Ô|î’ÜÓÓšv«çÌI=¾i·üávé”Þzwn:{‚s5Ûê:²ÓXsýŒÆç:3f±­UzÐ25fA#œÿ°¨?®Gƒ†&ý_ Lk¤ï•<ê_Þ&GÞûQVŠ´N @@*@Àý£JQ@@.`®áuÞ¬^vÑwTo.›Þ¥’÷+9q-ʳûÙ’µ¦COnKï=õÓª6—h7ê_ü@^ºöµ )!³@½MfE9+íJONÔš5ÉÚ²;ÐWèd;øŒ¹V{ãmÙ¬ÜÜ\o½Íy_6ס·Ö<§]¾5mBá@@Û à~Û„4€ € €À2 ¬[ªŸDsÙ–‹w}–% ÏðNÔ=¾’)ë«—&G‹Ku@øWµöêõj›1GÝKÒžï]V}©‰þüßÒºML «&ètÿ/ã=¹mƒ5¡|GÖªzµžðGÿƒÆ‘fÓ›ƒí ¿?¤Šú9«óCò8@@@ škf[4¤-@@X½žÉQõ¿3¤±ß^×Úµwëºos–R“óäÈ€Þ¹4®™ÄDÝý‰4=ø@v ¼gR—FŒuß’µážt#?²—{T}?÷õuwª2³RVFP=l— ô꿯ëk×jíuã:ïù”rÉQFJPÛaë’‰ € €Àí p¿=?j#€ € € € € à`Iž € € € € €DA€€{i@@@@@î<@@@@@ˆ‚÷( Ò € € € € €Üy € € € € € îQ@¤ @@@@@¸ó@@@@@@ Ü£€H € € € € €pç9€ € € € € €@¸G‘&@@@@@ àÎs@@@@@(ü? gŒeó7ÄuIEND®B`‚concurrent-ruby-1.0.5/doc/logo/000077500000000000000000000000001305460430400163625ustar00rootroot00000000000000concurrent-ruby-1.0.5/doc/logo/concurrent-ruby-logo-200x200.png000066400000000000000000000636141305460430400241120ustar00rootroot00000000000000‰PNG  IHDRÈÈ­X®ž (iCCPICC ProfileH ­–wPT×ÇÏ{Ûm—¥ÃÒ› ½J]ª tDeÙ¥ÃK;ÁD¬H(¢`4ÒbA,X ØÔ,€ŠÊï­Ì$™Ìä¿ß™¹ï~Þyß{æ¾{ÞÌûÐâyiiɨ@Š0SèéÊYÁ!=@È<~Fš‹¿¿/v÷13ˆøÑ]#q­ÿýWZZ“Á@ü1Aª ƒŸ‚qÆnü4Q&ŠÇXsmfš˜õ0f‰° b¼DÌq ,^ËŠ^`Á7Mp Óäé<ž(€šå9Ùü8¬µc¡ Aˆñ=Œùñ¨€#pêàœ8—á:܆^€G0 cð¦`æ!! „‰( jˆ6bˆ˜!6ˆ#âŽø"H8…Ä!B$ ÉC¶!EH)RCꑟ6ä2réC #È$òù„âP:ÊBUPt1jƒº >h0º CÓÑ\4݉–£UèI´½ŒÞFÐaô%: ÇÆ©ãŒp68.΋ʼnpq…¸2\®׎ëÂÝÅ ã^á>â‰x&žƒ7ÂÛã½ð!x>>¿_Œ¯À×á›ñWñwñ#ø)üWƒ L0$ؼ +q„µ„B¡†pŽp0@#̉D6Q—hMô"†‰ë‰ÅÄCÄ&b±8Jœ&‘H $C’ÉÄ#e’ HH'I—Hý¤1Ò2¬F6#{#ÈBòVrùù"¹ŸH0%Œ%¼%›$*%š%ú%^KR$µ%]$WKæJ–Iž•¼#ùJŠ"¥#Å•âIm”ª”j“’š–fJ›JûI§HKŸ¾)=!C’Ñ‘q—ÈäË—¹"3ÊÄ15™\&Ÿ¹YͼÆcYº,oV"«ˆuŠÕÚ’•‘µ •Í‘­”½ ;ÌÆ±uØÞìdv û {ýINEÎE.Fn‡\£\¿Ü¬¼’¼³|Œ|¡|“ü€ü'Ž‚»B’Ân……'ŠxEÅŵЇ¯)¾Rb)Ù+ñ• •Î(=TF• ”•×+WîVžVQUñTIS9 rEå•*[ÕY5Qu¯êEÕI5¦š£Z‚Ú^µKj/8²N2§œs•3¥®¬î¥ž¥~L½G}NCW#Dc«F“ÆMª¦f¬æ^ÍNÍ)-5­eZyZ Zµ)Ú6ÚñÚûµ»´gutuÂt¶ë´èLèÊëzëæê6è>Öcè9é¥ëUéÝÓ'êÛè'éÒï5@ , â * V† †‡ ûÙ..ªZ4dD7r1Ê6j01fûo5n1~½XkqÄâÝ‹»5±4I6©6yd*cºÔt«i»é[33¾Y¥Ù=s†¹‡ù&óVó7†1‡-î[2-—Yn·ì´übem%²j´š´Ö²Ž²>h=dòñ·)¶¹aK°uµÝd{Þö£•]¦Ý»?íì“ìOØO,Ñ]³¤zɨƒ†Ïá˜Ã°#Ç1Êñ¨ã°“ºÏ©Ê陳¦³À¹ÆyÜEß%Ñå¤ËkWW‘ë9×Y®w·Ã çæéVèÖã.ãâ^áþÔCÃ#ΣÁcÊÓÒs½g‡ÁËÇk·×·Š7ß»Þ{j©õÒ K¯úÐ}‚|*|žùøŠ|Û—¡Ë–.Û³ìñríåÂå-~àçí·Ç®ºÿ/Äÿ€Ê€ç¦y]AÌ 5A'‚f‚]ƒK‚…è…d…t†J†F†Ö‡Î†¹…•† ¯X¼bÊÛáŠá á­¤ˆÐˆšˆé•î+÷­‹´Œ,ˆ\¥»*gÕÍÕŠ«“W_X#¹†·æl!*,êDÔgž¯Š7í}0zŠÏåïç¿8 ö &cbJcÆcbKc'ââöÄMÆ;Å—Å¿Jà&T$¼IôJ<’8›ä—T›4Ÿ–Ü”BN‰JiÊ“„WSUSsRûÒ Ó Ò†ÓíÒ÷¥O‰|D5HƪŒÖLöóíÎÒËú.k$Û1»2ûÃÚеgs¤s„9Ýë ÖíX7žë‘ûãzüzþúÎ<õ¼-y#\6ÛˆlŒÞعIsSþ¦±Íž›ë¶P·$mùu«ÉÖÒ­ï·…mkÏWÉßœ?úçw ¢‚¡íöÛ|ÿ>áûžæ;ìøZ((¼UdRTVô¹˜_|ëÓʘ߻³§Äªäð.â.á®ÁÝN»ëJ¥KsKG÷,ÛÓ¼—³·pïû}köÝ,³(;²Ÿº?kÿp¹oyë­»|®ˆ¯¨t­l:¨|pÇÁÙC‚Cý‡7Q9RtäÓÑ„£÷yk®Ò©*;N<ž}üyuhu×6?Ö×(ÖÕ|©Ö×Ö]­·®¯?¡|¢¤mÈj˜<y²÷”Û©ÖF£ÆcM즢Óp:ëô‹Ÿ¢~<ãs¦ó¬ÍÙÆŸµ>xŽy®°i^×<Õß2ÜÞÚ×¶´­³Ý¾ýÜ/ƿԞW?_yAöBÉEêÅü‹ó—r/Mw¤u¼ºwy´sMç£++®Ü»pµçšÏµ×=®_éréºtÃáÆù›v7ÛnÙÜj¹mu»¹Û²ûܯ–¿žë±êi¾c}§µ×¶·½oIßÅ~§þËwÝî^¿ç}ïöÀò¾ÁÁûC‘CÃ÷÷'$?xó0ûáÜ£Í ŸH=){ªü´ê7ýßš†­†/Œ¸t? zöh”?úò÷Œß?å?gÚ|ìúöi|nígÒçò/ú_Ú¿ú|}<Ÿ2?ŸÆñ¾yvEccÞÖ0Â1ïЋù3‰ÏöM,øLŒÅnG<Äñ/^ðußžXÔ:„lðí8Œ mŒéØ,¶ŒÁ΀š›ÿ5°Œ82bÍ;BaÖäÃüü;R;ÀÑüüÜ¡ùù/Õ¸é ^Q¬&J•S÷†ÿŠÿÈNÀÄTäV pHYs%%IR$ðŸiTXtXML:com.adobe.xmp 1470 1470 ³Oú@IDATxí} `žU•öIòeß÷¤IÚ&ÝwZ ´ ˆ ;²9*8‚Š ¨ã(ˆƒãøë¯2:Â(ˆÀüâ> (¢@Uö²•––îûš6û¾ïÉÿ<ç¾÷Ë›4I³|i¿´ïM¾ï{×ûÞ{ÞóÜsνçžÒƒ$^ò(àQ`@ „xÔ;èQÀ£€RÀˆÇ† €!ˆãò(àÄãCPÀÈÄñNyðâñ€G!(àâœwjR »»¥‘|óËKc¢€1‘/¸nîììŽj…„˜¡-$4”`ñ€2Ú7â Ž–tÁu_ÀÑÕÕ-¡,(¸êd”¯Ë“ £$\0ÝFµª½½SAÐéAp å3û*LºÅç ¦"O˜²x™0¯jð‚¶µuöJ‚ÂÄùíéêQU+4Ôë“œŠŸñ20]&ÌQªUmFztÓq$6Œ$q@"Ýéd¤/ÖÈH)d×·Aµêê„íé@{ƒjU4Ë釪êŽP óùBÕ ²*uq<€õëºp@k[ØèA÷.  °Òܦ!OƒÝKç€áÓ*è®lïèRãÜtåZépP~Pz¸ÀÂC¸>2"\¥LÐU&H ä$H_ÌpŠÕÚÚ.ݰA0Ú¡R„œoÕ,£jõKwW—tâîõh ‡¼za“*¸.¤zÕÒÚÕ zU7U*Hl÷$€‹Žƒð˜ó¡éÆuìö2üwédø´ ª+Ýê•q/!\„ÀqÀÂßÐPZ*"íèñŠ•È ªK0ÆH0¿ÊF&‡0––v5ºÙ3elÞ^+^`©Xºzxéx‡w€C@ J0"“35 T³¨6±¯ÊtçªÐ ÀP›Ä¯f. cÐÒLj’ñ˜_@ŽI¢à»€ƒƒ-4Љ 0¼a~#[ü]¼8å…ÐfiC×pLtDðU,Kä$_Ê`E²êU[{‡ÚaT#ÒÁ%%Œ7/¥†#Yx7sŸyð~ÇDìQÞq‡@&+8¡zE;"$œD應¡½X44ú‚ÅTÐì¶·£»÷‡‡{Œ†:ƒ{œ6Aw†*Sss›ÚQ@ðD‚Ú!‚¥×᥼.*ˆ'I Mûö2e‚ô8r„œM[„ ï7ƱcŒuªRØv$.ÆåNð îãU]ÂÅÖþ ¸ ‡;»y» IèîNUŠƒ‡f¤ó´$Ür«4ïÝ!…™Y²àI“åã»vIÁ¼yžzåÓȱ¸*HΛY„Vµ@€ ví2ø‚U¯œIC–XA`%¤§É <,gÿ÷öj™våUróÚw$gæL€±hÆ{ÉS±‚œ,£j˜”•ö‡&ð/mzæ2R"%ÉpYšÝ¹AdT”œõµ¯Jê¼¹2iéR‰d¡â­#bHÌo ½´Ú-23FÑ58Õ+§¤ÿHƒÓ¡&Š”´ú ÜCN¿â ' .´ã)yõLj›A¶m¥B—3BhÐ÷в¢#躌ق£MV:ilˆ;P8ÚüNÆû¼æ"˜ß*¥U).³FJ t籄¸(‰E/“evÝáWVÂåȺ—ަ€£itG‘]Ç@ c?+ãÚž’§À0ÇÆVì@ä1¶çÝ@‚ó½ô)•‰¤ˆy(V‚p4=-eôêUŸ`ÇHŠ˜}Ϙ.Au”ƒ„´Czœ@oí÷î˜KËù%cÎä¤ÌÀ“ àµj$t¿²•ç_ì}ã„'¦±Øæ~O‚(!øò2Q‚í%ˆ™Zk@ÂÅ8“cýî%(¯‚ôR_ xéK Ü£!ëZûƒÓn•$‰±^ÂÌw¢çå$˜ß 3ðÇÕ¤L o@ÂUm“g “B(˜éqÊæé'€èÃ}¤™hiÅ(:dˆF25‰È% ëèÄtCô¥ª'AúÒ#èö8¹©«Ù2QŠ0– th`«®™8_ºœ‚û€·íM˜ V°ö2ç€p©&ª@ —”£>SL µ9úv1.×@•îÄåãIGûc<Ù°)b‚Å‘qM^ö`:QQZ1YÕ.ÐϘˆùy ò·Ö•JÝL -è H©‘ èD€X è¼'r~@‚üíqPë°Yç\Ʊ=T%ˆ†´?;xéO‘ Û§£bgÜL quà7*ÊçAdQÙuL+€fM ‹wÂò @L½hâ`“Ý?V­6 ñ¯߃E—wDšù&Ç.שrŘº½íÈ®ÿàP"ƒÐ {F¨°u ãêg¬qßœÑýR°àËÜÓ{üTߢ'o'T+6<:$>ZéGzÒ˜¦Š¥ã,"Þ²l½\7j€ ‘L0ðÚc0õu‚ àœ•*ŒéÇuó8:<ܧ^©>l;Xò—Œ×“ ót®äX€¿A²AKG¸QYº˜$ šHŸA‰3ºÂó½™0¦¦«7]‰Nü]£ˆßÑ€à@½ °*“М)ÊOWObÁb¥¤n¬õí¼c®¼Ê°™ÑQáºd÷czÌé¡î¨‘8NÂùÔmm÷Ãu@Pg6B ñ¦ ¤ëSìŽ9‘ž¶«W[7ÇœûÄÌ`T±Ìo_šŒJÐA=O©fáÏœÃö}b>ê¼!<)Ó‚^šF,-ÆkÙ(r®— ‹ÃtRŽSÂØ¤ÀÁE=ímR_]#¡á៚jæS±nUísOÔ/Ç@X-ºÐÝ$>6ð.&|†®”R¶'k< x¢¨8úçŽ †á ´~x× ¾xàC_m®Ä_§¾±E£y„ãý¢£"¥£µU ßxMÂËȳ·ü“$Θ'ù×]% >ýiI›=K[ÚÁ¤ÏèÉtâî4k¢s€°KŠXéLãѸ³ma·²—z)0ª^,Ù*-  ÛÈóhÉÑ@J_p@²ìÆLJŒ‘iSÒ±ødšäNJ‘œlóášI9Ž€ás7¾ô’l»ìr ©©”¬Ï^|õ­RüýïɆ9³¥åÐAm ©n,‰1yi·uÁþˆŠôõYÒ9Ðudù&^ê¥À¨${¢BBº@L£S k¬[ÉAI‚{¼8DçÈlb~VfKÉ–PôL“„ø}ë·ÏKBVŽäþÃ…Ò–v“D)’Ï>-Óoÿ‚Dăâi«[V ª‘bÖ‰0ÐmïxÈ6@\çÐK½•áíT{˜È‡Cƒ¦ªa¸Žj¯'8Ì6THˆ7jÃDP·ùëO8ÀóÙ9õñ'dïú÷¥ôƒ­rxí²÷wåà˯É_¾ü5©(*Ò[l^þû'èF[$AÕ'^¼ìýcì³á# ½ÔKQ„­:{ÈèFÅ¢T06F¯ÍA Çú€Ã¹Ì®v îïBïVoÞ:ó†ëeÑŠ³EZ›åí5ëdß_ÿ.åóæË‡V­’¬iÓ ñLöȰL5±ìÖQ‘£è$d¯q¬Ê[º/·ŒJŲY°w‰½L Xž-š…ÒÌÏ\38ø’i+pç;$hM$T;xOlb¢,ý¿ß•¿Ÿ¾œ{ÿý2¡3s.”ÄšµÉúf-ŽNÓ;æ 3vŒ½fè§Ù«NÜ/iH•‡´åHœmx0À)#žŠÕ—¨c³âZÛB}C38Þ¨A`þ!À¡*–Óº×Õ7KVH²zwß"öݳá13W,—«ì—ä©ùþ ú…P§ E`g0À8¯‚Ûg‰€Šè~+#ú3;¸¤GÏ™º –-@ìù@‘#è½Ý¼Î}bæ7jË]]†àgÿ¼®|NS€ ™´¡©kÑ,yïpRXx„ï³àé?ŸAÝå$ ©zÕÕ·HžiºQ{ÁÁ§³ý¸}‡¤§qu7Ò9Æ ó¸õÍÉ馗 fE’]µd>j©ºNS5‹ ¬xÑ8¯ej¾œÁõÅ¥ÕZ"w«®†ø²`ÒQõaªT½¸dËʱ•Ʀ6)«¨—Úºfíâ¤âb³²ùQ„q:eBºPµ"íhóqð”)ðÊ•©tJZ.-ÍäàÔœÇÙ°›Xªë­xîK{+å¥?.—~z­üö¡¯"Øwü¨@2n±…æ/‰ÉP5³gNRž=V4ÊÙZñœëkì3'dÇîb%úäÜôQUÎ]†±lóÅ3Y¦ˆ€Dœ29C&C…¤êu °\ö,Ç‚6ñ8ž†ß-·û›‡f4Ì/Û]N Œw‹D#i —wÖ]y_¼Ö!Jºúú&©€D8\ z*‘ûŠeÓ¾ryõpH]–ŒEþñá2+.\’Ð`®œž¬Ý×Ì»ŒÍ©Åìbæ (·±êœ>Ó€ÂÄ3q”8†Ÿˆ·IxÆ”ëgɪ_®•·?ñ\ñ‘•£â¡ã2‰@Ukl‹ÂÃr¸¨J[D˜ÀàÇ‚ƒ€!e8Ú½uç=7ÌÈkØ$›×È×s|“erƒ…á>Ýñù©©mHÊäíµ»54hÁ”LÉ Ã:èå®{ôÀ0¾ºÑÝJFéÓX€Žþr(A‘ýFž–£mî[hƒ0ÙÑ{Jø¨1T3y½žuˆß ;  ’á0¤ÂÞƒ%²cÏÙ¼¯LVª•ú¦v‘È0™!i1árÑäDäaŠIuÑÖ©½e~-ϵA™^‰¬ÅÑ/>Ö~xÀnó×a Ÿ¡¼ÆiÃWm #RšeêxÏhÒq FÛ—Ë–—êÊžýÅê‡åóù–@l Ðè@ÝÚ¼½P[(2“ÍGwNÀ_Še4[®6{Æiq2»©R²\6n-Äç`Ž Ë­±¬ä=& ÍI·úR:8ÜBC”‰ˆŸaülYÊc¨cô@°‰ƒ­¦T½F:¥¼MMÍ'ª’C‡¡"í+’­{Šdãþ ÙTÙ,Q<¹h±S†só (ý„¢@@eXmÊ!Ö_I€}[‡$öqGýš²uxÐ{ -ìl˜/‹æÏÔëjÍÀ9qÜÂçÙ’@\€rñ‚€¤ã µè¡1sÌIXCD2ƒÙÇÜÍÛ Õ{öŒÍÇ2æ±*8ÞçÝuâ³âàr³pÞ™5}’<\.;÷”È–Gd*ºgLˆÏYR:ð›·Ý‰z¤H=1£œP?aŽ¡ÎëÚ›š¤µ±QZëë¥ ¿í0|»:;0çË% "cXD¤„¡ÓÃ)‘qqOT|‚DÆÇ‰Žý]s×p€‚.ï´) ÊdûžÃ²e7@q¨ZÊÛÕFH‰Ô¸¹8! ÌgJ”•ÒÝúÜ7ïÐØ ,«©#ŽŽ”Óyóˆ"DŒù˜B±ñ¹=ò˧>‹ñ­Lå`t*ûã [” NõcÞìC¯sç1¢‡óņª½õ#ЋйmçaH–*Dh†=6I w(Q·Gryyµ¼þâkÓ\%µ›?²Ÿ?ÊNL¡Ã C7Dà/,o²„Æ"Ú;$lÚæÏTP•$Ò´D÷”„`,¡§h?ÚÌÃa =iš¤|ú¤sÊt ›5_ aOÿà^•hÐ:'=N­XÌ”îÈÞI|/”¦1£´ãyG ný5*oà}, {â¨þpÌ ÿ ,Þ×5Œ÷2?óÎmÜctóË{xŒççcŸ÷pqÓô„mz±DnûâéòÐ¿ß ¿;J8ãˆËFœN(@liÝL¾ÿP™ì‚4¡Oíöj°‚ d!Q›°âR œ Ï>k¶º€»ï·yË/_& ïo¸[ZViX(;÷–J4æ™Ïšž-ùè˸ U¨.¨7»×­“uøƒ”?ÿŒ4ï.„oÜx&HdR’vùÀì¡Ô±ÁT! [êP<‡‰4 AóM¦Ä¿ù8!PcÁ¡œ@Qý G†T×IOánálš¸|Xb¯¼Fšg/”­ òÂËÈŽÂj)ÈŒWnlí~ꡆ5âñDB-c×l|D˜Ä¡>‘ø‚&ÿ±¨Î¼¦ð²zH¨2¨Œ{ê`ÈC:©E.Þ‚ä(É„ÊÆò6#oªl¬kd€`ø@¤ÇzÂFƒTÆŠ6>wX¾üoçÊwî¹ ]ãò¡Í6ÚaáÝLÞ€¹-0ÌKË롆`>þÔÃ#±øâ[Al†:ç¬YÆÁÑdÒ‡GK”ñºÏ]G>£Ι›·R¿¯³—͆º9Y*·m“w|PÖ?ñ„p@\|–DaŒÅ‡zû`[„á`#PF†×?7È,<ê:¦ÛÎ1œ°çHYæÁz<B *Œë„6IâùçJæWï•°¥Ëåýmûäw| IKNTØ\Žqºhw‘©Sµ$ÈÍä´PíÎ'§Ó>1ã:xwíÒ„ÎŒšº¼ãjôþ•ÈÚ­å©u‡Ž.Y<#¶¦A´™ÉbC¤ˆI;_(”ýì:¹ë¶©v1Vp K44|kA”ÜL´÷ \ØŒMËV‰bÜØ$(8šLº‚sÜ™‹ Tßg5Ü÷Qµú¥OAþ&´ª±<ô?¿•-Ÿ¸I*quý’ÓÕµ"ma¨w8™ ð¡ÃÑB@¡sxX†×_|Y€ð¡dœÞó¸;v_U'Ý&gÌ•MJQŠ¢½’óÃÿ¼¯ü‹ø™¤0î™q€SsK+:JeõšÍrד¯K´„31XØÀÁ¤^©Â±K£Ô(kÙÜ(Ï=s»\uÉJsý%‡f‚¯  æf úfmDër¸¸ ñ©¸¤qúh¢ÎÞØÜ.sfdËY§ÏÔ‹„³}úæª`û¦îà±,ê³÷‘IÅ]÷HÓòeRÞÒéR-uh”ÕÁÎw¢Ûcˆô2=™×Ø!¦Î#n¡MBcÞéìËH“NÄ KÿñC2õŽ[¥½ªL"`¯0uÓ¡`5ìê@?öȽ_*õ­-ʼ‹JÊå‡>-®Ú.§çÅK#$ ŸcFÒaˆãÞ4¨Þü\‰\üÓäÁoÜ ›®€·÷á=0†¯ ˆ­(û–ªPÝá9&@I—D:³Ulhlƒª/+—ÏS‡BCÿ¾º¿Í÷„þ¼Z`¢»©v¢ýé·Rñó”îÈ ¥cCåÐÁ+ЂÖaŠ0¥•$X†Õ°ê¨‚rÄêú’DÞ[#¹«_E×p»tÁlH>ûb­ƒ»Ca¬4å»&iÚ tZ¼ûþGä‰÷Ê¢Ä(Ó0RDt~C5|µÞ¨’‡¿FnýÄåPóØ»[ ÷¤Ã-/é´‰­ ÇÄîÒK>´H¦OÍfH öճ׆ç©jÅ¢²¢ªQž}q-tú%’ûþ ¨$ëB4#5¼ý7i^ýŒ4lY#M^_þ5ÒÓŒ [8g?¼ÎÔÞ½Á£æ8m³±¤îvÓmv 5­yˆ†]°þ)zúÒŽ\S"ñ]±‡‹à ï£hÞ|ý"{UR°,Ñ0úÙ°áÍR9';AÞ[ŸÜ}Û ~pèj ãÊ#¨ÂrZÑK ÐpÙ³äÃ+çIfüQjð8yŽŽq3 û«^Ù$o½»M}Š‚$.pT"À]å —H¼–ÛÊàoÆV¨ƒð—›¦ÞÜê›lƒÑ÷èè÷Ü€8*ÆŽ¶÷`ñP‚B£¥þµgd߃ÿW:›› û|«ÇÇ!`$XåH­±¥ªE6m®’G¸J^xìë²tÉ|m"H“±ôTÙçôô±…¶ŒÎ:);U.»h‰œ±hªzž¶ÀçÆœ7­Y¤É†-‡äyî5³ÝÔæw<•©"Å¿û”]û1é( Spº„ )ï 8Ђ¢`¬ /wné[T'Ö†JýO÷ßê^žó_ÏÁhç~ø”| O–Î ôr¥L–ú§¾%Û¿úiÇ(~ %‰»lÛwI„¢‡r¼÷R‰|fyl}ñrÇ-×¢÷,ΨT¸Á4&î;·=aÂ*+ãà—cÊipU¹ú’30ç$Ò¤U{´ÈTìíâZâÕ5MòÔsïÊ›÷)Åx?m—ã™XVûþòI)¾ñSÒ½lô|ôb‰]|DÀ‹“/$ QA¹¡@q ÊûKíß0'ûí:wôþ¸ÏsÛ½o¯ì¸^ ?9žO8k©øÓ`7ÕIWC½„\* <*[>§´Õ BÙ{h¸1Ù®ÙêÚzyôéÕhQÚ¤FúóOß.?ûÞÝè /Ð÷OºŽ—ÔpWïaÂ%2œ¾T)³È.¾`±\rá"¨`˜}Öª-,@·ö|½üæ6yîÅ58×¢’ý ÈÆ»âœ›`Á±ç¿Ã7ß"¾K?"k¶HÜM·‹/s’ÒÞ ç Eö¾Yp8åô²¯ÅÑ»7Ëûo:zc Ëc½§ŒÁ‚Yyï¼%I?øÄÂ%¥Ç)íÖ=mPm+ª$ü¬s¤å÷¿‘·Ü&Íåå„ÄÈÊl úÿüø7òÆïwËO¾s¹¼ýä×åò‹Î† mœZISK×£+Ø#ìÕ›IÙ‡@qZè‚)Y’ ÕkÓÖ²nã~õëâÀÛÌxøæì‡mañrá¹ódî¬)Jàñìv÷ðìxìq)ùÜg%jùÙR[Y-õ(UNN†Ò=~ÞR©]ó²´nX-¡q‰8ÖàØ À‹^¶U§&ÝцÁÈsÖ=ú›Ì>ôGߣG@Oôx€ÙC¥ ]¼)÷|]òîºKOu†GÉÎUÛ°Kœ„a¤°úñ±\Úžû£l„ëûÂß>)qyy J”‘$6h” }úíýJc–íÚû€Ìœ6E³Ñ*¼ïã!5Üåên^wAµmÂëªkdí†Ý²mW1´¸;@c‹«á}0Waþ¬l9ÿì:ÌëÝ÷r,‰yñc_ä¶Ÿ=*{¾p‡ôœ~–4ÔÖHWc‡$¥ÅËyßû’ÄÁïÉ7e®t`îõÁ¿) ø¹´¦œ%pÈ,¯©—JøBÑO‰¶ô‡€QØåËÿìÀ ¡|™3Î>ŽvåQlëyóËqýà_L4è…Q kõúœ_ýFò®½JÂbã4ç6å¸áÄ÷âó9j"ŒöP”χ‘õžÅ—•'g¼±JR`œ®AtmIâÌçÿüšÌ™>YÎ?çt½•´d:^Cæú:iÂ:õ'fá‘rL`Ú)àƒlìå¢}bÜÇ}rÑÊù˜+à |‘©Áp£Iú q¿û%²E\óðòõî»$lÉ™ÒQY%Ñ0x£÷·È¤Î’yW®”°´ ÏÈ‘ˆé‹¤+$B?ý”þüÝRŽBÔÍ_ Õ`Þv¸dø0&†üÃÑÂö‰‚cÜã>Ö€Õ Û¸>ÏÁ½!È#’">»{çé,Á’e%’ñïß–iXŒ(iî\izõE©û«AkÊQŽR FJÙÁ#Rôò«–‘!!t*¤d­;››yæTi@^Õð»šý‘‹ÕpG«… ÞðPÍ­‚´¤×Ìi“a3šxÏh¬¡ÞÙHÏT¤åÝ6F3fÄ­û`¼³~¯tàŚȉ‡¹8Ù…ÊEçΗ3ÏTæs3~ÿ<:Ç9Ü%ðÐݽ÷ˆì9\#í;¶Kä÷î’ˆ…KÀ\uÚòGƒIÙ›ŽÈ‹WäbZɘX ÃúŠáYžš®*JäôèNM—Š#˜ÆúÎ;²ý_þR%usgÛJ¯ÛÈô\‰À(wZÇÖ½¤W‚€/v"2ž´RÛ =å‡t.ñÄëÐ- I·Þ&9W^!ÙKdH‘â_”ª;îPïáè+/€Ch·D`úlxr¬ÄÍ›#ÛTËú>!13gIX+òÆý(Iºq¿d§KÕúurÚ52㬳ŽihƒÄñÜ?mqø„¦“ –²Æ4­XEe­¼³n§Ž“©â1óŒ5$1£ ].>o±Nfâ½îûzyœ‡~€îùNP\Z‡øÄQ’“#U?}@ºÖ®–ž¤LñARE°5t áP©8Ý6†vz§hoø˜rß+¯È®{¿!më×JÌltàšPLßÕ‰M€=†}záˆF“)uð¬^¿© ª*{MN-°ë8Y‰»=Pa»P&ˆùÜÆõ’õ‰½Stbð Û¡'‚ü«/僼°c)žmlK597Cn¼>Cví)”×ÞÙ*û «à¾)‰‘QòÒ[;d#æ£\rþ"Y07_uéʪ:9ˆ¸^Œ×ňð™è‰:ç¬ˆà—ŠÙp‰#1ízþÓ‚ÃC—¨€ùŠ}Ƽ ‘X¸MDá²vL …ëfA-šBÕ_@OQWS£„77JT+昷`ÎDM»ì~éu‰Fža0ôÃ0àó™y ¬Àž:ÎÐãŠ0|èÿ`n\†aÔ94!QzS¤+u’„ÁØîÐ_üÚפú¡%qR¾øN_*˜ÓÞ®[‚"  † }º[h/aTªn¨[>ÎÑ¡1…ëXëH¨m]˜qHˆ0¤HZ2¦ïÀ2ÝU€”•V@€pA#€k'R:e$Hÿ—bÂã´!6mÛ/¯¾µMʃ7£ð\l‡áv.X>ˆÓhtœ”•¤!USеé`‚âI™¥±ºZþ÷Ü ¤£¸ ªR2›Me J`Ar|’‡–˜÷ÁìÁ Û‘@Bàƒõ¯U傯 Mü%*^öm?,{~RYJÓ…SmÉ”d3Ê&þ²•£¥d޹ˆT|’3a§dJxv>z¢¦I$>á“ $fsí&yîCJê²³%’.eUgAd®ÁSXnÝÆ/ÕQ>‡b7zÖhÇñ¥ËÐÔö ÃÛÇÒUð¢?¿ sV¬L{優‰˜N ÒÿåX‰Â®D†;=ã´™rº|×¼¿CÖm: ˆå”–’(\Dsë®ÃªR\pö™j”y`Ä…&l0¿Ö†iÚ¾Y"fÎÑi³œÔÅÞ¤ ô‘Ù¢ÐÚ3[{ ‡ …=>¡°Bð¡4ñÅ 2Z÷ýš·ÿÕ½ÒV{X|s¢ËÑF²øPŒˆ(ã’1ÑÒ“‘Q úÈÄ èE´*œùtB} mÐMB õž:H©÷¿ûSI’鬬„+G‡ÄA‹Dþ,'„Jæ¯u@Ñ P~Ê Fœ"@be€ÄžºzH-tG¼âeJÁÉJí]½‡&\:eblÏd/#Eªª¡ÚDD!êHºˆcdû®BÙ×ùH4÷ÔŸ#:ÉGÎ[$§£·‹SJ‰•Dš˜ j‡ó7˜ÈÈܤËI,tÅtnœ‡ê†OÖã¸Â»:$œ")­A\­BlÞƒ.é,ò“=¶¼f¡^µâþ&0r àȸlÝí/ (=‚9Þ=^ÀO7¤SO>íÒÝÚ¢ƒŽ;V¯•šW^“ØY2ÔE²ùw!ß(Ѓ Î0ê ÄÖÍçàA|– ÇñÎèã@ ÓJ(áØD=ë+Š$nÎLIŸ4 wà>Ülé¬&Ð×)«ZY ÒŒÑêÃÅ•0¼1ÊÉ8»³§ÏÐP©3òÓå­÷¶ËjDKì€qJåæϼ%k7î‘Ë.<]¦å›]ìN&óGÁ·*<;[:´w*„z:-2t@e£ŠÞ é¡=°Pô5L8®©©œ[¥¢j83˜5ª ¢½0“P0™°Œm72p/·±©sºõ—Û(—.-‡‘I©žUïÜ-»þº]¢ÐSÖ{2®i"`ázÎÖŒFþŸÇ²†)H`^ðYÈ‹ª¯ Gžl$ü‰÷&&KÙþý2÷K7I|2ÔL¤‰ –ý”°Aô%’‰Ùô9©º¦K3TêÒ »“ƒÅsS×MÐ^ËÀo®Ù  ìQ¦ã"  vö’¹påb,‘¢—vAÿýwJÉãIôüùhî1x†D5(†5ABU…4§ÏrÊ(S- àJD1‡¶ƒ›—LÑ!f<Ï0†¿ì²®0·4«« ¯åT»H4«¶n’Ïnß&SçÌ=æ8ïætRïKÕûèÁ`Ó¥˜#ÂÖ9-5AãêÚµÿx_2ÁäÞæ±b2XýÎyóý½þ°4‘0Z/>gžœ‹ná$xo~é%yêâ‹1ð¶TºÊÊÀYXªT2l‚C{›Ài܆Ù!õG;º©é©:ƒç³”WlŸÉÀd~n«ÔÑc!’$QüÛó~&Æ1<]±‰*WÆ2Úpõæ-(“²tïO4Ç|8Ž"i—-ŸGD"c¿ Q€ìÇõô3ÔBŽè… ÏÍ‘ò ïË…?}X.»ó J?w£„¬'\:)ÒŒÆH`Ô@jÐ¥Ë10–®ûå î}÷›ìl~@y{ý>•$T¿2’ctnÊ¢Yyòü}_•Cb´.Ýhi{°"XÐH2Œ\´Þ†&€C¥ÁdNýÅ—qHóòöyŽR„j% Ûôf9’xÔ/QQÝ»$9PÓ,UUMÁ։ωB^|Nï€þ¨$xŸ…Ó*AßÓÚ¤ÏÆí(lŒ”©ß±Mr¯¿A>ÿË'%2&ƈ'ˆ¾ú3y–y®¨ª×‰¿‰Ãf±-“ ŒþU#S¥±©±k_{³¼óÁ~hSíÒŒð=ËNŸ&yÒ(‡>“„Í™%á0îS:ÉÂF*©¤P›€,Œt ³”·æG·pè9aY!EȰ ¦•§$Ñ27@Zd6£x?"Ęž'd€džÇîá‰D>Vj¹Â@$ÏbÍ™7m‘Ý%eHHLœtîß+i—_*ŸûÍo%6)c0èȘèé¤ d&Ë·d®?ÂeÓÈ\œ3)1Ö/x-½`>ƒ÷“a˜(Q”7Öí‘2ŽHE€ê™å{$ò™ÿè¬Ù’Ž"ÛëõŽma™‘ e‘¬Ô`ù,H˜7[v^`ð°…§=* ”"¸Ä‚`± ñK\Pˆ^¬f æY€(ø$–‹½WZ@ˆ_>ƒu퀄ˆÀù N&<¾·£ ‘F`ä‡cä½½TZ›3$êî¯È§o»Nfäâ Ü‹û4š£V\M¸¯“ ¤:m ®NÛˆ^)ºµst»¦Ï«´p155©£^¾—xý͉ß) à¢3*wË´u¿ÇlÁlõF?0˜ÐØÊðÊø½ÌoÁ¡ŒŠÂQv¸šÇû3qRX¸Î}AÂ–ÞØì%k@ÆEð«"só~&K³Íƒ 'pÀ,1øÝ×&FWzxÔ.Ÿìm­—†¤D‰h8(ñó¤ôÜJÉR,¥ýO7,“k.;ü2ˆyR£èœ€i„ކ è å8E$âÂ& GÊÝÕ_íw¤[ pnm”ÞÙ%“ß[' ·=ƒ Óðó³À¸íó n©áßF>Vªh÷ÝÜhöa‹`ƒ½JÉ SP‚PC;Ò0I§•y¼ß˜#{²t\ÅÉŸuR°@â)Hp ƒRóÞl_„Ô¢ÇïÀ–è:ž*u˜Vƒù,áÝ좓=%u’Ÿ/wÞt!â”-Rºh…{-ÜÏæí :¶ ¸gÜÑ®à|t›È|d–ãúƒ±ëò½¶v»¬úo’óëïJ FÃ{æœ&]pçØ™e%Û‘;¤*Ájð8/ÔóØT0é}ìy‚ ÕÇòz ,Úuð±¯@¸ú™y3ë›xœ÷°ë¹7o” ÇýRÄÙæaXfº´mÙ$Ëá­[’5GîýÓFùH^€„y!è)dÌäfŒˆn)©—¼`–|ú† %ÊÄ4 €ô¶.|q|Ń'J zÔ2qr '@ÙÄ}"€aŸo{ëcêR†u7ÖÁ=}ÿ÷5/I æ‰tÁ)ó'TšàFÞƒâë‡LÊD ÀdöÌ/¯²ŒÎ{ Î€ê㦜GŠ;8m׸‡ôæesÔì5ÞËÙŠz ò$8ø,WväÑ Ec‘v,ŰìGÿ)þÒ¬PYõÒ»òÍÇ^’ì„H‰…kK /‚›ãE…•Òõ÷Þ›VÊ•Yéh­+Ÿ3¤É ˆ;° ÆÄ—>á¸ò*['žc åÖiùºÝÌ¡ÁWÕ«ÑÌ×ýö7ò>Æ’fÏcó ×p¨\`¤^€°>–dT&Æü’u±m™˜ƒ{ÉP{aXpQ"ÔÂ…¥¾ddV&çvÝv9¹‰…‘s æE;‹ Ç W±ÉIÒJpü¿_ÈÙ·ÜìÎBvì>(ßùéŸä`yƒLN‹Õ¥XÿpŒŠ Ïï«–›M’/Ýz|Þfè½Á69aq¡¥ª ¾FˆàžYx³º“†Ìg è´H–iÜ×û6ëJ&³‘>6ýíoòâ%—H”Fîœ|éBŒ´»AB“™lm™º÷×€C³TV6*¯ž?2+O;pA ¤Goî­^Ši¾Næ”ZT½@Õ.œ‹Äòá˜ÜÕ°m³œ÷Ì3rÆu×éy­Þ ym f->ü‹?Ë/^Þ!gL˜ í¹Îó‚Ch9fo¾YÚ(Þ|®|üš üë—3³`}¯' $( R}kßýê×Rý¯ß”¼K>, W_. ©ÙrÚµ×@Bp)6ƒR|bö€(¹¾4fÔþnÙ"¼èri);,q˜Á× yŽ$ªS’g-ÃòWyØ9î[{ž£[$ ªÏW¢ ¶ÄôM™BØ<˜›n›ÃþmR™c&v‰Š…ë:ç~4ìÝ)c:î¢K/Õ»ì;t²ð÷Tñýþ¯È-?E.ŠõñÇÕ£øÄ0¼GÜkV¬‘ §¥Ê=Ÿ½ÓœçhÁ*MŽ;@¬ZU¹oŸ<6}:®EÒÏ¿Pr— ²Ç]²úÙäsB–Œùý_‚}ý×2Cmi©<÷/_•ƒP»’—œIR퟈…–R€ Ä({£ÝLM?zî+X°aX.æ‘Ðñqüp[‹ÌÞc-í|ØaËo¥U4z "8ˆ‚cE(¦ÏvÕÖIsI¡\þúë2ç¼óô0Z|÷å7Þþ@nýÞ3’Ÿ-ñðkÆ1UÞPHtVÔ5wÈêâù¯›–ËM7\„ÀñZ´`{çÇ ¤‚xöwòþÛkÔ Mfä&JÜ®7?ôˆäëßåêoÞ?à P ž$_$X ä¥ÿú‰¬½÷IžGt@t5·HT’4¨]H;zŽ, >j4ë/ícH\Ý5]¾K)~‘ŒÌì61 zZÅ,;XØ£: cXú­££V®Z»V ÎDPÈ1Ùü+ü«Týó71‘ê°D,X,m:—€d(þÈ!d|ܦTa*@`÷6øæ¸žt}1t†ÄAzæÝ°_B›+¤¾8T®ßý¶äÍ(ÐY’\w´É¾K¾÷ÿüù3rï3ïËÓS¥ƒ¼6©Dbá QTÛ"[‹å7_»B>võ‡t:´ÍÃ^<Ç öµ°u$SÔÖ1²!â+Å Ø™K:taÀ¬ ±Ÿ¢SÓ0¹¡Ñø¶]ç'Aý,ä "Pïv§ÚºFDJáB¥1Kñ€üá½CR€Ÿž(§5ì–¢ÇÁ´ØyÒ›dZØLx ´S¿Bâ·U¯¸mö ÙŠ1Ǽ i yµ9o¶Ì7ÁA7J(Ò»;6^BKvJkþ²÷ÂÉWî»EÒ1%€åw¿+wÃݶ Îߟ<ñ¬|é‰7åò ƒ<˜ƒyQ-㸠ç̼º±\þéê¹rï7 rL†–ƒ×Œµ,Ìc$iÜÂfÙN„G:ÜÍc&ž/†ÉŽèõc$=>A¾´F¨ƒ­†û…’*«jl® ÉXsqÝžJ9ÔÐ*Ëa¨®<=_–.š.sæH|ÊÞýýïåïŸú”ÄçL•.tßÎÁ\öt04AÂçær¤ ö ‚°¤aM©6 âõßÎA(žh¼¤®ÄDéÚ´^ÚÎú°ìúеÒ+ߺójIAЊ@„O· a~ÿ¿?É]¼.—-Ê:Hò éeêch‡@uo×IzÀž¼ÿFY±t¡VÂæ£;Çá+ౌÁ²Ó%¤¸¡8ÑšLAødîóîúé‹à –ÌÇí«ÓŠÉZ%ðÉÚ»¿H¶í>";ö—Ê^¼xvsNAÆ¥ósåÌÓŠ™ˆ‚©»ýïßöÆjùËùç!.‚þ¤¤ËBŒo¤$mh™HO«nÑ©ÖL)辯9WÄ ½_ì ˆ—O'ºW;>x_bn»CÞË=]ªºC1Wä_¾A£ß |¶5Ü™çƒP·þù¿ß”Kæ¥$\!Œu1à`™9úƒ°H4ê×ﬖ'î»\>õ±KáEaÖ鯢2ÿñHÚÀŠrô» ³÷*ª„ âræ´,Õ¹‡"vÆÊ*OÖÃ&–[?Î2WG:‚9"{°bíν%²¿¨Z*0ŠÜ†‘å4ø+]°xŠœ¾0«%M…úÞÇû˜÷“†älöM?穹óÛ’ò{ÄçEÏÒÖùˆª×õdt·áZ¢Ò„»” ÑPǘXJ~lb¶´cp~âpÒºî=™ýÈÃ’råµ²ê±U• \8~Ú…†ì½øež$wß~º}Ûä_ŸY/MKVu‹ÏÐ2s" Û mðç.L—Û¾ó¼¼µ_¾ùÅOJvVš‚‰×7ß ¬‰ÏTY|•06[ÑçÒ€"%SIDATM‚LEHN¢}(p˜;ƒ÷ÛBë‰7×ÿ¥4"Z;ì?Tªqz÷©DÑW ,)€–0jÂò¹²hîd™ I‘‹ÅsØÚDÕˆôc¾~Æt 7õÒ¸ùÄßþ e¯þU^ºç^Ù¸h‰,ƒ$‰°Ž l\Ï$ ÐoDOñ´³Å}+š†ð¢‘yÚpÌÄú% ?ÿ99ˆÙ‘ˆ5œˆHøt2¯Ú‚„Sþå ÿ 5P¿öæn9+3Ît£|,'Û ~(íÚ!EV.ΔGWï•ç7~_žýÞ­ˆcfÆLÆ›¯zßé8ÊÄ×Áù” ËÉÄÖ/ ±¥èŠ>Þ•Ðð‹ååKb"ÃY@8< 7û64uÂø¾ûŠý…•ˆÈبÉìtÁ€z0crª,˜“«’"  ÷±Mö ³Ý/¸ý6É(È—ß~øÃò:Ž\º|¹Ä`QÍv4H>StÝ"Ø4îc8PÖ‰ §4›„Ññ)èÒ€cç7KIWŒœ÷–ÌôÔéð!Àë×/Épÿx$J(Ú‰ëúƒ{n”Ÿù±$Ã0§ð))âHðiVÞ¹XHÞ³.È–k¯ø…<ôX…|áÖkÌã’1„R£"² glËàTO‰mˆkÙoæyæ9#ùNŠÖƇ÷о›wá…r׎ò«O|Rþþî»råÊs%¦¶Ób  x}ªš!1¸*U'ìŠ(HŽE‡oûVÉ}í5™±t™¼ûÎt»þQ¦MÍ‚J gGt1·Ág*ö Ë:މ΋dìéùyòâ}7Èe_xRÎ;3Sê[·¥æ­™N JÁ¶nYñ±ùâ·WIÞÑý_þG„ŽÖ¼­Ž œûÝ„¥—©N°P¬¨;±ÕbàªY$¶¶Ôøo² n€—Þ ‘]_ß„îWÄ˪¨Õ…pJ+êuIºj´¸D_ý‰¢àþ‘Ÿ›*sf䀹²µ÷)b õII‰Ä‡<ù%hØ„±&æEZgc»^~I~ÿoÿ&«°ÔÛÕç#aXv€ÁëhCЯ ¡è$shÚл¼¥I’É> €J^¶LóºôÃ+ä|öî/”_?ó†Ä ˆÇñ¯2Ï3#ì¬Âx€ÆæyÉ…ËäÞ›·É÷_ØŒÑöØ#PøÐXYp€ÍTR³LÔPª r-[–)<µ^cñ¢‡þís’ލò–$#îæe ¦sÀñ"Ø}Â$}~áÁ—ËIN±èÉÉÆºP?l2 ¹©ºp ãój×}6CüZB»õÙäd+ªJ Äy •å•õÚÓV‹cmôB¢þMû ÑV†óá,F®”; ˜5m:²0¦“ØÇÕ@s= ôv×—}Ùÿû§—% ó1®ºä\e+©µµ„txþñÇ¥ü _KÏ[f¢%b­W¡îAt—0ÍÜÝ»eElW^—X¬}hËÊ_Ûâ>úä ²ñ’â¢Ðød9ÆdæÍÊ×ÖÝ‚…Eã=Ç¢µ« ÃÚ´õù93;Nã†QÝ#“YppÏ·¿ì‘£Zöþ¡zYV,OýçÝ297+  ‘¡ÎÝ †!H(!Øï>0»šŠ°%ªol‘ƽŒš‡iÄxdͪ^Ýû5 áٲХ¡ƒdMXr­Ïf ŽXWCšQlÂÀTTC&ªI\Kƒ ŽCçNˆïH.òÉ”ŽåŽÎΕiXbzT'Úîd ð 8Ó¸ŸÃu5êáŠâNdluv„:tÅØ:UÞ¼ì29«÷úÒ“%k ¶¥§Jæ®­rÖÊ’õä¯%<¿ _(PóH¯¢Òj]»±u_4w:V^"Ûvî—í˜)Èñ®˜Ž%,8lÝí¾»l#ÝÖº€Ùó§äÈC7¯”/>ø²¬˜wŒç#úA¦npP_aé+1ž´xr‚¬9\' nù¾l|⫚ÝHËÒÿúa„vF«ÓÊ’(–@ý3ôï£ôèÎVqOÆ+†,)¯…~Wxî²w‹Q©¾péa2+{¾ôz’Ÿ RÚ;`RP2Ñþá £&RMjBd“F|š¨úÄ|é¼–ÄevÌ›-/ÁÀrЦ/¡=o”T£raOäOÎ)yˆÀ˜ŒröÚ,Ë¡¥C¦`æy¬”€ wÅе™Ò˜m‚„åÁÁ³0‘)uófÙô™匊­7m±4ýí9ÿšËeÊ#KHVv?p0 6o0æA«j4œÌD:Ä`Œ$-%IÎ[5Aû#˜Ìµ@ÙÞs@ÇmráúA‰f“òéaŒâ×Öãâó°üó_¦ÜPÉÁ"²”~^@} ¾ükÝ+1ÐxZVŒl,k”·= ;žÄÚî9‘$Ã[\örðå°°ö[7ñe*AÕ…qÐáÁÀTsºæ¥kh°›R·õ‡[~@ð`…—ΗÈ3F"×uòø§d”l£œè‹Ã)CLª ÷‰h(¬¯MB@gdNÍMÇTª†$µjK£/y°îdDÞs¼SÆ-:0·| ¤ EýYÇé HŸ_’Š|[:|D.¸ñãrÚý#ð©:Š!yJM蔨®Çà#×k]#`c1Ù舓s³¡ºd£AjC|â ¸Éì—h,å– É’ãßM¯òÎ1ÛØ±¯\‘#ïc1ÔLŒ1Šü`à0oj"Þ}9$ÉÂŒXÙ\Ô ÿÊÉŸv´–Ä1«[Ç™‘]˜¬€e¸áT¸ÿ5ÊÃ8Èn`†ò E †%hÃPmc·ûáù²ÙºÆ6-‰=Newªq[Á°—cucÃä甄Å9I¥ Ák(=hKäNJEk˜ªáH£]­!Ë­õt*ÀzŸL˜§;fM $8“e$sóëHÒ2#+S’¾ûÒuÚ’ùŒ‰58øNøˆ:¨oõh¸R @¬Ô´ŒÏ÷ÀD©Q05W °MPU¡ë™Ë^Çb)v×ö§£Þ4Ì/[/öNÍJ–¿ì(—IX7’“·(ƒ[rp˜wÅò¡M”2‚$'AÞÙX*÷}ÿ¿å'ß¹[5¾O›ÿ0‹ã¿lH€i•Y´Ñ4Dòß9 fa*j[e0°óÇ—¤-3jI"„袨º¾AèIÐA,.kŒMýðØ}ælžÀòªÄƒêDéB•.3=A²°î×C§qG@7ÁŽ„Vx„5 üå¶1•Ãwq¬¤º<@èùŸ¾E/Wæ€KûP©º¦òÙ ˜;Cgÿ»q2°´Šhùab[3:¨î2R¾˜s‹ÿÇÞ«±­ŸòÊÍòS+8‚@ãÉX!˪ã}ƒƒ'¹È”•cR%P¯ÍN‘ÇX‡ßçä ·˜þBŒpcP€ØÖx„ùúrs»Se}azœ°‰„…Wk(@Ô ÿ J7ªT¿Ø‚R=ÈHG—_‚d¤qµ,õŒy ¾;õ¾,JûªÜW϶i™Á$ U2õŒv˜†µªn¶ÚåX›ÜJfCäÇ!áûÒÆiÈ}ƺ²ñ®°Á’û^÷5ZNçý¼ùîFyöõCræ|éhÄ2ábÓ *K8€è –”²†MA1º€ç]™-wÞú¿²ô´Ù 1oX´s—Én …DùN\ÂóÙÎP|ЀìÚ0|w\X3zp*Öð&¸¬UÚ!îÔ ܆Рö²Ü÷œðm‡ƒÙ"à\J9.ê–1-ë7èÉÞ–¥ì¿WN_„yõ8nA=P9:6~±µ²O%qLéˆ/´žªI ul홢ªä\Gu)c'\"‹jÆc+á`­”ÿQNþv¢ÿ’VQèzmko—8ÁŒË@$rò¥ýP„ˆì\)‹ôg#Ôkl[ˆŽý´1iÌÇÆdÉ æ-;c¾T`åÝ}ŽÈ¦íû%+y¿üÏ–"yç¯Å"`Ëœh™ƒ©ñ°E¸"0mÛQ¾6Ø•ø7€@ñlChAÃ8­<Ĩ$&¨+@ ó¬.CDó÷çg9œÌ6¿ùé›Èü©z^/0=`¬@ã™’ûD Õ‡hô.Ea‚c$œ’K ÐÑÏv9ö}F/ax\Á†p2&ÛêÅÅFé˜M ëX‡AÔ¬:•…°<|7êIàH“Ô23ëŽÎIYéú9w9æÞ£SåÛe•²÷ÀaÙ¼ý€¼»yŸ<½þˆÈÚã¢<ã.©Q’ßujDÊNY£7 –_imrI":hDÊUzñ™zÁùdP€éh7±»•dåXó±Ûƨ3ç°¦_Õ"‚ÀÙ&Ñ5d @ÃQkö*ÑŽŒOQÞgÀ]À%7aY.&û;Ðõ'Ó1Öu¥]ÅÁO&6+cå]¾G’²nûôkÊN…Á`)T-J+¦±>C3q}õg–oxœ®ïSò²õsáÊ¥rÆ\~„éɇ‹Je÷þò1ºÖî,’7·#Î&ÆÀAçþ4°p>‘(-+ÄÃPÕä0½!šåî½VÎ]¾Û<=ò ºŠPä†rìÄ#XÈð:ï€jžª@€„@aÃù朂ð>Žywx‘bÛÇsüUÐS †z'`G[›™k„X^).E\`§å£ŠƒÖÙ=oeàÒæ(ùÀò‚}ï¸sÉËÉÔÏŠ¥‹´ŒˆVƒÙšTÍJá¦ÏÕ‡Ë`ÃT¢›º®E qJo€¬(V—)‹Ì”%‹æ¨´bþöY#)ý ±™0S>” îN¬ˆI¦=³·Gõk b®#¡œ-»q¬ N±óñq1 ¦†–Y THL$ t¼Pzò¦%Å@ºÌHÍóûßcËc_¿åËØ<F‚Žê»y‘ã'ª© aî?ÙËæá¾g¸ÛÇÈ`ÙŠ &ˆ?~ûÍ¿?;Kÿoc` 8„¦ŠU•#É2 }°ö®xH ªÄlÐBûàD'Ëö×ò“ýeùxÎ|èó‡îeW3ëhëióMÆ*zQ4š²y÷ *°Ó¢³œ 6Ã98ÆŸºz¸Ä/ìBv˜pF!âs2ÆcÑŽºÝò“ýu_à ÷gì„ê«7¹Ÿêm8°Æ@$+Ø9‚¾¯ë¦C}¦zÂì‰ê†ˆ§¿<ƒ@‚Â]r njã¶#.èÄÇ6¦1·ìNÃÊå«胅ÄV˜IÀx“î[éÞ©ûå$Èß½UtÞ Zz3v4¶B«c(²Øs DÒ£Í:slXá™À¤j‹nÚ_@&Èûç`*Ç€a,‰†+§oãLO¸”Ó•‡ÇÛÐÍ›ˆÙ‹š< ¢dðbØ!¨¿-SÓ‹LöØH n%coØ_ vt+w|Ý ®Øì¥^ xé¥EÐoqðÌdÔ…u$C!")¾_Õ¢.tÙ Hâ"Bu®ŒÉÛ*w£~ÒIq£ ôéDÈi°cIÖÀßµ÷ÖÁ4hG¤x©&qðºÕäáCÉàd,ÜvœïeOÖXŒtªeH;?ØQ(S ²Áî@¿‚âuK:æçGc¼…ÉÇ’Þ^^ z Ø®^¸€ŒÅv¶öGü˜ÞÞQ,)0Ф}VM˜k’‘ëruzª—z9.dÛClkÎ@Öý§(g]{÷‘Ê›5j$]L˜}k§d"˜ß+PÃõ#*`ð]ì$øÞÉ %âˆ7½¡™¬-1èÅœ°àZ¿eŸäÄ¡ËØé½"@J$+€Ù1 ʲ9¥y™@¯› >XÄcUÃv ×Ö5ÈöIA² ñ£jÐP…€ÑˆøÂd¯=Vž§Ây ì-v®†eú}‹äù=UE© µKA‚ÁÂT½`‹3ÁÈyÌ⎛7ï1Ÿì]p\)`U²÷6ìÄ|WNWålPc¶ÓÁB'’‚õCLâqOÉ"-< b8â¤þ¶Ý»to_õöYÅC9÷ÃH3Q*6I² Îíè~~ðâ'ÅÉ»aÕ«­ˆÖþüÖRáËN‚Sޤ^¼sÓcBÉøay²£—<€ôÒbÂlY†nmïÕßßø@2ᮂ±e ëƒÂ¢Á¼ °tcWy©/<€ô¥Ç„Øãqɵ3¸8Í·ÿº’Á0j®ÖldWc›LÉN†·°ÍÄS±ü|àÄOŠàß° ` hèX¥¶êÒ+onÀ„vÚâjœ3/‚‡ ÐÙÐ!yˆtÏdŸ¡;Þ—g¤ODàÔÛj,ÛÌ4Có{¯èZòãgÞ‘eSuÖ îÒûx^%IK¸Y€LDŠŒ_™= 2~´·œéö¾á4‡›^|ù]Ù~ AáÌÒËìÕ6œ6ÐíËÅp¼t4<€M“ =bÇ2ããd×Þú&©èWjJž;x¸DnýùK²|V VŽe8hªVÆHç6ƒDçeÆè’kÌÂ3?úÒH_zýžÚ ŽÆy!ë6l×òr1Ow¢êÄž+þþì—‘u3`|˜®]Š#=Tce©3''µ@©;¿SyÛÈD{ûÔæÌ˜,÷ýäºfÁ`C騸S§?>ÿº<ðäû²«À6ªô0À ÈøÇ™vÖ·Ëœ©nºx­”r²8å<€L4pt z~ç©}òëÿý«ÖÀŽu0&2™üµ·ÖËõÿú´,[œ. peg¢D1à0ËhVµm2}j–:–ð¼—úRÀóÅêK ß³Ý¶ÉXUëò[æÊg¾þ'eü민àc°žz£¼øÊ»rÓž“Ó§%H\J ¿q ú=XS±^“û² 'Äq* ãDè@=ƪ@ñp ™å«_ØW)·=¸JþûÏkdñ´LY·»TÖm«”Óç¤HlÃôŠ ¿ü¡ƒ V—âl”É™”nŠÇƒ^êCOÅêCމ±cgΛ‘'r¨IVNO‘¬sþÈê=RÓÒ.Kç¥J+$ùŸ]ºªV)%j{ô ‹X¨méMKÅb§¦‹×ÃÇÑïßÈÑ4™GŒ­0=?G¤½[ç“ÇbŒc¼t£°HQ rSJŠÆØ!\ksgm‹œ9{R¯“¢cßL·"z*Öq#uä02˜‘q B¦£§K%ŸD%Š=U” V-ã6Á¤SkËZeþ¬<=O)c§Ûš+¼o¥“G†‰G« ¥§&ËÇäÈκ60·Q¥¸GEüj÷]âC?8†edeFÔ4&î{é( x*ÖQ$ þ”쉢÷íÒùù"Å-ÊU¢ Ÿ[@ B¤ s@R¦ÇËdJ!&O½2tè÷í¤A&Ê®íª]89Ðþ¦BÉÁ6¬¿•‹þê9,¦ q³ öÇ5‹r%--Y«l¥’îx_~ xñ“b¢m–žNiI <Ù;Õêpú© PP%jN0 ¥ Âޯ勦iˉF±Ñ”×Èh¨÷X(;3M>¹<_öV!Þ&»p ûKÀ¨TA™ ~x^Z»eáÜiZ+‚ ZAW A÷J†W k‡0âùgÎÙÐ(‘*‡á€‚ÐðƒÅ —å.E¸9geHÁÔ\}˜íåÞ“O­«<€Là÷m[þ% g²×HÔÇH «Z™ãF¢tD"¥G庳g"– çdp&ð28m‚þŒeìéùyrÆu¹²­®½YˆyEàã7Ôm¿ý±½QÎ]:Oëg½€uÇû:Š@Ž"ÉÄ9`լĄ8ùÄ…§‰¬©“"T«ô£jí#UèÞ^õJÎI‘sg˜ŠZcfâTû¸–ÔÈq%wàfÕ¬óW X÷ƒh ¤ ±À ¡Þ…O,ÀS´»Nî¿r‰Ð¸gòFÏ• ƒ~y”4ã„U³æÌ*«>3W¶—6J,gV’(t\ôQZl–Ë>´T+ç©WÇ~Ç@ŽM£ ¾‚¡w/—g»õºó J–V³Óki,±¾Ùð\}û]ŸïIá½ ãSÐ_eþ²‹Î‘Û¿ºR6üé°ÌAÞ)JCÜv?¨“ïüóº'=†ÿ:½ù çUP_©RêT¸Ï'ß»÷3RYÛ(Ï>¾e檵¡âð5™7{4.(¨+D… ÁTU ¢2yEh°3²ISs‹¼²z­TÕÔ˹ËN&òU[I3†GœR·z9 _÷@@èØIXõ€WÉS±NÒŸ!¥Á'ß2QªxiäøÿÒUÚn9ÓkhIEND®B`‚concurrent-ruby-1.0.5/doc/logo/concurrent-ruby-logo-300x300.png000066400000000000000000001316761305460430400241200ustar00rootroot00000000000000‰PNG  IHDR,,y}Žu (iCCPICC ProfileH ­–wPT×ÇÏ{Ûm—¥ÃÒ› ½J]ª tDeÙ¥ÃK;ÁD¬H(¢`4ÒbA,X ØÔ,€ŠÊï­Ì$™Ìä¿ß™¹ï~Þyß{æ¾{ÞÌûÐâyiiɨ@Š0SèéÊYÁ!=@È<~Fš‹¿¿/v÷13ˆøÑ]#q­ÿýWZZ“Á@ü1Aª ƒŸ‚qÆnü4Q&ŠÇXsmfš˜õ0f‰° b¼DÌq ,^ËŠ^`Á7Mp Óäé<ž(€šå9Ùü8¬µc¡ Aˆñ=Œùñ¨€#pêàœ8—á:܆^€G0 cð¦`æ!! „‰( jˆ6bˆ˜!6ˆ#âŽø"H8…Ä!B$ ÉC¶!EH)RCꑟ6ä2réC #È$òù„âP:ÊBUPt1jƒº >h0º CÓÑ\4݉–£UèI´½ŒÞFÐaô%: ÇÆ©ãŒp68.΋ʼnpq…¸2\®׎ëÂÝÅ ã^á>â‰x&žƒ7ÂÛã½ð!x>>¿_Œ¯À×á›ñWñwñ#ø)üWƒ L0$ؼ +q„µ„B¡†pŽp0@#̉D6Q—hMô"†‰ë‰ÅÄCÄ&b±8Jœ&‘H $C’ÉÄ#e’ HH'I—Hý¤1Ò2¬F6#{#ÈBòVrùù"¹ŸH0%Œ%¼%›$*%š%ú%^KR$µ%]$WKæJ–Iž•¼#ùJŠ"¥#Å•âIm”ª”j“’š–fJ›JûI§HKŸ¾)=!C’Ñ‘q—ÈäË—¹"3ÊÄ15™\&Ÿ¹YͼÆcYº,oV"«ˆuŠÕÚ’•‘µ •Í‘­”½ ;ÌÆ±uØÞìdv û {ýINEÎE.Fn‡\£\¿Ü¬¼’¼³|Œ|¡|“ü€ü'Ž‚»B’Ân……'ŠxEÅŵЇ¯)¾Rb)Ù+ñ• •Î(=TF• ”•×+WîVžVQUñTIS9 rEå•*[ÕY5Qu¯êEÕI5¦š£Z‚Ú^µKj/8²N2§œs•3¥®¬î¥ž¥~L½G}NCW#Dc«F“ÆMª¦f¬æ^ÍNÍ)-5­eZyZ Zµ)Ú6ÚñÚûµ»´gutuÂt¶ë´èLèÊëzëæê6è>Öcè9é¥ëUéÝÓ'êÛè'éÒï5@ , â * V† †‡ ûÙ..ªZ4dD7r1Ê6j01fûo5n1~½XkqÄâÝ‹»5±4I6©6yd*cºÔt«i»é[33¾Y¥Ù=s†¹‡ù&óVó7†1‡-î[2-—Yn·ì´übem%²j´š´Ö²Ž²>h=dòñ·)¶¹aK°uµÝd{Þö£•]¦Ý»?íì“ìOØO,Ñ]³¤zɨƒ†Ïá˜Ã°#Ç1Êñ¨ã°“ºÏ©Ê陳¦³À¹ÆyÜEß%Ñå¤ËkWW‘ë9×Y®w·Ã çæéVèÖã.ãâ^áþÔCÃ#ΣÁcÊÓÒs½g‡ÁËÇk·×·Š7ß»Þ{j©õÒ K¯úÐ}‚|*|žùøŠ|Û—¡Ë–.Û³ìñríåÂå-~àçí·Ç®ºÿ/Äÿ€Ê€ç¦y]AÌ 5A'‚f‚]ƒK‚…è…d…t†J†F†Ö‡Î†¹…•† ¯X¼bÊÛáŠá á­¤ˆÐˆšˆé•î+÷­‹´Œ,ˆ\¥»*gÕÍÕŠ«“W_X#¹†·æl!*,êDÔgž¯Š7í}0zŠÏåïç¿8 ö &cbJcÆcbKc'ââöÄMÆ;Å—Å¿Jà&T$¼IôJ<’8›ä—T›4Ÿ–Ü”BN‰JiÊ“„WSUSsRûÒ Ó Ò†ÓíÒ÷¥O‰|D5HƪŒÖLöóíÎÒËú.k$Û1»2ûÃÚеgs¤s„9Ýë ÖíX7žë‘ûãzüzþúÎ<õ¼-y#\6ÛˆlŒÞعIsSþ¦±Íž›ë¶P·$mùu«ÉÖÒ­ï·…mkÏWÉßœ?úçw ¢‚¡íöÛ|ÿ>áûžæ;ìøZ((¼UdRTVô¹˜_|ëÓʘ߻³§Äªäð.â.á®ÁÝN»ëJ¥KsKG÷,ÛÓ¼—³·pïû}köÝ,³(;²Ÿº?kÿp¹oyë­»|®ˆ¯¨t­l:¨|pÇÁÙC‚Cý‡7Q9RtäÓÑ„£÷yk®Ò©*;N<ž}üyuhu×6?Ö×(ÖÕ|©Ö×Ö]­·®¯?¡|¢¤mÈj˜<y²÷”Û©ÖF£ÆcM즢Óp:ëô‹Ÿ¢~<ãs¦ó¬ÍÙÆŸµ>xŽy®°i^×<Õß2ÜÞÚ×¶´­³Ý¾ýÜ/ƿԞW?_yAöBÉEêÅü‹ó—r/Mw¤u¼ºwy´sMç£++®Ü»pµçšÏµ×=®_éréºtÃáÆù›v7ÛnÙÜj¹mu»¹Û²ûܯ–¿žë±êi¾c}§µ×¶·½oIßÅ~§þËwÝî^¿ç}ïöÀò¾ÁÁûC‘CÃ÷÷'$?xó0ûáÜ£Í ŸH=){ªü´ê7ýßš†­†/Œ¸t? zöh”?úò÷Œß?å?gÚ|ìúöi|nígÒçò/ú_Ú¿ú|}<Ÿ2?ŸÆñ¾yvEccÞÖ0Â1ïЋù3‰ÏöM,øLŒÅnG<Äñ/^ðußžXÔ:„lðí8Œ mŒéØ,¶ŒÁ΀š›ÿ5°Œ82bÍ;BaÖäÃüü;R;ÀÑüüÜ¡ùù/Õ¸é ^Q¬&J•S÷†ÿŠÿÈNÀÄTäV pHYs%%IR$ðŸiTXtXML:com.adobe.xmp 1470 1470 ³Oú@IDATxì½€^ÇYïýlï]½Ù’%«X–mÙ–»ãÄvbšC*!—„.5Ü |ð¸”K $$ÜË…@ !!øBpÂ'Žkì¸KrQïZ••V[µ½ßÿï™wÞ}wµ²di»Îìž÷œ3gΔgfþç™gžy&kHΗP ¡@B@ìÇ$‹  $p $€•4„„ f Àš1U•d4¡@B°’6P ¡ÀŒ¡@X3¦ª’Œ&H(VÒ $˜1HkÆTU’Ñ„ ÀJÚ@B„3† `͘ªJ2šP ¡@XI˜±HiÌØª»àŒç^ð›É‹ ¦ˆÕà`XQ–•5dYYYž“xž¢l%ÉNÀš"'IŒ«Ac,8ϤÁ+®ñ£÷t‹)¬éV#I~^“ýý€UફàÂE¯l :Њ´™]ç°fW}ÎêÒôõXÿÀ€e‹µÒ_–þ‚‹g8.=Ñ‘““€Ö,l `ÍÂJEBfÕ×7 D2”Ü ¬J‰®¶"dÁYÁi>''úÎFŠ\šeJëÒ¬÷WêÞÞ~—]eg@³"ƒ5”¼OÑ{``È› g\U¿f†ÀzMò$§²÷öõ{VCŽœ»‚Ñ‚ÓJ¡”Ÿt?”b¬úõ^^nÎt(B’‡q¢@XãDÈ$š‰£`Å/pWÀ²*À y\¼†Õ†]–…Ì+q³ƒ `ÍŽzœµ¥¨zzú]wåC¼ˆ?Ž]€V«xŽàŃÍ*fç%\Öli `Í–šœ¥å@vÅÐÎg@pU‚§ÀUùx0ÜUtA‹3Ž™ÅÜÜdÆ0Pcæÿ&€5óëpV— §·Ï¹«(—r@R‰0 ÿ|v0Íy¥ÐJáúX9­„Ëš %¬ÙP‹³¬ ‡ ÜQ/ª rpPi—&­”wÔr÷0)΋`ƒ ¸¬°Òô›Á `ÍàÊ›­YŒROOŸsHQ=!ÈÎyz~à¹2´ã®Dø>ó[LX3¿ge ਂ°=à€ã@u®Ò3ç/ ¥!¯¡a~^ÒÜgzcIjp¦×à,Ë?ð01Œë‘ÀnJ…)§'ºvEQŸ ³†ÃÊ¡é€!Þ›ø¡%ŸV¤ãÌ='€5sënVæÜ¹(• î ®ˆ5>°*­såˆÁËgÏ^èj)>+ÄS˜•ä›õ…JkÖWñÌ,`·äW Ž£ÀôY~>*äqJX–è„ðp]Îyq«÷X4,+/ÑÉAf®KkæÖݬÍ9œ•–J+6 O´të ¦‡£Á‹õ:q¡#ù°%gêoX3µæfq¾‘]¡0Êì tFÝ9Ǥ+ Ëw~àÅ€ÐAM(`•XAêýä4)ÖL¬µYžg¸«¸vsœZx ‰:xA¦Ày }½(‘†õ…îf9!gañÀš…•:“‹Ä°««×õ¦†VŸ ‚ržâ@ëüÀ+ÀK|¾#ÈOṲ̈@X3³Þfm®Qg€Ã©Rú €”•—úõ€W S”y¡Ë۰°0Ï9´YKÄY\°°fqåΤ¢EPAÐ ¦dB \ÅL ÿ²s‚W*CÆo©x€A·k&Q&Ék&ÀʤFr=eˆ ÔÕÝëœU¦í+‚<+Ÿù;'x1ØRV[ÒæòúÄa1 Ébh|2w7½)Öô®ŸK.wȯ†døjp0@  ã,Óé6‚A"‡‚„wÒ2/AÓP*ž>éb%‹¡3 9³®ÀšYõ5+sÁ&è_õNJ åsIa>ÐÁËq+^ €Uæp1ƈ5¼ÜܲT&Š óîj¶¦°f`¥Í¾,äÁ:2& &Únç&èR ´R,žŸÁy¥P*‚çLƒf¼×Õ-9Y‰›qHkÆUÙìÍp—k@ò¥œÙ®räI-Ý</ ‘c4x9À ­6pË£Ò È5J©QÏköRsv–,¬ÙY¯3ªTpººz˜€€&ü N÷ĸð!ãHðª8´"t•4ÞwÀ’à9VA~ÒügTCQf“›i56Ëò 09'$$éêfÁsà'ËÕpsPcCäee¥…áåäwÆP ¬SU³;£€ kýpƒÚOØd9'•b³ÜÇ/€ Ó1pP‹V[uUi”ú-,ȳRÓñÍÖÞÙãÜW·ÒKÜÌ£@²¨jæÕÙ¬Ìq·†ƒ²Y4ÁtŃå4˜êE8) uÙ’š4X¥9ÄŽ —ÌŠ^ýýÁ*‰›YHkfÕ׬ËmZàÞÝã–@=#Óðå0x9 „¼Šcéâ aøÇá#H€‹žί´qbhÔ£÷…#|âfÀšõ4+sq‚³[h|„pL€@â\T¸ÐMüP+åÜ'niþ¼J«ª ÃÀPg’+€–¹Â蜚2º¯+Œ99ó½ÄgzQ ¬éU—Vn"9t¯ÜBƒÐÂ{¸Æ/tHÙ³°¼¬ÈˆkÂ9¸ùÕÙ~Bz5’q1Dì”EpÀ\âf¡ûL¨¥YžGL¾XÀ†–Î’”¼äøùF©º÷uÏ ñÄ…åædIÈ^“±ýkOä²Pw¨®,q®ŽâðÑK~¦5kZWÏ¥‘9T °¢>ùP054 àW”Éu…¡ ÜÕÜšr+- ª QvnŠ.«J€†ž‰àýÜ4›>!Àš>uqÉå$‚ 3„XÅ ŽÂŸ u=¼jË rmždWþcÈót1ÍÂÂéiå¥íc{8yž $Á&” `M(y“Èχ]š!€s’ò§p üñc4xb0ÀmÞÜ C¿ ¨Š t>iÅ0 KJ g=“ó´§@XÓ¾Šfg3™¢ÎhÃ]úVp:Üy>âšäÁþ‚…â®æÎIÙ[ Ð:LÌDÎêB@ï“M^» $B÷‹ ^òêÅPÀy#ޡǸ+ìÂ&ý"#€D÷(—ÎSîÜ©xþ:³“§¥;Qëu¾šŸ" $€5E„O’ `dX¸!8,¿bù}˜ä:[`ÅÓÜ\qW5»‚;ºÀ"N”IƒIQvn-,ªVÄ$›¸iF°¦Y…\jÙéÕš>,'<̺+"^ Ç ljp‹TIöôzg=Š?슊†7VÍ¿ø|ÄKÉÍ”S ¬)¯‚K;è_!—ÊË“e…(Žâ"´tÍp®gîÜr'Ø…JN$×rℵŸ8iƒ]]–WXheóæZÙ¢E ! ’  é '?SJ°¦”ü—nâ‘›ñ]r4C˜—äViŠÀR Qea:¦WKp*d6¦²¼$äõ_QaÈ7ÔÖj/ýköØ'þÂJvo3x6x­òUëmùÏ}Юøé÷YÞœ¹j \½~JOÔ `Me“xÏ‹>Cˆ®•g¬@GÀ%\¢î€e…9Õe)£|ò¿SãÎÖ»í9;ö¹?°ã»kíÊŠy–SPbCõ­kï6ký»/Z]EUÜþ&«X³Öó‘üL $€5=êá’Í–3SB+†`€SÀ¢aá÷Àà€åkF¯F€…»á`|§þÀA{â?b7}ôݶá×ÿ§u½¸Çvï¶üÖ+½ê~+”5ÒY~hih°g®ºÓÞ°ý)[°fµëe‰ÓKÜÔR ¬©¥ÿ%™z˜uWi¢¼Ý 4ÀqaÕ“ÆUsJd!´è‚èÁŠ—wÿà)k>yÐzžÑúNwZyn¥eåØœ…eVµñJÛ½ë¨ü?k9×\e;lÁæ°1Ö‘~Ü_JkÜIšDxN €Db£Ø­4 ©Âʨ#YŠ‹aõ³@Æš?,,ÄÝ _ïpÐìJ“óÂuël—âÝúõï[[övë“÷Ǧ@XcÓ%ñ + ˜Eµ†P\Æ&:›E\èp0#rYܯºývûñ;¬ìM÷Xöæç­t^5f[ÿÊyÖ´åE»ìý°÷~á ¶äÊ+°Šœ&ç°¦IE\ŠÙ@~ÅBæNádWÐCxe9̤k-ÒY²v­½ãŸþÑ.ÿ…_´¥©ª’ëxi‹Ýöÿü†½í/>mU‹ùP4LdÆ’\O%ÖTRÿOÛu°HT¢… ÚSgî]ådçH~5>ÃAÈíC;¸7Å]½p¡Ýõ§Ÿ°ƒ+–[ãÇ>f÷þùŸÛí¿ð –UTäiÇ} y/qÓƒ `Mz¸¤råAÝâ°´ë?´&+X„ò2\¦c\Ø&ç¶Z%ee¶ú#±ò›o¶Å’o%`5®”÷ÈÀw’&ž/à°€«8~O~b·,,ƒækÙ.Ýp¸‹»Ê’ΜKr–I®…#/ guqtÈ·ÖDR7‰û 8ÖoM@Khá š‰ ¡ÑnÇÅ÷üf-ÒT~08Þ 8ŽYM¢+iSBfÿ˜%Äáù ËÐúÂB™0fýà„;$ëWâ¦=’ZšöU4;3ˆþU6ž+à¨\oN‡9;——ZIq0%3áT ©´'<­$ ¦@XLºäÅ ¡@€#öìOÛSüU¾ 8ô7ЯY<ɯ0°çnô ¼ºÜwÀš\z'©¥(àJ£%œ EùC~ÅB㸛3Ï*N¨S‘»›Ðt’È/Š `]ù’—_/"ðX,»ÁùP Ö+Åâ ß*,ÌÓpäWžƒ 7ó|¤î“Óô¤@XÓ³^f}®ÐÁrÀ‚³GÖ†#ê åZŽSR¸È—]XšçóVþ‡¼L‚¸ì|²”„ƒ ‡5Q¯‰¡@æ««G†û”L8Š,ÇÁ³ª"˜BƲàÌÌãÄP!‰õb(ÖÅP/y÷‚(À°G[{988P°B²Îbè¼¼œI•_ " O‡ï“«éF°¦[\ùa3Ô`¸/ÌÌ ÛÁ ÛЗç[ij+¯É$‡›¹A!,qÓ– `MÛª™½cYNö#t±šî©á3„Ü µü¤;e(. šô´“Ï‹ `™’@ãIv{îqK£Ã± ²|ˆ`TJ~åÖbQH?râ®Ð¨j1q©$1_ Àºê%ï^ú¤åHÎ]Á^î†i*Ò{Êsà˜pX“Hð H*Qk¸¢%¯\,t­²a8ˆI—^ì]ž²\ÁõL–°°pš¸éK„Ú¾u3ks†üŠa!l•æåRgÖX‘4Üã‚çÉ+ˆúVÂeAééÀšžõ2«sÅpÅÍXé”±S¨4`¡!-pA&Ñ¹Ü Àb@nr¤“XМTX3¸òfZÖ£kõö8 (1ì_Åp“ WAÀX¹ò*ÄMkÚ5±°¦]•ÌÎ eö}>GQ‘Ï \Ó]çÊ”À}*4Îaè`®†g 3s=;ëe¦•*¬™Vc35¿©aÙ^©•8>[˜+ÛW“i¡a4)#gÇÐ4qÓ“ `MÏz™Õ¹r-w•sUnj4ȯ $pŸ ÷LbÃe¹|Í='{Pš™“äz, $€5U¿ £ ÕÓÓï»â0à ŒWØá¹TædÒ÷ ËÁ¹#Fß]‚Wç&Ö$‡Hk’ ~©'‡|¨WBw*Ê­.·U^”ÞÒkªèݰ?e 5Á«©ª…³§›ÖÙi“<™ øÂgÖ ¢Ò(³q £QŽäJQþ¹¢Ì–ª=ë7=)Öô¬—Y›+4É¢Âl¸ë ·¥G;ÃÄÉænH`ej»Gÿð4ùj LÊÒœ8Eä96ƒÐ,tÒDÙë±oMvC;'‰ï…R€áV\G9,¸+fËJã–ôSPÓ©$Y.DQf¼¼©&îB«{Üß›PÀ¨¨x—U¨A„søšÆÆJ;ñ/*B–Sh,9Z`Æ9Æj7Sдǽ.¥ûµß ûòåaá3!wA~®OÖ„¯Ap¶©gØ —•‰æ¤…½¹&ýÑ„Ö0PX)°JU« Uœz®†ááRY)¾x¼°ñ“›í_ã³Xè '6é-é<„{áàãÃŒzt»–äM… ¬t¾0ÑÖØu®//mS>(¹˜b L`¬Ô@‡Á*pV^~µ^_¥bát¹²þÁ—–z¤g4*+ûóeN“º|S¯†€úõ؈S‚’¸©§mŠú£Ž©K¬LFû ´5ýT»凥9Vâ¦Æ°Î¬Fq]™ÃFç´pÑ q7B4îùúõ÷Y·Û÷‡¾;p¾À«  × Õèóòʼn À¤VÑ¥ãËð‹ÏFœ•aCꎟ¦&ó#ht7½}}ª?+[4-†_å%E»ä\`äãð>ê>™)bN@ã XÞÉcg÷Æ:½û§@Ég„F?ówàˆR@Ÿû;#ý# sÁ­ÈEºº´ ‹ÞÃ?_8bpÎÏ˃ÉJˈCAÝ Ã'ø2Lñ#&žØ–*®H ;cV¦_*€¶…€{ÐJÅa »ÌZöØ«&™CŽ•¸éGq¬Ðéé÷RT½n†‡ÒXÏäÇaãó1À*<ÇüG*ËFñËH˜.-®m€ ¶YŽ"Ð-*Ê÷9‹‹ ,_÷£»ïE¹˜õ÷Zgc“564Z~a¡UÌ™k…å¬H“wAèÓÇe@Ã|Y–¡ÒmÀë0+=C8¢.(…‹{)´ÉÕÜ^—âJêúâ:Îo+`´?eÔÏ<€LxF»=Xa:)&‚ñÉËÓða(„‘à !‹ÈËÍ V-åÑÑÑc=.°VTÀ‹¯* µëôi«{þ+íi¶]_ÿW{ü¾n‹V¬¶¹×_gË~ø>[yß[¬lÁR’S"gÀž?H~Æ¢@ªãcm4ì=è5êö°r¤Òöõêdú9‡%ñr6\òišLêŸ;­q,fô¨æ4`X9.@;Xy1J¬²GŽU!ébqTȵ²ÕÜo Ü4,[–¯=ÃÉ¢Bënm²ïþÆoYÉç?g7}寬¹?Ç´€Ärìµö»mÇ¿ý«Õ_·ÉnøÂç¬æÚk“ï¹X ;>:X¾“x¯áv~^¶ê+lKw ßÌ3®ì¬ìak2OÒ:'ưH/Ã-ÈEqV)!®V\grV¤‰ ¿ª¢ØæÍ-w;þ™pñÆ(ÝšÌéjÞÅÿÐþývX`uçu«¬g×v[r÷=Ö_i¯l³vXqU™õm}ÞŽþÉ[Õßý­e—Wªã%2­LŸí:„zÅa¥ªÐƒc¡$ÓÊhfà³E8þ(IæC–¸éGq,Ø{fXÂn(€I ¼TvÀ!ȳtÍ÷ñ¹sccø+@&XÅðaÈË)ÓºÚ.œ_é&^ÿNRcМ§¼—É!-Xy…-ý±·Úo=`ÛôxÅ^«™·ØJ×/·ÂŸøQëhê´‚cG­ìÚ5VûíoÙeïxeI˜oŒd¯1(‡„¡ŽTw}¸+L˸«Âƈg¼½2“…#O˰”Pª5w’I|@ ™«G/ Ì@Vá D¥ËãbÀ*“S‹ª´$üžªÊ/~ü2a&mð`wÅ;eÕ5võÿe;¨gõ…eVÿÐ÷ìä?}цv¼jÙíMÖÜ~ÚzOÕ[ó‘Z{ò'ßou»veF™\¿èñ)×+a6·ÞDw>n¥% ß`­Îâû“q†Ã‚¤¹ËÈÿd¤Ÿ¤qv Œ;‡ERÌØåKª« »ÝãV´ryZÀ®tàÒ,Ö¡!¯ î›üª;î°+ã7mߟ~ÂòoºÅzê›ìàá6kú½OYn^µu¯Xd]ßþ¶½ª„n€~yPú€^â^‹ôø@#LË@.ÇÑN¼Dœùtq´__O(a[¶±<'qÓ…ÖJÔ%[:oΊÙ@5b¦Pº?¬Raxgœ.3œË7˜›Ÿo7}ð¶PµS³}¯uÉ ÜÑUÖ¾öjkík²½»·ÙÉ•«íÍ_ü¢­Ø¸Ñë¼"?ãÝÖ)K–}>=λg¢{-Ç{¼?ݺt°§çù®%$—ã ¤o‘·öŽnЂdKÞ£»˜|Ç8¦ó™ºc–— €¡7¼ñD1¦¤ ´0}ŒÔ^‘½&Ö”TÂk&:aB÷Ñ©òÕª„%¸Äàò3•yÊŸ<¬†–ZËr³»ÍR ’»P°ò—ãû©¼Eq ÊD—ø<ÎÌ€KNS)Õ Ö4¢ãÓ$ðnhj÷åBqú<æ;Ðà<"žaA¨¿¸ä…úÈ Ô¦ƒY™LRÒV©“~&7­(0i€E¥ãVW•øbd¬L:èD€¢—Ê Â=OFƒUèäðx•¯b}Ãië’,+Æãú#p@"ˆ\h4™ïÁ?ÀY¡3V­[^ eŸl±Sm鼃‹¼2#™Á×pÄ.ÃR¨gäD…ùi¥ÑXæ©."@g÷jHÏ60Õe›ééO`ÑYé||½jªË¬X¦_à´hÄ4ÞN#ô¬x¦÷ÎVþ’ÇËpM; kØUw¢Ùëdº62ŠŠc8È.1 æU:xQîõ­vøhƒ55·§5­¼Â+N§Ôë)Ÿ™u‚#öaV ™É~™©O'ç€åV¬é”·K=/“ÚRh§tXÄœ͸Éa|4 “+€ê<ÀЏ8%¼åÌŒ\Cãi«(/vP$Žé\©¾êùe‘{js0\jÇÕªãTS›ÛóªTYJµ24‹eq€WË÷3¥ûÌ›s-ˆ‚þËr‚:Êô)tåeD‰›^˜TÀ¢ètPÀ…F1W EGljîHSeˆ¥ü‘|^‹³"ŽVÜÐÈpµGNù–ç ¿¦#h‘GèeåtuU©†Œ¥. oni·#ÇF—ËÀÄ™fÕt-_,[æ™Ud“o #‹±<ñœùÎT\³–PÚé ‚©ÈÃT¥I[tGçÂA‹p5-~'°R4p@‚5ê È¶êOvA'&~éuƒñòÕ¦ÑwÊxß¡Ã'mõª%~?Ý;ufƒ fØ8ç`˜Ëìj“Àëä©VW²¬®.• âÔ,cx›2{¼;]Š˜(ùâÈ/uZiTu>]ºòP'¦+=_+_7Þ&F† ^)0Õ^è;éæ3ª!…öâJ_g„Ÿ¬Í”ņ0¡‹™Á=°°îd«ëéZpL0[„¢a‡Ð ýQgE˜”Ÿ¾Ø<Ï•0!vQQ½]¶t^-…IW†¿1=b;¡Qаb°@V(0›Ãðù”&:é`U#N¬Zò@†Œ™ &4¨é^Ô#\ïÕ1½SUvä| 9::»¸¯cuMV&áý¼9þ ¯áwÉ`¾ ÌêyGµÇYàåR ÀêëtsQ^ˆÎíµ…|ãÇd*ò ½hž¨ãXÏ1?™ý)úqFY···W³Ð=2HУH·D]âÞ{üÜ®öÔ§EélÒ©Í]èK>Û®]_P²á bj­mEy© Úa™&‹*üžÝ«FãDu™Á«¹ÿxýL)`e‚>ÎeKæØqÍô5JG)4œð5&,a2eVi¿gEçôo]¡R÷8áñ¢;fºÓý:6Jo45Ì —,+´E «­Qœä‰úÛµ÷˜+ªÂ‰^¥Z]ÚPfCš¨ft~T¤ €ë/ò9,¯²Õó‹lC9ˆËGÎaäÚ„ L85t‚Þ˜õÁÉÉ“†TP?¡"Ô-0„ÚÚ:¬åt»ä§5qÓ*UŸ«olµ:}ÜN¨Oíoì°ý­=f­RÿiÓò±>q¼}J óº¸B¥¢:2Åß=:ÐwÆòŠC¦žÏE./²;®¨¶×,±7¬²kׯ²+–/KÇœ¨¾6m‹z È³–.®qK'N6»64~4ða°í Ÿh9š³òÊaN•ðuÙ±ë¨mX™&Š!G÷+”;pMhÒ/”5‰ùRh‘Œ«®¾Ùj%¤?t¤Áeƒ¨LÀ‘ù¦©†Nùq™ñ¹Ç$üPW>$è@ 5–ùÓ`/ÂÑEÖ‘JÀa‘ß`¡ºÉsœ]¬xNƒ“'52=LóttjY€Ô 54Û‰SÍvìD£>ÞhûŽ·Ø'$ ®ï2Ùø€S¦ÙƒEÚˆEæÃçäØêŠ|Ë«Ö̳¢‘ŒŠH)áåÈ^^q˜)?Fô½úi”Aƒ'÷5Ú“5;õ˜Ù•åö›?½É>ðîûlõÊ˽}ÑÔÆÀ׋¢à´,JAeA$ÎóçVˆÀyÞYØÌŽÏîRŽS+'³î!tJcCï‹]t¶í¬µk®ºLr­‚t!ÔÌû`Cyqp¢È²8ÚÛ»Ôˆ[í¸†ŠÇO´h¸X(]¯ çºÊ%¨O¿Ë‹¼/Zì<˜G}T¤‹Vž>DlÃæn²2qE£“A'8,Øóxç\Ab]e†#XñÌsÂL-­í’ŶØIÙe;v¢Áj7ØAÓ®£-ö‰v’X¸ "qzÊgÊKñܹ-5~Â9y!´nÂW?À à⺀ض©#¿²] %N ¹Ï2IxkfýÆüS÷ WêXº¨ÆgªïÞ['A}½ÔHÊ#Cq×¹ˆ,—ù¾{Lгn¬Ñ£'^ˆ¦“¥ÑXlèˆ 6ì%Ÿâ¼íñ¢ª2ǺàÑ¡¡\Ss«†öMv´î”8äz; Õœ=Çšló‰6kføÝ $Ç,ε%Åyvë"qΗiÿENZýjï} ÃÑ­™XÔƒèÞ?èº ­$Ô·?‘'¥ V<Îe¼ áCä™ûn[4¤ì×¹@ uË;—Û3ß8jÿ̿ڿþïIÆUîôc¤3^nÚKõ#¯fÉV®XhÇÕñXÂBE¤wÁlü;C¥ð~&XAZ ±¡MÝÜÚa/o?l×^}¹wÞ;[C"ž™âbT¹P&è¶LòÀE «¬¡¡ÍŽêë\'úQ'¨Ôf‹i(©ÉˆÌFè‹ñùÍxþ(z;uÆÂg¶[cFwº9ʲ¡óå°¼ :ùý= ¾ é"2aÒÜ"y’ÀéȱzÛø„í9\o»Ž4Ús§d [Úõ¹Y¶´0תÄ9­­*´‚¹%)„ˆ ºlpL=2㜢'í\)Ó<-BóŠûñLÞø…§éì¤ÃŽå?2Ô™wćU%x¹¡Þî¦.[v÷ûÞ÷©l'°ÒùÌ×/ÈgZV, •NC –,žãv“ÕÖû.ÏÞÐEeo(© á½Ñ`å5¥Ï¬1[€¡¤úÒ+‡f§5L/®hF.ÐíÔ"s5iq8À¿å•ë:[,ØÂÕj\AÎ_Îx?ÞÇÙ7QUGÃÑé XÈᦠ$ Ààšùgæ0à@@yÄ‘ Dn¿Ž¡‘Ÿ"oBÖtôø); pÚ}ð„½z°Þž>®µ£½Z¢–c+Ä1UJÆtÇ‚²LЇh‘Ùú̪À '5Ò )\zvN×þNL|ÏPpdhÇeÅ9é|w6¦akYÄZœÑg ËAKpO¡ä‡€Ê _¹ð5á{ã‰gŠ’{¸{Ð,{ÙüÊAÛ¸a¹ÏRŽøg“‹å <”¡ ÇòË:]-úí{ŽÛ¾C§lfáÆàº2µÏc‡òx‡ òŽ˜¯3†gu KÝp©÷Gøí&#ÓéÚÍð;Ûk€Ã¸«¸e}H6䇸}‡ePÄ…º@c“6ã=Ù 1ÆIÛ{°Îv œ^©m¶—‘7‰k[_–os´éÆ—VhÏL‰7T@ÒSâc‹@šãÏ9R@)9(¸ÏFežüödÂn¡ó%z9Y×nwnZ(¹éœ;šŸoæ¦=`QáÎ7äò§5«Û1ém!ÛꢳÍ+— öŠã¬‹ °Ò_-†",0~~Ë>»þš3zöð\ÚŠ@€¢ ´DøÎqÙÒ¹ê\Ív¨¶ÁÕL“ +K¤.±XG¦AD§§¢ˆuq®tÇzîqPGúƒÃbR…àèâóØÀI+ 41ÐE6þXo(©¸Òeʈ›thÄ —™ÔàžÚÁ=í9$Jà¿Kr§: ¡kdÈqÀiIe¡­Ð°ÇÔ'åÔè`jÈ—·QÚ­œ§ÃO¸ ÏüÉôû!‹|vò©Ëí-öþÿ÷m6w†Å/®½x£~f`Å<Ó°¨XÎ 0ï—Öwkk§@‹†OÇ _¨`%ŠÒB£æ´Z¤9þÜæ}võ˥‡ž–G1¢QÆ´gú9t€‘ÀÅÂã+._`K$ ?¡a"œk]ýiéî´Ùžu¶HÃÅËDç9ÒëbÂ#ºÐéã(úžûLçgBä1ô+ i28Ü Ðˆ1ò^O·>N}ÖßÕ¥ë ^üㆶ9šªW>áŽr ,¯°PÖ_óý:;eb,pòò¤€B/{û wå”sÀ@8@ÕŠ{Úsà¸ív×6Z­d7}ÊO™l{Uhh·J3gëR³ÚpOÈ›º¤F¯(.IǶŸÏ”3ÔA~µT3”۴ئw¬²¹÷6Ï>u4žw"Q€E†cÅr†ذî2mÅuÒŽoâ±€Kr4g¥Á*3(št‘ü¤MV@ŸyNk¹Ï¢aÓ Yä¼û¥@!–ÓvÅm-^T­)t—„ÀǤ±c÷qŸ]D-…Þ…ó«Ýa¤ Ãâ‹÷ç$“ç ú¤fr¬¾ÍrÐ@D7¨Ý–»ÚÚ¬£±ÉÚëë­íäIk¯«³N]Ç묯^uÝ ØvÈ{NÆ×üìùÐ_úìÂù–»ö2Ë[´ÀòæÔXá¢EV¼`¾/Zh%óç[ɼyV\]m…hžÿQ@ ¹×;%€:n;ö±]¨]‡5yÑÒ ®Y…ã%Ö®Z ù_êý Í?dÝ)-yG:e^A>÷žë×÷C#н¾7'&4ù¬æ‰ÝÒûÚÑmŸþÂ{5¬ñ2fÖíxå KÄ›N4x]劎—Nžj±}ÒjgYr* ð¡ø@$ÝX`Áñ§³‰èúú14Ù¸ár ‡j<™q»Ç,þ‰M @T/zª=å‚V©„ 35Gò¯eRê]*®‹Et£ßþñL|À [vÚïýõwìÚ5‹lކž·_w…­¹l®:|ØNíÛg ;vZËÖ—¬S»oc‰Š:¤SBD~–¿6½ÍVg PØ}ÛóMeJÈ-ŽfHg“†· g{Äã">4¿Šï~³•]U^u•U®Zeå—-³2Y_vŽmÙ¶Ïvï:.0Ê—ŠÁ û‡‡¶œò¬LÜS©ÎùJ—ŒÑ¾à"˜Gm-ch§.zFÚЀ,rÇ™gúf†0©3ñOówÒáã{< ÿ ËT/y¨ ¹WÊ/)ñÆ>¦‘™˜?–~òï¯éAÌ+a( ®W‘VˆùúíûN­ýÿñ öî·Þëψ;¶'÷§Ÿ XÐ “0]²Ò°O_ÁcZÚº#”ç‹G€Æ„¥ZÂu¸w?u&×R­]»n©«QŒŽ›ûÙî}qºupLn „ö|³†ÞLaW”jYm—/›'…ÔJÑ:„ë}ü8¨ýµ'í¹¶Û¢RÉ›OYû¡}vü‘Ǭõᇼ³$…: æ-µ<}¥³4œs΄Þ&î‹^—%@ò³Þ Õ¬Ðwüš¯ók:3“%ðÉ’P? õô‚Àl¨µÍ†íö4ñb˜Q|óVõC÷ZÉú«­1¿ÔúkX_N¡ƒì·ÞlW,ªT<ÒÍbˆ'í GÙèìÃí*ÜÓæðKý Ã…6ˆGà Ÿ­žÚ(`á@©3yp Ñµ‚¸szsÅû)ÿñ,RëJWKF—'¢î}ð°}î˰Ÿù©·z=Ä”ghœf<`EzP9±£CYr¿†0¦Í©ÌAI8Äg¯L¯P@˜FÞУåk¯\dWk¨ WoLk¶Ÿ)3.Ò“kls1ô> áb³d »±ºH*+.Ÿ/!}t‡% X¥õÆ8z::l÷–­¶ï©'­á…g­éß¿i³fésÑe+-¿ºÒ‡UÙ¢¶ÖÅeI^•¥8²°Uìÿ Œ3yJßs#§Ç~„ëÔ»ø©<<óx4.Ëf(ªÙfä[(ˆfµ«<;_rPÈW°Êw¾ÝJn¾ÕŠ®¿ÉšÊªíÑWØ£ÏºV[4GÚºŽøzRÃ>χ~8Gç¢t!C”;áÈúÕÙQðôyÆð:£yf C,ÂG¥£Í1m‘a(Ü b—fS®ÐF‘ öHÑ•xI›‹·qE5ž€EÎ:•Æ| ‡;Uþcß;.°zŸ}ø½÷û‡k"äVáwÖÅÉv¨Ù½ï¸/¤†ˆëÕ.F€U¸÷—"|X©¾\2fQÀôLƒô—ÎÏXÀuút‡@ë¤Ov4J§ÎȬëÜšRWT½\æ|ØÖ-î.Ô}ú´í~æ{öŸ¿b‡¿üNC8©‚ÒV ûê-C¤ÔÿR1tH(þÍ¡<ð ÆzîÏRaCˆ–'øèâf«®¥1¤á¥ÀK ”£á¥9x½ìœ`Zõñß²ò·üž³Ð¶ì?n=²Å^:Ðh¥ù¶¨²Ø;)¶ßáº8wiW¨NqqíêÌtènë‡ÑQCb%Æ—J8_,d¨ù:‰~X°`ØÍ¦4z§S²>8D;$#:­™ÇýÖÚ¡•ÊJGH‚éË‘«Õ R—(ηBÅhuè9€Æ°Y-–€}[³Ö+>Ùd_ùú‡ì=o³Ót¢ÁÊëNÄif ¥¡¢h–f‡µÄa·ZGg¯ƒ¤Œ&*ü `åoéÝ™á˜'‹¨7m\•–×&Æë‘_"?±‰d–¥N5•¿OЧÛkX<¿ÜW\¾l ö«s=ýŒmþ›¿±Ýÿò/¾à?g†zš¹Cé7[:K åò) ÛœkÝÕýä§Œ*"®¨—ÌÒSÅ XÂOKp¥?q$ª[÷hå0{)Î.K³‚Cv\ׂ¿ø´Í{绬C×Ö—vÚcO¾bßÙZkR ÀWK…¡FÃå*-)«˜UÈìO¥fŸËJŠÜÂF©Î’‹a²³:õÑCãE\ã ySˆ#Óp˜VÌ¿tèCÌ:Ãf kOÉ Ãñ“M¾ŒgËÁS¶u«`¶¸ØnÖL%í’φöN¤þïqÓé½ÍÇs|–º‡K‹Ïyýº•%[¤2nÝϾ YöÝÿýa{ó]7ë.rüg=âQ?³ŠÃÊ,ÄŽŒÎµkïqéËÈܰ¾bÛëj-U1Ã5Feñ.œ›elÚ¸Ò§þ‰?3ÞÌô.•kÊR¸N-5Ù½ï˜[FÝtÃjº´©µÝ_ø¼íþ½?0-ѵ¾k¯³6S¯¸—l-wÉÑWš!N):– ëþŠýB‹üx¸nÒ<Ë#ü'ÂŽ Ÿnñ.\æC.©BdÉ8bO¯ lÉŠ×o°+¾ðwVvã&ÿ }ÿ©->8_k4ËÊL¥Å¾0 E¦(O|~c´wtÊ"íiiÓ×ÛÎ=‡íñwÛ¿<|À¹¯®¨p`ïV=å Mž~þ€%æQœ¡Ö©êCóʃuvû;.³¿úíÚ†«Vy‰à²£sŠ8"ÊY X”Ò;—΀ý¬VЦÛw×ßã츼ÓZÆN…¡*ý=]#¸eyÌuW_fW­Y‚e€¡{\‚?™´Í,~ÃóÏÚÁý²5~ÿEë¾ñzkSco©oé¥~׆Ü“R+$> g%þ…èpñÀ‡ú !Âs~ϰx×J1éû‘Šƒgä ù–BrçTÛÐSO1ßfK¿ù-[ðc?Jrb-4=,» žgþB¯H³3Ÿ¾~Útü ~»EÜ×î}‡í[ß{Þþè_^°â9ù¶¾ªØÚFªœž½ÄYÕÎÞöiÿáž+5«é[¸ÇF Gë:a¿þûwÙGî]RqA“2QŠt’ܬ¬HC*&ÙÖŽ=Gí°´»©<N½UsVTÿ~è=E‚P´[ò„+W,°4Ï^z¼ƒ‹ñúÍ¥ôZꈡÀÉDz#¿þë僧îùk­¹±ÑN‹k©Ú$‡a<€C)¦X¢Ý0§Åsªgލ‡ÌRÓO†Cà3€¥4¤eHõE •Ý*U‰]ÛmÉcOØœ»î´žcû,«¸Üò«æ9-h;©Œy~ÉÓDµ‘Øã™t2ÓbùüÖíö‡ýïöàŽzÛ´´ÜN ´ä“MÞ °èÿ T •în•B¨uÚ—ÿè]ö®{“kŽN²N´Ëù=¹‰Ndªã‡°±R‘c±ì¤\v¢°ÞІ9fMÃÒR ¸VpV>E«gÖP¬¬©*s™DŒ7³‘LuY'%ýX‘V,{Ãsß·Ÿù9M±­Ó´ß\ë=ÕàJ…½ê4þz€ñ/Õ‰ż“4£ý#S\éû1+„Î KŠºO=ðëÔ}¸wE˜ôst¯öË©©²¬£G¬{ïA+¹û zØoÝ{^–>X¡å•ë™"ò8¼\¼ÏÝÄ8â}ÐÎ#¢¥‹çÛ6­u]·wÕÛrYÀüLÌV Ë™œrf¶²F:gÜoûfýð¯°ùóÿj÷½é—·EyÕD–MIé"=æÃÙä+6Êo¼m­]µH”fw$¯¢#á¼Òá…SUO±‘…×ì.ýG·Ú^ òqÄËþ’q)°ìhµþSµ^ìÎÚÖøïŸµì¹«-«P ¥mA*Õyiù±ƒŒ¦Sšrô©ÇißtçýÞdÞ‡ÜèW»¡†&˾ívë{ú k}ìqé…i˜Õ×c-O<`í{¶…l©°±Mf>I‹öH;æLh»KÍ·ßþåwÛ2­i¬×$A‘fÇÊ͘•¬|Uw}ÿ”}úoÞj_úÔ׌ùZ/JWMlL]Ê“]“©ôBEPÂúèÆ +ì®[×Ú\mÕ®™D¶¡ò¾£ŸÀ.G ò®"i:æÑ§¶ÛÓÏít½-¸39:ó¬uÈ+Du„¾úcÖö½¯Xï®ç¬ïÄAkyá1GúSEåê¼²J ™¯è\ôäïL¨•¢YéÂ@üÌðgóÉx5d´ßùT ïŒ~/!D"éüÖ2Òq:ðŒõiØ+t¶Á¾^kxàóÖ¼ùÅÛYŠcw)ø!P·zåeö«?¾ÉïlµBÍDÆrò "(3”kóÇìÎ+æØ÷¿ûQûÕŸû ­p¨tà£O–p<åÎ--ë­îçõ¨Š¤¨Ôóª|˜·G\Ó¶G]áÛY|©R §‘ÑF陯B=IL1ðÛ¦5Z®yäbœ3œD#³/:ñ—¥ŽÙ]{Èšÿþ¥ØyÌlÓYÑ!ØË.®°–6ïÐôhLgÀ…s¼ ~áW=%¥šé l„ÁãHßó¹£#Ž•Ò¹Þó½LÏÔõÓ‚”ÙÀ‘:”úË`/‹±•ç¬\;ùb}m±ywI7 phE´såa"žÇ)í|ÕŠEÈùœЬè„aiaKíii÷Ùgþú~{ïÛïÑ*†jÏRNDþ^oœ—‡•I ÿ ª!2LA3 xï]WkÉɲwk:;ÕƒÜÖÍüê®D¬s݉VûÖw6ÛÎݵþ<ĩƛ ÞšÁ¿VP¶uØouûEëzèóÖ§Î:”]&.TÀߣ!`®Ô,)´:FZŽ£b™à)1š<ÜÇ#†™ªópÞ†¯†ó‚ŸJå2•¾°T—2ýÜ¥ÝËyTXiÇ?ñ³vô¯û+´†ßŸÜ+Ï- ׫oò(¬ J¥ò›«6\ßÕg[þÿ:{צeöìWÅ~ågßí`E[瘈EÌž¡ ø¹¤ zygÒƒ«–@ý ·®·7ܲÆÊ¥±}º=˜2 BùP„ã«3 ¡!CDó¾÷Ä6{ôû/ûVK€ñÆ8 ?# V§<íûöÚ‘ŸŸõ<ÿ  •^o}2J—wÅÕ*¤†‰ýZdƒù•°ò³Ÿ†ƒÐ¨<ò*ÃÓÃøO:`úb¤w:äÈçiïq¾‘ Cª>é”ÉDþ¼…ʾä˜Ý]6 ƒ‰šìyWÙ±§üÒ—ÒœÖT¸Ø‘ÓnÛ}XZñRÑPK£ûç^`ƒ²×Å9÷ž;ìØ>`{?û7’oi]djxxfJì“j³O|ûe[·¦Ò—Cm=Ùa›¿Ò>þs·Ú®¿ÿ5{ÿ»È7H¨hßÓ‰«Ê¤Ð%)ÃÊ$Àèk:hü*Hïj•-]2×¶jìA™[aí»+#{A‰öf ‡¤é\`M²hðM 1 xý5ZÔËr ¹„Ӫˎ.úð}Xµlßnû?ô>³­[-ï wX_S°;Vz÷[dwŠ5ƒjB²geI¿‡:¸¦´~à=»:»C¡ûp568ðx8œçbGâ|sIìT-PÂUÜu—†ÂZÊ#=¬!÷à€f%ßìÔµÞç]³øÈ/I/­ÓVÿò/YNQQšã:ß4/&\”=¡õÕo>n§¥0]VfO=tÌîÇJûèŸý°ÝºiCzÑz 1iNô» `Aaïxò ƒó{ßx­L×·-/ô]©ʳ>{¦ðäÆÓ@žz~¯oøpÇÍë´ Dµwæ0%|þdŒ¬M¼WX5 ¬v¿ç=6´m›åÝq›õ³´f÷f+úðû­TfXpys©l)Föp1,$CäXîsƒعƒ7œ½VTžYÃñL´Éªª´¾'Ÿ°ê?ý3+¿î+·JZß’ie ¨ŒR0’Ùî¡68-}Ün¸Åêãc­[ûëµ<Ædâƒþ`¨—ï<úŒýÎÿzB:ryÖ,ÅÑ/ÿí{ì‡ï¹UâÍêÊÅáßtåª<“©ŸTKËôJ®#èdpPëÞV¯\b÷ßw£]íå¥S¸Ÿ‰áJa+ÞƒÛª=Öl_}@ €_ÚëþqÆ&rpÉ4ú‰ù"ÿ /¿lÛî‡õ ¬²o½Í†d4+¿È:µîµàÞ²©Ö [ö½´¶¯à¦Û­åÓŸ²WezýþÉLóDpZ™ÃºÇŸÚlo¼ã3ö‘ßlú‰7kk»+Ó³ÞÓ­ý½FF>ɹ–æŒ,ò…Ýñâ csÆTÈËH©®TK|ØR¼Ý¿Tà½ë'66[8~²Õ­äi}Öü¹UrÞ9Rñ]X®Æç-f¶¢*©Í[lÛõZ(°ê¿a“5Ÿ8e Êcƒ2Û{ò´•.^bWܽQf˜d¶D3«@&Sæ.´ìªÅvú©·Ù¿²\é(uôÈ‚C¯ÖJï‡w93|V–‘AÃÌå8‘¾Á/†Öâ_(ë0øé^7ö3ò9w!l ¡{]Ž—ºçmŦ!S™³‹‹,»¬Ô†v´þC»¬úwßVþÑY¡ÀÆ"$ßTø¾Ý[­gû+˜¿Øzeà°WÞØŽÒTÊ-{Y2 “uåëøæ¿[óÑ:«¾ù&Ë—ê EéüC âÆaÝWxÄ>ù¥‡ìïÿò}ö3ÿåGµø|Ï+mB¤Õu.2ÝÉ~=¬×Iq(.²Ò5Õå¶RÀU,õ†“§Z¥¡µ‰­ááŸ>ÒjÐp`p[;öÔiOÅ·èŸÏ$zg¹ø†{¾Å¡ ެ:¹ÌIçºçŸ·6Ý(þ¨ÓÚ®ÛhMuÚBeéS‡+ת€¢#mZð»Æ®]æ²CÐÜ#žK\FñòÕ–¿âZk{éyëyü;6T.ÃÅe¾hL˰–°Wt4 ¨è3gèõ–¢RŒ¯X1„÷S… ޳’óûø~@¥f—–Xv¹dMÚ§ïvË]¾Ü.ûç/Û²÷¾Ç²;›¬ÿø~ evFCdÊÁqxóf;ùôÓVºt™åvKT€¿Ò€Îb¶¼ì]mÖå•Öüз­nÇn›sûmV\UuÑ ?¢äƒ]¥¿úÀ£¾ãÏÿøoï‘n¡†ì’µ:P)>üÓy¦º°. æBcܯ£tЉàå²q>$á+;+wË:%i 4Ô˜aÄ:'ÏwÊbÜ6ÑÙ™æ pÑè&ÒѸõï_ØØÙHïÀó/Ø£7ÝdlÝÐsÍFqS²fAþu_.@*Òñ¾Æ>[xûr«”©’~qW˜VÉ’¡¾¡®6 z­äòUV¶é.ë-›oí_ø'ë#&k˜Y*£õHqRÀU0wž†;·[ñýoµîÊJkú¬õØ1ëk8eCË—[– Ý98ÊóüÌ5‡n"§5~€0…t¼üJG=X’ÊXRl9å¥bdÕóÕ-ÖwìˆåÚâ¿þŒ­úô§­zý:k{þ)køÝ÷XßKÿ¦w–JçJ¦¡Û%Ãkk’–»åH/«áXýÆ¿[î< æEW”3(é–»µNM ÐRFúeõ!ïÊÕvâÛß²ÜuëlɆ ^/±‘½×ãØ‡àX]ƒÚÖ ÖÆ®1û7[€*Òã’°‡ ;ÑgŸJ¦—ÉaÞvÏÞ#öìfiˆk¿YzÈÓš­Aµ\@)‡ÄÓšþÆäÍ7­’ÎוþUäý m¼¼]&HE?Ô0´þ±V;á>.s9µÇmàþ‰|Ár®ÞhƒZÌ;$­uÀ®J›hi6L ž[úl®”×^³XE ±I©†M9åÚ<¢\­VT[ŽŽ¬2qŒó—XÞüeR€²“;wÙžG±_ø;´s‡wÚ2Å]xùJË• Ûíc©£e‹&9âBÙ¦ËÏ´œ2©YÅ`x(”ŽäTWx<É»øP—ëzb* »Þ ÀéC`Õϸȡ†#„ö­¿*~êý¶ðo·…·ÜìT4>ÿœÕÿ¯OÙàƒXá}7Y^¥Ê9$º†ÿ¹•å–3wŽÊ©ý¯Xc{ö³ÇþcV²jµ üò•ç|¸k*Õy<+-–òÈn²À±ÞÛêí]û÷Ûü+.HO‘Ùà•avÚpQvê7³ì'¬q®P@f†!®C_ÛW¶´ç¶ìsp*v[Þaû1Ö$"ïêÕflèº|i½ñö«%“ö´ÜX€ã^ãçlïœnëÔWXÛÑËÆý Ùôj“PÈ:U•·éÅçmÓ_þ¥Ýû‘(¥‹ûP­î=âYò“ÖUäèÆÓØtÚ^”>ÖÖWkµmyŸ8®Ð)±fJ?õ Dè…·l¼ÂU'*+4T‘sŽL˜ æ~£F§Çs»ÖkCQLCÕÎØ-§»Üä3;Æ”H^“WWkÝ¿õóZ¨=÷45?$12ehù1UÞ¹ž j…AA¶]½¾ÊJdøp@@—­N雘²w 4¸RÃi9pEnK–]=ßòç.•º|•âà´64XÃÑ£vbï^«ß±Ãš^Ýf?iým§< `Âútn¸Î< Aæ¡Ûtø=g\|ð-¼ç-Vºa½U¬]cUW®²Š¥K­láBqLì†hÖ¸k—øÂ¬é“ŸôôóoºÅí]eI!GÃÇœB‡ŒÛåÊK.»ÝäeY‘0[”Û§Þ)‹’_iAñê5:®¨Î~p øŠÃìÛ·ÇrÅ•½ÿñ‡­Z;TÇ[Þõ2(œ1¯áˆÿ|½F3âQ¢‡5AÕOlHÌ&¾åM×ÛºÕKí¹Í{l›vfάT[}X‡@D_o„ói¼Ú4ãî;ÖÛÕk—;F6GëÎÄ âe¦×"KªÇO4 ¨í¤ ²?#œ-ËæT•ØRm¯5_;½ò7ßÓ¶QíV´b•:Z«dGlŒ O ´R=ž9ë×[ã¶W¬VÜ'€ñG||T·ÜžÇÙ\¬ÿ³=Ÿ-þ `MpMƆkéâyšQœcÖ·g´»ÉÎý'¬P_j6%e9À§ª¼ÈZ$Ûú§oÖ"º¾ð v†›Z$âˆú\±01 ïnD&×!yQË#«ó8  ©“Ñù¥'yçÔ%r8™qXÈ±È 'âÌAA¥ás[)N˹-]³aꪒmekÈÙ§aâ‰G5K¸Ãêÿó!R²â«6h° ÊI׋~Ž'4Šùyøî*GîɉrÄyæh Kj"Yš±“}_¡U® ‰+ÕW/i–Nkc4ójy’y)þ<åÙ‡¨ S»ë üí[ÍWÚiÉÇz¥PÆì­²@Ù²„$”p ªÜž/QÚ ùs]ËŸYÌ¡>½#ù»GS8±ÑŽ÷ UÖ^½;ÅiQ\M Ü&¹Ý¶]ûmÅš+m쯣Œï>qú($D˜: Œ®*ÍÜÝ{×F»zÝåöÒ«ûmëöÃ0/>¤«ª(óáï°¹+Û—wi ÈÕkWÚšUKGb¤À˜á¦$áºZµøfÿn-9YéÂrõ£RtV=ÀÅp°Ll«îJ‡àÍÕÁ)›€\:\:9å ¸º†´+q‡&vÚ±o£‡¥k¯6As6=*`›fË*¤‘ÊgrÀi ’ ¬Â™kÍÚ ´†Zƒ#ŽÜ>éI1$Õbì¡~M0µ³M¡@¶cO¯½üùq…Nvh”ú^©2œ=K¤Ê'D cÚ!/º×…s[ž§ððfˆšÃa@ p£Ò ;ïf:=±"@K%’„ÏÕ4²°Ê¡U.^d×o\o¥å‘ßTzÔ‡ç'3–Kû:¬iQÿ4åáæ½`^µÝ~³ô’4£ÆÞ‰…"#(£¶É\I³:Y“dWíš-;-P·€ëª5ËÓ_ebz­†Þ«7:Iަյ†(p ºWÞ1éjáé¤Ål4«Ù§›Ay Žä¯>´UòÏÇÀ1KÂè¬ ¾Õ“‘ˆu Xk–ïÈî&ë>Ôey+æˆK’ 1Í4ö‹³€;¡ÃwèºP`”§x;‘_Éâq%¨wég@ðZdpvÔÊO<ç iS 'ãZ¬~µ|ñe«ýìßûÌèèÇÌ(ñÀLˆ¥D­ÃËOYS©¥dN*eŠÛDSÏ•™¾ò²ºšzp€¥£%’n½{Ðúg®Às€s׬¶RÙÊÂ¥ ðKÜ $€5‚“w£þ!—ú‚z»T§Qljn³#Çí”dT}R(e¸Èÿ'%ã:­aN\…¸‚<É\v¨×Ÿ:»ñêýö¦;6Ø—/RÇ N¯3KæJŸò硾éŸNË[±€ ŠÞG[ýùràÒk ÀÀ•;(=.…@Ô5vÙ‘º.;]'U©Dä¯Òf *Ï €“*/ Ä¥ ÅHÃe9xè>àDÂ'œ¡à9„ ›|p(ñš`ážp ¦ yštó­U@¹ý[O Læy•dQÁý3à§‹ü+S…BÒl€Y( É >üéJåà"¥•%ù  Àa¹íð#¾b n$±’N›fu¿Xê ø¡MŒ~/¹Hk’[‚ý•& ›æc-Ø)éK•JB£dW¨7”—jÝÞ¢j›?¯Òª*4Õ.Naéâ*{R{!nß[çï—I8l +[v±m{Žk6q•ÝqóÕ¾¨°™ž'§Y1é+ér ¥EúQÚÊIšÎBÇ'Gt(@î þÓ0>tÎÊñÍAÊËýØñNk[Ÿmë¶Æ O Q%³ÁúÐZDçR”éàˆ›g¤P„á%üCÞ!\èþJÇ_Ö= X)o”ÑÏ\§ï="æ šÓl²†Gö[áÚgO³©°D¡¼üÆühY•"0ÍÑVW”Ê9ÃéFù17>pX8ÿ —~ €V¢Ý¢[›ŒùÛ+6\ã3GÝ#ùAdñórLÜM&p°’ µ]\ÈÑYn8¦µ},^5[(Áùê• u,r°**”&¹: KUØûðšuËméÂJëÐÌÖ!Y4EkÓ6Ì,ÒE^Ù}Ü^ÝqPbÐæÔTHY4¼÷Æó˜ö¾½{­íÅ-oÉq=”( ï½:)”_—ÃÅ)]ò\è´!`.ï¨úéR/<ÖÖo‡šú­½[ËR$ Ï’;Ò…#JND¥’ð âppÒ™á÷Á@ Ñ7u`)“—K¡‡3É¿Î/tG×!³?¯>w@C>Ž£¯ñR ‰9Ø+pýžgpSÑ…Øu¯ÿpÎX¡hðvéBh²Æó3Å5 ÔB-”n”•‡k~ç·í¶›«[F¬#®7’ ‡5’ã~G‡¡ÆFÈÌ^‹ þ¡Žp²¾Ur©AMa—há\«‘öyÉ(}©ø>g>r˜k®ºB€¶Ô¶ï:dO>»Ó^ÇU,Á3\Ù¢¹e’mõؾö{vë>»÷Î ¶AáÃôxèt%²¢°èíêòohÛrͨ‰£ÈFè­BçÔ>êr Ðú$Pw…U! ÂedSb€6ˇŒš¸´FMí7i­a·ô‘r¹•â y†Éì´ÀaøCÉ ¥r‘nòÁžÊ²4åÞp5ƒJÇs­° íátò÷œ¦B•!¡eà¬ä ×E´œ• Ž>î¡£­Ö~B ÍË% 'sŽøQîÄ—wõ«thu),3™š{Ïåï4Ò4ÇÈ™¿¦ºeÒ!rXÄ4–cö4»¼Äº¥¸ŠˆýÎw½Û•^c]õNâ(¬%œ€–Úü07C½ ûÛìÄÉf ›:xæI¡sÞÜ +/—V*:..‚\ôçì  ÇQöÒ)¹Ì6YÄ|â™í¶Sò¬b­q+•:DŽ€£QÊ™]ŠmZ¿Ôî¾óÍ&.KGµç¹çìßn¾ÙJV¯ð />:bü‘|‰:i…@L^~äè‚!¦˜.7ýKúèeµihÖÅ´¾b¦` æCö¸(MìÔ\„i¿txÞ#î,«`qµ®=N?`ð{ò£'á9yJÝ“?f4 ¥ö ™ÄÉù²5sXPœgÊç¶m2Æ×-Õ sÉéã(+3ƒpv88+8BòB9â’ž£–@q¤óºÆ/Oy8.á~þxœÅa,oÉ"«ßü¢ÝóÙÏÚ}?ÿó2¬³,Ã;¬ b\ìåX@Ó!n§þT‹ŽÓÖ£Æ\.!ú<-•a‰ kû2¿¯†~ö¦>ztZX…xyÛ~{\Àµçð)iÉçi‰O¡Éê›´ÔDhrצ•Zæ³Þ–-] Þ8`ÿúë³]ŸùŒU_½ èkÖç…Y>(M{å‚û8\tönq6Ý,IQÏ–·ûÑÉ#4„ ¿( ‘ ë æá@ Ô ŠS€ ð yà}òâ÷\ã¯3àîyDO+X9¯< —žj·²–š'uò5ìp.…g • X€‘;ip­}HÏË)x:ºÔdÔð°4úClÌp Ã6`ù«Ö­[lÑ;ÞaøÜç¬LrÄÙl&ƒ}™ÖE“PÐ{AàˆŽûV­åcm_³tèL ûÐ>// fuc²£'úŸïyôûíR‚|yÛ>×NÛ!Ž«Tk«µ6±WÃúÆ­IË·{n]c÷¼i“µ×´¯Þ}õtXþâÅZTdY +Xê_) ÒYhÀAf˜db!—iðqx¢üx"Fø¡:2À—~ÇÆ„ÁŸt+4ÝO<)¿Rz}—h…¼É–B)Š¥ù%¹Ò,—½õã­V {•ÿ‘€òÅ»Øþâ =ÉC8”¯Œû~]ç)ñR…\¢ƒ$’ƒSk‚КIÀ+FÊ”vâ¬rjª­]vÁøTýìζlÍš¬Ò:÷EXç¦ÑYCИ3‡mȧXÛWß y‰LŰ6pކ}UšÉcNt£A&ú_ÌytœmÊo}e¯=&àb¨XQ"+ â¸z4D<*nï²E•ö£ÚÙºåÚ®ßü5Ë»je³ÞOe*ÒblI§cg£SzgW1@è[×<€CçŽ÷œÃÛt|.C†|Ì<!Dx'\{X=c€”ˆ½#­4 éš{.]€iK¾Ä ×C˜ÉÑà´je©¢Yª ˜£lG»èU ÷jò€ŸçOÎqqŸº´«r©0ˆ+ãyÈGΊ‚¶¯[I\ä#í¸—9åcµ–_Þgï”zÅ: ÉG·¡tøäbL $€5&Y^Û“NF#Íó&éM56K%A_Q¸¨šê2_Ë— h“Ñ8GW«lˆÃq=öôç¸ÊÅaa K§­’//Ï·ê'þò7Û–¬‘–x·UÊHz.Âõ ×RI²x‘c§ D÷ƒê¿”?W<ÃÁ¡à<”~ÒÀ•ò#ÿ„…nå-@„W¤ð׆aÁ0 ~qxΘÉ9-}±ZY‰@‘5]aŠßÓV<ÑqO¾ÒqÊ¥s*/ä'ñCÎÅ?¶î"†w,©4èØ§Þ=,¹Qœ<ó³eqVúhM{Ú›þþKö6mF‹c(HY3Û‰?H~Ƥ@Xc’åLOoxú¡óD‡):[e¤ZœÜTÜžžp£$¾;Ñg†lä5v8.d\?õªmß/ŽK½–jfQ¶¬¼£Õ=ö5}ýŸ‘-©«¬š@éD :h+hÀÀ'W{ôéí¶}ßI+”¼§X–M«Û›mÞcÿfåž³‚…Rbd ž¾þ”Ý;¢"gº+Wº×É;t¼aä?*¾äW€Œ¿;ú/ÄLìÎyé¢2'ÏeCøQ )®u“s^ºàšçÜ2õguZOÜñîhüF>AQ”øcÞ#XŠk¸,¿æ¬AEžÇBså¿¶A悤”û‹o»ÁÞzßmZ MV¥ã³‰*)…¾„]X©Ê¨ØÈ!P¾¾xEÒÎ~zVc™­í…N‰‹_r¬CìÚÌ6?ü„ü¥ß“…V&Дyå #YH9$ïÔz7Æï‰Ï»¸Ž¾/¥ÇÊíÃg•%OJ]§Z»më©Nûø[¯³Ÿ¸ÿN»|Y¦PþÒä¶f4`Ñp#G :áb£ë9Žm¾«èx>[9©XÆs4DßÈeöË&û¾ò{òCÒLX¹®_iƒ²&ªÐ Ç9vìx-Ç¢g|'†ó7åéqøÃ Üæ9œ u9?·@æÃ3y<d:Åòœr¡6>c»=g>ËÌON’ßèÏ™ô>ãß| ‹óVùÚ¾«¦§÷î´›þösvû‡>è[V‘vÞõq66µÚ—¾ú°}æ­vãRÙ%“à½GL±ÚéW7lÆ[Ïi±uóJí¿½÷ v÷n÷d©çXl–þÌXÀÊ«^ S:eÄ?Gò•Âjm—^Z¦ °%GÍ«±ÄKfýج/KlTþ\?!¤O~D.:Ÿ:(îÕ‡¶ïjÿ<¤0¥×Ý MZpÌx‰Ö:_¸¢Ó¦k*˜‡ Ý4T•¿¡‡ÞqÓOÃ=:Oeš1œ+yÖÈ÷Íê%·êRý%'KEã§ï¸ ¡ð¢¤€c”Uñ„xѳÂ"3‰Y樭õ‹Óìÿ¨6¨Õ"õ²ëÄN&t `*_qȈ…ÙÆ¶{¢®Ý~óžÕöÁwߣmâ–­ƒ(my¬³˜e?3°¨‡N ÷?ú¨{à›6ðÜf+۳͖~êO¬[¶±‡æ-±÷Þc…%Ú‚Ý;’ôzÔè8¨$\*<^íÕwÃIÍ Ù¶Íü•ÚÉG¾§} %×ÒzCšed·d‹þ怓êxÞ¡Fe$õÈ;g¼¦¯âÆ+y_ÖÅ|íÝW"uÙ–"oÓPй+*7FFDréÛôEð¿Ãžñг·Å ÷‚^V8´ šºÒÄDöÜjë?xÌzÚOÙxÀ®»ÿ~2“N!‘¿™œ×ó›wØ~ö[v\f€VˆƒêìÑ~ŽÊ@,†—W%€³cÿ'Ú¬B&„~ó§ßh?t÷M²Ÿ¶rËŒwdгënÆY|›£{öüßö¾¾®ªÚ{¥™çyNš¦M:¦s)ejAedPPÞó) 8#Šã÷©Ïù¡Ïñ§>§Oð!*ˆ€By”2t ó”¶iÚÌsnÒ$m¿ÿí³oNBÒ&í½É½¹g'çžykïý?k­½öÚòÄ>(Õ_ø¼œØ²YN47hÍä_q¹4×’?~àÃ’·³Ó«ø:E?~ù<°#&ÍôëWÓóó¥bí¥ð®yRj~HŠŠÁÑ‚ë¡2ÞýHÈŽGp1Ÿ "ì| þpo Î¹æÜ³àÅ8øÍ(@°Èõð¸z+º5æò\ƒoãÐøº NTš¦Ñ2™;ä)„% î$lÜsº‹:2}:Ïh¬Ø¿eÌÓºeí“OÊ¢+®ÐNV|ˆt4#³Qºš÷ªÅ3¥¶æˆ<±£Nfd%e¾“Y[væ‹’EÀ‚´x-÷×Ù"¾ºZ)ÃjÞ¹9™N¼¦4S¹}‡`Ùq¬¥Iþtýµ²ÜUÞ¢¥r¢¾]’®¹FrÿíߤãÅd`ÿ>iª>(iÿr©T®X®•ɇmXÞÏ™Q€dÇI;{õj‘¢"Ùó‹ŸI V²‰)Ì•“XÕGýj‘ÖØÈ¥¤²ãÓ† ‘]ŠàE+vŠ<ºáš±ï„?x9—hÁkÌ=“r¢2A« ÜUÖG$Ð0ðq»1-{ìÞóIn–ƒŠvD=Š|´Ã"XYÅ; åb r¥oó«zíÊçž—¹kÖè±m›ƒ~Ä2XðÏÌH“UËçH v¿ûÜ>™ÐbÚfáÄÁŒ›}§&1ÐmÍÏO‘§vÖÉÃOo’\˜x•ÁÇ™ß6è;UA+ŒDBÖœi”/<-/Þ÷eyeg»”Ì.•ÈþsÖ^ -мüá{áb7[°œƒ\½q£T.Y‚¯¾¾hˆ^Ü"ȦG•'®ºJ»U"DÄã M¦9z­DÐ>â"Á†º(Z†sJ ÷ `¸Ç=AÆ­;2â<£³†ÎŒ'è~&f Xo°õ;`,(¡ï£Õ Õ=ÎMK0ט'wH@žíôÓÚœ»àpÈYõl|YâóJ势ýYÊ–.Ñ›–ëwÇ3ÖcKGŽV?øçuòîü]Ö”À¹#\as™4åìÐô-À±pãG# æ7]XÎþ™ýmòÁKçÈo¿‹ñÎФ¯~`H€)°l£h­> 5¿ø¡”ž³HŽúNÊá;$®fS£»äÐÁR•‹áåM2ã#wË_ýŠÄÄÅy€¤k;£?ðêFyìŽ;¥ù¥%Êx™Â®F¦ä —U±‘ÀÄ`:ž(r\´kòƒ–^<çã|Öl¸Ø ùN7Fè,(1N^7]t( ñßw÷9)þÅ#ƒîëú<Á œ•ïÕ—$åÜóåÊŸýTŠæÍõƒÈÙr3n:>ñôùà·þ"¹I1’ e|7Ü:›òØòcïТ%í¶èGÿ¥ÚÉnë‹ï¾T®¼ô¼);’V"!Ʈ瞓Ýï}Ÿæ&IýÎݲã{ν{0Rƒ…S!"`­·Öf¹äK_’üŠ ¬Ü=4ÀǬå^±Ï(,”YжÀAí#ÆpŽYûú%ê ¹Œm©\䆨ϢG±Œ F®†“ h8¦‹r6p=‰þ ³Å6 ÜÉk|—§á© Ëç^Bƒ·qbÒ&w5$8À]']«¬+¯’«ïÿ±TVúAãlÁŠé1ËÍ*/–sçÊSëwbbtä¦Âé"ÍoðŒ–ÃÉ“-EÇ~jYF‚šc|ãáMÒ×R'³¦çËHÚ¸‡”-LOÂŽÃÚ¾îiyâ’7H Žuõ-ÔG» 3Ÿ€R½sÓ«2ëºäúû±º/ætyâ`ð[&¿øÜ˜::äüÙt¼˜NŸ ù ¢ e 2žQ6F» !î°óQÅ ‘{<œËÎù°kÎóä:|講Ü\ˆ^8åMÁ<Äw €OÿfçQ0 íÞºIŠÞþ¹ük_•Lèì,Hó~ ƒ•"箽å³ßü½¼t E§K'8-C)î ˜WËm1»ºb¸­'¶ÉÒì$ùÒWÊ¥kVª¡QôpÄka‚ÃbÅØ/Yj^¤\x¡ô””J†›·l”˜º£RØP%œ2¤¥¹IÞðùÏI1VЀŽâ…àPÀvÆníŽbãã¥âüó¤ÆL©ùåÏ$6êR°˜¦ÌÐÄ´=‹Ý< îÙçíFNËr]¬oå¾È5ñ:ÎõÎù¹4Žvƒ»ÐöcîG£ß¡ÎŒÊ{rt Œ[a çQ))Ò¿}³”q^à—¾¨££~ñ™p`ù,Ms²3dÕ’J9| Fþ°£^æ€ÈIÙû,‘=¶ÙPÝ ¬çù,õ_÷ýþeIèo“ ¬ž–š¬ô³œœ}'Üö!Ía±B,PQÒ ‡y±˜A àã5:°ÒKÓÁCR¿m« ¼òŠDaɤ#¨«–T,ªàqWoެ~ÍÙ_mÝØT¸Æ¡š£²ç@V§®•îõ$®—wm—¨y .>9à:0(Á¨pZÃi¹¸'BÓ)hðœ gF ã£EÅýàg‰Oì] ӦØI¡7ε|,üƒEíÚ*ͳ/‘ëþôc©œ;KÝ_GÜ‚,9g°±©U¾òýå¿Öí‘«ffJ7&N[zÙ|°>H=¾Ç@{ÃÚm¡Oíi‘+äÉgï¼FV­¨Òû Zd= ¯Ÿ,ÞÝ:°Ž_¾©ðC5|i,Kîc½ðYUS#’‹‘AóÅg†cµØR…ÆÞt S'îzaî¸(lMmƒìØsH6m;(û°uÆ Ãø Uɯ­•yýµ°Wâgc¡ (ÉwtÉ €U9–9˃"žœéjœüñ¹îœó>k•@u£dÇð1£Q§}·üa¤k¼ÉëäÒr;*¨(è£æ 1M;¥uår`Å%ò¾»®WŸ»òÇÜ›^[{§Ü÷Ãÿ‘/=òš\Y™->®’ ~ZÙ Î5V&‰X›q³Oö·“Ÿ~àR¹éÍo€«¤D?¸ ¯O4„B°Ü`åƒÓ¼¦æ‰‡ÛŽ\¬ŠlÅû%±t 7¢Û|‡ê^û¼Ö¾òF3¹¥csk»Ô&HÕÈæ5²çp‹*Sàá‚+Y·ƒNÇòbUù²rÅ<™_’%;zPþyï½’^V!Ñà^úÁ9`ˆKfÃ}O.@‹àcú Ó5€ÂsÝôœGæœb‹:±°°ïtôY>tš`ŸËEúЕšÁ•œäˆ2bž¶g»´]ûNÙ[užôa*Ð=ï\+3ÊŠ´Œ¶ ž&‰€Ý¶ E×ÖßüÑÿÈçzU®˜“«øANËÝ í I-ž“Û¢8ùܦyß[ªä#ïºVf•S î`?Ñe:â„ `¹Š“’ë°Œ;9«Âü Œv7îg†Ú© Ö‚gs5”:§;3d3´SúQ–p…cø¢74¶JõÁ£²so­ìØwTÕÁk:{*\Eƒ!‘¶®cÁEæÏÌ‘s•KÕÜr™^’bÎD]ˆð/>ø üýÖ[ÕEL|åé‡éÃ4€ÆüdXÎA§5ZèjÈs„šu;ל¬ò^58¬V ¸XÀre[Keî°däè2aFîŽàÇ•˜1ÇÓ‹08P½GšnxT/\û.Lr>y\î¾ãj))Ê›´ÎmA…Þa¿ý“‡äÓl+æåª÷T`œ޴Ùâ(¹­§ªÛ¤*'I¾u÷õX ü>2iåÒÄÇù3é€E‚ÚþÁ‘Œ6,îPWߦrøÌyhG¦ÁVã,±÷¸R€ôdgf‰Cåýh]³ì­>¢ µçP£4cÎõ*‰ñ£Ðh#ÔÓw\JóReùÂ2Y²`¦”—ª‚×Mf.}fu?;ÿ÷åÉ÷¿_z^{Mbæ/–~ÌCŒÁýEéXq½ªÏA›?žê†s<`Ì{5l½ê¨,>sª@®,e(ÃàÝ)Óñž`$ðxMDµ•¶¿G6Ï“Xp%àc`œy«¨ gR;¶´¾þýßËþøª\>'†£àB³Fͱ¹ÀcÄ—Äì1Ø[­Ã0—Ø} S¾÷ZyÇ—©Kf |#µ…SÑs¢ïM`‘˜¨XhúMoÂÚ~\ä> V Ðqx@¸&¡ ³Qo˜äj[àyàpm£ìÙ_ ç}GåÀ‘Vé %¢ÓÆãëÌ_o?ÌÜôDY4·X–TÍ” ØegÁÍŠ+ðãÃ`ÍÙÇkOþñQyòú«$ U>>¡à¯§W–f¦b-B‚–y×ßáðÎH¼Q« E.óS öáŒÜC9T \Sp€“˜s²¤F¯à»dÑãˆîxyô™mRŠ)2(kÚ « ?{R‹ù¶4ìèì–/÷·òµG_“Ë ÓêD> Ù†ÑÎ+óÅhÌ@ÿbý¼°©QÞsý|¹÷Ž· ¿aåo›†ž„à™/1Á#a-XõÒ4¡¥K:ºzÔ™ÁjFiŽV¨PŒÈØH *rQ MmÙ«—]ûŽ`t¯Aêš»´nÒœ•¢éܰâ^g{Ÿäf$ɪÅŲh~™ÌžY"ùyYC€éÙ`jðF <ŠëÑùÅòäÒÛå]eø@=ü[‰+(“^p9[ [ž™&)Êi±‘0ç¦#úWîÁ^#Ï@¥9¹%}ÆIˆÇ£*¢‹0:™qpbdl^¶ ¼¼AÝÉ,‡ArÉùç˺_?.Óp‹nP  Íu¨èx˜ M>~çè3½òƒç÷ÉÚ² éÀZ’¶O±”&ÃÀŠÇ}ø‘»\½"Oþ{Ý^ùçŽïÉ?y³\´Ê V…2hM(`‘ˆüÒ‘°TÞ¶¶û°´{·:Òc§­M~^º.¡ÅÆ?œ ­!z× ,` Ò™œïé–©ïǯR[×$Õ‡êeïz9.ª£ë+b}B‚T1Ä;zÂlíì•Æ6Ÿdayû•UÓ¥jÞt©œY,èäôzaƒMSS±=ÆÞ¾wî'ƒ[ÛÔ'ç~â^™vëuòÐ7Kj]¬tUÍ—-Í­²:KZ¶÷àTI~PÒIÒ( —ò¢[dN¥a`™_ÌU>AýX:òMsŠih{±Yp°ŠËÊ—…?"E+V¨‹ìÖ–˜Î„e£Ï´Á’LZ¯Ogâ®XÐʰöC7KSûýòøîFYY˜¢ Å>ÄR[1Ps† V\ä=VC?hÛß{B.*Ï꟬þ÷Ê/?­Ü|ÍÕën¨‚Ö„–­nŠ\ˆ´×ae9ûœ£KÉIX6‹’jp·9ñ~‡SÀ ¼çæž,ÍG¡Sêë[ä D½êC rèH tQ>ï’0’GâÒõœ|ÛNª¡µŠô8Y2·HÎ+ƒ¸W¤âÐÐ…8¨+Y´žÏ‘Î0J({;áh1Y–¾å&‰{"S]»V¶n–xߨ ½ÖŠ”uïÂŽExÔNÈ=Ò%hQ¼ã°=9,H–Ú!Í'®@ZðYê¸Ê¡·Jľ½ÿ€V`^ôào$·ÊØ'ƒhÙ ½ýÇ3*« ` ´+êI;´ UˆÉØ_úèÛäÀ'þ[C¿X€i<Ý0ÿ!d‘^†¯ùÛîµùú¥¥üyqrÛ'{ ³üлoPß>JŒCЋ„³ˆ¢ \ítÐõËEYÚ&ŠWíÄá ”äÞ«‘YڌԈ¨cêÄÈj#ļš#r ¦ûiõ¢!Óà6 ¦9fÔµW>=PܤæWȹ¥ÊIBgCÿöîÀ¯.Óµ›ûÞXŽYÏ|7™€5+IÚà.˜a!<˜fB ÿ—~XŽ>ý9ºp‰léé‘åq0€„®‰Ü‘¶&vG,'PÄÄMžl{ Ô‰ÍÅô­*ÒÓÒ%~û+’sÇ{dög>+ Å%Êá“käh(Ë%Gż²mòºŸ£´ ÙD;©¿¤#óX9³T¾{ïͲêîûáØ«dƒÇðñç}¢i…Çx¨ïè1¯á˜ j—¶(9u¡üÇž°|áî[4n¾Dà&ç !è€Åb’0äª::{”“ŠÂ8xô4ó#xŸ_²D(CB„6š—Éú!M¸#=´âÜM޾uB÷×ÔÜ1¯Y@m@u¡óÁÑo<ô5䢲¡bœ=àj›`ÐMe¤ÄË¢ÙE2·¢hT²ù`úÒåÐoææèRj,#¡\Î-¿þ•üík_—-ßþ–쫜' Q1²eLh PŸDz€„/,À¢ÿ(‚!ï r\½(sÞŸó Nµ‰Ý°^áz{ÙÉŠKÖ9©z°¼[§âq´vR꼌mDbÁ³uîò*yðž«åÆOý^V/̸@×ņjpgiºÔc^ÓûæÞ4¸g:?[L¹`e¾üvÃ!Ùðïȯ?¬ã*X…ŠˆtÀbÇéÀÈ; ;(þý´3ÊÍÐkþLùÀ߀@ Òi$€R± #DÍгÔ5´Êá£ÍØP´è!!WN€þ%ÜAŠzAÒš´oAô÷Ÿ,Œî-]P*sfÉL˜ pôkˆ¸Çr:™lÍG ‹¯œ[VûëåâÙ9÷LtrH¦¥Ç¼æ+”RËʲ±Ì-PÞŸ7#]65uËyÿú=ùó7ß.W_v‘Òߦ¥Ä˜¤Ÿ ‰Â•“»Ábë×ÑÅfÛþ`ËÌËåŽ8´ÎÕkøn0:ŠMo²ö¦Áèï,°¬¶¼¤… > ¶ut+Uߨ&GRõ  >œªD@¢¯ïT€Sô (ºáè+¹*ÐÉ]­\4C9)z¦ÌÍÉ R 7ë„ik>Ü™°™ àž«¾œ‡ º\Ò«—‰ML”7b™¬œ²éò8|nc“į\)U}¦QO6‹œW*Þ¹¾+©k® "Þ2¸ÎXùVÙŸü¤”}üãp}“!Ë.rs­<ýü&ùØ7~'sa_1½tŒ7 €x9'úÕC*-©ù±t#°¾û–+åù-dó‘v)ÏH¸h¥ë—ãg$°bÝ3ðY†´›™‰Ò™+o~ËOä§?j—ÛnºBÁ{²A+(€Å¡pê8*E"P‰É‚Zb)U\?ì$o¨ß¢XÈóp­‘Êz*0àŠËœ<ÜÒÖT;€©M0-©â]õS(v dLgIHáÓ¯Cï(.E#§Å晃Á‹EóJdFöJKò Då’RƒÊcæÏÒ˜ùÂÿ„v®|t¨”—Aë{Ûù¸_ü¦7I&´?|û{åñ $þÜseî LtF›¢Éépº‡"‘Ë"w`{ãë†ò|6€yV:F= VpæX‚5¢“è7£„˜†3wv¹n·\©l|m—<ò÷:zà@P DÉаüÙ }Žf ?J7Ô'Gp?õž«å¢»~,Ó¡H'_HÑp,`ŸøÛË×½f2FŽ—¼1_ÞuëïÀÅ·ËÞuƒ$Aÿ8™ pÀò¡¡p©wV.;LA@þ$£½&ñ0RÌÊLñƒßÐŽ>ú«“zÇ“-û½€Ñ€Ê]rOíàžša,Û`â¦àƒ>Ø‘^'‚=E<¥%£tâ`D=*ÎûVô<™—•*³Êr1²Wˆ©$¹˜Ò„åΆ!‘v:Äsº<…¨N^â0%¦0+YõšþtÐQûQÓ'yIDAT)í|Ú^€ eË–ÉmXäâ/pÆøð~$7®\!³Ó’ä¼>`Ý16,“hŸ„×5  V/¦ëdÂuIZ²Ä¾ø¢¤~ï{Rxûíåò>«:vN¼›ž–"_°Ìùù_„å~š¶_NeilíÄÌ‹&ˆÎ9ªŒg~ý`wG¯eÉ&äÀæã|¬ý•w^ Ÿüɳ²zAŽ´AÄc.‡¶S#’^6ðÐý ÖqÅ¢´ÇñA˜&Ë®+’O|èqÙÿÄn‘ Ðk²@+`€Åtƒ`gd`‡°ÀÉ¡×GúáslËÜŽÔµê{nvš¿ðw\|n"Ã`Úƒ¥`Ü~¤,‘k¤éF7¬¸9zGST3:mÐ:aF@½ ®Î×NÔA%bú¿š6I‡¸û1pP´6§MN«¼$[ʧçIyi¾d½nZŒ;ïL‡À7YÁ¦L+ #Â>Ðe¤ÀAæ›[fi©¼õ¾û$z­?~ô£ò–¥UR1¯·#ŒQÁm¨”?A sO¬VÂd#ZüÏ.¹ïx‡Þ³†«LS¹$ÐÃŽ€‘ƒmh‚ €Ÿé’¾ øxÖãÚaþ=xž·|>Ö,ÃGÕHŒ‡íÞÝxm2ó`A䦫×Èÿ¶Iºú$ eè…ª…´g3BŽýà®§øáuÛNì1÷äÐzð.U:+®-’¯}å9pŽò…{n“¬ÉhÓÃcX\²œõ%Cjìå`µ_‰Ïœ¢“ N+-5 Ãë0D… –ÈC¯ã¹×?jkËõ(«äÔÁ¦i÷|z¤¨û:}ð@]'FCÛ¡oCÚ;zt$ CQ™ ŽÅŽ‘ˆaè¤D‚;Df4 ÒÁiBš;T/@Šœ3Rá•'¥Å9ðb‘áŸ`Ì7ÜtqçÝÜ ß p?mp33ZÐ|;0£{oúÈG${Æ ùë 7ÈÕ0vœ¹`™øÚZÑ.HG#êN€XŽ´¬¯GÊ·î’”?üAÒñ<ƒ¬ÜiÚúd¶Bç¨ ëh‡êš»å¦Ë—bý¿sdóÖÝòn”ÇŸyEªæ` `A%&æç(‡¦ñ›ŠÓ¨'‹æ6]N³ùäÍÈ_xÖìùÒƒvgîè`e{ÛÙÖ¸'°÷ácÐ NmååEòƒŸ¼‚ð1¹ïÓïÖåÅ&´Î°ØQiãÂS\õ¦•7Ö6U36`¯`ÕƒÒIÁ|ô ñ° ²–Ƕ‚Æ”†m™þ‡_wÁgøÅ/‚2õL L¨0н´'낹uO]p…Ó“´ààE/6;ú™n( k^’N¼Ç¡{‚”“ ¥¿î)r_|?À½Ó•ÊJs¥£zõÈ¥¸ƒM4]Ü‘û˜t?Fûa†AÚÚú´÷Ü{ÕÏ€‹á~Õõ×KæúõòØ­o—i<%e×þ‹œèê„ûp¨ UÄà‚½ûdñ@d<þ˜$¯½\£ ¬x“´g®h4ÚŠ §¬ðÃA’¦loWŸ¿L·šÚzÙ¾«Z~ìY´I̧œ7SfÏ*hšIú6NÛ&².Lž ­.¹`©U<+G0c!Üf/è£y³ '<´eî +û¼¶KœÔaíœÕòËß¼†÷~,÷}ævÉ·;‘ uƀŲóRÑË€n¸¨¡WÇ÷ƃ6¢±pv?uªHœ €ŒËqX<¢‡äé,Ž÷ȹD¡Áñ«` ÷$¸vhįD°ÀƆÉC€ øF]A‚£Ke£8׃†LO§=ЋŒ´ÌxŽï±¢ âGGÜL‹“„©‡c)H P|–£w¤xÏšÁŒfá fÒ5>Žh^^š-ÓÁA‘‹ÊËÍÐõˆnHpƒÔdŠzC2uŠÒˆô`ÙSaåN—4 û©‹Ñ¬,èÌò=ýÉ'ä)¸ÁŽþÅ/¥ü¬î p‡5¬Èέ² Þ˜K}Fâ/\­9±ïéÉH?¦¡ÎÀì tn5»añ,ÛÅB ¬¥Åù¨“|ýxª­Sßë[¶ï—’™q± \Þf£C`yXæ N:3¦Ê¿­™'_þíËrþÜLŒ"u“͆m›ö’ö ܱœbÖõ¹Á7ä(ÄÌåȯ~ñúáÏä??u»~@' ´Î°X8 9 ­œÛ‚kÙðc+ZA•@õÝX‡Žb–!°I•y0Ö+‰&€úÛŠ«Ì%;9ŸDXvË¢×p̆ª"š-”¿Ñ™‚Ñ”FO8a|¼†˜®N”ÏßóN•‚&´†ö-ΩH v6Ú¨ø¶ú­3¿kHÅ´PÙh4ÔYØt — @ž`©K Ðk8'¸1oË` Õ‚~4ëh«N‚þvw¯i0çzÝܳm‘E¯h-…"þÿwäa€ì£w¼MûûA0¹ýq3Lź„$•O‰ÄF½ÙŸ¸ùLÛœ&Óø '£ÏñD4@Æw jÜ“ý…¼ïÜãK|l’¦3›ŽÙ#Æå¼Ë=Oô4¦o®ñËÌhhÇà~`E¶Ãå…yPÖ¢ç¤K‡Ý‡é¢lšˆR]06²9iƒ)tþG±; ëv,óX‚ÕkÅaÚÑxz8°._fÀûBÁ i4cŒÌ>ÖÚÖ sަ™¶‚V… aÒ™.Æz¶Ù¿mÌ×äÆkt%Ý ì{ªëÀHvêV÷ÁìÐnú錪QaHhm³xPó½ö çEÖïë3ú¬yžÏ:„Òü€4B¿ðÍ%rïûÿ$Ó¡?|ëukµl|6Xív\€EF3c ärÒvJU“ºçº¹µ2xŽ?ÃeñïÛ½}Ö¾o^ÆïˆA¯þøÁ„_r‚9΀}g“N´¡J‡ÍP~Nlx2 œÌt å[#Dw"|ßéN¼î»Só89 ! h}0C0gœK§Ø¹õZ3Ö\¬OÚ¶9VäÓçÄ¢© 3D b}œT½$tXpàg"Çï(Ùcç´”ÜóÇ¡nT;PäìòÁ”6d4¾ä‚*Û‚ØÎzh6ÒÑ/±p‰Ì> ÀÜ2ýÇã+¾®5Åù‡@­®þ()º´PÞö®_Á¼¦Hç5:Ie7fÀ2`”<,R¶'§®†Åé¾3xB`'8­ø‹s‘î“réêðP[¡é.¿Ãóºó1Öé" ýû¤ f¸ƒSÛ§6 ŠÍãs´¥J‡'ÎLpPô‚š9õV ë.³Vâ±ñº’ÜiM•cr.9lNv`'oÂ>Ò€õ&kdËÎò ìåW¹T6&[bä³ ÓÁâ$†¥ÔÝ1h¼xqárc¢l6ËmYÑ’^F˜7ú΢××x(Ý|ölÐûBŒÕ8<êI~ÆXFÔ¢¸Å"™‚*mÑ>Kö„@d¤áHðÁT~Æ9ß! ™ äqιçãà/ Dâžþ£JTârÞïkýFï?òçÉ¹Âøl¾üyFN€¦«X?Vlh(!¬­o×9„ªÓäulÇ ÞP§iuX6¡°gûV:-´€v /JÅ…yºq ú¨k…Õý8"¬>tTvì¶«Fþ°»^Z6·À.ÜPtµY²Tl‰ÑRÝm@œÐä< ÷©I(}Lj1¤ÛN­ ö^›÷BŸ¶ý¨ü¿?ŒÅ‹ôá@×瘋)óK3M'î"«Ð ©g'’XÌ4+Ywøá^¹‚}ïðvØîHïóy<„ÀÂ1X@6 Obqê ßfƒ§Aét_>щ׉|â:ƒ&èýœŽœžsÎØÙ.tÞåé^ä}Ó×¥½½Kj›:¡`†hdÚ!9cÁí2FÑ-é0.ö ¼¹^çÇœS¹-[4WéMÝá×À…ˆÑeN5VÿÞ‹u+wn’·ËÑjˆê9‚ë(ôeˆ–nŒ—¸uÛPlF’\yñ yÿwn—µ¯âÓÚ¯m¾ôB~Æ XL‹‰ÇLhíC°!péÞ€–Ó̬z¿ðáž À‚’Í3ãb#Uw0€oze ¥±Ù¹9­Ê¾4Â^›˜˜ðÙD´†ËâBN½pzÎd>ˆ0 .R‘aÛ2¨p¯kï•9…i:8cÚ¦ °R1AÝì þ ¡yÀ~eÈk2â…=âa½ÍÁ‘3}¶`'¬9Ò,IP:«`£ŠLü  Ï6µÐxßt%Ó—Ü`F Þ-1çü°L›3¢ç2}×pxÆ(ðƒUÚ€Öx3ê&àxßõžo Ð[í‹(Š`¾ì„N :PÛ$é˜ÓHCQdýל?ûn¸îœ˜yÃø‹á1Ïý÷ì£n`óß ÒÁ¤VÊåEàW›F»vèAȘ˜Ì·cŒýµ­’ o´7<†q/“€Á‘¦aMLÎB'7CaŽ'7oÁåß&·l^ê¡JûiFþÒéÈÏeÚ0‘Ynlj“]XÄ#„à°©F­ÜS±šÑT '’¾ÁHˬ`PÕ‹ó”à—ÚrSÆ˸˜Ñ/ø)ß ÐM0k뚤 öCäô¬†yà<¼T{€ z0°HL/ªqPÀag8Å$XÓ8FÊ IˆY »£*ÜqLµ Ê5 Òáy TæŽTŽH½æV¤Ö|ˆ”›€Å%ÕÜ£VÁÎ^7Üï=X/™˜Nb-Ü¡k×<ø`æ‰IñœIá…Т€X¡U—ºðá¨Ër9Á"9,†æ–Ùs¸ER0µË¤ëä¾À~ùÀaq0`¼î‘ƒ•g/ÞA x€5H ïh(@=g8X Qù,¨ù0š²£õÍr°Ù7ÈpÚÀT±Ð³.èµèYvøŠFAÍ–ù˜(àÖ˜Èä=, p¢.“胵ûD*تՉÓoh ªó^VŠWøñAéÎyŽ)¢NDÙ§B`M…Z ã2ÄÐÞ).óø8‘V¥² •Ærq}XHdwõI¥u(„PkEa‘Òi/~¸2µB`…^DTŽè¾…ÊícŽâ}p¬.ðd°€ÕŠI½;«$£F¤É( ~ŽÃ¿ZDT»²¾ã² |®¼ÇC°ÆC-ïÙ P€z¬ãÁñP9R†këe[m;î±FáN};¸* ‹\))#~šŠ„ö]#DÚ3o?™ðk2©Ái»õC X Aâf(îÙ‰¹Õʾ®>øV›¦^x©Žû²1·®oxÝ ¡C°B§.".'VD£k®ˆÌ,nƦEåþ޽µ’°"h޳ .F‘›fܬh†<ÄR2„ÊX¡RœŽZ\ps^%‰c²Ð WÁ›v‘b,ÈÀÕ”˜.õW)$s× “†l˜4L´CÁ€–u GæÖ®Üp)ÚDL±@XSÛ ÿ¬n‘ÌäXuƒ¬pÔ2J÷(Ì-ÀòcÉž§†m<`…hÅDR¶è˽œ–å¶EŠƒ°vï;,õÝý0¥‡#†ª¦JY­“Ò‚i9Ù,æ‰!H*µ@-ââñ+âª<ô LW»Tˆëz’Ìž#¾*§»}=òÊÖj©ÀòVþùƒÖÊÉâ¯:¬ìÌ”!¨|xñœ=<~gOC/†3¥€Ã¾Ð/8WC²Šñ3n´÷¬"ŸÓqžÚZ+Ó3á4‹îᆂ™êuÆõƒ}{ðŠw4yð8¬É£}ħl¡€âZ,D0?c@9Œ€ä±ß–#]º!—ñR)÷)ò*á žX‘šÁˆ’zèý„<+D*"Ò³‘ ßîX,„&DA€Q?¦ãlؼnc\Æ¢†¿2É`N!—öš™ƒi9nÀ hnR¤HŽÄ¬H®ý*»5ê t–”ÃB¤\0ôï¯VËüìDul„AF† é½6XiX¯Ï ¡IO$ Ízñr XþhûîòÜ¡vI†ÿ+®9¨â ¸/Õ›aÏŽÐÝ7 Iþy„Ê‚M)àqX$¦UhQÀš3 `ÚÏúWwKZš»)fÕêÊ€^°vf§H’³€*­y¹Ñ‹GS’vÔ±¦¶^i¿ÌËH€9ƒb––—÷u\ñï ŒFósÒ$ ¼2X<Óï'$(à‰„!Q ^&‚A«Äß´u¬¯i“gýA¦¬ôŸó²Ó_·üú½“I¥€X“J~/ñ`Q€F¨,‹>½~»$c*ÚSÉQO£üÌ$h¢X^NºfÉŠ“ÁÊŸï™QÀÓaݼ·‚@+ÂYÎ(IìÞW#ÿ½~¿¬ÈN‚¯+3Ç¦ÃøÉhÁÈó q-9Y`‚îÁŠÃã°‚EY/ÞqS€sû:»|ã~oø $šIPÌ{öÅ×äXÛ1Tëöa¢ ¬“°|?.Uiq’•™6<:ï<„(àVUF¤g… ÓÑéÓy~gC ÕG!‚šÚ:yàÉͲ¸$U‰qºEA>Ç"¡& åÙÉ’îžMúÞ»Á£€XÁ£­ó8)Àmzz{¥»»Gßt‹ncÊpWÆáù—¶Ê‹Ûš$/-^è˜AAŠ{ׯ7ô Èô‚ IMNâ©ê¿ôÀû ) x€RÕ¹™qƒSCc‹Â}m¬”±_CS«üâÏëevyšXã]ÃVYîJ9,ܬóõKiA¦$`ŠB—`…nÝDdÎèß½úÐQ-û™L×± ûgžß({©VŠÓ”»R¨2X¥\–ÁK7ì|Ç¥¸ #‰Úl<Y !\h°B¸r"1kœÇ·‹œvuå»YF~l”PS<Êyƒ?|ðY©,OÕyƒ*þaù.÷úƒ–ÃbÌš.ågkBgÂÙé‹ÞOÐ)àVÐIì%0 °º ÃÚµ÷ ¾F°K0º+Óœyòyyêµz)JMP |ßpXˆ ÀÅÍ‚Uî}4wÀa^N¦&5¶Ç’+ï™@SÀ¬@SÔ‹ï¬)P˜—)¯{Eã‰Vó„ÓCˆåжíÜ/þÅ3²º+º‹ÑëŠVˆ{ÿ!8ª®(,žÚÞÛ'¦øMŒPxÖÅð"<À Q½(ÇOêŒ,èT”˧¿ÿ¬¬1º,{}´X) RßE«öüê¯âƒÏöôÄ8è®X©Á??b!2Þ‹ÁÈ䎮c2·$Ós+3CèºX!T‘žr? …ù9pN5 xdž#P{W/ù,XñÂïÿô”|ÿÁ-²º,]:{ûuò2ß‚7\Ü;¼@ Œ`h듊éy’”˜à×;M x€šõ™¹r0‰z¬Ûn˜+÷Üõˆ¬y«ŸÃ9-7X=±îEù÷¯>*ç,Ê‘n˜1pŸ÷o<×k¼ô>®¨ø×1 3Jò”Kó'æ„$<À Éj‰ÌLYw.)ɉ2of!ˆ-Ÿýöƒ²gß!5ä´b£!köðÔ³/ËeŸþµÌŸž ‚;d(Ñ D PvU¶ãÏÒßLü4).Ìå8ϤAI’?`…dµDv¦¢±ìW8©Líõr×çï—ÍÛö(Q&vã¼Ãß<ô„¼ñc?—ÊŒx¸‰Ÿc$zRå@¼â –¼p@À£§Šƒí½’]œ,ù¹Y‘Mô0)½ç­!L**²i9(îK‹X•pº÷Ôá6Yrç÷ä;·]$ËV WŠ®=Ú(=±A~õè.©šŸ% ±Ót> ?AÏpKáÈyÙp‡ä°b££äÕ–^¹¶2Ï?BÈë–Ó³Ï{ûС€X¡S^N@r?,*Þ§W¦Ë®ÖY•“$Ý}òÁ/þ ­Iކuh¿HU²¬\œ«k úú0R¨@DıEðb0#²^L'#‹Ç›ÉüË $5ÅYxÂ>¤ïy?¡F°B­F¼ü(²3ÓåŠ\y`ýAéÇäå8¬¸je<9@œÃ¿8ZúaÎЕnˆ3äŽPzÌ=€‹ÁÀÖ xñA}–bcK¿TÌ(Ð…\ͳúŠ÷¢ðtX!Z1‘š-rW ©)\@Å{Ó1E ‚S‹¯O:áwÝßUÍÎ1!Énú"Ïq^1{ž;\6•ÇÀ?éE<’D}Y¾¾j¹;·= xVèÕIDçÈê±há^9³“’O¨7P#î€ wdçç Ø™_sÙÞæžXhž‡%M¾cRZž"E°ûBðËÐ,”=+”k'BófAhF)8¬ü8媢6vàd1ÀE^É€É^ó›. £ŸyF„Þ££¦Iu[¯\T™+9Ùfá°Ç½Ó¤€X!X)^– Š råœÙY²â.æhŽ ‹Gà+œ[ +xù9°¦>©ª(–tˆŸ –kÓï'$)àVHVKdgÊ„8o.Ä–cPœsdÏ€­Ô-p¼ÈÔhúÐOv­ï¤ÌUâø7£“‘MùÐ/½X¡_G—C Xññq²pÎt‘z˜08ÁŠu–›x£p0¿‚˜‰8 ¤¼¬Hc¶b¨MÇÛ‡&<¥{hÖKÄçÊΜ[ ÀJ€Ï*(žÈ'b18;=vd<^Šrîôü¢Ÿ}G6Ëzíîꓵ³s p7Srœ[Þ.Ä)àqX!^A‘›=7e%…R¶ CbDo쪬XGpòo8 &éæ\w‹ŒäÂ쳤§ÆÜÜ+ç.˜.´÷Òk8/„><À ý:ŠÈZüÈ…Ы–ΞºnËx 5ú( Dþ½.îA9nnð"1•ájî—Eófè²ô­Êû^] x€ºuãå H€ëœE³D¶û$ÆX:"ˆëjºà¸;¶×,@ù÷8Îy‘½ê„R” sfAÜDðôWJ†°øñtXaQM‘—Ir<–óY0§\í±üž”EM6Œ¼–Õ]©ÀgÙ37Ù^8'èmmé‘7/-’’bcáîqWnB…ö±Ça…výDtî0 e0 ½è %²«©G’c£eÀ5ix¹9¬AÎËh»‡Ý8JÈ9‰²»[Ö,¯”ÌôTßû  x€>uq9µjp*Æ/?wŽÈK’­#…*ê"V¡þzðr LUl4àEqVîÒ~RÝÔ –‹ã±BŸ`…~En±žEÏYÀ:qæ ÇaGåx^pX§±€½<$Â+Íæ6ŸÌ¾<óK•®ŒÂ áC°Â§®".§ä°¬B|ά2™õ¦"ÙÖì“T8ëëJ ™3xðÀóI'eG‡¼õ¢yð0jMµ\\Ä7L ìV˜V\ÄdÛQ ÂÀómÙÜ) ÐC©Þ Eв›ƒY~¥•›ó¢·‡ú›© VÌ—ˆ–úàH úˆ!nøÔ¬ð«³ˆÊ±º<òÄ`4Ò §}ðÛ1QÅ9gek8çÅu&RÁ]miòÉükŠdGèÐã°Â«9y€^õ‘¹µbáÂù²øÚbÙàI‚?+ŠyVé~*ð"€Åstð¥¹õ’…RìLÇñ̯9y€~uq9¶ÀR\˜'·¼q±ÈÆNõßNîÈZ±ÔF/š2$ÂB¾ «JnŒ¬YµH½3p®¢7âÆö+Œ+/R²N`!À0\rÁRxYˆ•v¸JŽb©. ×yw$ðRÀ‚8Ys¤Kn|s¥TÍ«`4^S x€¦iÙ¶ÜçÝ7/’º ­ l”£a§hè/º’!Ék=rãå«$=-EAÎ.Âit ÷òz€î5!ù'`‘›JLˆ—›Þt¡È^Ÿ±Ç"B!pGóP\foÅÁÝ0…Xr]±\´j‰y–æ…°¤€XaYm‘és—WÉw.–{Ú$7!FzˆL«@Âõ[ô•›-Yß"÷Üò)È3¶Ww¾íǬ𭻈˹å²Òàƒý®[/ÙÓ œ”8YÁÿ‚±‹±<€Ù¶ÃrÑ[+ä²KV)½T<Ô#ï')àV8Öš—g¹`å¹÷‹ÿ"»ÿZ+e)±0Ï:!ÇTÔ_g• 3ê¯dc›|î®ë°2N†Ñ]y†¢aÝz<À ëꋼÌÛÃØØ¹ó_¯‘¼K eÓÎYÀÕ¡P±ðJš1°(9Vv<)àqXáYo^®= D$þ?ªC õaJeáIEND®B`‚concurrent-ruby-1.0.5/doc/logo/concurrent-ruby-logo-400x400.png000066400000000000000000002115421305460430400241110ustar00rootroot00000000000000‰PNG  IHDR€¿6ÌWiCCPICC ProfileX ­Ywrtt8†€ˆÈ8Š£¹‘°»‡§0a`à|!ûÅF:8Ø€ÿy­„ZùT*ë²ý÷ ÿ€X?Xíëëñu°Œ~Ñ”8p.–MÅ3³S ‚§â  Œ‡Úvß_X|ƒÇÙÑ< 2™£ ¤ 'øA9Œþ°Ž5Ò?$6K‚XÏ/˜ i¼G>""ŠŠ§ –öý—œ a2Ù÷¯L29è/þe l ?lNÞ±ñòÿYD„ÇCm\"°d¦X8Â';ô[iX”53@|%Ò×ÎbVˆ›B E¿qOp¼… ÄTþ1¿XcèKg€,û“M¬!æCæbøK’)mðcŒBâ,cWJ”ãoù˜ÐÈp;jÿ€r0;ƒ,ÿàü€XS'H‡:`BCÌ,!†±ÂT%;»A õÄ4&„¸ÚAÌqGl˜Uªœþä`c*}ƒ‡ïHÕYÒg)fT!Ê ц|TÔ¼ñ-nHW‹ v¶€tصñ01…~uˆtù­gD•CåOŽßèßPO4? ÜœJ…ø\l‚ÓŸ¶÷ã(ÎT:ô:J¶¢öW¨3:ç@õ UŸ/À âáí ¢@(éY¸±ß~Õ˜2 € ~Sþ´pÛ¨‰„¥Hï@$ä‰ýÛÎh£6$@ú¿Ô_m@àFmÂF‹0ð~!Ë‹ÕÃê`m`io, «õ§0Ó=ñ¦x¼Þ /ó‡ü Öáð¦€ÿB³†uÐ: ,#ÿØð<Ü\n÷ 7†{\ÁÔ†”ß–z‡¤QþhðW²-ƒÒ~y%z,ÌþáÁJB­Õ±FX]¨?Ôˉå X5h‰!VÚ¦©¼GÕ:þ¯nÿøòßÿðQµþ—¿éŒ²Œê¿µðýcŒäOü§”jB€?ä²þONôz }€¶¢hz£-h#ÚÞ¡âß:›mx'èï×7<mùã|QyVùûŸ·¿¶’!…ª5°ÿÇ$ÅÁþŒ£¢wPB‚‚ã„ á, lé§(/¬¢¼I êœNåà“ãÆ\pöþC£¬ óÎýÿж—PWÓ—h&°ÐêëOIø%K}à`‚#ƒ1 mR@S`ì3ðۡ׃AÔ:ì{A&Èyà8(§A9¨—A¸š@+¸ºÀð þ1 æÁ"Xß! D„ áA„ DQAHˆbŠØ Žˆâƒ!‘H<²Ù‡d#ùH1r¹€\En"­H'Ò‡¼@Æ‘Yd ùŠA1 vŒF£„!a 1ÖgÌ6L&“ŒIÇÆaÊ0—0 ˜VLæf 3YAJr¢"¨JBQ{Ô D)èn4 -@ËÐôŒõSt ]@×°x,V«û§Öë‡ÁîÆæ`‹±UØlö)v»ˆý‰#âøqr8mœ%΄KÄeâ p¸zÜ=8v¦q«x<ž/…ׄcÓŠOÁçàOâkñwñ}øIü @à!Èt ö2!ŽI8A¸Dh!ô¦ _hèi„hThÌhÑÓÓ‹ÒkÑo¡¡ßC_D…þ!ý8ý+ƒ,ƒ1ƒC<Ãa†J†» />‰DI¢Ñ“GKJIºIî—¼!9#Å-e)•,uQjDš(­/#]&= ƒ—!Ʉɜ”y"‹‘U— –-‘í•ÃÈiÈ…È”ë“ÇÉkÉGÊ—É)0(*$(\TWäT´QLS¼¡ø^I\ÉSéˆÒ¥ŸÊêÊáÊ甇7±n²Ú”¶éÖ¦%Y?••U¢ª™jªj£êG59µµSjÏÕÙÔmÕ÷«·©ÿÐÐÔ hÔhÌjŠkúh–j‘ØI¤ÒC-œ–‘VªV“Öš¶†vœvö0j™ÍR›6ŸÛ<©+ªKÖ=«;¦'¬ç£wFoL_DŸ¬_¦?a fàoPaðÖPÆ0Ôð’á{#e#ŠQ½Ñgcmã]ÆwMPs“,“SVSÓbÓQ3Q³ ³‹f‹æêæ)æw-pÖG,†,,ý,/X.ZiZí²ê°f°v².¶ž°‘µ¡ØÜ²ÅØZÙµ±“°‹´»aì-íÚ¿rrˆq¸½¿ÅaKÉ–7Ž›w:>pbsòvªvZu6rÎuv‘v‰wiserõr½àúÙÍÄ-ßmÌ]É}—{—¯GˆG£'ÁÓÕ³Âse«éÖã[§½Ô½2½·ImKÚÖ¹w{øö;ÞLÞdïk>87ŸjŸïd{ryÅ×Ò·ÔwÑÏØ¯ÐoÞßÀÿ˜ÿl€n@~ÀÛ@ÝÀüÀ™ Ý £A³ÁúÁÁ !Æ!Å!C-BO‡~³« [w ¯ ‰ð‰¸ÉÙ%•Õ-=£sNSNËO[Þç¶ïVº@úžôÉ óŒ‹™Œ™”Ì¡ý:ûOÀ9ÐsPõà‰ƒ?³ü³e+gdÏñËythÓ¡¢Cë‡÷äjäžÊÃçEæ Ñ?R•Ï’Ÿœ?yÔöhÃ1ácYÇ–{ï,P+8]HW_8VdSÔxBüDÞ‰ïÅÁÅÏJŒJjKùK–~>é²ÿ”Á©šÓ§³O=ræùYó³ e’eåøò„ò7ç\Ï=8O:¡‚·"»âGedåX•cUÇÍ ªù«s/b.Æ_œ½äuéÉe“Ë5 5gk9k³¯€+ñWæ®ú\¬³®k»FºVs]âzi=[}VÒ°£añFð±Fƾ›V7Ûnéܪ¿­x»²I¤©äÇÜfºæôæõ–ä–•»ÑwZƒZ'Û¼Û†ÛÝÛ:¶tôܳ¾÷ð¾Ùýö†Zê>lêÔî¼ùˆôèF—FWC·zwýcõÇõ== ½š½O´žÜêÛÜ×ܯßßúÔäéýË®gvÏú]Ÿy =÷>ó"üÅÇ— /¿ ïÁd½b~U0Ê?ZöZæuí˜ÆØq“ñî §‰áI¿Éù©Ø©ïÓéoˆo Þ ½½0£2Ó4k6ûdnëÜô|ôü·…Ìw,ïJßK¿¿þÁàC÷¢ûâôGÊÇõ¥œO<Ÿ*—Õ–ÛVVFW#V¿}ÎúÂó¥j´öà«Û×·ß¿¾ýùqë§õÏ‘õˆõõh2…¼±@a‰ `©¢lO cüuæÚà€[dò@,:$…+ðT-ÁŠa/á p#ø‚%\æi[è.Ó_b¨'¶3¾bƳ¨²F±Õ³ç4ã:ɽÊëÀwQ/¸]èšQ4@ìºNÒ]ªLzN–$·S¾E(+gljWEÕŒÕÓ5š4—µä´=uò6wè®êK¸fÕ˜bÍdÌ---S­Ž[_´¹cÛc7bÿ~ ƒ£Š“‹s’K±ëm·—î_=¶nöòØ·=ϻڧ<âûÉŸ>@&r\¥À°Ð©(ðDBqFIAiÅÉë§ZNwŸ<;^6[þáÜZ]¥L•Í…˜êâ‹­—æj˜ku¯„^-¬»ís½tƒ×ÜÆÖ›Ë·…›Œïø7§·”Þ­mmmëjïéxg§æW–uæ>Jé êvylÔ#ßËÞ»öäE_}ÞÓ°“gϾ >ª{žÿ"î¥ç°ñˆÒ+¾QºÑ¯¯ÆÆÆŸMtMÞ›jn~Óü¶iæÎló\Ë|ûÂãwÓð‹j)KMËœ+ûV|ÉøÊý­þ‡ÛÏŸñwEØ‘8úÕ0˜·¨z +€=Œ£ÇijâÏô£4™´$ÚUºú= NDF"ãÓs/K;k+ÛcöW¸°ÜÜ<Ò¼|Žü‰‚û…Ž Ÿ¹&Ú"Ö)þTâµä¬Ô¢ôY G#O#¿®ðQñµÒå»›jUNªT‹Wß®a¦)Gb"}ÐêÓ®Ñ9¸Ù_W_GoQ¿Ó Ü0ÕÈÛXßDÐc:eöÀ¼Úâ%ÅÊÅZÇFÀØNصٗ;¤o t´sÒqwapùàÚãVížîáî)ëù}k·WɶíÚÞôÞ¯|®’³|üdý¦ýOxò¾ªÞb*†„½ ¿q"2.Ê.Z*úGL%/Ö)Ž+îe|i¶Dáĉ¤ò~ÉÉoR*ví’Ú5³»:5vÝ^å4–´•}/Ó›3Ê`? ?àpP%‹=k5{0çú¡#‡£r·ä©̧Ïÿzôݱ‰ãC…EÏN¼(+™-]9¹~šö ÿYý²Èò“çz*Jµª  %Õ—.sÖhÔ:\ñ¿W·÷ÚáëåõÍ ƒ7n‚[¬·E›ÔîX6û¶ì½[Ñ:ÐN×a~ïÐýÁ‡ôê¼»rº›/öÊ\SrëȆ€Q‘ß¹÷Œ¨ ó4CX"֛н]Ñp;pwàh·ÂÅä )„n˜7I¤ U§-¦]§ ¦{JoDAî?ø‰%ŒÂŒç™T™Ú˜]˜çY2YEYï²mgûÉ~–ÃŽí£\ú\ Ü'yìyñ¼-p\ë ` f Ù³ Á5)W,JÜSÂRRWŠ$M’ÑÕ’Ó•×SÐUÜ®tBù‰ ªª¨æ¬ž¨q\³ŽÔ¯µ¤Ã·ÙB7Y¯Á€Ñ0Â艉¶iµ9E¾³u®-§ÝiÅ-­NæÎ5®ŒnqîÏ<7o­Úƶ=Í{•ãûÎ?:`-(+„7´2\%âz”ftE5öz¼|™$ÎYÉßwFíMµßó0mó¾séË™&û ÌfieçäL&åææ}Èw9Úq\½ ¾ˆtâQ‰oéú©Sg”Ï6—;Ÿ{_‘]¥táÅÅôËò5WëX®UÕ«7ÜnÔ»yó¶|ÓÙfÙ–®ÖðvÆŽÚû¶f:S»xºëzLz‡ûbžÒT M¼Ø7,5Ò>êúz|ÜbhJoúä›™©YϹ”ù¼…“ïŠÞgˆ]tù¨´„[êûTºìµÂ¿ò|õØg«ÏŸ¿œ_Û²öýkå7ÛoŸà©CçÇèÏNjücUU¨«@Œ`úqt}ý“$„|~Y_ÿV¶¾þ£6F¸þë•™úŸ¨´ˆŠ:bãöPŸÿ¾þ¹„Ùý©|¶ pHYs  šœiTXtXML:com.adobe.xmp 930 930 d³ìâ@IDATxì½ `dGu.|º[êÖ¾Ž4Í¾ÏØž±Ç6Þm°áñ0„G€°8L B[x/$ø/ÃBžYcà%$5Œñîñx<ã±=‹gѬÚ÷µ[Ýú¿ïÔ­î+F£¥%Ý–ª¤¾KݺUuOU¯NªS¡8qÎQÀQÀQÀQÀQ`ŠO1¼ î(à(à(à(à( pâ*‚£€£€£€£À´(àdZds/9 8 8 8 8quÀQÀQÀQÀQ`Zp2-²¹—€¸:à(à(à(à(0- 8™ÙÜKŽŽŽŽyŽŽŽ¹EÿÒ­Pˆy×Cn}„Ëí‚ €QŒî# ’ÉTúS ##! …ÌZàA“ôswá(0Ûp2Ûvñ; d‰Tj€a#äÅ@2ˆ‚‰9; ±ôqçÙ¦€Ù¦°‹ßQ  xðGpÈò[! &ápe²º‹ÂQ`| 8Ÿ.Î×Q 0H¦R2<œôÀ#3\•f5&FG")› ¶h݇-  †IÁÈTåðð‰!c¤3Œ•è„Ba}¶èà¾!˜pÌrq¹rP $ yŒºRô}TßáEüC\Ô—D"n(ËU¥Ù£€Ù£­‹ÙQ`F ‘€ôA| ô‘†‚ zp–`"–yf5é^ªxȈÊšQ)¸—'¢€‰¨ãž9 Ì#âñŒôÁlB$Ä‚ Š%8Œ<üÏ€À<€â=Ž ¤sŽÙ§€ìÓÔÅè(0c PqÎá+3:E„@”@ •FxÆ ƒŽ‚—‚˜°8{`Âg)x&S!‰„Ñ ÒùìRÀHvéébsÈ 8tE±k:*Ò$ü`2j1¡Lh „ §$u’•‚q‘Œ¢€Qäp7ŽóO*¿ãñaá¢A¬çPðŒr“¢ œY€È¡,"£hènfL 3&¡‹ÀQ »àÐU"AéCPV !Šà^®Î&ľsÖ¯C ‰:)$»åb ®8 ŒCñ¤ˆ„ ¬ñD‚ƒ 〉ÅVÅz",ƒ'“’?I‰ì“]vr”@r´à\¶&¸âœúºÌjï[¡ë @(èÜ]=pðPÄà E<¬‚‰BòóÝŒ,šî” 8É]ŽÙ¢@<1¬: š!IKˆ\ª,¡¸` ÃdÁ„ÃZs’­’rñ@\=pCCPžãL3íÖ½e 84¨X7÷•8xÖ À óÞ¼ §aµæë”養sÙ¡€ìÐÑÅâ(0c pˆIg_!&*ÏéÌ4^Es£Iƒ ãÁ_j„F2] éY¡€¬ÑEâ(0s PyžÄÔÝ0D J^ŒP¢ `¡“µoB¨á«x…ÑñÈa¬hÔ5{%‡;̘®&͘„.G™S€ÃVƒƒ˜}¥€aâ QiÎK7 ˜ØÅ…ž§y¤Á L¤=ø.‡™gº@CY‘ˆ[bˆãŽ3¡€™PϽë(% pöèFÿáEš6 ÖÈ€ %>Ò3¥\éÄB 1ÇFå‹'™4³±€0ÎÍ”@fJA÷¾£@(@åù(³íˆ“`Bæ¯àÀa,Ï LlØQ`‚÷5¼k‡²Ã˹¦oééÎÓ§€«EÓ§{ÓQ kJè~çÜ¿Ã2|܈ð3`e|01’Æh‰Løã¦„æRÜŽ…Y+¾E‘E[ôîÃB_™ÕçTzûÀT…ºñ³ bÏ“³†„¡9–RI‡+Ó£a×üƒRr5®åjɹ|ç<,pênÜ[}Nóëtdõj–Ýw?Y0Q @4Ïct&œ!Lez4ß5%¶;L›®M›tîEG™Q€: :_QÿAÅ6‡–èì3#3ŒóÜ?Ô¥p“æb ™÷ñŒ —ô¬l”¨°/–}s˜6€L›tîEG™S€CVÃåýs§ÈøÍ} Œd¢èà“L¼¬p;·±åc¾§˜A|£d¢¯Ásæå¹é¼†:î8 8™ÕÜ;Ž3¤ƒº %©þLpaÿXé‰á…sMoÄRT0RÐ`@uD§‰_×À›fM¨{qâ‘ʦE Ó"›{ÉQ`f°‹ Æú.Lèð•aú6öÑ€`|-^ð™ ͳ_2±ïÛ³‘LˆC¸xæ0VAA¾ âÎŽS¦€)“̽à(= Xý%*·-`ðœsi† Òâ…zˆ" ΟJ)8§#ò.ée‡×é]=@¡ŸsŽS¥€©RÌ…w˜!,“'ó'€Ø¡+…ËódÁD‚æHü‹ ñPÁƒyÑͽ¾ƒp—®[ç=¾Äõ TÞçå¹=B”8î0e 8™2ÉÜ Ž3¤€2|³?Ǧð’­+{j6Oð0€ )yá-¨øa€€¡ï<ã‚ <­ÎD7¯R=ˆ¥³;L™@¦L2÷‚£ÀÌ(`˜¾èÞqè@(¤¥ D­R‚LÉ&–èp”„7ëÊ„Óc:®³gdù$¼L“ñ XaA”/:ç(0e 8™2ÉÜ ŽÙ¡ÀàPÜL¥åúPfÿ­RLTZ1rÊùÁ$£÷°Ò‹=ó ¸dŠtç¦K Ó¥œ{ÏQ`†PóíœyEûW<ÑCÏÌRÉ~”èÎ’Làc½Î’6&!™p¼ŒChœÒ›ç̻ϰ4çë@g¹»¯ž/ xbõƒq͇¯øK«º½0fœŠêîI€ Ð…Òݨ×Õ1{ x;|fÃr ±®qbˆçŽS¢€)‘ËvÈt¡®@Ïl_K¦nüùÀ$Ù™P2I?7q[I…_Á´¸?mqÄÜzÒĹ©QÀÈÔèåB; ÌŒäöpCžý+šT7 t…#t€³«Dâ…LÌ6·|gQ‡—ø™øø€÷þa.4TF‘ÎÅŒ"…Þ¦B S¡– ë(% pøŠk0Âa;…ÖBüvxÉ2z{fÒ£Áļ3˜Œ;¨•'ÏÔƒÀò+Kßè¢Yøp²ðËØ}aÀ(@¦mZ°0@Àl'™{9!”‚  Ëø «§t¡ñ¢yÇ¿Ím Egß ã‚I#&qì†HEz¾[P¨ôr‡ÉSÀÈäiåB: d…IlæÔ?0„¸ŒòÜFêA…½=˜4!8Œ¼„‚>KqqTŠ c0Ñ5}ýCFqòïFÈÍ¥¸ÄHšôîb’p2IB¹`ŽÙ¢€Ù@ ë/ÀùS#ž”@]Á@% œ}eÝhÉÄèHøl´D‚ø /.ŽImu™””¤¥ †­®‘ž¾iiëâ<¡ÀBãP‡±ŠŠÜþ ¤“s“§€ÉÓÊ…tÈ 8|Ž8ŒÝD©COÀ ²{^0 sQ‡A‰KªKeÙÒ Ýœjt(ÑôÊK‹¤ š/'Û…ëPÔˆ#R5Šô±o¸{G‰)àv“™˜>î©£@Ö)ÀèÔO¨Ú‚" žì0B@€t¢g½7ÏM8óœÏŒƒ³$µ5e²¢¾JÁ#óltöéÔÝ˪°¥mD *2NÕɤãýŽ»s8€œ‹2ÎßQ`–(00W`°ì zd€„€¢àá“ Ð0{.¬…äQ_W©9¦ŸU”ýú+ˆ@ ©«­”0þÔ&LšP*rÎQ`*p2j¹°Ž3¤õ P “‰“qs؉þŒón<ûLÏ &xÇ“LèG¦_^^,õ(è&?ô+ԼÕBGRUY i–)Ý`ŠþŒÃ9GÉPÀÈd¨äÂ8 Ì–)sÀ¡886õ`ÔüHÌÙ&äádäö7æ–’ gOÅby:e% çË®ÍOue©îJ¨Š}(Òs˜ €L…Z.¬£À )Àè‰áaHÀÄeñÁH">0ÁûL“´7<{ïñLɃ: ÂdÁƒïÙ°ùЃP ¡…ºÿ3½qG (àdâ¸GŽÙ¦„: ™>ÿ¬³q˜ø‡¹œPÃ0‚¸¤ªTª*Jôu 6®Éœ=,’J Dó0´fd2ïº0ޤ€W怖Ás!M·+Xè9$L2ÃŒ>¥ÞƒRG]m…æÜGMõ3–Ö–Cwav´à4bztååE*鉸×<êwp87€œ›6@V(`%cÂúB‘q{Ì›ÌZÿ$üA2!’èµ}¦C*}”`øªLófãžnF­B“'¤,.tÎQ`²p+Ñ'K)ÎQ`†Hpt f–™"ªØ€DgDÑà Uzëô]xÔÖ” •ßt3‘>4ïÀxJK Ó+Ò³¯? w½ð(à$…W¦î‹Jqº¬J*a¨ a$â†ýé%¡ÄûCX>££k7 <§›©ô¡‘øEEѬÇé‹Þ].@ 8Y€…ê>)˜àðÒ™E„Þú󀉆W£‹>–@ú ÙuJ¶¤â]A,ª u3KŒeüÝÑQà\pr.Ê8G,QÀ2z*ГÔoÀ©P˱³¬R〠u&I̼*†µÜªJ3m7=Ô•…6ŸJp¡£—?˜hv¬¸’åt]t¹I ¹Yn.×9FBTÄðø³"ÊôÙ^(˜ÐÚ.Mµa«@¿z6¤ Jù@ø£³ÙÒ{ °8±ÔXôg ‹¾ 8Ìì.„!lbõVÚྠÜPŠÒ ¹¶âŠw¦Ê$ ÝD ”çt–ÑëM6È„&ëBo{»t?.ƒÝ=ŠrøKùŠåR´t©‚‡æi; ÉF ät@rºø\æs…”>Ì~!ÁÜ«t¶,ž×(0 sá`R*`«ª¼¬HßQHúí^<̃ćäè÷Ë/¿üÒÿËŸ Uõ\i嵔ɿU^}“¬½óvYù¦7J^Y™'€2‹Û9YÜåï¾~Ö) ìY÷c§àêŒ\¦ká"(êio!~pój¬ûÈãÔ]ºô;ævÚGù3º¡†£ÒèYiøÈïH˘5Ù¼M GÂBæ——'yЋ >þ 4àMôKÍkÿ‰Ö¯6ˆ‘iÁBxÑMã]¥è¾!°°£³œ¹·sNɵsùÍ9 è6¶´ÂëõÔm‡ÝJ*ÀÓ/™è5¾´¦ºLÂ`ötVšÑ›éN(lšýÑ'Ÿ’f€Gå5WIï?þô?¿GJóÂRÔHX³¼H.}íUR½}³4wuËÉ»ï•SŸÿ‚„¶¯’#HÿГOj.fcVØt?Ͻ7·pÈÜÒÛ¥¶)„ùu5¢æmÁbTŸ]ñýx3D¼Á&Oùºß¹ñç"C$pº_‘ÒRá&¶=C"zê¤ùŸ—nÜ@…^®–¼­¥Òò«ûåÀñ6i~ô)©”eRVS-Ý å©ê ë5~IK=ÜaÑPÀÈ¢)j÷¡óE!Pä`¤$bˆ]Mˆ *FÀ/Á=?*ÊÔ|IvómòÀ¼l¾îZiüóOKÃç>+± /—áM—HøT› ”äKg("¡¦aiøÞ>i“V)ªY'ýØ>·ëäi9Ñ~BnùöwdË•Wf7k.¶œ£€œ+2—á\£×€¤„ŠsïtMˆÞ-‚_QP òÜJöœo·@V„é¸7ýÙG届JyæÏþTbµk$²z‰ôŸn•áòY‘ŽÕEÄú¬CÚû´@X‘7üûÈ•o¸MÑÎIÙ(‘ÜÃHî–ËyŽP€û€$â˜Â‹=ü‚Æ­ð*J,#ÞÙ"‡Þ›o2³¯BRUQ"4¯NgÈ„Èî1 ˆÐ]ðÊWÊ«wï¹âZ©|ö)©ZQ'=ûv˶[_/¯ý·{eåŽN%"o&—z¸Ã¢¥€E[ôîÃg—™¡*cÆ]å2`³ïΔK*8Nùåž™á«ÙÍ'Ê"k.¹D®ûþ¿Hþï“á]Ë5ÿíýró׿&U7¦ó9›€6ÛßêâÏ.œ$»ôt±9 Œ¢% ³:¼½á*½`(jÊ1ËÈ$¸Åsê?h÷ª´˜¨æÎ)ˆx V³v­bfVôúkeÃ+o–‚úzf×L›»|¹”‚M Á.—»§•ЃØÊ–k;<þœ>›O3’{õ”J¨+©(/R&|>—½}M y 4TRS#¿ó]šEÞS¹oO½ÜÁQ@)àÄUGY¤7g„]… ³“”I |9í(‡p»ôp$$•ÐÐÆ­œ;nÖ//M‘@¢™lx+ág=m—@ÎQÀé@r®È\†s‰œQE!W¦„¡º;–EñP„Ìšú‚X4mº}^¿SήÍkN\⦀ŽËZîS Oè´\öë ^pˆÈ€ % eÑú~²’ßêó9–>Î"7ÓW9ä¬'ÎÃQ€pCX®8 ̬îbú*ÒuF.ŽÀ¡gXÀ¤Éª)Taö§ÖÒ½ƒ^ÎËÁäi^’v‰æœ’#å²™›âN„\gn 1z{æ­&º ºî>Hgýõf¾Ès ò1_ßïÒ=/€œ—D.€£Àô)0„!,M9øç­GÇ•zÑ[ÔÂ|IY©Ùº–ƒàTgã\òãò, ¸!¬`•‡ËÍ ù­~âÞ´ó±5¾Kìà0¤àQXhÌ—Ø!0ót¾Ž£gŠÍW.\ºÁ¥€à–ËYÎRÀ@Av°vûZ FôÀÑóàöµUØ}Ðn„OWèq+€ª¸<ø)à†°üÔp׎Y¤dp€»Œ&LF¬#V8¨0¢7¸¦’ë?¸.Pz '8ç(0œ2UœŸ£@(ÀUå4cB% €¤£†ôÁYXÃÔ`ýGÐô6ŸÔƒ8ç(0œ2UœŸ£@(0 3&Cø Z™Jôæ ˜ðÚ$BûW¥¥P¢G³j–£ è9 $ËD]8Ñ9 dᔥû’€Q`пˆy3X:$^^ "I¬V¯ÀðU^^$`_€ìp ’sŽãQÀI ãQÅù9 d¾¢-,Â…îóá¡Ož6DRA]é­ÿ`²ARXS‘X*ÎG ãQÅù9 d ì…žÄðÝD þ̺ ÞDBfÿXDÊ‚¨@G¾ f\ä蜣Àxp2UœŸ£@(‡þƒÆÁ†uÈJê<0¡/Ÿ—Aÿá­ÿÈB²YBDóì‰OYÝE–ëp’ë%èò8 Ø!(Zá5l— ¡"‡‘Æ2vÍÍäÓ]9 丕m Bg†°"àÄdÆtv*/Ft»B3¬ežíÈõ*æ[‚–3—Ÿù¥€š_ú»Ô((pƒJhó3+ÒùÉ4ß½´Ôè?2Auœ!æ_IÔ|º|Í=€Ì=Í]Š‹€ ,"$ˆP ø0_ìd+†ñ,Í“’â€ë?s- ä Ýq®)àd®)îÒ[ ôAá •Á ³þƒGb õ±|(Ñ­\²p&Ä® °°\".М9Y ë>k~)ÀXdºtF’–C!fa^)¦ïÆ¢ùÆH*z¸ƒJ ˜…•YîITË©ËÐ\SÀÈ\SÜ¥·((À5 Vyλÿè™×Ô¤°T¡c‘ v}H‰CÑa·ôT^; ˆ¹uyšK 8™Kj»´<ìJrJ v#&«;°gÓ“a¡Oÿ`žl¾‰ÓŽÍL¬ KK ¾‚ìÝ4Þ€ˆËΠÀÖ€Ðú‡ÑàÂ縘{ —–ׄ‰/»bŒ–@üOÝõb¦€“@sé»oŸ5 pˆ·dP™/°³(/»RBgýg-33ŒØJUÆ4ý #s¯/( 8YPÅé>&(à*tÕ C™ùWRR˜UT“oô  QÂ<: Jí N>€§,\Nrœ‡g‹#W/HÒb6‘‚½RXˉ/¦Âa¬aowŜȴËäœPÀÈœÙ%²˜(À}Ðu zí†è0• *@`D1??¢d±CDA¦ÍÎC‰nA2‡AδËÛ¬SÀȬ“Ø%°Ø(À¡žAè@èŒôa(@¦KÅ:]‰gÂÄÜÿ¨¦ñZ1Ðü|»Î.= ËVÖÌÙÃô~¼–˜¦§eoŽãµ¹Ð«KgÝ],( p£(J ¬¡f&–©«¬“v oyi±~3ëv.ÔU]L`䷅î߹ *ì >&bÃpã²ù´?<ÔOÏÜcÁôôÒt€°ÇdÀã·¿i¸Î(:¬»pÈX'Ùy¡bL¹ýúíÂ3²]Öéü¼0L˜øÖ€d)ýÙŒ† Aó+üå›Å󳙜‹;G(8!H°!š3.Æ8 " ħúÓwLX½‡‰$ÌŸZÒ(T*¡a¸0À?ÌÃD"’SÚXÆ$¥·Ì ^õã…p~Ž£)ÀwÔƒ «‚¨@¶®\Ѓ/VztôK¿c›¡ôaA´U<×.{³M@ÈxàANgÅ„xh†L{¤ù:ï5•BxÇ÷išhx ¼Ð ä=¸J'‘<ô ó07ŸóóymÅtö(ýŽùëç$×Kcê+%Ñ……0¢ô]Ç#Û‰cßkÌcw»H)9'x ÑY (Ð<„ž}à¡ïz¨×¨ã<ÓÙw½Çz2`W×b¸ 22`B £¥JfÈäc§¸~œ-“ÙôÇ“»v8›\…NfËN:«¡¿ÓÁzÉ)¼¬[9áØŒð¬ÿ´ße·¶u¨œ(½YÏd j±2}mhF2àW+ÿ§ÿpÃz|.ð°TÒpçÆgÒA\éNc…¸qà.qãåðCj(J!•H¸íh û7Ðz*÷q°€bÓÎÚÙûVƧX×R³FÚÙŽÈõd¶&µuŽ¥9‚¥\‚è¶þ˜a®ÙÎÙôãgžYÍ0¯hÛ˜~lîÍ…F€H†¹“ÀSBÝTÁ# L°-4]pm0Œ?wѲêà ±®J@á0W,–‡…`Q]MLpaë˜'ºóβñ@CcðÒ·qix¢hä\NP€fLØ¡Þ@;=ZX¿Œ¡¼ÔØÀÒ9»ÚëY…‘G‚K·=XÅ3ß¹™w±=4Ël=žKvn@:—äaØsöÀCó‚ô¬^…÷¦WiZ9ï9¾=0””þÁ¸tv÷«®$èªâ¢B(º±Àaâóq ħ~`4>_}×4d‚áèÆÆiùsp( ,Ë …jë(sǺÃúÄE„tgÕõ æA;HÈãBEJ~G0 çåÉ@O¯<õÍoK;ÀãúWÜ ±'ü+_!uý3yé‹+ ÈyÅÕ’_S"ù믑Hs§4Üñn)­ª’úÛ^oÀƒùó@ËŸ†»ž_ °ãÀº£ÕÇV!d)Âë iÎo.§–:Û(%nšhñwª¦‹ ½Ð(!QÙ‹GM{llsì¹ÙŠª=zòz=’‡¶~“(gÔPâX^W™ÖgðIºw©Áг2ß»&#eñÚZ`åPF¸¬TÊàJÉñžƒ)–š¥ë¤ô–þ#‡eàȉïZÂÇŠ¥à­RxRdh磿â‰.[e£vçP€uÁv†††Ó¸NÉWæÃ²÷ÎM¤òÐÈ5ÇoSƒŠž³½\û—ßìS 05YM%„Í ^6¹sõí–qÛa)’…<[ÁÙ¶bcá¢ÂºÚr“6‡¬2 pV±L 0ŸTÁçcê›_)CÚ8ÖÒ="JdàïþIò¥TVÜpÔ/«”’ß½Qdå{¤ëàq >*õx» EÃràëÿ üÙŸK¤¤D¿Ù2®³òá<本·œ…•®‹6¨/-Å>èv ˆ}”+gZgÐ!,|‡sޤ@ hïÌ÷\àA`°ÃJ³ ÊÀè™^LoSßAGf=>h˜‰|߀Ȇk¯•š~XZî‘¡XDÂõ%Y[#í=']ßÿ¹DŽdw«475Kÿá8ðœœxò)yú¯>/'ŸÙ­Éh^ˆJ΂Fïå3厇dµNDŠ sc©±Äd=ã¶°¨Ë¡Óº76 »_TŒBª“¹FÑÛ`ÎW ÊÌçPò° ÞH !)ò¶õeiF—TFŽ€±D!Aìxïr䮿—ÞçHÞúÕ"}I)X^*ƒáJÙ÷‹¥ùŸ¢#cñð2IìÙ-]oWEû'Ÿ”Õ×_gZ1¶sÁ %Vê ¬TÈzL‰“ŠgNÿ.ôˆ ŒœŸ t—ôóJÉI%¬„“@ƧÖâó ”BòsÍM… À–šð@»1ÒŽYQœíªa™ÇÊíÛdÇ?~,¦O¢øö~ôîúaû»I†å®“«·JtãvéߺLÚ {ž’6d¦ö’K<ØãåÏ‚^¶óéâ›X,Ô\"‡q`¾¬KdÀv o®”M™XÇ!,š¦÷¯±ÏÜyqR Pˆ-‚ÖK$!öÓ(ë¯mls1lÅ<°×È4Ósùé™m¦B)„ÒÈ̪:ýoÿ.…÷ß'e›¶Is{— €¡2˜üÓ‰:%€ T½î6yû‡> ÛnºIs„hW3¾Î·ÞÀöÿ•—ù à1p–ÝÆë¯—þOý¹tÿõç¤qSÕºþ¦[dùï½EV]w­,]¿^¾­àlÏÖŸ ÎdS~yì%b,º$Jq”J8“Œ€béèÏ]gƒ¬0ÆÁî‡îU õÅ^”ës.Hõ‡õŽß✣)XaætÌÓ»{úµGæ—fð^¶’‰€½f ™g£ýÇæ®·wPRKfÇ|ƒý¦h,&n—<ü×#½ërÉ›ß,Kaº¤°ŽFMŒã·ÓA¸˜' :ò§R/‰ªc"˜à™s³@Áfꥊ óaÂkgóÍBʳ%;'TªÛiÊ®32ë$|R½f.¾êîH%MOò˜xXfÍ<ôäT€Ò?Û ‡€@W±aƒ\sà)[R#Q¬8·Îæ¸gCÛ§Ÿ Â…ØáB¾9;ˆI7ÌÓ3.ö£}.†ñ;â”IËïë®'C#rÅ9ˉpo ߘA/Îq D¿ƒCºì€q¿ýÀ©UÉÉÑ…É @HGö¤Ë ‰tvù$Ô\2V2;Ã`3×l´£%ŒÌ³Ñþ¦þ›xL6¼ *F;;û@² ZO”[˜ÐÃ[²i³zé7áã˜^6ÒdœÝƇ †°¿ •½ýýC ÜÛ`bÌÊhÜaJ0\”4¨ É: e¨³ù@ÒX‹zJñÎ`¶1æ›ú6~¥š3'eX¶5‡ó_Fó•ƒÑ]ÏùÊÅ$ÒåØqyy‘2»”'‚°bÏ&x˜æÁÖ#ÒÑÕ§fÛ™U“æ$2=¥ ¦rf–ÎÎB‹% ÌÇ¡TW sóU•ÅRŠE’—.ìmÒÔÒ%í½2 …´un@1’túÃAϘˆAç_¢9s0ù·Ù¥=7ÖQçrB±ÅÄ!—ŠŠ"0¹>í±·Lg„Õ|´„1}ÉÃ4}Æm¦Ærè§µ½[V._¢ Wž…ƒ‚Æ,Ä;^”Jüq–ÐÀàôõÇ¥·µ[•ñEEQ)ÆÂ7J-ÎMLöÐ醡ëHbˆ‡÷¶£A „‹‹2û€dCªÔçð 3úÐæ8 ˶³9LÞ%@ äŒbiG©®„…Z(‚9´ÄFÊ?ö‡l¥6 7;àAp¢#Chmï‘Þ¾A½·ÌAoÀ!/Ïèšh󫇣Øe‘RÉÉ3írª±Cº8‘aœÙ7–> €Yùn ´Ž þ(€àÞH®ÖneÀï†ôA]sŽ9 ,2‚Ç’ª09ôœÁÔ”‰yœÌl¸£AÅÈ c~ˆ Ü^Ûw™†^{àÁ8(íplûLS‡>K3^`Žcõ5Õe²bY•TU”hº±©KŽo–F˜•§ÞÄÐÊ7ÂæÑq‘bÊŸc$ S¿ôet<8œ&z¸@6—¥(6¶»6ÊøåòW¹¼Ï„9;6Ái¨Ü›ÃHCf•,AÁH#–ɥϬþS⇆÷â¤î :‚æÒnYZS®½±™?èï’ÆÐ;•—bZ\º!‘PáN‹ö¢‘ÉÒbš$c'áO:ÒÌ0Ò aöóG©˜S§YW¬äÁûX,·×€RyØß†[ÛrË^yªsbè°H9 äé“eO9êÑi¾f¢c) `fti0P1L Ã3!¼kN‡Ç•FHNnÓ] ¹çùb`–î‡Â_u¢Tzz¤³ÒN逮¤K×7p¡e1¦9sÆœ[ö^ b¨+ã,¥| šºaÌÌ”Ç0ï ÁqøÊJ á{Ü7LŸ¹[£dìZª]R¦J_öŒýÎ2°4L<4RŠî&½A,Êk8Ù"›7ÔëÔÆÅ"öªT*Ë‹¡R áôêÖ¶^¬´Î×û‚«8XVàýe´ð®UÖˆ9˜}Ä !¥åú–NñÆ 7‡ä(i9ç(»‚²#C²Œ©:J$Ím]j¿*=C áÈüÌ7öÞœÕ#öÚJÆCÓ±ñph§½½WNžn—U+fwV–f( H¸&€CXü-­‰ë4gN>ÕØ.˜Ì}ã+*Š¥¼´HgqùÁÃÆ€ÏÊzXÓ0êgC>ÔÓ\í*t[g³žø,GTÅrçöΖsn4X¯çÂÙ¶8i/œ~œ‚Ïøq¼ž³‰¨èå8-÷$×u ð°u„é$†²hô±fI9"_ÎV^?¤Ò}™§x§Ù™6€k'ô%m=ºx®åR e| ô%Ú‹õ¡ÉB®‘àð–mêBBðÚè@¬áKßççV¥aûÁð0¿)au ¹õ3Ê-ëªB„2ÎHËDÇvaÛFÆwv®4¾<ÌUºã}MÎ?ÊWŽºZ|E}µÎ–êƒùÔRŸý^ÆŸÕˆi²1ihR&Is+ ’çrþÆÃFEzP2«ªÄðÀ‚ÓÛ0í¹º’Ó(.µ&P]UªÃ\:[ù í8´C«ÕŽ„Ñ:4¢“¬T¬žƒe’2ÆG©ž'?á¼Yf=¤³gÖl[×õûùÐzðzG£šqüØ¡à.ŽúKñŒ4È—ø¼»·_c _QALJ¼µBL+Œp^^žNÀàN–ÊËZóáËãë7A¶²úhAÈXŠp†ÐJ‚$*{Ix˜uÃT _%¡" ¿þ™GôH‡×gž?ÃðŸN[@C0þÒá3rÁ–•:ÆÍ°Lk1¹±_Ëï' òWW‹á-”Á„ç–ÖÕTUëa†!ðXš™òÉK®ÑQëkêwÒUèVɵo²ùå:óËh2—]¦|L9C+ÒõÐÖDZßÈ¡;2ì~,ºíó’øPw†q)y÷ÂbÅ  ô£ëmÐvÀŽÝ˜É؃)ð=8ëŒÎ¡¤4wsÃe(Øï8OÖ™½Jp®‚ù¦%Ð'®ÂÚ¬UK+¤¼¢Lêë–ÈÊe5R]]õpå:1ÃÖ+æË^Í÷lÝ/Haå Sâ:*}›[ºµÐM¥° gó¯}*àÁømxÎ:¢¡ÇC‘-›–kº|~® 8[´x- tx«.*K0Ñ¡‹ @Ò]IÃñ9Y\v¬ÂÂÐÊò’ÑŠw-›Ü¡£QS7´ji¡Ùv6 =‰+hå4¥ü LŒ~LJ´e<¥8æ!0óIg϶CI¿ñÚ)‡¿h™¡­³Ö¸û¥¯¯Òè÷:¥{õ4£iì”#-}²?é `bA~Þƒå`¯åøÅ0ó ? {„£øÅG`çUQ­ÌKÀéH/µ©wHäd·È âj_‹YÀŒHD¶ÉÍ—×Ëõ—¬—+.Ù$mÝ^W£à1×e² „•Â’ë5b0ÅÁa”x"!Ô]pèÉ«SÓ¸ î4—‡žuÀ#,›7.×JiÓ×p‹ð`¦¥v ¦\sˆ«Ó€ÛÚº¥¦ašA·V\s•v%”î|ÎY\*•°!Ái^1ˆ¤´ßȼq½Œ­\¬cd]|ν@èüaÕ#‡¬Áóø:,´oa~Æ:ÖC[íÙ†!Pú!1´´u¢vÁhj·4œnU°hF½|©©Gž8Ó>€Ûð&íšñW‘'••Q©‚ņ « $V[$ù‘à¦[4aGŸáΪIä‹g­8°CÁê̳ú#4ó^ˆÅ¦u°vï`•ùeTyk±=â¥_<)mƒÃòÀΓòÀ¿ÄÓ_ȵoY#ïyõrë-׊DüÁQ/gõ° „#ñm¯À”SÚs:…YSÝ`^º¯ …Ê?–.xÍ÷ÌÏóFý§?/èìIÃcá$AŠŠûë—Jß¼°8¶Ñ’žtÔ ø«««Äl6ôæ`{« ¢>M§P*áÌ®j,%àpìׯÁ÷m™ò:ˆŽC;¶1\3ÁaŸhÔHó<Ù#8qT«£)„bÈïæÕeR¸®\~öÍ礫ïŸäÞÿõaè€k•ÙöbãÍöyAˆŸX¬„ì=­ZY#N஦2K¡…Œ0éÊŠ—-#P?™WXÞþð ËJGéæÈÑf5ûÀ´”¡ ðl¤Í^ÐÏi:~J3Œ cp)@„G'ô$Mgn…²½º¥®î]ñÎ5%µŽä,.êl<,Ædïñý^žÈaØ3åð]Ô·q ò8ÍLzC²3åú¶©l;ۮȢ٦X¶-ÇÐñ8tºKžhÄÂb0ˆ ²ÒÄ€Å(ªëË`VíÔÆÉââ·$†ŒVoe¾Õëx‰«þÜ]‹Ø;Ž9¥³i¤oϺ8ßó±/Øð$EP.J&gú*™\yÛjyä{å¾×>!w¾ãõJ7Òr6ÛÆ¢Ñ³=ZÎË?qªUE[;Ñ™Š«—¨(þ£ôZxϬ?ŸáÚóUf¡½T΃/Qo"–>cÎd ä°p¤!3% ÝõØŸ¤¹  ºtJðXædˆìcB…¦Ä®.”¿Ó¬FŸ¹HC/6$êæç'××p†Sgg¦„·ÉñSÍrøx“<¸IŸé’gš1ÓeëKó¥@QŽõY¯\I3GŒÅ4RÖ3«w 4ÁtQ(o¹­CÁE³ðè( €ð³ýHÌqöë–é0 ¹lÕ¬6pajŒ`^±Ú Ïk:­|úÀTPà‡V¸ý‡Nëyµ“D ¡Îq4Ü<$mYN¬üü-¯¯R!˜p0וtÐÌü©v(Ü‹1M˜RI™N¡¶åË8è콉yö:޵GZ™¼ä¸ Š^:§–«cÞüì… öI¹°ÒS‡}ñ ÚcŸÆbBS4ìx™rfÙŸ¥õFýXGÔÚÁD:zÍ: uàh“ì9Ò*/´H/˜eMQDVCš(+È“ÿ²¾L»‡7‚àÀ¸X.tL›úm”^búe<ŒööžæÆ‰_—‡oOPÚ* ë4Ṛf½¨Ä_XɨX_·v©C2³2T$geÂs¾ÄâÉúó™õÓš‡{”ñ2— GŽ¿xà”ÆµfU­6ÛpLŒî8––é[:QOBÚÕ×Ua\»K(‰´aC1.íÃì®õ)§9 Q*!èøã`üö~lZÙ¾g}!³Òºƒ Ât“¨¦)÷…²)—m†1Sõ;±cx¿3e1ZÂÐu.š§¡à>v²I^jh–—Ž·Éž“]rr !10y*´+‹óåå«ÊU¯D° q'¡…i·LÏ&;:uíªûÀŸÉ»&þaê†r8ñØ€l„y%Z}˜ ·h„Ù2©:ˆ}œFÊý.hb:%E¯¢±BZÆ©œê©•Õ# 1¯¥À8Ø#JA¼|ñà)­èÖ:Åúd+µeú¶ŒÈ€—/«P`æL¤œ>Ó†Ó­ûº·Àc[{ʯfeÊd]-TÂ!1ë,#³ñZÿlžYeP䨦°b°'Ìá+;Lj*ÖRµ• ¯˜:6ùw™Ÿ´Ó›Q>éGS¹°y0:ÎkÍ8KcëCZGï€[G7†¢†:z€¶wäT'fBõ«”@Åö€ÅÌ~ÚÆH©ž6¸8û‹Jí¡A‚—Í ®2—š¼–Ã?›¯…x6»Õóƒ‡å²mÒv×fû[-€°¬Ü–AqEô–M+äÄ ,pó6âþÊ P. g~¦H”EÐ/-y˜ê¬uÖ Oq™"?æ{É~€ÇŒ7opëD 'w´ È–Á:,šñ§Â“!8{«+|{ušö (Q« tçðW$ê»üñ0e{?¹\L>óéw¼'øM¸B˜õˆ/ÙwÉý<çÏgÆ×>Ú97›^×ø}é£ÿ1'°Î³÷O¡³ñúóê§³¢¨è¦tq¸¡QµHÖX´Q .T =Q LÞïXàç‚;üQº d1È-t½†f©kt¦ýúÓZl׬ƒ(‹¥ÆÛwªGV½zµ\~ÉV%¥aÃf*‹@HV[éÙØ8ÖAJ(Å¥‘~ìnf™œ<ˆÃkþàÄ[ÍÍ5 R±Î1ñ­›VjÁ2M›þìñˆÙÒÉ0+Ó³¥Í-þÖ@Çt ÉI oqÓ+n+KÛ[”PÊ`¢~Y¥J/\{bã!Uf‹þšG”-këõVRfÌgø©ƒó¤à ÷DǑ䰤PÆs!tÕÃç˜ñ•þö1éØüÚøǹʱÆ3ý” cÁ‘&>ÚÚ»TwqøØyñ¥ÓºÞ¢¡¹O¥‡B¬c(Mª1$UWY`ÚâäpfÏu&c[0,˜)Ï/ÓÂè¹x!œ+Ûc˜i&{;ä~ú¿¢=,S‚Œ)æY!Ò¢KU6.ËPh]—›#Å8l fñŸk•æ5X¦Z{•;Ò«åÔ…ÐŒiÒéÃm]¥÷6M›wž˜– *ÓCPÞð·”®Ð)Ú\çC „ wJ|’¤âý%(`ëë*0?~ )–é0¥?.{=qê?eq³N°ÿÀk²Z® â^ –%kyƒA—^ ‹ã½½2„Ån‰D\Ï­­2ÔÕ-‰~˜×ˆ«1¾DG§ ÷ô¨±=MICj¨g,XŒÖ,‘0ŒðÑ_´ P¢e¥«¬XE¥äǰ(®¨Hbåèésq#è§yÁ9ãP{½N}fë©~Ò£„ÉÒuÃT;VpŸ<Ý㢲€q€F+§Ñš¦ÎCºXUƒYsH†)ñ]•bê/àC!CsÁ0zaèÉ4œCˆ T¸Õ%QÙûó3òö])¯{Õup®ìb9ñ•‹mÔl,TÞnݼJÙBµÛÄæt1j¾ØŠ¯“iÐYÉÃ#lŸ³ypÍцXâ–‹/\­–|mã4±¸ãd(`ËŠa-ýXf0³nåò%XÐ! ˜¦ÍUî©aÌï‡TòÀû(ô$KkÊdÂPŸ2zM‰)Hܓɋ Ã9í'48ÔFK¬§›{tL?ß›Æk{ë‰éïèž–ékm“®£Ç¤·±QúŽËÀždpçcÍN*£õª—^“oŒ, y|V³Àk¯hX†áuëÏëhýV)¼z»nÞ(E55R²j•”,¯—¢JÐ÷1€MC·´Ùd·D°R ;RN*ÈÉs/“‡Û-/:%û¶È ¬ææ:Š%`heEQÙ¸ Óh ÛËÂ…‚¯Ù&ôŒçiz‡èiSu™ñtWi ÄA×zè‰öžÆÂè«*åï3lÊ•*]m=Kž¥  ã–š•›b3™Aäð±&Øoêñz®hšlüó*üùÀÄc`® Èà Ùvej;¶¯U«µÌÓL7¦qò弯§€¥éGÇÿVsæŒirÉ1èµÎ4u*obšœá &»l@IDATFW.¯†!ºj)ó oÙxl¼ã§z¶/ßÓõ zè 1æŠË×C·¶J’°ÚÚÙÔ$­ˆ¶Ã‡¥õù¤{ß ÒwßOÕÄ’e×dòl”°Š$ùKK$„º¦Çcêš'HVsxmßczü@íáCÒUØ ã¨`v¡ÀF×&$N7Iü‡?}Á€ C®Ý.E×_.åÛ.’ò­›¥|Í)©_É¥RÁ£ û¼ìÙs@š»%ðàPÖÎ=‡åÛ¿Ü#ª‹¤€±€Að4ú3EšèÙóÚŠ—ôÙ§ó=?ûEë“@ù/Å&e‡º0m|÷€<ðÛ?‹¶¬›sz`ýy‹uÎ3”IËD¨»h#j8ÞªC#y˜%Âç(Ç´¸ï¿äa)ÌðúÃRDL¨M¨K/^ “¥úÙþ4ƒB‡\ËiHgËŽÊ^l<Š?§0Ä5ƒt´@ŠúÜ=±¾¾cǵºÞ¾GŽÌ¨2÷ãSÂp:êw~ð+9ýË•ÛVK5LrG‡ze°é´4ïÝ+M¿úôïzBƒ AëXÑòU’Ï-™¹Ù´’ÙÃ<84Èì®ãŒÎjê™a'âÇDÔß|¾Ö1Í{Óô€ a(K$&Áš‹‘ã'ðµ°þ G@‰É )~ÇÍRqÕˤêâ‹%Q¹Döbª{w<é#*ä§åÙªŽgŠnNƒç¬3›/äb^àçôléjÛ?FÛŽ6&\óÞ{^Æ™²°ï˜Ç&^úÌÀ„É µ?Ϩ8ÜË£I˜ïzéùŸñ%ÆkÃÚ0LHßÐÇéçú xBšh†âû6¬%œ~‡Ö†Iß§ã€I¥ex²/.}tÉüü}ò†×¼o™xÎW_5`–@&AHV[(4GNÓíÜqÃl,¦‚˜ ÇèÎ úŒáLubœZ¡’uÇö5ªè5ïgÒã½sÓ£€ŸÎŒ÷,?nF=ÉœÆñ8$Ã^s Ë˖–ËÚ5K¥ni•Nª°)Kým£öI/<XzOËЙÒ¸ûiiyè!éÜõŒ2Z•è’Õ’_S)(ºÃ‰f(…À|Ãø)P g¯ÃE`¢øO×;^ÓéÙ>3wÞ1óÜVÇ{SAˆq°>“k1ßt†Â0Á †ÁŒ6y‰€Ò¦oìÊßüV©ºùRpÁE’¨Y&íÃay+žïþá#²$ÆdX£…eZêNT§øGì”G'œ”<êµõç=ÿ”“š÷F<1-…Ù0W|OýHÜð’ïÓÙrâ-}L¼æ)Ÿ±­”xmî=o^×7Ì› c®4,#§³ïz7FßõÒ`Æ­g äñsmâ´ÏõEª‰Òïhü¼×?½ðâ2ï !óœquæÞûé™íYWæ+2G ZLxÅJaA$ý™J#èÁR7b* Ù§ó ]¦Bñ¹ñÔ,pêC÷ö Wbu|}ú›žz¸Ã´)`iî§gGg¯9ÚˆÎ0g†ÉáJü£ãÏíhC°»U&ëa“»[‚±Žu~½Ÿõwboˆ={åàCJÃÏ~&OíÔW¸þ¼ f @+¥ÑÀCXüÂÂ8Ó £¢^ ̪"tãžái˜§6Œ ï¿kuŽÉŒJ õЀ ê#òF`2†g5è‘FšªÞ%–_'e|»TÝr‹$V®•`œðÑgÊcOÆÚŒ¦WI †VHÃ8’ÀÌÆÁl°Î›²à=2A:JTÌnµ@ V;g|?45ÄgtŠ\u­~ð«ý*Qý¥¾3ßç%I¤ãÐÓ²å©>~LƒùÖ¼j™˜ükÞ7˜œ3Œý †þ|Ïœõ¬Á£Rí¾X ~œàñiÉc>Àƒ_çÄ”ñ¤¬¶Ò5aýÁÁ#F0æÍ)ÀœýÈiˆt¬XæÌÊ„?Ük…´Ï¼¬àŒŒ+‰†°ec=6ˆY•žõeÓ2±¹ãL(`éï§if~‹Ó¶iNžÊG®C ¡Mq-©Â4aèS$å°œ‡ç,:«dîkƒá¾G“§¿÷}9ðý{5{´@­ÆÐô*ʨ0$EРñ;eÐ`b`Óx¦¼CFÆönÕ‘ùf®­ŸïŒ‡|nCÙ° aüMXÏ ÄÄ`ßQÆê½C@!Ë ³^îT3ºB–¥Ã\©cú¬ê½wJíïþ®„6o•ôˆ}bŸüö‘¤¦F*¡©*‡Dƒ?®ç`ܤ;;Lün‚‡þȨ‡ÑéâA-à׃_8Î?€wЦ:8”‡ûRL¦!Á%è…3‚CKãDžY6hiúÏž='ÿö!¾vì¡AÜJ+¼´…ÝÕ!ÊZ#É ÉÆ’|XçÍ—HTÜÛÁ±%¥@Èvj)n‚‰ÐÛ¦Éúƒ‡9ÃNAÐ\šð|÷¶>2Ÿé8ñ@ŸyaxÃ÷A©GþöþC#òÓ¯Þ!·Þ|Æj‡P½$æôädäfa[&4‹ T°S?B†ÃYVZaX´"ÙJÆjA?{0Ãø¡±¢q±1€Fºzeµ\ºmîÐg+™Má›9üeÈØ¸v òÒ‘F5•½¨ŒïëÖ¥“Më—ÊŽmÐUU—kâqL£=öØc²çîoÉ¡ý€µJhÕ-Lm‡É4!YRê0L“’† ˜3*ÎeûÌ~ü.|ƒngK0ÁOÁÌ?uh7BŠÔüñ‡eù»_¢[/“­²óÉçäѧÉû¥3²(‘ `ëg.ìÆÂÁ.0sD©íc ¢‹«1›¨ ROeI ¦i t$­CP?Uе<<b2AÚuE…Ø?œt¥.‹áx­m ù¡óZ›¶SΆãêw¶Kž(Ÿ!€z;¶ åÖ­0ÐHëÇš{åÁ‚›TòZÉ…µ…ÈWTã'˜$Û&Ëåþ¿¾C®»òbq>ÁƒpâìtN~&Ôˆí.Àxb{g¿Ú>"s ­L¦†™Šæ]³2Óñ¹¹À5[#ªÖz«5ØPé²KÖ©IõE8"J©¬üeȈ{°ñÐqìqäX3ÎmÐKUÊ•—mÐýH ©ÅÀæt»1uõÛß‘#_ù²p£Ñä¶Ò†4€Ñ¥Óeï½m†¸W £c1Ѐð›(<À0š=€ð9ž…PAè‡úMØ0¬7°N?¿ß#²üÿ$+Þñ{˜ÒU¤+Ï÷AÁ~Ÿ;-›ê±%¶/®«.‘%0‚YZZ¬‹@—`òH À!p } üÑô § Ó׳ ™¬;¶<‚ gÎűƆÚXsCއ7btá´üú¹SòÂóÐÁ×&ìR €£D5„Ÿ¶aDbš° ˆSÛ¼žM–µCi.5ìd„ªò6 >uoxß…ò¹?}‡\°iÆÆxYóé€Ìú~Diä%Œ«Å:J#v¦–V(ÖVSÓLÅÓ[Ö>“[©8tÀFIo!zn—n_§C( åO˼åŽÙ¢ÀXÚ²§z{KpÏöU+—j2ɾ^9þÓ÷¿[`¿Y†·ï¨À¥·¹ ü`ƾnxÀ&‹²$s&`°\UßkúùŸ‘AÓñd Æ^«·úÛç¼΄²þöihý2‘›#Âxï3´‰Ç{7 $x]Ð Ç0àašññ} çIWy03ðLÛ'¥·¿WÖþå§¥põjÍÄá£§Ô {U3báb1f›q½Žê~H¨©8¤mØôè—Xv¹±/~~Ä/q4€{4·LŽ’§ž=(ÿ÷áå™-R¹¾X6C×ÃÞÿ ‡Ö¼ämÖöޏm¶¦ ”ÎRPUbº+$¶¦›åSŸ¿E>xÇ¥®¦Js=¶¾Nð)³úÈHÈk+°­¨Ô¼ÛWœñC¡˜möa7³@˜¤¾3¦â±ÆÙJÇFJe=ï·]°z‘ÕÚ£ÕŠÃf¯­ ™wQŒ¢À¹fßÉrüëwIÛçþVâ+ÖÈÀò:é…}§¾þAéGaô@8DC§?$Ù¤ý€ôW}ˆ÷ŒÌÚ0h}w¦pmóì¿f(Ö±áÔß–÷“ Ç÷§“g•:èÏxôüQm8ÏЃÃöXREòéG¤ðÖ7ʪ¿ÿ[)Ù°žQÃqæÜ`aÛñh€À2qÏÙöeïgzfºÚm£C„Lc¼t8Eùtc‹ìÜý¢|÷ÇËj€]»RÕõôQŸâ¡ã³ñÚh' ünjÅ]ilÏqH´]I¹ç‹o‘7½öF õE5n†/ôŸkç$‹÷3NÏ=tôŒÆî„ ®bGc`¯ÅV,Û`Ò•X#‰¨¸Œ÷ׯ©•K/^§â=³ìO+‹Ÿà¢ò(àŸeÕ{ø€4üýg¥ïû÷ˆl¾Zú±¢Cýà‹}:ú¡VÁ™e«Ìþ‰ƒì“L?ø †A›Äùå<û¯õ<ŒŸ M_ãgÃò~²Âwl#Ù=ïéŸy~ý¼gæ›àÇ¡; ·D°º?¹óa)zÓ[dõ]'Ë–I¼í´¤ wˆ.!Q Gp¦›'}…â“ÒŽm‹Î¶±±y¤TrÿC;åSßø…ï’«êJuoróÖÔ„ïq¸ŠàA©ƒ öÿªY®{ÓjùÂGÞ*×¼l›æg¾õš‰1‡ÈgàÆø¹ÛiR€ÍV>Ú½¢ÕXnzÔáN¬äe½T£z¬1øY‘W轩|ú ÷:ƉVÌq`îÆÇý*0³‡¶þmZc+÷4³î^c᤻»o²MÜ÷=$'îúŒ íJ".“Œ& '‰cqg ±Ñól¯‹a¼xW±žÉ„ñÇkûc8õ³Ïx6Žaé2÷£¯õ³ç…²áì;cï5B[dá¬wùÌúë5Ã{á2ÏxeÞå3#0^Ð ½æÀ4‰,²i‹Äø¹$Ë«¤ìŠË!}'$~úˆ¤z»%¿¼@†¦gâÓHtH—>’×¶M3‹¼/.*”í¬—›v¬“–£'äþƒm²¦¢@뀇=£¾†ub"Gð «…²~/f°µ>Ø!ŸúÜòùÝ.z«ËÍ4ÝsKqÅ?›Ïœ2KÔµ½FO%u#`w½×ô2¨0g¥ÜÛ<З¬Š÷|Οý]«á{fÃñ»4öt#ûŸ‘¿~PJ/½@Ž”áæ3P¼WJéÅ×bjp!€3Õ¦ªAÚóéØÞø³¶¦Ž4œ–?ù«oÊ4ËËjФ£tÚ‚•î¦#è]zÍ=3tÆYhEæ.Àæî]­Û\.ßýÈåÖ[® äÕXÚÒÆæ0GïÙS¡ceËÓߊ½F^~õñ«Ò©ºÔo°Q²yšÊ†#ÿžÆÏYa1_½;®Xçz‘GŸ< ïÜ@Áú_: íÜ)ÀåÏ ‡›ŽÉpë k¸m¿ù‰ÄO¾(yµkdd¨Ï„C¡i¡L {éº1~¦$3×^HœøÄõrÌç7'““Ì·Ø{&í¿¶7ã|æè\BZÆV‘‚”L×õÓû$ÑÞîÕSL9²tý)¬ ÃÊ5Áëï£# îÛÁÃɺÕõòñ?¸ ½Dt"8T IlÝÎñ)qUc¢Lf]îþÉi¹ó—È®øpZßÁ!+¦gÛø9¢šWo7„5Ëägá³²ñÌÍÜU¯óÝ»°ø QÁnÛÑøàA1™¤ÄBó);yªCZ°—{%·Ñô¼?Yþ¤…½Š `bØ_£ÿÙ‡%þÒӏޣw\$}ÇK×Cÿeä’Âì«lF¥ ¦ÐØ“q,.C¡èðÎ:|¥÷fu4Ë‚ŒÖôÊÉp õ÷ž1„þÙgÏptô7g=é÷È{bÂÚPö™}gü{ëøéð¦¯gGß0Ïýa½kÿ3‚,%‘[¥ðæ«%Å´ö®ví Þ''ŽKÁÊõ0Ÿ‚e—–ãZ˜ÏôÑ´7~{»`VÊ@ã)ùñ®²û›pçD¿óß±kÈû",`,Äo÷ íÒ ä_¾üùÀ»ßˆíjõÕ ê;üßd¯b)1‹gV2:™?MdÜxÝ…˜Å±L% Ud­b0V.ãQÛkú©§{ñ²+}Ï4vÊ/~ý,v;„Ý"xšJmÞc Λ>!r '¤ó¾JïO¾Ž!ª2ÜxR­MÒwh¾ÜÉM'Êk9ª¬—zÇÃ8Δ˜ï=Îòô=Ÿ‡K›uÍV:oé‹IçȰE±rFÚÊJIÞ)‰3M´£ŠôÔЀ„‹Êe`ÿÓrê;wñžöèŠwme·ÑüÌ tœuíå›EaC Îkîzm<Ì%uQ´ÿr aï˳?i”;ß´Mö~ë#òŽ7½ (‹½ö"ËDÌ+ sX.–Á3In¡{Å¥uX‹æ28•àìÔ>T6Ûž,xð=^Sá:®¡~å7¾ ?ö<Ææ‡¼÷G+þøžs رw‚GÛ÷ÿYº¾ôVîÅ*ã“G$‰UÒ4)“ìh’PA1F¨ ‚÷Á/´|•å¼z9u†Ë(ƺìÄ26ÖéÝÏ(/ Ò Ïê6i˜J Á´<¤¸¡A £×þü“râkŸÇ(ÇHXó³•~zÙžó·lÛTkÚ=è”À9-“Uuâ¶&aبŸy¶UŠ0ýýÿ¸]¾øßß'Û¶šéÎFê`û÷U®L4¼r2ÇÅb+‡­x+°CÞ×oƒ™ŒÕ:ÛŠSDíØ'³fÃÙkm_^#c8ÚmŠaÏí}/ž”ûØ…}§U¦ãwŽ?3°ÉùÁ£ùžïHÇ;ß+©Èå2 º%<Ži¨kÎ0µ1„Õ0K¢´ÔrcÃöÚ6OdzËçÞ½yÁÏfÃÚS÷â8W¨Ñ½yêì˜ìÛ³q“Áq’•ŸQ7¾Àð† K`w*&©8k›Ü©A€He½ <÷¸ù‹JÏÁæEÒ8‡@ĶçŽ.èÈJ,;Í„Üh£•0E² {–¿°»S>þ¾«å7_ûcyËnÆ–ËEÚNÙV­bÞGÁÀ_Ú/|FZ-ƒgÅ¡r|ûEkå/¿HÖ®Z¢F屎Dùp Çv•ÞC•5²¯" i5ÁjêÏïFž}îˆî½îOc¡Ño:ßã3ÿümi{÷"×_Šenäž}LRù[$ºf3˜—™ÐZx>{™`XSJú’ç;úDP°lÅž3!à“‰ ã=Εÿ]ÿõ8A§ì5½ø8¥`Œ£†wt#+\æ×ÕI^Y•JgDú$óöq˜B9ôGï—ögŸ5ÀvKÝ11êÖ¶E‚ÜýüQ¬¢íeκ2È"­ÆÔÜ~s|ê¾F¹yk­üüž;å3½Ã׫¼°fèÙ‘zæÐÁÈ<+eòÌF õ]õ…:¬Åõ½0äGÓÒ&ÌÙàA@¡ã~”F¸÷6׎üö±ýòÀožUqcÓ0o,¾£$¶’=ñOßÖ÷¼OBW_JÓUÚs‚n“èÒz06ìåuäꤟ"¹w­4õH8úÚóôÊÅ»›à” ˜¹š ¸ï‘?ü¹®}Á§t™:Ô9ïM{NGäyœåd¬!lá;r²“ò%¶r¥DJÊt!c{¿DF 'IaøðŠ­X7ò zõ[¥u§1ƒOã,³ ; 'N6ÂÌÉ~Y±´HëiR„½QŠñ{b_«n’¯Üu›|û $¯yåUª3a{åûœh‘ËÎHJO™òÁ ¥JöµËä–/†¬5Ú‚û¸ÁœQÚÉAõ™mì¼çìÎÒ*Æž\sòÓ_<-_:©ï2 Æo+½z.’C<úaq÷«wIË~àñ2]ñ›‚¾c{yÌ]_{=6WÂ>¤-•æT’jWôÐk«M:Ê€FÀ×'t^€QáFÝLøöyž+ª´úÂ|êy#L0/ê1ó¹é§zAzÑ>½G¥à£‘XÝR¬ >):è? €D ¤::%rõõ’Ä:‘ƒW\'>d¢â$‡€‚ˆ2Ö¸_<¸Sö>×&õ¥0_ϧ’½íý²ófùÀ›/–]ßüüìX-_V‚&‡«l»×Hrôà$@çgò%P²_¾c£¼úËêÕªd§åPãPKÑŠýàaürJvZ8íî”û~½G~óÈ^H3˜›ÚmÓÐgÏjVüàqä.€ÇÇ>.á+¯ÂT\ô~A“ÆçO¿ ø )Z»Nó).׆n8hÿÌÏÜ«—÷H Ã÷|vngž’ OîÜ1Ìô‰éÄâËq:’ô…F8‘.„iê#½}ú}¯»U¥‘PöQ/Ŭ, [¥)êBôIð©Æv‰l¿uº@^zÅrêç÷i|\+D±±gö?üÖCrÁÖrìh–NLó~ò©¹fE¥üäßß+óÉ÷ #¸Y% JD;{k:%´w€¬DÆ2ù¥°-ôÊ.–®Ù*%Ø¡û s–+¡óFº°×”FR0‘QÓò»ö“ÿçSØïÓ)á,ˆØF`ÞZxG?xúÊ]Òô‰OHäò+%‰]“0¹‘Ì/dOŸ e7Ý Fé.ºd& q ΓB8¤¢€Ê^&Wd+;å5‚©ŸzX÷³UÿõXÔõLœýƒfs¶’A;TU&Éý»¥ô¿FÊ_v¹¦Æ¾J×a̤¸Œ‡ª !ˆÀáÈfiµt)ˆˆ¬’÷¾FŽÿßë»A%ˆ3MmòÅoüHª` ¬3¬~ÃUC)ùÿ>ûzùîÿú ¼öUתÙ!Ó6sSI~¾jâä|š§ç~&O»Z[6­”×Ü|™k‘™qVJ[AU&AÛ4LÉH#Œ‡ ›[{äÇ÷=-=ù‚nªC›Æ<}â¬&kÁcÃVŸxìx80ÓM cÁ`r×n‰ýáû¥ä"c°Ž™Š-]!ù0ü7¢3±Œb4D Ÿ³àa¼F?|ž¾K_ŒÁ¹$ŸëÆñòõzÊ&žzX¢7Ü"Kï¼CWÆd ã’¨t>"ƒ}ÆpDBîÓ¥-,ã–TS—„·bÈ«v‹~ãmräž{1@) ’ˆn@öõïüX¾÷ø1éFgíñýòÉw]!Ï}ýCòþ߃,¯ÃpÛ¨mkê±ÀÞ<ÅöU äsXñè`÷RVZ$W]±EV¯ª‘=ûŽa_öm\èýP:fe5 <£ë ío £±>ôÄ9~ª;šm•ËkFˆMO_ÈáƒxW—ìÿòW¥ù/>-±íW`È SG¡Ä¥ÕØT æ×A3îëQ‹YBaìpGGZÓNSñ…/“C˜Âú§óR‚`©°<üXÂkSZMúšÔ÷û›§g‡ñûOt}®¸&zg*Ï&ʯÆÃ Œ :b鹄0%æÜó¡_ñ•/J!”çZw=Bõ`+ÖýßýT^~Ô!!‰â†Ã@-¥:ìW‹½Ez!Å”H^h«{çÛ!qÃõÛ߆=Ú¡˜gyLæÃYðÄæaw÷gòW¿_ä¢2yç kä¿sƒ\ý²í:£’yÓYdø¨…4\5Í€ŒG•€ùYÆn㲺j˜O¨€©ø3òì¾£X‘Þ¥AIÅÌÈbKTlñÎFqGÉ¥Ã`'NµËö”\¹c½\Œ­s ÌÐ__Êуe0CPŒ?÷¹/Hë?/…Û®]Ž»cïë!Ìþé#ÄV¦4}·Ìl¤å˜¤ªê%TXª_^²/}¥tüç?C±^î8¥"89Êøô ßAŸÙû±ÜÖ»G˜XÔÔ¾âǾIïñüƼ–¥ÛLJã]¥ó fÿ…ªËdà­ß$«ô])Û¾]sËï³ï×Ö@ xúŒ„*)™<аã ê%ÍÞ“ÑNo³—B}Æf^ù%;¤áÝ·c¡g¯lºó=‰A¿2Ç ÂvÁ‡­¨KüêÝÿ.Ÿüã{åuw\%ï~ÓË1¼¼Cª*Ê{ö7pø¶µÅàœ-¬*e?p¶Ö4Ú5«juún3Ö€ôbx†³°Ì°–V~ÓˆmCˆaŠ%W²Äþß-­í0¡P$åeÅ9/XÆBðxÞØö«%E^}è5v¡‹Û†Þl+öç Z¥$^ ëÞö )©(’á>ÌÆ»S&0cR¸|$0ÜÕ÷ ºUöˆF°KœšpGXcÎÌ5ȪŽüC A …}f… ÏßZ¯5aÐSÕp.Ù°zöûiÔé—wgýø„×ö>sm|Ò÷¸û®>Sólô=üÈ7êõ!tXÂ%~Jê¶¶Åoü]YwÏÿ–²‹.d6àß0Ã8,ŸýÌÅ÷WVñ¾ vPiIÃ`­Øií ìû½ú• RƒÒˆÒ‚ œðÀã $¹ø*énïÔýÊÉR Hb WR Éáž)zùF)ȇAÄv Æ`Ø/>ˆ¡.(s+–J^E­,}íÛðNXZ¿ó)I…W¢Ç †ÃK¼ßp>²aòHe­Þ‰äÎøð¡ÞŸí«|Ï3÷¼b#·íBÜ_5¼ï)ýòÚ¿ûЬ‚¤-‡Hqåy‹ ]”@ð*¢åõÒ¶¤F\…$ê¨ÙôÊ|1“HX Z— ðö)—@/r©øäÇ0‰¤_¶ÿÉ¥°ªjV%Û¾ØÖèöì;$þ÷ÿ*;6ÔÉ¡C)Ö®4ÆÑm™iïEqá$-fí z@ÂëbØZ»ºNjkJ¥½äVŒ#SÿA‰„m€ “.s6;#R¡ ®ƒØ9± =,îž+Òˆ¿‘“ƒò$—¾ôØö2éÄ–³´1–xèø:¾?†…eØÐˆC%‰®©}ù&©øÒ|;‡TBd°×4’à¬%£×[º½ÞåÛ¥o÷c’xø!)­‘dI©ÄÑ£NІÞÁLTíEs79:Ò\Ëé˜3Y)$<à}ZÑçöÏÆ1,?õÊÜã?œy:úúÙ÷3¡q5λ güÍ[öZi‚NGCUáJ(:'©vJ²å´”¼å²î›wËŠÛ^+©ÎféI>ú`aG @bŒR"vÐæäÞ=Òöøc7¬—&‚ä£<¼ªÉDõšåJ?‚} CŽÃ9=¹jœü·{¥;’U×]ƒ¡.lñê ñÝl9¦¯e aêü}¿zR~þà.ùƒ·Þ,ïx󫤺Ó¼át”:«s’ã%ÏŠn)‡®*+JÑ;Z†u\1ií葘'³â–ºÖ4YÞ³‘d¢Ñ°ÎÔÚ½Üi ª»)ró*Æog’Tö[mç™®³¥M~û7Ÿ—¿ôÿJhl[µA=Î=W8ÌÂïF˜|„- aÌ€’¤â6•'˯Z‰éÑ1Iê¬ ô{ñíø`<óø ô¨ò¶tóERrù ’(­’¾{ ƒ§NÊpe5ô&•ªG‰ƒ& [V¤"H“½{¼çý<;¬¥aõÃǰt9ò¹ÏI3â¥òwdÉ XôžßPÖ &5„da6j( QYNúQ*äõd¶µõŠÑgæ¬ElžÚ0ú}üF^xŽ ©„€¯ú+Ã¥§' !/º§9†¦"èDè4Ù3Øü©å '8W|àòìõ·ÊÒ+¯Ð™Pí»vIÓ׿*ñùžD¯¹@òëñÝÅ"ä†E#ŸHe…Dª«%RU ºÕJ¬~µxö –c›¶ª.K@NÕž×®ñÄ®^×<´îi;ÐÝ/[öW¦ƒ !$Ñá…ˆ°Š½Gb­Úê2m9¿ÔÎX>O\LØæƒ¼Ÿ_§X&uÛ-±ÛŽ]­¶¿­[:ˆá@Ì„©ÊjGÀ>hßýˆåÌ\"Ä(=Žo$ ‘‚¥n &žÀ¯C" ó–Vج™â>@²" ˆˆéžÃU*n¤4͉@Hòd}•W^%‚"nD¿Ü2‰i*ë<,ÖŸû@o¯u¶´X‹”ÆÍ›7[Ë£Ú ›¬ï·»EÄUš~š¹›TM…Lduƽ`뜂*ŒÈ-´D÷¤-ÌÉõñêÍ$¿`ãp‚µqbZ(9êkíQ@óFp±Ü’WÞ ³ÅVµj¥M™7תD0J$rÊ]ÿþVÛþÃÚžw}\´g¯N_$Ä_g9´Z\„ˆ:ºHNÖR’Üb)È #“@Hò $¢úESÊuþw‰ÝïëZ³Û ghÇ^/Ÿ4.êJsä‹õŽ~'.Aw0´Mºë°7>ñ„M_ºô ÈьѣI›ªôiêÉÓ¬ãÇ-û;í¡u›]ÑÞ/sÉÉÀóQXjêÇ/äÃwÞ/¤1 „¾tÁ4[²ÜfÏÔ /xñÜŠÅÒëÊL4'’„qn$žèFr3u#""ùˆ´D@rø‰ˆ ÖÊÓ1­9˜­RP¦bÔ |p(]Í-ÖÕºß:žÚjÝûöéLðfxr“ ür²pšdDš™Y#¿ÐÂà'] ÏŒ#M$P…"®E+Yñâ…VZ_oe3¦[Åœ9VZ]måÒKˆÃÀv¼ÒÊïwßmÛ¾ð%ë¿ã§‚©ÖŬšíDÃ$N„ðÁ=…²¡ËñÈ…#Iq""(âHr%Ö*”xkD°yè‰fk~¼ËŠ´Öædt• ÎwB¡JABܯdøi³ÿd-—7½ÁÚÖ?l/ûÿ´‹¥TǃãŸ=QörÌ Àä'ëN#Dä?¬†ú*mÒx®ô3¥Ùl6ïÕÚ‰Q­+)ô™e°ØJô&…B´OH!¿E{q]zÞB)Ù§ÖŽ€ìÁŸ±œÚL¢ãHÛ)nc¯¶òF!Þ&å8Üž…Žp 'Ìlëµê~jcµMmªñ=Á6Þ~›uŠx”@<´£n$ÈÑZr37y^CZ°QU•k%BêœnùšÍ(5Ä’¼~ÜÑSà‡«a/¦YXåé7Êz~²ÐÊsK­ËÕQ­¬ab^EmÐÅH¾D*ªÄ*…RÐó«ž.Ý îšp’å`W— j‡àaå{Pgc°’~@|Xq˜«\D3¬UlïPù2O¡+”^!±›`–¯{¾Äoˆr %n+Ò‚¾âª*q…VXRlÅSÄ)IÇólŽvî{d­¬ÚþÍÚ¾ò÷ÎH\†Ȥ™þU] ÄøGÞ¹ç \쬛Ëöìâ,|áfw-\ÕâKÄrpŽE‚ƒH׌éà çÄHyay¥pÆßñó§~W¼3…ï”BðF¾‰ ãŽ-Àzö°ªÐÂۨ߈i³÷ç,yþ°›ÔoÆ+’9³šlÆ´z[±u—=øðSÚæ¤YHI§ªÉô¤ŽXÇL|õ•Z<$Dö“;ÑÙ#nd™-[<Ûßñtz"“pŽcqßþÖ¶kO›,^´R\œ{!ab̽ŽRqB3¤¼Ÿ&¢ÑØP%¥l ²r}âÛßõ¼XÜ6Ü*„*ù;„ƒ$õPËäOð™T!£—â0ÅÈ|±\Bb. äßXja½²Z"Ž‹Ï[fÓEˆÆ;ÞëL~os‡[Quh³<Þá}ↅ\Š$â¨Õ.¬ÓÅe4ÔOѪxé±ùQ>³Çš!ßröYV0uËàGY0¨ÊPŸ€6BéÑ!Ÿ ")*ȱ¥ …VQ(¦d¹X%±y„D²zülÕ¡‚qú‰²$‚AÌ¥JŠ8h‹H+SÁ. ­ `—H«¢ÒŠj%Ú+žb»žØlx‹8žQ½ZÚ@õ@ÂŽ !^`Òðœ‹NA"Dÿ©ÒXKÑfÚæ–Mê‡ >R[µ~‡vó sô"8fùœm’#–‡Uz)ýs’»‹Ú E|pª™o¸ãvïUWºåXñ¬¥2¡€,ÛTá·’"SüÀTOsyS}àéH«?׿A¤¥n5–öê ³§¶tÉ€!p2J:¡ƒ€ôK°GÞ*Ré!€MW;ê÷ÖÝb¿+=È,éA¢ëÑØÛÒîðfåx}Í”Ôä&¦ÉÞ_8ôEdÝé8+‹„¤TV3gŸ±ÐæÏfëŸxÚ É~­·`¡aXÑ®™¥>náDÍ,ƒ¸ bðÀÚ§m£6h¼H{sŵ#pèYvK¯B¼_ä9 päL­L:§5UËî¾Zâ¥rŸ¡Æ>‰ukDÑÃ>! Ö\iGbN²c6Ž2áðÓcâ zZ@©(y•Ý­¿¥°Ü‰²dÚ«=O7‚_b-ÖÈŒjµ:>GÜgVàçD½QÄYp!ܑֈ8ÂC²R~-;wÙS÷ñ¦]¶Œ¥hØ3Q'ÊåGã=Ó㹫F)}Fê¹IaÊ0OºõS±DUÅRîkz{PåM4E÷Êjù«-_Ïyzw4RÕ'K°F æZo[›­ùÌç]Ópþ%VЬ…•üਥ* Ñ î(î©ðôg]#!¡¯o»’ÑÑZiZÖi]¹ð"Áy™Òó k{wÄ™—_}‰ÍJˆq¸#MB<2{9&ÈcÆS7“@D„{„ˆÀ-ˆ}Ø`±I¢§ªª'­yÿÆ&¹»¶!ï tè>ºe%Ó¡g, ÄŒ²[«–/,Á*,p#’éÄUÌ”A~øYe ÑéÕ±{Zzm×cm6°¯_ûAi¿,)¬LqJ-) Qeé3è^U†.Ç+Ihp¤á₨Oþðï ›À©=´I?§#ÎÀÉïAª?ÍU==^·|€ˆ¨Ñ´CD®iD}%ÔÞ§wÚæoÞ,K¦:óÉé_Þ§&\ûõÞˆÂJÄ@,àh;õ‡#83.HÞ å ïÂÁ¡*¤CÜ™S*“cåwHãÂS{™dp¸‹yAt‹sò­×—azi‚­L½[ö…-cÞ£O‡—˜ 9d ÈÑ@ë4K›9“‹³9V£·ˆh´ë Ÿ|Ú‡…Ë ôƒBN^-2똩«ÏM(á@Ðy`Ì™#OlÞg«WÎ’Ùï [0oú9u,ã™Á ’g†.„(<ÂL•r^âÝ UXâQ DÅÉ! ùð>³èH<àDâq¥¹!i¸)Ùó‹D …h[zúl×ÎëÚÒ/]‚ÉÍ” ©Ò°BWÇ àòÄëÕCxÕ/Ì_,äY,ŒJ¼P!'8´DÍ‹#ª¸Õ‘´tN5’›ëâ¡_â§,dzÜœ˜$ñøƒA€`÷¡ðþfO~ÇÃÖ»y•j¿®‘ÍãUe;DU®WK甆À»Xñèp¨7ˆßaOõƒ8˨dw¢AX’–vèt•!B¤q"[íÀÑH/Cšgv¡‹GD04QéWFì%–§5ڼƽýí:Q2l¹òÜÆÐ3—–}îÈç«Ó&%H‰1~Œpâ$ XR¡(D4£4Å2½m’Éí´©5Ö)3ÝÛïZgOlÙ§3 ü…ŸõDÇyìÌ@×<*¹»,^|îB»èÜeR¦k·òÊ$XGv¾Lhsd&<º‡Ö4ÐX@\BiÎuÄAXòƒ³ÀŠÅRHƒùÀî<—¤æ¢+%:7¢·\¤E}ïiD0˜Í£ié¶ÝíƒÖ¾‡ýÁ´“l“TÍÊ #òÀE|èeS¯TˆWÁàB8H âæ8Õ1¯¿êo»øÊ‘6Ôeá$H`JÙ!ûø '¢ÀäçF¦6»D}²O[ào¿ùa+ªžãDÏ‹ÓEŨ/“ß?œG¿Þ—³bO§|½mqˆˆÿ©hEFýHÔ/QàÊñ G †¥ôW Œ•˜ð‘R"Å!QÄ)Srµ†Û«9\`eZ(™u'Yrâa~R–‰•‹„cPë+Ú´ Y‹ýX·Ñ/E1È n¢QD£¾¶B+êÄ>oЉítm³=kFƒ=þä6»û :S¡]›5æû>[ ”íÂV«óÇjë’[ï\oëßn—io­sÎZâùPþ3V16ÖûÌ3_X•ü@,BMîñ¹*‰™ÁU*-ădÌÑAl’Ѝ=‘ûŸ´ü mÊ9vI×±¯mКé HŒU¬pe RJ•ÙÜ”gôÔzò<( ö«ü2ê Œ =p¬! a@,¤'CW¨+ÀE‰*ŸÊB¢D¥‰º2Qós•½î<eUˈmY³Ã†;ú­xV¹k‰+Mâð†_¤îä£×MþªZY¯(ð>µ¤¸¸ðNãÁŸ)—xÚJ¾z€€H_–#“çCâFâbN!©ÃD7Þ~¥ÃRœk_²ƒ­-.¾š¿zµ'ÏýŸ ;öÈcÓI•cüè"Ñ òˆ©Zu(¢¨a¶¢²„PÔÈä–mEªdÏ™ ã]…θ@\Å™ð®{l‹Ý»f“vÓí%V¾¯. JGÀz’ö\±¢@IDAT:òÿ¯<`=ú´]uéJYzÍuë ò¥n¸Ìºi_ݹçXóm·ºU×h¯Ò€Ét#5h Bbƒ! ¬DñˆŠ_A Á-!!!ï]È¢#„¨¸ƒ"Ú|±¥{X; Â`ù%iú6/žK(GÙ9²ô|yÀ…ìÝC‰ @‰~q3…ÇÀÅvzV*Ó Š ñ,ñz«”Þ94O¨ï;¨x1yŽ\ˆç˜<ݱŠÛ«³TöÞ·G„¸Dú±ÄC9Pe‡~œ Ý!Ê^v2aÀЍ1&Ä!i/ ~÷ó¬8êt< 'éÇF5!aéM.º%¯¸ÂŸÅ9!•˜°Bk<ž^÷°ùþ?°Ù‹‡·ý™u' ‡c€Vt¶ |РȈœ-a-µ¿µË·éÕ©z|ùì}UWS"SÞJ­¯°Rï™éA) æóeùeŸ!‚0ÇZ»ÙÐ9$»öuZiq¾ï³ÅLší%е p‘~Û´óîW¾õ3;oÕ»ü’U6N8>”²¢?‡5u¦­“ŸuŽl$©pBI„ƒè$."t ÁÚ* \ܨ°™‹Y„ÙYû +2$+$–jñèíg54ûMq P9Gz~Aò\¸‡9!¡éxˆÈ^à°WmÐâp€Äú¥`àNRÊuEÒžÔ+œ¥¡|FÅbB»¨ˆ~ª#·¨ q‘’^íé°§7ji£¬âròÄ@Í&pJš.'•„ÐÐ.ì¡ÐÍcæ !ÆÇ€Ò¥WÂâ¨OHÇ{è0ÈV`–‹ô‡g¾è½œ)ÚóJ­•·ó_ý+ÖÞ_ž·¸à¬;±È ï½4ÿÐ2ÖQOí×âí²–’õÜF•¸¸ ˆF%§Ë1õNœ#)¡ ð\$1.>Çrjµ…Ä5Wžcg­Z Åˆ›íWnÔján«Ðf%ZGÂ,«£r=³ØîþG¶ÚÚ ;íò –ÈbKÛ¢ÈtØuJ-lfèS¶ÍܽÏò+„<ØkŠ6)Œ+w'JFQ.~Oî⥃¶F#7Bbš($$ØÍr»Ñ7ˆZ@th¬ªçyFtÇ+¸XÏ1޲øÅ4òzÍ2ãÙª.+aêã3sÞà%€›8æç´*ôð ³{ `ï05Âß¡i®DA^1Ú¨½¿”$OmÛÓÚc›;µ]:ˆqă×qJê„4.ˆa¡1Ô$V‰ÓwEÊ—Å|´ÍÛAm•Y ·¼E“hÕ!ÕwDë„Fdx1¢u)!G xnŽCª:[kç~üOm¹ôîhkÌž[NÙT/y.÷B3ɾòC "ôˆà{µ«E«Å·k‘›¢g¿«†úJ“Q§mÚëå×b?­:œVò~ø=s›c9±Ü²Òb·ºZ²`ºUUŠˆÐét=2'ò“; •'Î#Oì²'žÜ.9$BV)ñWz›ô"Í8÷‹EØsÛO¬xî<­·èÖÊl—ö;s,¥ ÈLÕJñ› 2¢‹È&ÁšÔ÷~]"í}ÃÒ÷ˆp(­·]wG º;’Lòpüý“<è‘o*$£èæMÖGººã¦7ªbå?øIAL¼â H™Ê‰¡ÐE)ýå˜.iœÂiG¿ˆâ–-6¤ídØk‹ØÔ¿«0ÝÙÕ˜õ1'ÅzÚÌ;!ÀE sÜMúL’6yþ!“1§„]ZÌxPD„è Ä ÐèêeÉ‚,W PnX/ÝZ­]ÿ•/Ù”¦ÆÔÄ‚¬³îÄB@bKº<ëNÐÕ]:< ýÛ‹@Dø–Ñm°‰!ë9Ê´À d]‘ Äð£½Gî!¾·w_›ŸCr×ý¬UœO•öF*”eN $ÎHL>d]¥-œ[kW^¼ÂÎZ¹@õ ‡mº÷^»éâ‹­|Á"Ÿ¹#O÷Œͱö ¿)²ËòÖãhÊÜpÇϬ$ÌöáB°²¶B?ãk>æÈOw®Ñ<éøG<NÁ‘©ÞL¥‘'ø3ÂxAu¨öí u§þaO ¨_:ÂDNò Ïð­çˆh•Ú¢3léÂéÒ‹äÙ®½Úv[k*43©#'‡3)“909>¨wînÖnº¹ÖØXgõ3§[Ì8ŸúÎw¬tî•RVTB¨(8›x'+Ö¶â8žÇDò : ë'‡õ±½»¸GÐ ƒø;~ˆ’,¨ÿ„áIzâ]’*Œ·äbÅÂS*È‘±â8+ Ú$A*}RšâǺô³¿§Gˆz$Z¡– ¤>ÂÞ½ƒ£2fОdHUÐû7#äÁOq¾°ÒsÊhòNHŸFü<ËFωIhK ¦žÎ«ê›Ü]êß^a) ƒ#YæOá>‰a—áÚjk{òq»ä3Ÿµ+ßöVíB,í‹~,Ƨ—½5²ÈQƒìä|! æ±uà —pˆ¨@&eUË‚ ýF©ft™xÉ?Teq¼?ȉÊÙ±«ÙXó¤Ý«³H::û]'R$…;u1KÔÑåg³çØÙËgØu/¿ÈŠ{;ì–÷½Ûößq—•,_a#ºDC4÷k Uh'Ýbí%˜<:^bæ ñtŽgøJót¤Mÿ𥟉8bé<¹”í*80¼iúÝ€Œ3óA¹_¡MÙ2ÇÛ>cǯ„„F¿sbçq!ž¶y¼ÞÉe#Æ„ÉÞ-n®Y"Ã|¨›\¬›?Œ»GùpäI» ¿ ¶",ÙäY±<£/7W.äžÉY8ܽ~¡ §ýzc—N–Œm%ÿP»P~×Ê3G‡gµnzÜÎx×»ìŸý¬•éDEß›,«8”^<—% /ìIÉ>㳋_žråhZDT­Ú´®ï DšéMÑÒ5Ú*½Rwž3Ý‹5‹›ˆlßÉ}“ˆ ÒãÌ>mZ¸ýÈdÀù' 剜SNˆ°Xy“G˜x_(g÷+y¦X Qõ¨D4§6Å÷Éšp£SMì€6®Ü:ÌZò`âÓ) í4qÈÕ9í7o°Y¯½þó_÷9ÓûïxOtÒ•ÈúŽ,9dNòðñHŸgÖop,,â*h*ò­’É#JìLç3;>æ“ÀMDH¶íØg¿~x£Ý«C­šµYaµŽµ-‘?Êݱkï¶© Ÿþ¨v¿ýñ·lxþ"ËaÛ2¡¨J†ç‹ë„ Xô‡¢&;á@FæOŽ+ÉÀ"Ù~8rÑŽõÂ[xAæÔûzæ!<§ÓñŒ#?\HY®]&@B-#!áÉÿA\ "IºÌ8,¯0CÛ£UÛÚÅ8ÖË T”g [„?AÑQ 8ˆ°o¬rWdªÞJGZža‘OzV¹Ú‘ áÒÇp€Ý‰smËPŸÎSщŽ„Æ_䢌8œktÛfß0ñ¯³Åg­òèñ:µÔ;YÏ …@–€œPp¿ðÂÆ#~Öot÷ô;ÇÑ)2)%N4P޳ewtQÅ€yNBGýh_Tâãß¾3’_>¸I„¤Çªµ|‰¸ŠÕ~­(è³™¿¾Írü± ÎZdùZá\=œoE2bµy§ü‘E48n5:å@.É_ðû]1_ˆM‡Q·‰ÂýhÞ˜OòRÈ'<8’åU9rM’8º¥ŽS$ÊòµŠODè¶´HKQFZùðGBB ºˆn!²KÛº³»LD,ôš»XòÁO^pñ™0ÚëíÏž6çBÔÀ‡3Ñ,jS¥Ìvá{cû•Å m8Ž4æ=wAáà©V­˜Ÿ¹ÜÚ/~•­¼òBq+uÎÌœ$Yx#ˉ°½×,y1 ~ Ê’ø……ˆªúút ‘f×pU:ªTk*2?*Fæó1(þ¸f ¦§ 0Ö¨¹Žä¡ö«5›mÏþ.«Èì”4 UÖÕi3ïý±<ù ºÄêúµßÎÂ!bãØÏÑaDrñWpÎý~ψKÂ=ÒÑhHÓsGäÂÅ%Y%)3óŒñ€Ä²à®J%ö)Ofãä‰D$¦œÓðøPž‡ë9¦CÆnµ{sµžE›[«°PîD×X×ñqì}E/Äø‰ˆqNTàGš”HKqì£Ån¾5Z¸ˆè = yÒÞ­‡ú¬{Tg”¨E^£úåµì²áåYëÙWYWEŽWn·©5eö[¯<Ç®ºìl)S­\TïÈM¦1î>.Y2É:Åx§¶ÁS63¬ѨבÉmЬÉF8ÆwE $Â'LŽ=f{öµêP«'íŽ{6hoªn›‚hKÛ¢ É"«¬³Ý¦ßóc+ôN+ž¹J»çŠ‘•c·$sPMúO¸¯t¾Tx|Ç'k_b¢xfÖ ôtª§§!9âñg>#U VÉœÙ*>“ˆD¢òMs" Õ;‘€Ä4 ä®üQÛ«cv! N‰ôÞx—YO‹Ò^ÌyiS¬kŒÏé6¸hQ!Þþ“ì’% “¤ÃjÓ9ˆë8øPX¯Q%…8VU™3/ Nßà)ãh/.³{´ŸÓým°»îRgrt[¹, ´B¹º»Ãæßý#«\{§š¾DMÜ—¶¿ÐÛc`DœÉ‘¿ûýÊK?'‘ž[:]|'Üìz¢™~È-¼ÓƼcÞFRÓŒ4Gï‘&ˆ³hEšX¸Â]q!LפÏH¿°'G "eDáæ¸IfÜHæI˜'tDó.ˆ?&MßÓăºÓEÎ…8ŒB\àJ(‹xÝO­ˆk_èÏ]#ZÐ:,ómiÞGÄ¡8Ö¶×]x½í\v¡õK¯¥7©ƒÊ(ÀBÔs¿,õzµ ä —/±^q‘-š?ÓÛ0ÑX™°qÙÀc,9&`<~™ôõhÃA±¡;\…¶D‡Û`Õx¦ãÃ>…hFfÓRþ‰ ׬ÛdwÝ·Á¶îl·BÖi9¶`ã«þéM6Z;וhñ!G»¦a@pd RváÇ5¸T˜e¤WtLÒħ >Ê÷dæ•öž—‡Û†ü”RY¥™xj}ò2ý;‘^B’"#JÒïTà~‰®8‹üÙFºä3Ö)+ßzž²CºPÿXWï=„ç´èÊŸu ¢,½ãiO˜~ÕùV/BÒ>2hÛº,WÊò‰^Ëì°þ%×ÛÖE«í âóÄAÒoèá@+qz"$œ† 7R7¥ØÞvÃvõe«ýtLZ€’ï%sÒ1¶eÙ§c,9P<ÆyðQ²Jœµl{^( q¸Ì=©Žq±“&»‰ɾ–vmÚ¸ÑîyàI{xg§Ui¾{ÎþÍ6uÝÚØjȆKÊdâË‘ 'â-4Y^á'®&øÊƒÆ"Ìtš>>sgvýLŽœâ[ÜÃOWþÃÍsÚ-©–U–>ÐÔ;äM ‘ ÒbûÑJqû$¾ãdȸ:ïŽwžsf•©PƳÇ+¬Å¾Â‰æ‡s?uKHõ!.¤A˜Úæ¹9›—EáDrÅî®*¶‚¶Ëëj³þE×YóÕ—k»{> Šè£KÊ wº1 ,<íÕÖ,Oîí±—Ÿ3Ó~û7/µ³Ï\↴ìlE áåìõXB K@Ž%4_`^Ìšz¥ïí;賫"é7Ê5£f?ªLÇɤìtwŽ˜tÉD­Úrí£›ìŽ6ÚšMûlÅÎM¶|Û}V<¤óÉsÊlT欘öFn$AkJГÿ¸ÈŸÃ×$>"²ÔsÀ»Ï*É+¾ï^BRŒBp "VW Á–)>RÐõô?÷¨4÷0¥…`´‹ûèîÃ9"B%\ôrH‡¥žàáU8ÖÕ$Ù8ò&¹ÃßßGp˜ùË»lv£Úø¸¾Ùª¯ÿ«­(µøñz»@Çç¢ÛҎøñă0²¢ì\ÀÉÝâFzµƒòïþÆj»þÚ ´ÃBɲ܈Cáø\²[™¸U®˜âB4È Å8£zJ™sqÑ ¸òȺ‰&Àˆ" V×Ï›;]«ÕçØâY²Ü)ª°õ…VøÐ½VÖßb¹MÓñŒèDÅPGD(È(¸€ðb8aÁŸJàÏ™áAÞŽ×têŸSyO*/JIP­ßÙ¥3ZÄbºÔ88“ýÚdË*í#¹X#Åg†Ç´´—†Q¬íXXy“t -ÑÕý¼Þ%~D{­äÈŠpÊœ©Vøäc~(ÔU?ù‰ûº×ØÊeólfYŽÝ¾æi@éúJ ¥€W[xQ.rŸ<ƺ6¬-\X+T¡E§7߻Şxü)½›kÓšê]É·!ËŠ´ŒÇì’å@Ž(>#ºƒ±Ñ×ñ°Z(w¿¹ñ‘d F„Æ3ßA$ü¢ù/©»º{í±M;íW·ÝcÝûG«µ­l†–ÛˆN[DD‚pK9bÂ+çAÉ=Äxð¸4I2KÅòN@µé´Á—™ŸR%ø=]%„Rb¹ˆzª¤X®È˜ýǼââÂø@„E»Ût^x—¶·G”ó‰i3ïÏGºññ˜ßÆöâÓõåÙº„vèšò+Lí¥=ˆäØÜ²bV“zìa™õš]}÷/mᥗȗv÷þú1û‡»Ý¶7wÙì†r'èKH/ø’% /„GŸG»öK·1$“\tÅÚaqÕÇ8ÏÄDc"³Ï@H@¨iöÊŠmã†-¶þÛß¶}Ÿùs?O¤dùjiéÄ÷øH#Dò„% N %Ä‘dðx(ˆk"ßw]“w’[òJD¹á1Æóe­T/"Mi'*ƒ’Yó¼ ŒÈji<‚$OÒqŸÈÅpO2B Q 0"Šdñ‡'ø“¶ø3¢-…Kn•#"¨ÕI¾¤XgÚ\¿ÆŠëçÙKo¹Éæžw.Ù9פ”©~cé7nºÝ¾÷f[Ø$S^é;Ä¡§? JÔ{^p¨~¬´Ð’~婿k¬,±w¿î"»æŠó´VªÜßA7â„—KÖ=od ȳN#„˜Ïsбøu<­Žf  ³îø@ ö[&2E±¼áλìÎkoЉ€ÚF~å9¦M·´†“ú‰Õ^‰ïóè8*¹ó1rJëÈHÞôHñ˜p‰É=æ#ÊOé²È t9EKUÏÀ…À} ånÓ¡ ½R<£‰.cèÆ ç|Õ Wø‘j_Õ³<)¿|ü¡çˆmB/Ä¡YX”¡GÉo¬¶ÞDz ÁýÚo}Ýfœ¶&ÉܸÇ>ëéí·ïýèWöwÿuÕé™*‰©úµsr4,ý@iI=¼Žªƒ*ÑÃì·[Jöõ-=öºóçÚÛ^w…ŽXòOêËz΀É&LA K@R ëqäÁ@Æ deÌGŠÏ|‚n‘ƒcb3gÇ™i³þãH "²Ø½~½Ýþçi;¿ûm«Zv–åöhS?v,Vßû8B¢&iä˜ Å¦ õätí(Û/!ÔßoüDdÖ_Ç/s¶4>+'š-±ƒ,vëlX Ö:æ;>}öùøA Õ_ê ü•6ïò—ˆɵí?ø_ñZ¯M›JlD‹5}ûU¤ŽšÒ!œ©¿ãT¿±ò¼–vá) Ýã¹»_—F Æ[{°‚{¼£d¸”­—ö¶}7>ä˜YnŒ#fü/ÆqϬ „$>“¤Q€€Àp¼m ›BêñàœùQù܆jë–Øjúo¿Õ^þ·ÚQwþ<ÿvÈ¢ï!öW@î96G:“³—Ͳæ}-öË'öÚÔª=G"»G€ð¶eò&Ž£’IWS!%{QžýÍÏ7ZÛÖmV§<¦O­w1òø †¿›½<+²H&ˆ4øüSЇÀ´¦uófÛ÷ð#Ö½n½å¶ì·Êªj«½ì\Ë«®²Üê&«ÐGÏ"µqNƒCœpnb˜SƒÐ‹üH?ë÷8ØÓc÷}ëßíž÷ýžº¥V´t‘Ú×îq¼äèSƒBÉS/rvÏCþ >'í‘\x9^cVñÎ[øýY—îQO^¶fâõùEV®Òý»F©]ÒP· Ël×CÒ—˜O:d¬/³MccâÓØ©«|ê"*ô/â0‚ž$ƒÂ8 +GVT¹Ò;t?þ°ÍßûíªO|Ì*›šR°õˆYñž9Ikëè²ÿöÏìÿýï[5½Âu*GÕð<½jIõRÆz¦ÎˆÖø9” n¤M'‰}èõçÛ«_y‰¬µê¼ü캑#vÄYÁÂ×” æŽ;íñÿùŽíùÜWl°y³”Új[¿Rýf|äO¬[k3¶ý™±ôA;÷hµ3føàe𹩠ÒÁzgZ)(ëN2¤DêûGüûÙu¯ômÃKWœm‡öwêˆ=™úBüš/A8pqÆŠŸ¸@DxJ»$¥ˆïO=˃?"h¿'‘˜²–hqa“ˆ„"Â]5Ô¢ÁA’Ò}$ù(ê.Éô(byƒv:‘±`ï*zÐþ™ç¬€Q­ßÈÕ® 9ZüÚý¤¶aÿÐÛ•ýˆ•é`(çðùÖžñˆUŒð†ˆ¡ÇúÑm÷ÙŸÿÓϬ¾¢@;4iÁ­V¬«pê‚O<ˆ NP•¿Xg¤ H:ð³íìÕËí=oºÂ.½ðÌÔY9™D+¾™½¬+&œO¯]g?zóÛmï7¿fù:»hùJ+š5W„ÖäÕÚô·Þ 3 JmÓn± ÷ßg‡¦N³…]è>#«*~±å™Eeý/>è£(®l\´Ð¦]w½íݸÅÚ¼W›1Îr7ª3V8G$ºLBNaÌ#W@X W=‹?•.ñ„w!! ô”‘ T3ýb­ÒÆQv—çÝ:%p„¤r%Éaî™bCùÉ+IBp|P cA•/1š¶X‘hŠM!&”8Æñ‚s®v†–¼Öz6=j+?õ—vÕG>l%UU)x ñ ç~”7D?_›Mb–{Æ‚z{ðÑ­¶³µÇê*e–¸Ì IcšI[2a3(7²¤®ÔžÞßm_¿}½å÷uÚ¬éõÚ*¨ÌË#¿X¶{²—à % ID"=;wØ-o~«íZs¿5^t™Ö ”ÚÈ®6Üþ˜.^e oy•õÞû+;xËÛð²s¬mÛÓVsÉ¥¶øÒKÛ€ëÈŽÃÆØI""BNUÓ¦Ù¼«¯°.¯²û¶YaµäãZÐ9¢-ós2ÎUmÆ?D8%p›j%ºPN (èzMá¯$^7wÄ& ¿Ð_fj’…PÒ2+fW[t!¿ Èß*Ñ)¨Ïø7y;:*³rwøå‰¿$Ôoäap‹)µËESºª¼•KÜâFežžW7E®aëÝö„óÅ/Ùeïÿ}íQ¦]ÐÑ(Ÿâè/;wVš¯^1Û¶oÛc¿z²Å¦W—zÙ;Óá¥Òîà‚ÇŸñ*ª#½Ñ¨U•YcY}óþ§m³v1hP>3djŒÁKfy1§ì= ,á3JØð®_ßeÍŸý‚í|†vn×þ<:Å­±Öš^{½-yï[¬e«müò—m°h¦+Õ÷´7Ûùû˜M[0ß?n[ÖM>ÐoQDR2eŠ-xÉ¥fS§ÛÖ›¾e¹í}V ^GEDP®gºØÛeBŠu2µå^¬'ù!Þ H, j'*Â^¸d¸““Ág(£¹ó n!Œ ÂrD…õ@â¥2oÓÞ^=:ò5“xxº€(3é<äS™pü¨'Sù ê®;ù#ã§’«]R„ËGþGt¬kj¬’©ÓîßjþË7ìâw¼Ýò‹‹ ñˆåÆþâ^[=ÅÎ]5ßõvÙwÖl³YSJ¼ÞÑ  ¼j d…g,±Žuk¬ì•¯²ßþæ×­²®NJY>µ¬›ÌHÍ’…¨ùþìŽ×¼Z'VHÿµbµÚÛ°rF?Ôd:ç"Ï §`™$ŽDè(¸é‡I.FCp„;IÐ~òJ¤&‡Ïñ¼ RìfÛ.ÑÕt#pAît‹#„ˆãê?=÷Çxî¸Ø–xaÅ"0ˆ¬2Ãý…Ì‹ÌÔs´…å–f©ŽöÙ¥7ý·£3Ìù¶Rº¦ÌôÇÀ‰>me+ ›¾{‡ýñ7î¶ó¦—KQžoEÐ081¥)â¡òiÕêð\(à Â~º¥ÓnXÑhôökíâóVe-µÐîô& (>„,øô_kOž^[pµL;µµÈ–M»¬ýgw[ió>ËÝð˜ênµíóWZo[¯åÔ”Û¾Ú+oºÉÎÃXc^94¹ ""ªö¶5Ù­ïxµ®È*EDFÚ:µ!£HJ€”á*@>õ2W­gÀPä€X\x" q „Ø ú‚¸`„òrŽ$ñ“&">ò€BÒ FE„R -.–ï!4\É#ºL ‹wâ87ê\bøawYA±Æcè‰jKŸ]ñÃ[l• p™°<ì½c Ö?üé=öÁ¿»ÕfVj?9-<ì—r=BÂÛË=“xP•çU"K­úÖ·öÛ_½ñB{½¶Cij¨%™‹Ð²ë¸¬;bHŸž.¼{öÚÍo|»M»û§¶ò½7Xgq•=tïFkÿõ}²¾’R­¾ÞFuæÀ®þnþrdÇf«^|¦½þö›­z¦Äaœñž<õZ‰øZ·l±Ÿú¯lÓ¿~Ã*­ôÑ‹D"¶Ž¨©‘Uã".p®sàîà‰)¬<,DŒAjÄ&Á~OûÃû|­Ìª{E<:ey•I žíKŽy…<û•¼]ï¡RŽø®vÞÔZ;¨Õå¶«~‡-¹ò Ï<†Ï^Ú K¿eraÑá'¾t³8!éEʬOz\l÷ñh/ó?a©•jÿ­Ÿoî°7]0Óþà­×Ú…ç®y%À>Ý¿ûÓZxw[›­ýÀûÃÇ8, «ïßa»û,îlë-Í×Ç:hý:NSô4h¦Õ²ÏÎý‹OØâ«® _³†Ôé>ü«:….ôgD*˜žÎ¿ì%6\Ye[þç?µjo¿dýSmT[¦Kàî­æ b±#b*õ5$!„þ`ìŸó’~Äã’[ê>6,Ɔôp+}*+"EÏ`Üå™âÆ%ðÎÉ„ù(ñYncÔ⊙ví/nµEè<ê…+Ì=£çx¡¿ "ÜçÌl²³–L³GÖoµM{X£ ².+¶#ökÌ:ó9úÉgPïÀ,i*³µÛÛíßn_«3Z†´¨qª•–„“@£B?æuºÝOkBg3P ‹ ­µ È¶Ýy§õîÛkÝbÄÕH¯!sÝÑòRÐLdˆí¿‹òmøé«í·K>÷9+khÈr§ðÃØmƒ˜ KK}Ó¿ÊeË­åÎ_ØÐÞË©×â³!Ín•Ç ñˆ½TDë¬H HB*’ÇÔ s'Mò#/Òó‹~'BJÀ±","i¢‹H2>?Ÿ;ypŒ-ºÌ¼Syy!⺫+m`ãZ+?ã\»ö{ÿ1fSÄjm•*ë(<ô€;â&,´žÞºÃîÜÔb³kJÝâ*ˆ˜mæs¦?Ä{Ø5VYUa®ýý­[‡¬5ç̬³Æú/‹ñ£ÜÓͶÄš>r\žìÕëW¬°º+®°¼ÅKl° Ä<¶ÆºÚš­°EÛ&´µØŒº©fsgX³L/øØÇmé Z"{tØÓràœê ãÊB\š«þž¶r… ÎYdÛ¿ó-™¶ÙHI•å0¹À‘V7{Ÿ”å_³¡-æC4IRDtÃ/ÈUŠS!/E’>õNL¯;8n' .=#G~,,—.&*U¾Â©+?JÏ­ª´áÍZÕµ¯°—}í«6cåÊÃ÷|Wp‚/‘ˆP,Z«Wηîæfûκ½¶°"’&º™#ÓÏ»j†Z©¶ð 74¬582”XX_jwmÚo?¼s­5Uä;7R¨ã¥IGŸœnDä´Ó0P2;™£cÙ³ª\œzQ¶Âînm³ö];­yóS¶_[™üÅ/­ê!-ÔÙ ßkï¾ÛfjíÇø¼•u“ôgìÓÌ1‚˜¢­ý€íÜÝl›žÞkOnÝg½¬·¦‡î°‚]ÛÈÔÅ6ÚׯŸDZ‰r]ë¢EmÆŸ†Nô‹9Ð7d¿ÞØiúÖsìwßô2q$š`Êeêbb~§òý´" ™œƒœººûµ3nVž–¤Ìô2?¨M´´X÷îÝÖûà¿Üog¼çÝVR]}B,LNåÁ÷b·-9Œïw,zö·vØöͶñ©]¶þÉ]¶yg»Иáä»òš «íë²Æûî°Ñµ·YAÝl˫ҢÃö.'" §!ž !ãyEE. DB "ö›®NT"ÊŠá:iù;¤Ç£ôè@vJIÜïf¼áðÆ3_c>¥‚`Tˆ{¨LY’%ùê%`å‡oi;•üÝOZß¹WÛæÕWÛëßój»àÌ…?†•q¢Ã"Bïìê±ü×[ìOnúµ½|ô˜ê_߈1ôFªZÀ7öDæøp¸+qXÊj¢ £;»ýÉv»vEƒ}ô=×Ù¥œé[Q&°8á‘jè1òœV˜Ám´ì? ƒi†­¾¶ÒÏÏ„¥(-LNƳân«¯Y_^!»ceÝd„@&RÿsVKKk»=½}¯mؼ˞xj=½«S{/²Ê²B«,×v6ƒ2 íÐñÃ;úGlù”|»¸¨Ýº¾ôM›Á[ÉÒ3ld»#zÆë4ªED拈 WH„](=. )¡¨„ xáxäœR„NÍü–ú4;hkïÖ™’ÙÜYZX>z:õTìÐI:_pµÑ}:¾_1Án×9»öì·Í[÷H<µÛžÞÝ.}Ö•h[oú‚«àä:ê†Óè2µ9MSlÕ’™"slþ¼éVW&±ÂŽKɤ¢kÏûùç>oño­hæBvë3-"rñŠïYâ`ç‹w3ÓÇ1nýŽŸßøgMÇ-’íÕV&Ûu:"¬ñ.æ1&|\2ÑË`q5] !lˆ²œxˆ8XU…6’ì¶aíkÕuÝ;ì©UçÛŒŠ´0‘mß÷¶—Úò¥sñއû˜²O’‡L"òåoÜlþú=vͲ ΢ï#ˆ"üžxDâÜ€_‰ìÍ]í‰í=öů¶7¿î¥V#‹5Æ§Ú öSF„E‡Gâ1è£Ç::{uNÀäÖù6{F,­ŠÃ0ö´q¨„ ìuòA Ðï ¯LÆYÚû[;mǮ۴u·DSͶkß;$„^!ÑTE)[]è¼ ½ÎD£Ö-ô"”(;=Ö&@ s%>$}G~Y¹ÍzÙuö½·Û¼§n³ÑJºË•©o¾&4[DDØõvޏf­ƒˆ(#ê4RLi<œø$ k4اŠ?ÄNŒÿ‰yD„˜ïù(¢Ik *D dä)…€HVÛðcÛõÐegÞúËÑ™ñßûçYž®e̓Ҏèt‚ÅÅA'a“YÆÉêO‘"éD^å‹„?ö{íe+|<‡™*Œ2.©>ð`<&:<Óý2ºÈ0¯8·Á¾ö‹ÍvÏÆ¯Ú?ø»ú%çúDäT""“ž€Ä§[²êv±Ûˆ­èJuÒ„À¦j{é1Äû={9Ù!I,¨k c±$;°¶ìïÐúŒÛº½Y¿ý¶g—õ‹ hËsiuå–«ñŠqN¡ëÓ䢻oÐÊ$ºZ±hªµr®-xjºŽ5-Ñ)'$ÁŒ4–ÇZ*~OT*H¹|ç™gÚè¼&[ºá—Öµõ +’^$_Üð¨&9uö!ËÏfIœÅšÆ,|AŠx¨\¦ EF΃¶€G„U(êãˆ4‰·žyŠˆÓêÄy û ]®ÕƒxˆÛZ÷ jbvÎOo³Ù×¼Ô6ÈŒ¹¯³Ï*8´Iïqâ7fÔLЂ£¼59\$"e(Ößö*‰-ÚÿýÁ£víÂë‘W3<<Ç cN.ôVêY`àœ‘‡—Ëdx{GŸ]óþoØW>¸ÇÞôê—ºî,æál,jÞ'=Ðl®½£×‚p£:ÓKÌt«t PÖMÄŠÚNôaÁe Ëس·Õ¶i}ÆÓ;Zl§Îžè”Ì™}ÍU–I ^¥uŒ>éa‰¬úµ»rŸvÐí“ùm‘” fÕÚY+æØâ3múÔ:++{®=Ä\˜²¼{à+b-Öy´q¦ýjm÷Üawüù_X­ˆHÄC-ö¸ò…L€.¸c•zV]#$ˆ­ôš‹°@ü¼ A‰éå=¢Ókž¾D:›éÒg`u²ËürD@y@iÍ´7ÿ—͸äbϧ»³Ë†xDØP5v‘ÏK;¹#"©Ò™í7¾ó7­M"ïºo«]3»Êz„üã„!À>´%ŽQ‡urñÙï$å%¹Mh§‰ðÖ–Øï}ô‡¶Y QÿÏ;oH½Éã'»^dÒ ®Ò"¿®^EðaÀuà°ž)Õy}ƒd/'ücä;SçÅY~fÅ`õ»ºûœË@ÁØ®"[$¢„˜¨¿ µOYµ>P½ÉWF$Ìïw‚1¤Yi–¬Å|3jmùâ"3tPP£UŒ³ ¢.qœø$$³"Gáã¬HœÅ íŸô³-í̷҇s.»ÀòÊ+íWú iE‰Ö‹Ìµþ]ûíÑуVP.=„ˆ\AD@ÔÇͽ‚QäH(ƒ‘^,*")p‚'ϳ8R¸¸KŸ%âÁ‚Aˆ&J¾gCÜo¥ËWÛŠý'kX}v*7vµõ³5T¨ÃI5á^(îë´Éì"i”Øî£¿ÿZ­µ¶ì·åMâDÂnÇé> >¿&z,>‡Ø£,äz4)’ÆÅ5Øß|g­=ºeŸýõÞ`çžµÔ':“Y¤5) 渤 ç\ý| bfB ¨V[]ž"(ñ£žÌýT¨{DÒ´…> ?Ý2âKµk5÷nqÛ¥zG«ík•XJ}/QT‘ p?ÉHYyÿ³À¯G3¾ƒº—ˆ™=½Æ–ÌŸfKÎОEM~Öuº´ð¡Çç@ÀâÓ ¿# «®,±>ºƒR [Át»êÿ¼ßjgϲÛ^÷:ëÒz‘Š•«­_œÔÃ=}vA¥BæœÇHެñŽEP )P6mFÂ/"®çRkÆté1GàíÇDé ðâ3/°Uÿñ/V³l©ÇQ€îSŸ`¡D©T‡Â¸@lyâè&»snU c—ÝOýáëìmÿkÑBÑZY Ï`¬+œ_“Ëø¾ñx¥K@”$†“‘',½]º¬ÆîÔξçýÁWìöz»î¥‹ˆ„u*Ü'››TsL¶’@ß‘ÉúEâð /•b¯bœXb²uÌ©PßÔG§/Šp<’æ›Ä&¿Cº«½-í¶{O«íØÝ*k©Në–r›—еr‰~e€½Àc|¢ 7òÒ‡ÙÝ;è"ª!ƹâ4/˜j‹¤Ó˜9£ÁªeŠšébs–y ý¥ÅEV#ÎÈZ!hšèÈåHTuÖk_kÕ÷Ýg?zë;m¯©ªYy¶õKó å]¤Ìœlˆö½GB ¼"Ò" «Ç|DÑé!Nâ:æŠ;Bs1,Ì–§2s¤ó¨{ßïÙüü‰•Κå–Bdˆi2ðê˜/V‡­CùºR ~¦ÂÉdR8‡¶×tå²ùö)¼¯üÈ·ì"éÈ ÔnÆΛš\b?A¬¢?zbcWÿ°ÛPníZúoÿ¦}ù¯[í­¯™••êØ_èñ—Þcx™ÀöHÉR”!g è©nóN(‰â¬c«lVÏø„d‰HIôWtpXK¡üÞ³ODc¯~ZäÙ¡…|(¹‹tŠÙºš »bB&ÊG™Ðï|нR‚÷J^,¢1{Zµ-Y0M&·ÓmÆôú#@À2*+uî”U,"bIÄ60‘…V®øœ .°ßúÑ÷íöÏ|ÖÖýË׬fÑ ‰9íAÁåbm‘>E¢9çDT/FvÝ™K(ä3êŸÂR¡´ˆ˜o¡Î'ɰ!ª|)sE<öÚ Ëyù«­PÄÇL8ö%uï”Ò.£på±ø°H„=?Åœ¸zÃ…þ¢Íܯ¸älûÖ¶Ú[>ý»b¹D{*Ïaœ\Ž–x„ꆞ!‹n‘)2ðX}n½ïC?°š8¡ƒa zêëqšy̳<é û±éa4ËEæØiïÍâԇGgCŽ "‚‰¹M„œé¡‰g:5»Þ×ÜaûÄeì±h–Hªó@Ÿ =\FÍ”'4N0 °8á%{V #ÆêÕý¨à4–,œfófOuEøDœÈNÃÁ‘‚çu/ÌÞ+Ê¥œoÖ¹åZ-ŽËU[#Üj.°>ÿ9«ž;×~ù‰[Yõ ërýA-|½HJ]÷AD@Ë@""­àW€"ÐpæÈœgâŽäГ,Á˜JDØØª$W§¶_ú û§ÑYö“Ïßjyè){ùÕçieù¦¾¬§Â,¿—¯ ýS ¹~j¢FE'¹c G}Äk®¿L;/ï±OÿçƒvÕò:ëÒ¢b?`‹p ~æo‘ŽÄ‚»òé^+T^xY“}æ«÷iak›}êo²Eóg†l”˜úœìî¤% £ =ZÜ«½ŠP˜…ì5vÛ‘@ûlñGz/~$D¤ã'"ÄÁA°€K©æý¶·¹Ý·i••§9b"b›JYJ1 ·x„D9|3Ì”G4ņÓ@üƒ·Tâ„ÙÓkm‘ÄSp˜Ü>“"<Ž—Xç}§mUÒ-ˆô¥DX4Ö‘‚Ú ¢*ÖŽÎ×þñ‡¬nÑB»õ ¯·ÑŽ]¶oÙö`[—]¤-ÓKœˆÈ²PÔ8Å‘üX^‰ËILŒËl'a߃*ÇéXà:IaèÑ5VõéOÛ¼wü®}Zòþkî|Ð>ÿÝí³~—½ôÍ‹í-×_`W^ºÚ÷ê“ÎÑëÀ·—üB_¥¹ÌÌr'³?ê#JDdßó–WÚÚ{lͶ6[¬s@z4›tD„÷â‘4|lXšèÆ—ˆ¸^Dëi.>¯Áþû®-¶ußWìïÿôÍvÞYË|œDbv2Ãó¤$ pè9t‡#¶ð©/ÏÏèÔ³‰ÌùÓe#'„ƒ?Ó‰X†ÕÛÝâ0Ú¤ôni=à£Eȯ]k0p /f¨lR.«¸×¹ã&Â(Ã×HÄÃ: L³‡¥q,Ó;óg7ˆ`49Ñ`ExùxÝ–Ê@<øx±‰0‰ŽvMñmsiìr’Œ\€î "?RY‹ W¿þuVÕx§ýè oµÖ'ÖÙmÆX¤ýºÎÏ)°b!ý!!ÚF×Ð;a,˜9jWY!ÜKI]€ «Ës-gÁ 8›AµˆGÃç¿`3Þû-z,³šif«—γ7½î[»~“ýøŽ‡ì­ïþ¶Ù‚[ìo8Ó†E¨Äõ"3¹QQ%ˆ>¦ÊÊGY§ŠÖ{úÔzûÈ»¯³KnüšÍœ"Ž‚®1;†PÐø˜O¼ÇÄÄ8‘â^k—Éð…‹kí¾=]vþïÕný«ß¶k¯8ßE‰';9©ÂB@¬¬ Ní鄨#ŒÒè—w"±éÑûˆ¼Ð…§ˆ‰ŸæaÀÇow$XaÀ€þ³Ú¶¶`h-;wI7…ˆI´ÂÅ4ùòTh;‡ô‡Æ‡Î_ð2U„…²à.é«~Mè[8“sD8m®ÄSSE4Æ,îSc½c}ùO— ¿_ƒtP8ˆ°Æ×ѕԬ¿‚ŸÙeöÆ»o·[?ù¶á¦ÿ´'.×6"£vŽˆ*õ±VƒY+}Å4ŠžcLyi?Ï}ƒ _-Ä7µ®Ú‰;4mŠØøÕ´©¿ó6ËÕv*1:Ÿz7(Í5B\—_²Z+´¯³{Xo?»wƒÖÖ”ú^a)î_•ÐvXÎA†o4ôIfÛUì¤u´ƒ¶× Ï[iÿðž+í÷?w«]~F½o¼HÃÀ<Ó {fâ‘ÃI§µKDvÞÔrÛÞyÐ^öίÙÿm¯½öº+Nz"rÒ „®ƒŽq%9J»Ìz?] Ê:fmÛ>kz]ÈG}ª îgÁ£ã€(ÀB6iñÏ™øaº wÑ)séV 6¥lnív+88BD!pˆ—rìæv:*däcBXÀr¡¯e¤¾†ó¨ÑALË%ž‚h`9…M~‘f·™.ÖŸ°“½/©+u QúÇS@G´ÑÒ‰vÕ/Zd¯þÒÿ³;çͱûþú¯í¡úYVÔTkgJ‡’Àö!Jç°P9 Yk p‡­HÈH~ú”cug à‹§6XžÇ:´k³5þÛ·¬ñMo„‚Hïû+ ŒÄ± sñüYþ[¶x®ýÍ?ÿÔê«’MH•†¼‡ÅU± %ë­pQôC»Oöþñ ?ËÂgÿ¯~å¥vÇìší¢¦r_× Ü%`£OÒ|nÄ#>À´CœÈô ­ÏY˜koøµþVŸ½õ /ó²±.ÏRí}RÄl/Á>BQ\•1ž(°ùAl‚Õ>le•êñÃ>Š ']Ò·ôÐôqžñQ§~Ò2ÄEÅõ±Å¹sâ(I±Î†C“ú%ფ d!•/Ä3Eöñ¸h¡ˆÄâÿªˆÄ'JK=ÒgõkýÑX[aó´;òœY®¯­©t‚ä'G”òOV¤TàgÇ”¸ý2ö±­Žp•n ¬¾Þ^þ‰?µš…Ò‹¼ýív÷þV°ú<[©}¨ÐA(r=-ÄDˆ8œH<Ú–ž‡$ ÊS.q’|²d8äIDATËÙófZÙž6;زÅÿ÷»Vóêßôb]|–2‘>p§?á™0¡ SiŽó3Ojgãïÿøn;õr}gµNDˆç}ÒÒÞÌ|‰›L.Z£aõîߺÊþ÷ƒÿæ SYÄnÄ)B{S ~‡UcyŒc:¦']ôÓoô}”K_µüõö®w~G;lôÚ{ßvƒtQE)‚–*ê$𼨄AŠøE)€Œv,àâ ¢Oi¨¯t‹˜ÌÁL§Åp,Ê;QyøÀL ¹t©±mIÞ2f0ý"ý9Ê·Ï7d?Ob¦éb?Í€¢…[¾à¢/OíQ¤ U€¼¢8Ã?€P)çB|>«´˜|J¬·Â¦…˜æÎ˜Z#«©›%.}F•6LYñxSÈ;xb›Ò­œ\>±–_ècœœ;RÔq´×gšÅ%váïüŽtÓìæk¯µÛúµœ-c×,‰GQB0€å ¤ a;”~§MÏãV_¯^4ËšÛ¡~Øg ?ý©M¹æÅÐ7Alæ\¨Ä ×"îîÒMˆõ½â@‚ÄIÿñ·Ükû§ŸØÛ®^iW_z¶­X:ß7¡ ã0¤õ—t™ŒýÉЦ-—œ¿Êþèºåö·?yÌ.žSeÃA¯åÄ26P„üsHúç¹ø=1Që)ǹê¥uöÁßû¡›ÿþ;^íkÛN6NäE# ÌH1ËäîÃ^V7‘:§úãyzb§ñÁ"Û¦ÕÌœ{^[SîŠYrø<2 P‡'}Îwxx|FÒãá}¦¶g~xáÃ<¬ö©*¡;ˆ€z~C§E·L¡ÑU`%WÁ^a F¾ò‘³X/l(D®¯ “`œø±D8Q/á…#“›²Ng@ïVhûüÅó›D4mÆ´z«¯« ¦­©ÚâK42&ÅcRMƇÙòb‰ýú|œ3#B:R{|• øÅBøoyì1ûÁ>d·Üv«\p¾-ª(°!õm@áBôúnJÄ…th¢”ƒ]¯ èSÿ.]4Ó­[cVÝdu7ÿÒÊ/¹$ù,ăDô3}Ë&HMòï±cK{Ÿ½äüÅögz£mØô´ýüWk탟»ÉL«²W]µÚ·é˜ÚXçù$¯y~ø3ÇsŒ;YïÎA œføêW\$ò„s!À€sÕÓ.`%M*â!òˆTÝ”‚g$äE8ðîÕD¡X¸³_5Õ>únÕ:©>û“?x£UËâd""/ +€ëpq ¦;â…û4ܽs¼3ôÑ‚T™i3ãÆ²b‚5rvˆ;Ýߘ Gº«ÇD½à‡Ì)ÓÿLSˆ.â>Ší~‰†0“ D¢_ú‹7F€»C¹ 2 ×e6Éà/ee··b¡ ±¢!!”Òúo‚ŠPOò!žôˆ7Ð[!Ö ßꪛ¹¨V\F½ˆFÕH4U¤Å~cå%Ÿççl˘§Ä»!L«+’)ºtF°dÏÑe*×›–/·ßþÆ×íÖ/~ÑnþÜçì5çœióµØð`O·3[ Š[¢‡é Œ¢û%¶ª™3ÍÎ\÷ŸwŽ•ý×­ìœsCÉLŽ‚BóÝttöè]:,üâ8Õ“O:øŽÎ•Ù)¿w¼±Ã}ü)ûù½ëìßx¯]¸j®½ä‚•¶xáq²¬ó _X_<ǰçš5ÙÙ«Û/[f_¼õq»pf¥H¬NÍ€(Öºñioôû]!$ˆ=R—$™¿ 9Èw®­—Ϻ¾Ñ>÷§w9ûøoÑA_êK&/¶;¡ ô ø<¸Ç ä‘`f Ð9/„Elyšµa¥U&Ùb‰V…û¶aemЍx©ÙD¤åøÔ˜á¿„H¸˜OÄ€;?”Üìùò¦ ν`‚ài\EÐÿ„áJÛÜzˆ„ä“Ò‡·‹~"?` A¢\V(ó ô™ÓjüÌ•2ZhjhJ³¤L’cf?;â80=¼E'&ë±y5¥>{¤_ƒjÏ>ž "t&©Ë%ÊúÍO~R„aŽýä}ï³W.›gsçαÁ®¾Bœ­^Fdö<*Õ¨8½Õ¯µ†—_eåŸû[+Y±R9ÈÑÇG‰pwÂ=1ލ} R!+†ôÄ€¼5F°âºú²sµ~äÛ¹§ÙÖ¬Ý`ÿþý»ôæ]vé9Kmõ‹4Nš|lD¹`ÆìÉê¼®j#\ÈË/?Û¾xÓZ™&dL è#@à¿ñã¸!!]ô‡ïΓ†÷ýô»ÄÀ„¬'ò…OÞ¥ï9×þôÆ7ûød "'Œ€HÝPB¶.òWGçòc  ¦ã˜ÁbÒ«Ï9 ÈÉÙÝ+ÿÉO‹ÂXEÌ w™½î)ÿa5§UȲA¶ˆçd3/?dTƒ-p2iÕL$ì?Á¢:˜ìz Aà‡qðB~Î{ÔGÙúwn‚ºû™ P¸ %pÀ&œ…ÚÚŸÜI_æŽ|x%>ËOÞþAˬ¨[¡Ãm@ª´I`“ôJÓuP×tY ÕÕN‘5NrÚcÈÕ¯ñãá!"ŒŒèSÞ›››gu²0ë"†Ã;jG?ë%ÞÍ+-µ+ßû^«3ÛîxÅ+-§y«Í{É5ND´§¡Ï¾†:[®M—¼å VõÉ¿´‚ù B‘t.z”q'[Ì iÅU#Gc"¾wÊ;³¯™<°]9¿ë¯¹D'Bî´×=iÿü_·Ú4Yؽb„Îò£^ã,:ŒI&{/þ¬z"0ñyÁZ/sÑ™ ¶K‹c›Ê Uˆ;É÷|p\#L’(OýÏF<â»|‡úö;FmÕuSí³¿Ë¦”—Úï~­&o/¾bý„)DÈ8ÎDVíx‰œ+Ž$‡Ö«2t&’ˆ~zب‘ òK¾9HD€N@ôí 0 È# ïxEN…gPŒ 9aK5 X•MZf0Î F”òUæþ„ ËÞ¡¬PÇp‡£ˆá^>uá/©Ós/í£l vñ˜ú«__ù”–äÛLíl;­±Ú¦5ÕXCCµˆHYÂݤs÷²“ÇŸg˜NpšùÜÚLz·ÝÚó+6G †L‘Ö/…U>ôÝý‡7ZÁ÷n³Y: ¨Tç¡l(´Y"ç½ÿ=VÿÇ·Ü3æ°Ð±Ï¹XêJÿ!嬯_O„3®pÅâÜ£#<:Þ' A…_®X2ÏXúmܲݞشÝî_»Q{˜ÕÙ²Eslî¬iž.æÁ÷À»ñ9æ{2Üëj«ìêsæÙ§þí~›±D»õê;Ž-F8®±¿P9<¢ÿ¹ÏGy‘?D·ò•ö±oñÍß÷ö„XxõÅ"¼Ç€0X„æƒBˆ@th¼ˆ—øAÄ*0kB̧–ŽÔùøSßTaõïaøYL:Yiäñwˆ•Ÿ÷`óñ3yßXÇ—¨4™.~˜Aä%§HDfÎéƒÀL±jJ©öå©Á¨¶FŒšê ´™ùà÷~UäóŸæt}.Ð*rÌ•×mÞ+ø¦×‚<xd‘¹gŸmÿþöàß|ÁŠ¿ø%+»R òe—~ølî‡?¢%é>§ÿÚ…wzze'"R©E¡ ¡Ô8Kòc#Kã2³ïÃX‰â˜ÁUjk—sÏ”¾D¿ýZ—²eûn{è±Íö€ˆÉYæ±ö¤±žóçÓuæ}\fþ!ççŠ>oÉ‚éZ©í]–ªžÉ§•|…á3LêœD¥a§*-ñpøé½ X娲—Oµßõ¿þM¾ù5×?®NtŽ+¹€˜€'ãX'­ =| †0pC…¸`u¯FH’E¬âElè…ç4¡‘‘1¢È%¥w0<ï>æÙsò€Y¨“¿ýüáFFrñ£æ‘A D45èý—Qh³gÖúÊï©â4êtW…XåÈqÅ D8ÑŸä™ù±Ç4Ù{€°›ª ïßÛãqµ/0ND’þ¬Óι/ùÔ§më‚ùÖöþíêü±ñÑjÿ”*y¹åy–û´UëØn|‚9/Ïæ)A•¹0îB$c1©—¾„ßyg-×¢ß6mãßb÷?¼Á9íÙ:ðkÎÌ&åŸV¼û‹*‡/„<_LW]5Åt˜‹•© uÂq x#ø=ÌëŒ/|wÁGºà;Ò»1¯$™§wë,}¯¹’YθªÎÞòÚoYÃ/ªìšËÏs˜Pö‰†Íq# 4ÆåþÀ)@9ÂnÒÜÓ{Džþg !Mðá@|„$iH§g7w\¸f€"£”'#òè½áÃ¥\DAd†Ø ½ õ@×S'ñJcÛ*±T½ôS´õÆaSÔ5©3µˆù}NÏ7ª«Êµ#ï ôogr´PqÁ82.«¬´eïz•­\euKtºÝ1 ™õéå"c†&D z`ü°N$OúÄ£qQ̾£€ì V˜ûòƒËog²sO‹Ý³æqí%Vf3µŠž± 7GE˜¿ØÎ S¤&^¾oU*~'ñÛæ³‰~`]ôª=ˆkæ»ñ9õFâáÆòœNé#ëe¼²ëür»ö߲Ǿ&Ý×ây1ûz?.`¥± À9¡M:^…k‰eôän|ûâ)”X#r ãÃcüó¹Ç²)Ó|ÉìйÀa@0(­·KÕÖ–ËRªÊ?J¶@[QŒ)[éãà&üDÏjÆÔe’?”jm;†|ç1ƒ¥:›>á;ËÓ~Vó.»Ü¡Äó á<ÈÄóH0fïˆoAÚpÐîô<"}!ûsåÔŸ‡ “ÿ¼<Æ'„‚4M„„bïýí¶¿M»:ïo×éŽå:eT\±Ì†#!zE“W:uF¼m´‚³tZcÜ`’FÈ%Pòo.úñöXÒ+©Ze`³J;?úX»}âoþ˾ú׿o ÒÏÀåHø<¿ð,ÝàúA/ògIž~Žˆ’ä|ãÀ7WSB¬¼˜ aÉ%¢ÁG϶#•²–ª­.ÓÊ _ÄW£Ùp¹Î¨à½LÆ~:wÿÀôg¦ÊúŸ²%.VuÇÚy?&ˆ‹¼Ç÷ë )õEûµÿY!¦ÁÊ(=:ä×XÃ2‹mùq㆓‡=׋µd8B¼p„±ÏZ$&poº­UÇttõX}õ” õqϵÌ瓎ªÑN¬&×>þ´ÙâÃÁ%7¿¤`DXyab«˜ yEâAÏXgí׌+—ר÷þi½·âGö¡÷½QúKô¸'N”uÌ HdukÖðq%£1˜ÖêQÏX1Kƒ`sß2]+¿á2ê´x¯ND£ZŠoz×c„A2evÀX¢r j~ÚfŒ1b>ÿãÐyÇ,ïXo,° e «ÍcÇ„¥T‹pAòÇÒeÀ1Q™ˆU›¤\DZêh\̇w2ó?š<˜Çw×IéÿW7¯µó+­_ß^ü8“OÔ¿Íè?ÖœGÄž¿¬Gu˜qe½V«ÿXÆ ‹í*­Á9‘îØŽÀ v˺£‡@ØÒ8!|²DA$ÜRJD#ƒf«Ìikà2D,Ða°lœfV"Ý/`Dd™&ë?ö`¿/ ¡VXǾfÏœc¿¶Ká\·n È ý€Œp"§Hb¢{¼\DØäÇ.a,þ=—™Of^Ï5Hf mÙ¶[§~OŸL˜¥Èî×v@žg’ â[ÅOâáñÿÛûÒຎëÌCbyÞÃ{ˆ Š›HФEJ²MË’c)rTNb»Rå²+ªÉÔ8‰ãš©x<fü#?g«Ì¤Rq*.g©Œ'‰ËgìRv-Ù²Ûb,‰¤ÄE¢‰…b_É|ßé×€°ßwñÞiྻô½·»¿¾·¿{útŸC}È-䡹úÖùã¯ü‹Ü[dœÐVWÖšˆ/˜ƒÐ~çC€Y08²À“À'UãðÃ~æ4aøù"4爗aòUÌ…$`"„QY¡øî’0x+$Ä´x¾DÙ/R0¶½~Ä £}:§‚©°š£üsÂXƒðZÃÄ[<‹|6õ™‚4B½ZL'Ü®1òyâ1߯Ï nŽÉ¬rSÏWËÈ”˜–r]ðܦՇ—_=+¿÷åo_葚+Õ%mæ•Å9a“ªC±€¹#¨÷WËßÿåùø“'å“ ohïšÁ¶ðÎøØ?||!øµrJo<à×ãè÷» E¼ÚUc63Iƒ>¶ivÅSò/1 ·ϰí\ ÀFkkJnÂ/¼Ô ëÊ?¹ÈÓRÒì’!ô±WÂ3ù#¦`6…æShþ'ì°Ü8r‹ç_ëì…2þÞ18çÂ{E)½ g7L½zœ%>ëÅÏ÷¢/œÎUi»&ϼxZþF¥¢(RäAìÙVÐˤÖÑÞ„üù7Ÿ—À!XLЇñœ¬Ã€ç0#Êú†œÇ8 ž¢%‰‚_u~˜3†Å«9’8&lÑ j5ˆ# é‚„Án¼w… að1Z΋u×ÍìÀº!P ä@SR­Ú®["ktã`ƒ3¥5çQïÆ} |ù(ò<_î0^½Iˆ?ÔÔÃ4—–mêíòÕN9‰‰‹o_î’.¸anÞj$vy\ë¾%O¿Õ'3mC"5År¨9.å(ó(ª(érßõ0º­¼äáaä~1*¦w|Zöµ&åûû¦œùÔE%~hëÔ_³–k#5DSÉ‚÷ÃÆ/•,@Ó…£ÄAe¾t8’}¹ÔaTÂ20­sx"EmgüðîLaÜÉF8B‰±¥!%}@ø²³ñ‰z E‚.xôTÿ%iºæYçQ‰Oˆ0©ƒ:¢^˜tþè›eûÖz]~÷XÂäÅ.9ÿV»üÛ©‹ò·Ï¾!mß¾Ž³Ç±`èõ±¤ßZ)É÷6è{<Œzó/øiÈ÷œÄÁ^é9î Ömù¡ðÜõï¯n§÷ýµþ&Ü޶â]îºÖßœ‘~—R‹AÛ&¯À¯ýßÿ€ÚðÓ“ÖñÇdàfÐÖ€ˆ' ŽâÌ]F“*atfäãÐa$H$ 4,±Xé¢Ò…—,üzÙµKrˆwrDÜM%¤ÔI“÷|éù5µà¿V'&'Õ%4Š‘ò|~ÝX,HÎøâÐ|]©Q+“ÏoÀ¹Ïw‰s ¸9¸G>öáGå¿öÞ”+]röÂyíìeyþõù·×û0ì Šò­er ®\Rè²ãàF>Má§Ÿz~(º-ì¤7üîú´u;½÷ù+#VÕ($FÙ—WÏwÀŠòˆÔÀìûz#_ÙH£B6ñ‹ Úxã!ñ¸3€È®(÷2ñ|ÕøB‘(H”&(aðKî()Nϧìf²þã]ذøtgaã#P Pí0¨x~Ä‹6ó•óOL4Ë6+¼}˜…ã6Žd}Â]ÎÙpò™ö&O¢Yй¹ ¾S®LŒw&Ù9j±¹±N—÷¿Vº‡¥«§OÚÚ;åó—åä—åë'¯ŠœêEw†`µVÈþTL4£»P)•©ÕmÜS{Üí5Ì&÷æ%›Õ‘‡¶QH—>y$Q$=0€É!þa#¶ü 6ܬ\ý2Ä>.Š“<¦ú >$0ëÀWÉ͚݌—¨D•Úå”.Hø*£TõÐ×ï7Œ0f±Èß-úG™Âd¸ÌlîˆÕ7²}˜°× ƒT”³qt!ýÜbEGúó#Zœ³Å|ë{îI‘º¾û<¾ zÈ„.ûv·Èã<¨“?ßuz“kð¾Ø./ž¾,ÿüz Xb`Ä4¡1ÙQ‰FŒX+ÁD>ޛ ‰„^ I¸ÜæýHÔ_¶0.4V¾à!¿íNâ¾ßâZÏ€ tGÊÑ…Õ?-Û·Ä¡S]Þpçà—³½¦â*e9ɯõ¹sÕ›»‡Üç/ü‚(ÒkÎÚfyå6+‡Ê}žCÇSBK¥a9&O9çS¥*YPé¶ØÐÀ`å»—é[ÈwX׬{®›êª¤_…tдžs'Ö ÓA|÷`HK=ܧò«ï…{¿ášR• Ü;æ÷6Þ:ø^²ÎÜ;ë …²× ¶&¥Ëá»åÃ?=#¿Œ×A(mW®ËÙ‹Wå'o´Ë7Ïu‹œ»…¨šÕªR©/+’jpsFô­Ç¥„ àGX§‘’ µloÒhg@ ¶‡®¹x=í4 Ú#Œ ¼û †øsëú‡5%BÀEübG¹Ò1[×tÏî¯Å–xõá&ªH„i+ÄÜN³¿›  q*Q(sèéúbPWA·g¹¦Án'nÓaGœ,Ôåˬl}¾ÏŸ?ÇÖ…‡@ úÚ{GœGÉT2šåç³ëŸÕn(ÐÙÇOI›ÖxgƒÓ‡ðëÚOè ^7{ÞÆÝº‹LX”—í ãØ>p0êO~Æ­¡aùÍî>¹ÞyC.\ê€Ï“9ùf—üør¿ôœÇ(®nt'QRIbØs¢DvÅñ!Šûà_'j2 âMŸ”VH.ÄØé×éŠÌODà¨+¶³1ü”ÃRÛ³›cÓrò.É'þó#òáÇOèyaÔ͈™-}Mð+ž…c(¡ X®q×CZÈà+ÉÇ+Z¸nn „î uÁ$ŠÚŒ×sÍ´É>°ò‹1.œ$ÀÑ%\Szp¢àÊÛôÑÁÄ¿HþÚùÖLÃ|7¤kv)×Íw/;–Ÿðá³ÁÉ„ƒ.ÊÙÝQ >¯´vÐÙ}¯Â×7ó|#ó|¯Êøž`b^¾¾Ïúj§ßïÙwÞ•œñlGjª’ºÜ×*ôúê¹ïæ-¹ c—Ú»0¥GÞ¼Ü-g/÷È 8vÆ;ø,àÆ)°»žê@.•0Ùi%†^¦™»A Ž0˜â*ƒ­ÝÜŽ¡ž®õìËÅ1‘A¬›Ëåó¿ûùÌøy%7æ5ŒöhÍ „eà× ]z² jì…¦¨†G!VØVnÁšçèŸn“}±G°xž ×ò×MÄh>ݛɑÔ=¸´q éÓF kGN’à9‹ÿÀèc”uz•³Xþ,>êðAݤ×’Á3>áí8e=L*»Ù:{T®­_¶4ƒ°4|—i`‘Òy¡…ìwÞ·ÄÁÕ´kâðÇÈ­ðkrô¾} Ó&ŒÀA­ wõÜ”[·¥¯vÞ”›Ð9]î”tI×õQ‘7A â̤èÅs~˜–˜1:Z%O>µK:º[Þ}ì =´uã¼–fçuÎ-ÖpgÝÄç‘¡‡;´æ®á' ð`:¢HØ‚ÐðÇK.¼–‹ Žó9æ‚_]“ÏñèŽ4œË_Ç3 JF.eœêîë¯á},«E ™ˆKs2Y'ƒŠ«Í ®÷úæ«´w è t*€Ýxÿ±†~{|ýQ¹ÎÑ……‚íƒo)<©øµLáû\1Cœöª8a´“Æa·Ð=ƒÀg¦¦„þè0¡‘m[?Í꣡¢Ý;î×`¢qEE¬mÃ5ŒLVAòé³m]ÊÇñZÕݺH0£î!¥´à‹Œ]¿í¹$Á—e6}Ÿ§õKÝî\èTT”É–Ê2ŒÄòHt¡½£gPj“eú!Ço+’?îøÖ°ÑãŒl¯‰nIr“3ß¶ø5sá?€Š®ýa<{DŠñl0pä%–…‚Ç¡x~tóža’ó*,TøUç®7p¿|Ìü 1F«BØ.^%ì^Ã/Ⱦ$–Ð{ºÊ—w98ßàuÝè—A(d«7+Yèü«…wkÞT#‹Ò ßòR*̳‰í|m#– ¸™: J¾>–¢!€o8x£æöo ³o­I°Ñv£ñK:íC‘ô8\×5|.o|Ãf ¼åœ'@±°:±,Üny‚ÈNÅ?W~æ¾=a¢mi$l"¶5Tg$¨‚@gM× ÔÇàï›_·ú…;·£^$£Ÿ¾o?ªeɇ|E Ã17rÏb¹²xC `à¿"«1}¾)¢† È½€¡¦5°ÝF]‡Ó}Ìv±PÖŸ„t’„•hJU #{ ˆ••ÁvZ8ö‰VZšp¿Ö3„y°ñÄaóî_MúèI ©…<š>·.¬•¢œ_×äW}Zi"†€—@èÚ–¦0d“!­ÿÌynƒº˜ë]˜M=0¦ó<èàLG§P!‘`¡DÕ“æÕ 5õžóÜ[r€H®kÀÒÏk0帓@TúPæpY´®Í¡½$˜J ãµ`ë²çÀXG|Í$8”wFò¢ÐõãG`qÒàŶ.©€tA­‡³|ÍLB¼pâ‡æx ³Ð“¢6‚S,dØB˜È–Da# ]=€ ®Ÿ[°°ªmsPÉCˆèýÒՉÃ^zú‡æ†ùó {ª&¦f¤&YŸ9öÝ™ÃêŠTÒF ‘ªËL>"à‰¢žCya.$*ÁçëFo¿\h§útU¹?'|h~(ŒŒbH æ€ÄBò·œ, #`²06c¬ ¾ˆþ è93*Áw¯]‡í+7FÔ‡ê*H°PÛÏ}z'ì†Qȸ™rJF &‹F , ù»JKcð«æ÷ܱ\ýRúðòæ¥ëj·xÓ¬ w•N˜UˆÉ¹r©¬D–YâÍUµE.]“@"W%–¡|CÀ7ԩʸö eæ‚D  #˜éJ·ZॣUËh¿2Gk&i¥]ÙÆŸ°X¨µèdÁ$:ua9ÉsèºeBf£{ýGßÍ[r®­GRðÙÎcjÂ$-yhu¤Éä6Lœ°»BI0ÏëÉŠ·tŒ@–Ž•i¬ :iºÃn" ‡ÍuðRQ{G·\è„R kÁ` þûE»¯¨@ߤæMJ±ÞRUé²èËuY,ýÜ!`’;ì-åAÀ7ÖtÂT§¯ñÜHPÿq±íºtŒL©Þé´=C"ì¢"™B\²¢ΤÜ$B¶`Ø3`„€€ï2Ú’ŒãK߈'–’Ÿ“„ÏË ì_½xM1ÿƒy¡ºƒÁ ãMÿâ '=NNÞ–ÚJL"´!¼$ûUŒ@ìA0BD ¤´T†Ç¢1¤çÆM9s±KêáÐ9iøî« ™@A+1‚9 UåB«Â *™„ˆ›%MŒ@¢Y/–«ç‚ä2pøîÉÓoËÎ$F_©¤ÁÜ€2擌pŒŽ¤vÆK¤¼ÂIå²Þ¢˜¶HkÅò”×T%I ¥÷Ág^»*­5è¾Âè« oLÒÒ.-ìoÆÞaŒÛ†!¼ôgbÁ"`]XA4lÛJ!akA‚ÝNg/\–3]#êžvÒ…×u‹ÎcøLž—Áñii¬‚O÷ªÙ.¬à¹¶]¸˜R¸uo%/@h}÷ÅŸ\–TIÆû É,H"^OBx7HGR© L"´.,bba#Y,lËÈ{®^ë–g^¹";«Ë…>ÎUÌÈôa¹âÉ„RȤ”úšÊÀ°å§¼¯– [@ëÂÚ°Ug7–ˆXÀK¯Ÿk“S=£:úŠ t×]åµsïÉsºÆf¤¹¾ žc™Å7s/°½‚BÀ$‚ªn+l!"@j Ì04<*ÏŸÇAZßH‚¸°›+YQ,IŒcÈ&™à¹¶]x^[‰ 6ø^r8ùêy9sLÊJŠ`RÓË1h×ý͉'®9ZlÃ|·ƒ@jkR„šu©XÖR‘²ó ˆ „]NÝ0ÝþÌÏÉÞT©Îû ¢ªpüpÍn.°GÉ;$±É©¯Œa¯óDèïç϶ua#`Ha׿•>‡„Ñäõoœo“¯é’FؾâÌòL Y€LtQÚÈÈ$Ø»#c°ÂÛP“ò´Ìu¶a#{  À.¢›C2>áœK­™Ðt; d||RžûÑëæÐî«©´ïó»Š$fËñ)iiLef¡{BºëZ;PXVAV»:× ]Wò q”­››X:¨ÞºÔ.ÿ÷¹ór¼¡B}›3M9Âæ';P¹16-M›¨È­ý®ì¼Ù~40 $õ`¹( |»Í†|àÖ°–|­¿ìyoz¤òü_—óCRɺ¤\GU »Ê J*$æ‡fÜéýª¦:©×ð'|#,™¤m#‚D°R,KùÀŽŸE(‡äÑ×Ëù#Ç>ýµ þ^W:ºäï¾{JmË4!W™…i§ÿÜ–S¬O³« D²­©V³¥÷œGRY«<Û}6F ¯Î,ÇGe˜ÙÝÝ;€ ~#Z"ß诶x¼÷{þÒ˯Ë÷^í–&XÓåˆ*×UÅôý rGÙÅ%2··Û+J0„×I k•¿Õ–Ï®F Ñ© ËI ໫* W˜„æÕ]XÛÏû«×{ä?ýCÙ¿32 ÕÝ,² [dˆDwœ€Âó3 ÂÙ߀=î²çþ¦·meØ(,{ Ðp l7ƒÎ¥Î½Õ®yȘYEŽ(%x‚zî¥×ä»?¾.[)}L9éƒÄà&ãIÅ%éc\ÞºG§dF`mIë@œôâδ_C€˜bÏ!|wЖš*õ866®¹`ƒ¾áÊÕ.ù³¿{QìIélrÞ“iúE÷yÌ/Ø’ =¤wÂŒ{C] fÜmñ²p7F wcbG ÐØÖ\'§.\“‹mšæj¾ò½ôARø§ïüPžã†Î"Ÿ‚9† Yp{12awÕøŒìh®…÷"½Þ~ lŒ@²±}C D’•qI%bòì ¯iª¾{k%Y )0¼væMù¯¾ ÇîIÊ$á0›8W¼À9 ‘‰ÞÜ¡÷¿­Â{zrâ¶CÀ#`â‘°µ!"^OQ^V&ï>Ü*ŸýÊóÒÙÝ·âÜÆ]޼¢Éö¿úúw¥odRâ±b8òÒGz·ï§J“  ’ û±¨ÊŸ ³©-eR]mFW\)p¡HT²1z(°±Fk½«¥Qä¥+ò½_ÑŒ.W ¡tà‡íþãw^’/~óŒœØ–”qLTrÀç ?߃k=È]F<Ÿé`úO5'¤±¾&zàYŽ"ƒ€HdªÂ2Rh°±f¨¯E#}¤Iþ×_?+mízÌwGéÎ;ü(¤ã_9}A>÷¥•¶KNЉƒˆc:ºà'ÈsÈ$@(˜|.=cS²½!%ìb³`,„€ÈBÈØqC`ð$ÑPW#8P'¯<}]¾þô÷ÔW¹3C⺟Þ)œÕN‰s>¾ð'ÿîg'e ̯NMkWÓðédˆ„7|2!ôõOȾ ÂÉŽ …0Y;n„„¿òw6V‹2Áme’Š÷T‰Ô›þ#ž­BÀd!dì¸!°Îx)*Ú,M4X84%UñÌŸ’ÿòÛ#/üè”æ DÁsýBâ`8}ö¢ü÷ßù+ùÃo’‡keÿHTtxÂɉF0ra2Áe*¹ B‚ÙÑ—íMuî|Dø¼êû1Ò˜|j‚!CØÐ³qnÝÞ RU"½~{o]\Nõ Éßû ùÒ¯>&=|L¶bÂa¬´D}ˆt@ßñƒž’ßÿêäâ9ÉcDÉ÷Â_€+”L|ñæ˜bW1Å‘ ã¹K¥:ÉéÆè¤o­“Tʹ±õ×ÛÚÈFÀ$Û7BDÀHcýÙÝ”¡É))/)’ý5å2ˆ¡´¿ö…”û_”ÇŽìšTBzû‡äÙÓröl¿ì¼'!ïÙQ%C v?Í¥„Ù=ÆP2ñ!›Lsñ%†:»Æä]O4I2cDÑ_ekC`.F sñ°=C T|×Pí–*9±·^¾òR›4bfúÈÄŒ$bErü`tOÊÿó˜ÝÝDÙfi©)“Ô( £»I‰äA~ (l¢4âƒÛòôÁ=¯ÿà³d’Þ„ “­uUêo`kC`^Œ@æ…Åá"ÂH¬Ý-èÆú×·DšÝH¨1L,†º£z‘ÆJߘÃS ˜b3ÅéÊIÈëYºðD¡d¢‡ç’‰g ƒdR„›MÀj¯Ä‹¤u&7Z0AÀd€,ÚXO¼BÝÃÞ][¡HŸV‚àqj3èp£¢fé!Æãà,¸­Œ4‘Žðñ\ó|^1{¯¹úš“Ä(®jx/ljØ¢ ù.6ݱC …•ˆía#໓vl…’*Õa´läµK*@Üô„ÀH?îÖT…»?-G ò$Þ“uý¹~‹RM âÎ7ÇåCûë…fæ|ºc?†@F Y€Ø®!+š1lö¡5r:u.•Έ'®\ãŸ^ã yßÐωËPIúÂÀÅþžA2þ\¤w\öíj”*ÌM±`,†€ÈbY¼![`ùöÈ= 2<0‘ÑM Ùð ?׺Ïc~IÉ’È$s‘»'»¾&áöV`Â}ok³”bÈ0ƒïbÓû1²0ÉÄv \!@ÏGöïi›â"(Ë‘v-qQ)û¾ÝgI"~Ñý@¼—J–B&¼ècù%51ŒÀ¬xÞ F …ý,€€ÈÀØaC l¨ä¾g'†`Íl’hσ/'‰c%dÂ2,F&·¡¡þãÜÀ¸<|ïinœ6–ÞÆB øŒn¬œ[n 2¡~…£¯Æh@±¢Hîká-ôþ>/zÀ~ 0ÈÀØaC l|£M½Ç=hÌkŠáepJ'ùQjPÝâ|ç’î“!|ˆ wk¸+õ×m ‡ ¿=4!÷Ø"»Z0åóâomkC`>L™;fäú;ghmi’'êå|ÿ¸T”À/:uR÷L÷Ó V—‘N²ãtßË&<×g¹2ûWn‘8µb0òPìg ,$;Å6æÝ)ò6†óÂÊ!|O~²ëÉ™dC†Hæ‹ÃYü£ÀÂóäÚ”2áu¾zI™Æ¬ôb´÷ŽDœc¥dÂyä¾ÛT"GîÖ±ûʧ½ÎE´Ûç F yR‘VŒüA Øuìð^‘Cqé›–XZ™NñÁI”H–O&ÑÅ.±s]#ò¡'Zdg¾[0V€€È @³K õG"Â=­ÛäN´Hÿ1)¦Øàƒce’å’ I‡þ?äÕ!ù¹GK]Æ|‰¿¹­ ¥!`²4œì,C TüœÀšª¤<öžƒ"gÇT^„\¼S×ÕbdÂQ»1L?ïÙS!ÝoÖwC­ÙüJÌ$¿êÓJ“'°Ë©}ÏqÈá¸ôOC ÐÈ,(¯F´è~k·9ÛÍÅýi\›ŒKÛÅAyêÉ}ð€¸Í]Ff±`,#ef§a#Àn¬O?yPz/ 9=2à›{O$<âc6.x€qìºb/]ØÒïú“•ê*7úÊ”ça×j~¤g’õh¥Ècâåeòä£ÇDÚÇÑÝälb±¸A áÉÄ©ÕgãÄÓë`Ö}O÷ŒÈ®'åøÑ{5ŠóNŒ@ ûY&F ËÌN7ÂB Øuÿ‘}rÿG[ä|ϨÄ9©dà ƒù ’ w|\L`åÊÍýxyH>õÄ»dçç<ÊÈ#¬Í¿tŒ@ò¯N­DyˆÀÖÆ:ù•¼ÿ$ãŠìŽòc²2d‘ÖcÌG&$œ®»<8}JB>ø¾wIqQ‘Îz7ÉÃ&¤"„´%c¬ òïyoœî“dIâwßq!2!Û”b6ûà™AùìGË}`g‹Á÷r{ök, #eÁe'¹C€ÊôÿùÔûE~Ô]F±LsJ¹vW±Ëêî|y2¡9“2hÏ0ŠK*‹ä#O¼WÊËJµ›‹¾G,+EÀd¥ÈÙu†@HP ¡¢»ó7žüàC"7È©#R[V,“æà¦_²³V½Éõ3òë¿ô€ú˜êÌ©1é#ŒËÿ4Œ@ò¿Ž­„yˆÀ£'ŽÉ—ÿÏÇ¥ç² „°­¢D&A ’qN D™÷¤@í·bŠüÎç>!õ0šH2Åy>9*RqŽÒµd C`¸®,FUýâ/I,†À†Bà6‚$2:>!ßxúù¥/|Käõ~”ß„|¥gäñ§Èo}öãòÐýnÔ_uëºÚPÕùÌD¾Š,ƒ†Àüxaì™soË /Ÿ–¶«=‹ÁË཭ò¾‡ŽHC]^lä1?†vtu¬?»ÚÈ)A¡Ü1>1©:ŽXi‰æËw0˜ä‘ÓjÊÛÄ@ò¶j­`…‚I‚ Gi'f ÆÛ¶!°ZŒ@V‹ ]oDO$Ì%“:"R1yœ #<®\+š!`ë‰À\™w=S²{†€!`äF yUVCÀ0ÂCÀ$<¬-%CÀ0ò #¼ªN+Œ!`á!`Ö–’!`y…€H^U§Æ0 ð0 kKÉ0 ¼BÀ$¯ªÓ c†@x„‡µ¥d†@^!`’WÕi…1 C <Œ@ÂÃÚR2 C ¯øwíö˜—¯€âÞIEND®B`‚concurrent-ruby-1.0.5/doc/logo/concurrent-ruby-logo-930x930.png000066400000000000000000003556061305460430400241430ustar00rootroot00000000000000‰PNG  IHDR¢¢åšýÐWiCCPICC ProfileX ­Ywrtt8†€ˆÈ8Š£¹‘°»‡§0a`à|!ûÅF:8Ø€ÿy­„ZùT*ë²ý÷ ÿ€X?Xíëëñu°Œ~Ñ”8p.–MÅ3³S ‚§â  Œ‡Úvß_X|ƒÇÙÑ< 2™£ ¤ 'øA9Œþ°Ž5Ò?$6K‚XÏ/˜ i¼G>""ŠŠ§ –öý—œ a2Ù÷¯L29è/þe l ?lNÞ±ñòÿYD„ÇCm\"°d¦X8Â';ô[iX”53@|%Ò×ÎbVˆ›B E¿qOp¼… ÄTþ1¿XcèKg€,û“M¬!æCæbøK’)mðcŒBâ,cWJ”ãoù˜ÐÈp;jÿ€r0;ƒ,ÿàü€XS'H‡:`BCÌ,!†±ÂT%;»A õÄ4&„¸ÚAÌqGl˜Uªœþä`c*}ƒ‡ïHÕYÒg)fT!Ê ц|TÔ¼ñ-nHW‹ v¶€tصñ01…~uˆtù­gD•CåOŽßèßPO4? ÜœJ…ø\l‚ÓŸ¶÷ã(ÎT:ô:J¶¢öW¨3:ç@õ UŸ/À âáí ¢@(éY¸±ß~Õ˜2 € ~Sþ´pÛ¨‰„¥Hï@$ä‰ýÛÎh£6$@ú¿Ô_m@àFmÂF‹0ð~!Ë‹ÕÃê`m`io, «õ§0Ó=ñ¦x¼Þ /ó‡ü Öáð¦€ÿB³†uÐ: ,#ÿØð<Ü\n÷ 7†{\ÁÔ†”ß–z‡¤QþhðW²-ƒÒ~y%z,ÌþáÁJB­Õ±FX]¨?Ôˉå X5h‰!VÚ¦©¼GÕ:þ¯nÿøòßÿðQµþ—¿éŒ²Œê¿µðýcŒäOü§”jB€?ä²þONôz }€¶¢hz£-h#ÚÞ¡âß:›mx'èï×7<mùã|QyVùûŸ·¿¶’!…ª5°ÿÇ$ÅÁþŒ£¢wPB‚‚ã„ á, lé§(/¬¢¼I êœNåà“ãÆ\pöþC£¬ óÎýÿж—PWÓ—h&°ÐêëOIø%K}à`‚#ƒ1 mR@S`ì3ðۡ׃AÔ:ì{A&Èyà8(§A9¨—A¸š@+¸ºÀð þ1 æÁ"Xß! D„ áA„ DQAHˆbŠØ Žˆâƒ!‘H<²Ù‡d#ùH1r¹€\En"­H'Ò‡¼@Æ‘Yd ùŠA1 vŒF£„!a 1ÖgÌ6L&“ŒIÇÆaÊ0—0 ˜VLæf 3YAJr¢"¨JBQ{Ô D)èn4 -@ËÐôŒõSt ]@×°x,V«û§Öë‡ÁîÆæ`‹±UØlö)v»ˆý‰#âøqr8mœ%΄KÄeâ p¸zÜ=8v¦q«x<ž/…ׄcÓŠOÁçàOâkñwñ}øIü @à!Èt ö2!ŽI8A¸Dh!ô¦ _hèi„hThÌhÑÓÓ‹ÒkÑo¡¡ßC_D…þ!ý8ý+ƒ,ƒ1ƒC<Ãa†J†» />‰DI¢Ñ“GKJIºIî—¼!9#Å-e)•,uQjDš(­/#]&= ƒ—!Ʉɜ”y"‹‘U— –-‘í•ÃÈiÈ…È”ë“ÇÉkÉGÊ—É)0(*$(\TWäT´QLS¼¡ø^I\ÉSéˆÒ¥ŸÊêÊáÊ甇7±n²Ú”¶éÖ¦%Y?••U¢ª™jªj£êG59µµSjÏÕÙÔmÕ÷«·©ÿÐÐÔ hÔhÌjŠkúh–j‘ØI¤ÒC-œ–‘VªV“Öš¶†vœvö0j™ÍR›6ŸÛ<©+ªKÖ=«;¦'¬ç£wFoL_DŸ¬_¦?a fàoPaðÖPÆ0Ôð’á{#e#ŠQ½Ñgcmã]ÆwMPs“,“SVSÓbÓQ3Q³ ³‹f‹æêæ)æw-pÖG,†,,ý,/X.ZiZí²ê°f°v².¶ž°‘µ¡ØÜ²ÅØZÙµ±“°‹´»aì-íÚ¿rrˆq¸½¿ÅaKÉ–7Ž›w:>pbsòvªvZu6rÎuv‘v‰wiserõr½àúÙÍÄ-ßmÌ]É}—{—¯GˆG£'ÁÓÕ³Âse«éÖã[§½Ô½2½·ImKÚÖ¹w{øö;ÞLÞdïk>87ŸjŸïd{ryÅ×Ò·ÔwÑÏØ¯ÐoÞßÀÿ˜ÿl€n@~ÀÛ@ÝÀüÀ™ Ý £A³ÁúÁÁ !Æ!Å!C-BO‡~³« [w ¯ ‰ð‰¸ÉÙ%•Õ-=£sNSNËO[Þç¶ïVº@úžôÉ óŒ‹™Œ™”Ì¡ý:ûOÀ9ÐsPõà‰ƒ?³ü³e+gdÏñËythÓ¡¢Cë‡÷äjäžÊÃçEæ Ñ?R•Ï’Ÿœ?yÔöhÃ1ácYÇ–{ï,P+8]HW_8VdSÔxBüDÞ‰ïÅÁÅÏJŒJjKùK–~>é²ÿ”Á©šÓ§³O=ræùYó³ e’eåøò„ò7ç\Ï=8O:¡‚·"»âGedåX•cUÇÍ ªù«s/b.Æ_œ½äuéÉe“Ë5 5gk9k³¯€+ñWæ®ú\¬³®k»FºVs]âzi=[}VÒ°£añFð±Fƾ›V7Ûnéܪ¿­x»²I¤©äÇÜfºæôæõ–ä–•»ÑwZƒZ'Û¼Û†ÛÝÛ:¶tôܳ¾÷ð¾Ùýö†Zê>lêÔî¼ùˆôèF—FWC·zwýcõÇõ== ½š½O´žÜêÛÜ×ܯßßúÔäéýË®gvÏú]Ÿy =÷>ó"üÅÇ— /¿ ïÁd½b~U0Ê?ZöZæuí˜ÆØq“ñî §‰áI¿Éù©Ø©ïÓéoˆo Þ ½½0£2Ó4k6ûdnëÜô|ôü·…Ìw,ïJßK¿¿þÁàC÷¢ûâôGÊÇõ¥œO<Ÿ*—Õ–ÛVVFW#V¿}ÎúÂó¥j´öà«Û×·ß¿¾ýùqë§õÏ‘õˆõõh2…¼±@a‰ `©¢lO cüuæÚà€[dò@,:$…+ðT-ÁŠa/á p#ø‚%\æi[è.Ó_b¨'¶3¾bƳ¨²F±Õ³ç4ã:ɽÊëÀwQ/¸]èšQ4@ìºNÒ]ªLzN–$·S¾E(+gljWEÕŒÕÓ5š4—µä´=uò6wè®êK¸fÕ˜bÍdÌ---S­Ž[_´¹cÛc7bÿ~ ƒ£Š“‹s’K±ëm·—î_=¶nöòØ·=ϻڧ<âûÉŸ>@&r\¥À°Ð©(ðDBqFIAiÅÉë§ZNwŸ<;^6[þáÜZ]¥L•Í…˜êâ‹­—æj˜ku¯„^-¬»ís½tƒ×ÜÆÖ›Ë·…›Œïø7§·”Þ­mmmëjïéxg§æW–uæ>Jé êvylÔ#ßËÞ»öäE_}ÞÓ°“gϾ >ª{žÿ"î¥ç°ñˆÒ+¾QºÑ¯¯ÆÆÆŸMtMÞ›jn~Óü¶iæÎló\Ë|ûÂãwÓð‹j)KMËœ+ûV|ÉøÊý­þ‡ÛÏŸñwEØ‘8úÕ0˜·¨z +€=Œ£ÇijâÏô£4™´$ÚUºú= NDF"ãÓs/K;k+ÛcöW¸°ÜÜ<Ò¼|Žü‰‚û…Ž Ÿ¹&Ú"Ö)þTâµä¬Ô¢ôY G#O#¿®ðQñµÒå»›jUNªT‹Wß®a¦)Gb"}ÐêÓ®Ñ9¸Ù_W_GoQ¿Ó Ü0ÕÈÛXßDÐc:eöÀ¼Úâ%ÅÊÅZÇFÀØNصٗ;¤o t´sÒqwapùàÚãVížîáî)ëù}k·WɶíÚÞôÞ¯|®’³|üdý¦ýOxò¾ªÞb*†„½ ¿q"2.Ê.Z*úGL%/Ö)Ž+îe|i¶Dáĉ¤ò~ÉÉoR*ví’Ú5³»:5vÝ^å4–´•}/Ó›3Ê`? ?àpP%‹=k5{0çú¡#‡£r·ä©̧Ïÿzôݱ‰ãC…EÏN¼(+™-]9¹~šö ÿYý²Èò“çz*Jµª  %Õ—.sÖhÔ:\ñ¿W·÷ÚáëåõÍ ƒ7n‚[¬·E›ÔîX6û¶ì½[Ñ:ÐN×a~ïÐýÁ‡ôê¼»rº›/öÊ\SrëȆ€Q‘ß¹÷Œ¨ ó4CX"֛н]Ñp;pwàh·ÂÅä )„n˜7I¤ U§-¦]§ ¦{JoDAî?ø‰%ŒÂŒç™T™Ú˜]˜çY2YEYï²mgûÉ~–ÃŽí£\ú\ Ü'yìyñ¼-p\ë ` f Ù³ Á5)W,JÜSÂRRWŠ$M’ÑÕ’Ó•×SÐUÜ®tBù‰ ªª¨æ¬ž¨q\³ŽÔ¯µ¤Ã·ÙB7Y¯Á€Ñ0Â艉¶iµ9E¾³u®-§ÝiÅ-­NæÎ5®ŒnqîÏ<7o­Úƶ=Í{•ãûÎ?:`-(+„7´2\%âz”ftE5öz¼|™$ÎYÉßwFíMµßó0mó¾séË™&û ÌfieçäL&åææ}Èw9Úq\½ ¾ˆtâQ‰oéú©Sg”Ï6—;Ÿ{_‘]¥táÅÅôËò5WëX®UÕ«7ÜnÔ»yó¶|ÓÙfÙ–®ÖðvÆŽÚû¶f:S»xºëzLz‡ûbžÒT M¼Ø7,5Ò>êúz|ÜbhJoúä›™©YϹ”ù¼…“ïŠÞgˆ]tù¨´„[êûTºìµÂ¿ò|õØg«ÏŸ¿œ_Û²öýkå7ÛoŸà©CçÇèÏNjücUU¨«@Œ`úqt}ý“$„|~Y_ÿV¶¾þ£6F¸þë•™úŸ¨´ˆŠ:bãöPŸÿ¾þ¹„Ùý©|¶iTXtXML:com.adobe.xmp 930 930 d³ìâ@IDATxì½ œcÙ]ß{µKUªMµ÷>Ó³Ïx¼à lâ ˆ±ÇlÁ;6Åì!B’÷°=¿|äÅNp€‡ lã1<ð‚ÍØ€íñ23ž™žéîé®îêÚ÷*íëûÝ{¤SWWº*-WÒ]~êûQÝ{Öï¹%ýô×ÿü¯R©(| €»øÝ5ކH€H€H€H€T”¹¼H€H€H€H€\H€2×…“Ê!‘ Pæò    p!Ê\N*‡D$@$@$@$@™Ë{€H€H€H€HÀ…(s]8© e.ï     Ìuá¤rH$@$@$@$@”¹¼H€H€H€H€\H€2×…“Ê!‘ Pæò    p!Ê\N*‡D$@$@$@$@™Ë{€H€H€H€HÀ…(s]8© e.ï     Ìuá¤rH$@$@$@$@”¹¼H€H€†C R© §a¶J$à >¾Ëxc¢9J °ÆŸÏg£þ±+$@® @™ëŠiä H€HÀ!ÊeHÜŠßo*j©w2“ì& 8€e®&‰]$ €‡B¹\6 ÄLïRì@ñ% @(s»€Æ"$@$@€·TR5®™~¥Þí (s“ ´A€2· HÌB$@$Щqõut¤wÍ2ë+dšH€ (s @ø’H€HÀJиÅbÙlY ýj°ï¶ÈiewY €‹Pæºh29 °øã‹%}§zÑ»Tºz’L“ œH€2÷DDÌ@$@$Ð%ØqaÍmZ¸;½K¥Û&O’ 4%@™Û O’ ôJkÎIJ3TÔBžv¤wáÉТª^{Ìò$@î"@™ë®ùähH€HÀ×à® úÕB¤¶©wîßi9f/HÀö(sm?Eì 8Ür¹‚è5̯M»ßµÞEAÃê´¦õó$ ‰€H€H€¬% ·ãÂ9WTnлÒg·QïÖJÀÕ¡®_¢ž!tKÕeå  €»”|£!   è¶:Ë劢fUô®ÌÖB¹ô.ŠƒY  hJ€2·)ž$ è’@6[ÐPú¤wá·à÷ÓI·Ë9b1ð:-xd¢9L B±¤×¸h²R®:-4êÝ®ý`ÜÅ7<7Zy1H¶A$à´æ:d¢ØM °=øÔf²9éYkêœ`‘? ºŒº`û›‚$a 5w˜ôÙ6 ¸‰@¡X”ã25ÖždßmÔÇÒB¬÷ß…A×ï‡M×Ô ØMl9 .КÛ4! 0€¨M§USn‹h_úUÔÒèÏ Î›åÇU¡nñ ÒC×8|M$ КË;H€HÀù\Õ” #«¨®Qïvjß5Ëú…}Ïjx1t-˜@VA.$@k® '•C" €´M¦²fr³QïŠîµ2Öšøï6A£¡ƒ‹ xÂÙ 8ƒ­¹Î˜'ö’H€ìL P(¢{Š„AïšÙw[kk&aƒ?CcÍ K];ßì ­¹CCφI€HÀ 4“)xåV}ä  bWžGÂZû.jãnz¼L“ ´æòN  è‰@._FVCÈ)|õ®µöÝr©‚Èb­ô4*&p>Ê\çÏ!G@$@C%/”DûÒœ;x½[,•CÜþw¨·' Ìµá¤°K$@$àù<,H}[í¶|=0½[*•á·`hÎ1ÙQ þ ÌíWÖJ$@Þ …ÛùRï–KenŠæ›Ž£$v Pæ¶KŠùH€H€ ŠĄ̊òäpõn¡P¢Ì•sÁ Pæò6  è’@.W‹É ‘†¢wá;Q.—ý~nŠÖål² ¸e®ûæ”#" A€¬„Ç‚hÉ,rB?ô®AR£2˜n±X‡)s1ûlƒA€2×ÓÄN’ €íH«ïÙô®YèF¡X …‚ÜúW?#L“€— Pæzyö9v èž@&›¯(Õ5f>ÅäÀLŒžhß5VÔáæjðfd±î'•%IÀ](sÝ5Ÿ „âÔJ!‹-Ô»fÁÔVj‘Ë ;AÈžÀŸ«â(sr °pÊ\L»H$@v# šr5ÑiPœ'êÝFÏZ3ûnwz’— Ñìv·°?$0,”¹Ã"ÏvI€HÀÁ°+„è½™…ÕLïê-¯†ñ[¥wY,áB4]¾$/ Ìõâ¬sÌ$@$Ð l® Õ­¬GžiÓ¾Û?½‹x ‘ˆì$@Þ%@™ëݹçÈI€H ;Ú¿Õ¢a š:3 ÷À컥JºØû·»Ñ± €kPæºf*9 ¨X}(±Úª0Å wÍŒ»èâô."‹Qæân`$`o”¹öžöŽH€lF M×xÙJïÂoÁfØØ ! Ìt6I$@Î% L¹Pºb›ëÚAï–L¿çÞcì9 XE€2×*’¬‡H€ÜO@õXÈôã´‰ÞõùÛJÐoA?ML“€7 PæzsÞ9j è†@6[¨ÔÜ|õ1»†«wƒ‘ŠåX7Cd ÷ ÌuÏ\r$$@$ÐoÙ\5\.²¹ÞUü ºÜ­ß·ë'; Ìµóì°o$@$`#åJ%›Ëû£{À õncëfñwaßÅ>”¹6ºØ8ÊÜ#gƒ$@$àL¹¬ê•kL½Ô†­7ê]È\…Ž Î¼ÙØk°„e®%Y ¸ŸB‰éÙBqv­w ÁwÑœYüÝ­ëô®¢tCÜ'B?oL“€‡Pæzh²9T èš´c:“Åýõa Z(ÎNõ®Y02´ÛÞ¥ÌízÆY\@€2דÈ! @ß `ƒ_Ù†Î\Zç§{¢Þ5g@…fñ¬Ò»ùBqD Ëž3A$à)”¹žšn–H€º$ÉVM¹úòê]3ã.êì“ÞEK¥r PüL?¦I€ÜK€2×½sË‘‘ €u sÍÜЈõ.ŠQæZw#°&p~ÁuÒl±¯$@$0ðp•B€ÞÆÎ ›>§ÌqÈ3"û®8 çñö]ñ0\ªVT1œV_ÖúUwͰm[“b Ìí#\VM$@Î% 7?3©fºÖìY(8f6 u4xâÓ‹S»{¡õ­}½86è]Õ=7ÒYåõ„™I€†B€2w(ØÙ( ؈@:­jÛzCîpõ®ð7&øàž;3´eÄmÄš˜ŠûþÕõ]q©©ÞÍ"Øen#;ž!‡ Ìuø²û$@$Ð3ã_íM„­Éiµá®ýw ±½´Al¬ê9øœ==­]íþir|……ÒÅæj¢"½Þ…5W‹ußK’ Ø’e®-§…" A(•ÊX‚flÍDØšœVKwªw̓3 ²ªÞšŒ÷®qÅÐôJWœÑë]nù+˜ð™\F Ë߀\FÃ! ÏÀú3ˆWq4`rÍä´Zô®8 µ™ÞC~ 5®¨JwblÔÐ ^Bï&uËÔ3ð €C Pæ:tâØm °†€~·[3%ª¶drÍä´Z¢©Ø5¯ -ë]Ë5®Ú!EÁŠ´H(„}0j[aˆÓês¡P:~Á €+Pæºb9 è–@2••?ßË:Zˆ×Nõ®™qm™µ2>6b•¯‚‘L¨«Ù´¨ BìJ½K¿‰ˆ p Ê\×L%B$@ÝÈç (¥+†*Ì”¨šM\3¨ÆEãM½‹†û§qÑ%Ä&›×÷MèÝlVåÀ €›Pæºi69 è˜ÀáQF_¦&w«áä%S½kzÁÔXÛBï"úÁÙb‡ÉÞ¶NLOÅGbaCž¢ªñA$à.”¹îšOކH€:!NçLl²Uûnce¦²ÖôBz°æ66jù™Åù©š'pÕìœ/4„›°¼UVH$0X”¹ƒåÍÖH€HÀNrµPbfÕ̸‹A˜1¿`zEØwg¦Ç&´· „ Õ¦&â¢!¡wU­T ©;€°   Ìd6A$@6%Jç =3¯ýÖ»±XøÌ©^·0Œ¥õËÙÙ1±Mf£{®DÁ ¸ƒe®;æ‘£  n`›_3·±ð€õî…³s}èë™p(˜HŒ‰¿¢!Êܾgå$0x”¹ƒgÎI€HÀ.¤5·¶ADC|sç í»§ƒqÉ5pŸIÄõsPˆÝãM ùø’HÀ™(s9oì5 XA ›Íª¼ÞEЃÅùIC7ówfú8¸X«ÐíÀ PæŠ4Û! ›¡Ä*åŠ8 ½˜Þ¼»‚~¤S“#0X‹3É”ÑSYŸ“i Ç ÌuÜ”±Ã$@$` \®nC„Aê]9€ùÙI,>“/Ÿ€‡.6Ö”.Än…Ÿ¶Hý#@™Û?¶¬™H€lMÛÛÂdÛØÅè]±¾ ›A,.L5v`Àgf§Çd‹Œž+Q0A. @™ë‚IäH€H ‡G)kåœÐgl!V€uÓ{ëÊD£a¹.Óà¬l];¬‰H`Ð(sMœí‘ €MÀš«ïI?ô®¾~‘–ñÆâ±éıµ1ç Ï`g ±Ieî ±³-è7`¿`ý$@$@ö$ËÖd®¯®ƒÒ“Á§Ô_€é·\urðùë.™s‚xøê²«çNÙÀ]¡Ú9E]¹T*göËy˜ pZs7eì0 X@àð0}\‹ºøJ;ŽO©©í»õÙ[1l6159:6k,>¬3иã£h¾¹Ãš¶Ký @™Ûª¬“H€ìNÀà±Pín‡z×l±j3“ÈBïžøžg'·淠 {ÉTöÄÌÌ@$à”¹Ž˜&v’H€,& †Y¨IÑ&U73î"[­.×=:Ò»³3ã‘°í\æ° -¬õ*Ÿ/Ö/H€K€2×±SÇŽ“ @tN ¦z×ĸ‹f{Ñ»§OM÷Ðñ>­ù-”úØ«& ÊÜÂfS$@$`ØØA Ý€Þµ§)WpHL–+åd2cÀ—$@%`»ŸÊ‘Ý& gHi¨Béb›Cç¡wÅÃ!¡v¾!ƒjß­©¿fÎpÆ®¦\t^ø-dóùêàù €Ã ßÚ>vŸH€HàdBãÊ|2–­<#ÖÚwgc‘pHVnÃÄäø(}sm8/ì tG€2·;n,E$@& ןÆÐo½{æôŒ¡E»½œžÂ> ¶`·iaH K”¹]‚c1 p.3ËÌXÛ½«zåFlmÊÅ„ÆbaÄÐÍ1Ø‚sonöœt蛫ƒÁ$ xƒ@6kt?5sÆλ Ò»ÿîâBÂt''è·àˆ‰b'Iàd´æžÌˆ9H€HÀe2š«î„ ”¯Oö݉ñ‘Ñ‘Èq36NMŽ%u[ÄÙ¸«ì @k”¹­ùð* ¸ÀÁAJŒÊ,ü-®v­w›ðª(‹óÎ0å¢ócñX.Wh2 ž"p:-8mÆØ_ è@±XB/Ÿß§¯FZv}õáÀ§S†ÆüáH(1×7gç4|smÂÎôØ7°Zsm5ì ô€Xf¶=¯…ö]i>wÆî ÐaÐ=Jf 'ù’HÀqhÍuÜ”±Ã$@$Ðl¶îyÃö ²êí»Æ#¥éz5GSc²ZG$âñX>JQGô–$0#@k®ž' wÈdóÒ¯@?ÂNí»ÒX«¯D¤õñÈæç&‚‡}֌ţŒ)Ö8­žÇîº0zÛ¹Äý÷OÜ{×ì7¼ º°à삽'WðUä×vW“ƒ# å•ËWWŠÆcÕó ;DHt¦Eê7›ù_ò»œå˜[L%Ÿøã<üÁ?Ì\^ŠøüQ ꇴUÕ­”¹jBÝ[ÃP”°Ï7÷mß|ú{¿{îõ¯•ˆ˜ °Zsí3ì ô@¡X”mH+‡A¼š­0CAÓ"åjàŸabbÔYwÿ‘Ï=ý3ÿöÉåýÃl$«WiªøuûÇíòs©O~~ë%ºó}ï Ó²«Qã ؇¾—òA$@$à»{ÉÆ¡B¼ŠÃp©vº{LwÙ´H¹"âï.ÌMê²Û=™¾~iõÞ[Þ?ŠRèúÝ„–#ý¥¯?û}?PÎd*yîf`Æ—$0L´æ“>Û& Á(×,¯þOScm‡þ»Á``Æ!‹Ïö>ö»á…éÃ[ËŠOõ½…¡ÖL㊙2(]ù2e9ù_(Gî{QxöÔà§•-’ 4 5·‘ Ï €k ìí¥äØ wÅ!ÏÈ„©±¶jö•êN–¨³cñ”îñ5»¦–ýÿÜüþK`ñ^h\%€Æ…Ö•Å ¥î—'›&*Š™KÉdvsõÆûþ}zéZÓlúÑøß~>ý´õ…¯VToÛóo|ýü˾)÷äWv÷7òÿßLüÛ^ ¾)_)¬øò•J1•þä÷ÿÈÛ¿ö'ÔÂË$@}#@™Û7´¬˜H€lF@Zs[ˆT¡w bãhSïÆãÑøhÔfã®ëÎWý=Ú~f¾b¥‰G£‡Éâ†RÉæJ{»ÑÝÍó/|É»Þô?¯úoCS“{O_.Á<{k%µ¼ŒŸ>á»;vöìè™Óá±±É{îJÜߥ÷üçg~þß…¾ßŸ=Èe·>2uÏù½§oä_Q© tW7vž}vúâźð À PæŠ4Û! aHgr†.˜é]3ã.Š·Ö»‹ó C¶z™\_?¼zn E_ÊuJÉçv”p® ä •\¾¸zô©¥'Ö¯|î+‹þ`Dñ‡|¾ÈThb.::3:vn!~ßTô¶ÓỞ÷å|ø±ï~ÛL±ŒmÒJНPªn¦r»ùÀìÆ #qºT*úÊ%Ÿ²üÈ#”¹¶ºØO ÌõÔts°$@ž&px”Áæ @ Fˆ­X¥wmî˜{´¶Vðcç^Uã*þÉp ™/ÇŽŠÑÌ~î0·t=½yé‹¥ *‡XH—…MVQö J¡¢ øZiµxð7Ñ3*OLßygÑ_Æ.8"£ÑT®P*ûóÅò­Øèæ×÷”ÊÁÙž»™tfĨ¨’X©$‘#S†’-•ñ|íÑÍüÎAÐç÷Ëû~_¬T ‹~¥X)C¬¢~‘À#äóg|Å;^õ*ñ’Ï$@ƒ'@™;xæl‘H€†@à( Sn-0l­}kõî¢íÃå†ãñ±ÛÎ,ÝðCË&³© ? gó•âîàÀøŠwj°Ÿš8ˆ'3EEñ#]É”ÊËYøÛdo^Ú?„ aWˆ²’)7ÑsöòR¶Rý.}|ïC¯›_¨Áæÿ$@ƒ&`üÝjÐí³=  (Tù¥þˆ®†6¡wÅa8ߪH­2YdvÆî¡ÄÐÕïü½÷#D®?ÄG‹ɃTñ(m3à ‡<Ëpbùd6])”2«å+å|¾œ¾•YËEàÕ€'Å~¾r%•Êìù\„ƒÕW“/~Þ÷¼÷=$@ƒ'@™;xæl‘H€†@à0™Ñ·j¹ÞEŒ…X4¬ožéÄÅ‹oþó?ñ‡JG©üö,µšÀUe+U¿j6]ñu 9ÆË‚¯ O†‚R9 o>{ 8ða¢HY©¤²ùÍ ¿\VrJ Gh2þ–ßýH8TC†URÖ[Sð)a`<óÿé~ó›~þgeåL eîЧ€  bφV{Ñ»s³“†Úôò¡ßÿÀK~ê‡üÚçaÐï?‰œ G&Á‰@p4à#*ƒÏŸÍdj›úâPÏø‹õG|Á°â ÏL¾æÿù®‡^ï Q³«$àØêÅøNç…asŒ$@$à)pÌýÂ#—͆ìCd¬f“ÓÆà»pWxÅËîoV“ÎÝüÔ§ÿìûÞ…ý¢>ÿÙ°ºÉ¬µª3ƒú¬,ç«û$ËÌ€Ïõ÷»ÿü#‰;ïtÒhÙWðZs½1Ï% €ç à7yq4’èÔ¾k°ûÎÏM4Öé¸3ç¾å5?ð÷ŸŒf*¥ÕB!æóãÁ&gžaÁ…À•‰É@`Ä盢ÆuÜ\³ÃÞ!@™ë¹æHI€¼Kàð0%¢Þ•9e k ç§&ÇäG'Æ/^ü¾Ïzñö³‡%(ÝühPñûGUïbËP!saÜÅ1„3n`ñŸÿæ/|–v\GO:;ïn”¹îž_ŽŽH€Tù"BH[d•‰™Þ53î¢X£Þ ó³n°æ (# oûÂçï}ù‹×‹ÅB¾¹£!_<àÇ%ð–ÅþÅPpá¥Ï{õ~‹Øª4ù €ýPæÚoNØ# °šÀÁaU ýÚXw/z7‘p¡Î{èÏ>öšþ®+¹ü.”. ºA?¤­øžôùîFnû¡·óŸþ 5nã½Ä3$`+”¹¶šv†H€úB XÀ2ªê£…±¶ ½ëè 5$Mþÿ†_úÅïûào~=—;(”âŠo2WÝ#­òÜÑ4î=¿üKMÊð €ÍPæÚlBØ èýƒtƒÏBÕ¸+Œ”†6Û×»nòX0@8ýÐÞú‘ß»<ÎDăKî=ÑÈKë=çéßrò% €= PæÚs^Ø+ °’@¡¨Zs=kE]ÛwÇãQøæZÙQ›ÕµøªW¿å3Ÿx<>VŒù¦£ÁWý×ÿ0öí¯µYÙ S”¹¦hxH€ÜA Éb•ÞŸwð®&f/£sóoýÂ?L¾òåoøoïŸúŽï2ËÆó$@6$€)| ¸™@&“S ¹x4ì÷ = W¤'CãÎðg°ü>ß¼“7?ëhÊ_þ[ïGÜᎊ03 ÀÐ Pæ} Ø è/cknM¡Z¢wÿøX¬¿]·MíøP*)bC`ÛtŠ!8eî €x™H€œN •·`…Þ]ð€ÇB=7càáú«|E$`;”¹¶›vˆH€¬%P(õžu•÷ w§.Ùü¬H«¾VyHÀ~(sí7'ì XJ@ì !ªìZïœwQÛô”·d®ˆGÑè¬lé\±2 + PæZI“u‘ € H‹­¾oê]Y‰Ð»ã##±°¾B×§1p@h”û®8HÎ%@™ëܹcÏI€H -[;‡2_£1²;½ë=\Ÿ€‚® ònb‚ìN€2×î3Äþ‘ €…NŒ†0aÆæ †\íòŒçsÕMãŒdøšHÀÞ(sí=?ì ôF@uÌò¬^¾JÑf°ïšwÑ ©ó|>oZsKe†Îíívdi,ÊÜÁòfk$@$0X…‚ºÍ¯úh&vÕÓ5ñÚ¾ÞIÄݽǯÆËødàc¼Ì×$@ö#@™k¿9aH€HÀ:il¦ÈÞë»ÈÒ¾Þ™öVŒ…¿J©XVBµWüŸHÀö(sm?Eì ô@ ™Î–5C®_©¶=èÝ™Äx=rjQŸÏïÔ®³ß$àU”¹^yŽ›HÀ°7„¨»H÷®w=è˜ nbm^¹\ösÏ_oüíp”. @™ë‚IäH€HÀ”€~o‘©G½;ëQÖçÕ<™Mó €}ð'ûÌ{B$@} ]&ކº¡wÅa¼q/¨þ»Ó–¹~¿Án ž û 5×¾sÞ‘ @ïöRÕJ¤²!2nGöÝÙé‰Þ{åÐ|ðo–>Í»M^"@™ë¥ÙæXI€¼G Ÿ/emoz׃CÈ»N åRÅ[{ËÁ3A$@§N»L$@íH§Õhb¦n ¦3†Ùi/ÆX°?s% &HÀþh͵ÿ±‡$@$Ð%T}Ð\S3®éUï¢mœÁ«sù—ËôZ8¦Á Øœe®Í'ˆÝ# žÀúظ}—©¬5¹ w½ì˜«NhjF¤=M “ ô‡úÕµ’ € ln 5mÖÄ Y+cgM.xÜš Š]ãÝÂ×$`W´æÚufØ/ °šô®¨²Ñ)®«!w­vG˜›ñ´c®œ ‰Qža‚HÀžh͵缰W$@$`T2[Q£í¸fö]®Ö“Jeb|Ä‚>9º -žX±Tvô ØyðZs½3×) €çˆH ¶Pº>¿Ï€@& ö] ÷¸„×s%Àm~o¦HÀ(s0Iì" XB@šu»Ó»&&§ Dk®dÁ Ø›e®½ç‡½# ¬oí‹Òêö]ºGzwr|4R`yýQá4¯ß¿ƒPæ:h²ØU è’*ˆ’]ë݉ Ï;æj_±HßÜ.ïC# Ì0p6G$@"Ò¶@34ÖµÞ™0Tåå—ði6x3{™ÇN¶%ÀH ¶vŒH€z"™Û"rB-`nC-2ƒôj=€Ó‚L{:¡9-Ð=×Ó÷Ι+ö”H€º%УޅWî$4ø ú¹Ù¢­Û‰a9 ~ Ìí']ÖM$@Ã#°¹µ‡¹†ö»Ó»S4åÖs,•Jõ'øŠHÀŽè›kÇYaŸH€HÀ*Réú|uv¦‘qE£þ»³³Üÿ¬:!pÉî÷kÕýÉzH ¯(sûŠ—•“ ÀÐä E}Û]ë]g˜›™ÔWååt  ~[ o®—ïŽÝA(s4Yì* t@`o/ “­¯.`®Z¼S½ ã%s Üåîq†ó|I$`+”¹¶šv†H€,&ÐÊ9AóÜ583 yC‘©Il Á‹ê¼¨N •J¡Hß\‹oTVGý Àw®~Pe$@$0|ÉTNß ƒx•—ÌŒ»È ŠLN0”˜¤¥5§…ã×L‘ ؘ@ÝŠ÷“]# èŒÀQ2»#†b8!ކóÕ¹†óSqþty€ý Кkÿ9bI€H 'Bé6îÚ%°Á×`ßœ¤Ì5ðWýjÛ'.ñ% €Кk£É`WH€HÀ*{û)CUª]W{ÎãekûîÜ £‰Õ1 j;DŠu,êrð €=Кky`/H€HÀR…úhbúº¡uÅËvì»ósú²L“ €ƒКë ÉbWI€HÀJUënMõê«–öÝ)z,è¹héJÛC”ó[h@Ã$`3”¹6›v‡H€¬ °¾¹×~5-ôî$ן5p ‡8±Ûp…'H€ìE€N öšö†H€¬" 7¤õû¶ˆ0i£ÑŸÖÜFTÂüÍH dx†ìF€2×n3Âþ €òùãR½èÝ)Ím6ØXƒ¡šá9°:-Øk>Ø °„ÀîÞ‘4ÍÊ ¡wÅ!Ï´N,ÌM¶ÎàÍ«¡ ê´€G©T >“ Ø“e®=ç…½"  ˜9ݶ©w±Í¯p]2Be®ëæ–r:-¸mF9 ½Ó^JË®”h‚Rk†©©1ÂlJ@x,`׸¦Wy’HÀ&h͵ÉD°$@$`%½#ˆÛÆ;²ïr›ßF€8 UŠEÆkJˆ'IÀ.h͵ËL°$@$ÐRéƒ-û®Á¸‹èí»tZh:#~Ÿ”¿B²jš'I€†N€2wèSÀ €ÅòM¶@k®wÍœСIÆXh9-иÏ–Ùy‘H`(s‡M’ @_ ìî%¥¡±!hn»z71ïk']y àçú3GÏ ;™h“HÀ£„Þm» q‚ÞMp›_ó[&à÷•JJNœØü3< wÅ£þŠÞ—޹5F'üÏx 'âe*Zs‡ŠŸ“ @Ÿ @I;æöÝ©IZs›“§‚ÁÝ$ &HÀ¶(sm;5ì tI@[CáŽô.ƒæè^ŠmPº™lÁp‰/I€ìC€N ö™ ö„H€¬!°º¾‡Š vÅÃWïœÐŽ?C|4jMWX ­¹ÃcÏ–I€H` ª^ 5Õ+Û4³ï..LÉ_”E¥ÅQž s¬„BAáxj(—5€E&g4Ÿrò% À°p ڰȳ] è ÝCC½ªÅQ{4[”f¼4Ãm~ øL^Н HM²ó4 ÀPæ:›$ ¾¨ÉZÅk¡½› Ìmonü~õçP ÍÑšÛ1æ"Á ÓÂà™³E ƒÓ­lUX"¥ê•ç‘`41=éˆS Êe.AkÁ‰—H`˜(s‡IŸm“ €åÐDûzwzjÌò.¹²B ;DˆgWŽ‘ƒ"§ Ó‚Ógý' :¹|Q.þ÷)õûüjzWä6ógHPæÖá<á4n&›?!/“ ‰eîÀ³Y è?Nõ.b,0ÌB›Ó"ÚÌÏl$@ƒ'@§…Á3g‹$@$ÐGÙ\¡ÑéVlo&U¯¾y½?ÃÌ47†Ð³i•öû}ÂÅ™hÐmEŠ×H`xhÍ{¶L$@} °½£“J×ñJ*ݦþ ôXèbBTÔÜ!¢ p,Bý'@knÿ³ aq”ªWv¤©}w,•˜hŸ@¡Xj?3s’ Œ­¹C͆H€H``[Äð g¤ÒmaßNÐi¡Ý9ŠÅÂ)xRæ¶KùH`°(sË›­‘ @? ìì‰ê…ØEÚLïÄ.r¾;6JknÇÓ£Š]:-tŒH`è´0ÊlƒH€C —/R5˜v4œ‡(×Ümýõ«ÏNÔ»ÓS ³ÐÙÜi¹\F¿Ÿ?v†Ž¹I`0(sOæ,?ôYkŸ#úsêŠæF{I]¾  AèTïF¡AuÍ%í`#41ˆ]¬B‰E\20ƒÜB€2×8“µš„UŸEJäÐëZýyùA‚l•rí'@5ˆööW¾ØU´‡|[46Ì×$@$Ðòmªµ}wqaª?í»¶Vøæ%3®FÎ'@™«Îal­IUýÉN5®ú¡¢•)×jÓ·¥‹G  þÈ  ‡EZí $@$ЕÕùÞ…÷CM-ôîøC‰hµñïôªÏ‚âó+¥Ò±™£’ÌB$0”¹ýѸÚÜ5Õ¸¸RRµo¥XRß³ÙjK(]ãP.^~˜~!1ÿlƒHÀ½:Ò»”¹½Ü»x3çVɽ0dYè¯Ë\ù1¸R•êOvcÇÕ&JÖ†Wuê¦QïäP(¨[¢µÑa @Fß`õ9T寮(“$@$Ð.ùÔ¾;3Íõgíò”ùB!Ú#$ &HÀŽ<-så[?fFªRýÉi\Ù:z"4®èR®Tµõ¢'ø|‚Ø ‡H„‚¾|{µã_ûDÃ%mØMßùþÖ¨wC š«'Õ^2W"Íæòíb. Áð®Ì•ïM€-U¦þäp5.z%;#z‚—°øærÇ;y†‚Áp8 $/½{÷GÖHÀƶ¶Ûé|{‘z÷ôât;™ÇŒ€ø-Îì*Ï“ …€Ge®|‹tGh\qsˆ" W°|¾ˆ/aÆgU$„i&$D>“ x€øVܰö̃|3 3š˜)$ó \ufΆWHÀ¼¨‡äÛ:&À¹WÞ=ÂÉƒÊæ éLõW3è]ìÛ ‡H$DC¯dÅ x„€ü1ª}½;“àhß¡p@~ˆ¤Ò¹ŽË³ @Ÿ xNæºR㊛D¾Ûâ屡·R ü»ª•7áë¹ïó_«'[hSï2ÌBw³¨GÕ¿wWK‘ XNÀ[¢Ç#WS$¹¬˜Î•+YÜ=ׄàÕ€ç0},ÿ{b…$0T+k»Ø}]ð!Žký£µÞ©ÏÎWÝÈŠzáÛM,C$`)É\)þP~íÖŸ”È ?/ª«çuÛ=Èó²6CA½×V]A]%2®‚¾¬¾'\d}Á¦h:Ô–Le“)µ,Ã>л±(%o•*ÿ#wbciSï2šXó.ßé}…|‰2·’,JÖðŠÌ­Ó|5•©?©W–úóRË‚}T­h*1Õ̺ɪ+Xk]ËsœK6Z«X-o­ÆÕ*Ëd󣣑.+b1 >ð„̕ܨq ˆZÉDŸ|ð|”ÌàØÚV sc±p,p6 °'­}Ù1ùWÞŽÞe41É­‹„|-•…Y·‹:X„H /<$s©qÅ$ß‘ñRŸnÊ+*p¦×% Æ"ñÑèH,Ü—›‘•’ ôF —SiíèÝÓ‹ C)¾ì†À±¡›Ò,C$`9¯ÈܦN¾ûkàÓ]¨s«­—µ êßâê ÚÆW?L}ZŽH².­(Ø€ Çî~Ãcñ$/ž¹¥»å“¬z! ß…| µÔÞÀà‹_w ¶ë^óE'$UJ¦2óÊD'¥™—H ¿ü'›¿÷{áìÁü;ÞR̤òë«Å½£d±œ*”0·~Å_c¡nx¡­®ÁË•}|õcê®÷Þö¶7Ýñ¶7Ó¸Ûjæqüý5x'´Ö»ãc£nøÆ`ˆ<“ϹÃΦ‚Í’@ž¹7d®´5â¥^ÏÑŽ+î =“c¡ÚÌŽðûá}+òjšU÷ý¡‚ŸíÊ¥’YAZì„ x÷ßÚ>ÀY:9>Šu“ã#­]òÉäSðGkñWål6‰…¦ÏýÙ_ØþëÿV<Ø/îBæ–Ò…’߯@ÝüuW|Ìã³>}yéÒ¯üÆò‡?öà¯þÂÂ?ùf1R>“€Ë È?`½kpÞ‹¹H?‡‡€âx“Á+‘2·Ÿ¼Y7 tFÀ+2;{iÒK¥£×sÔ¸â~Ñ3‘‘¸$ì¸Øæá°NE‹«Ðñ?PºBïf²…b±˜ÉæöS;{GKe,œˆCï6~0ì^¹òÉú‰£Ë×áõùq̽ì¾J![Hæ÷÷‹kétI•¹Á€Ïm|ÑæV²®Ú`ÒÏÜøò[ä¿힟ÿ™ }vÅ”óÙ6¶TßÜã‡üc®×»ãîxœ2÷˜Yw)ÝWýî*`) ¾ðŠÌ<(]tõzŽWÜSz&òc—bÑ0–‘A‰Â|ÛËÝ“­pT˜Ð…-‚öMgò¿ù|aéæf._˜šˆ'câ@Øq?þÝo-nï‡|~Dmø|áÙ‘‹÷M¥þ³‘ ÷müÁ”›*¨ÎpðÊõW|ŠšGz,¨Î Õ‡vVS½ëøpî‰'Ÿ÷ûïPéÖèð—ÈjK ª_úôc“Øò/C» ½‹¿q}F¦{$Ëãôé"‹“€u<%sý¥ÒñAÔ¸â.jªqñÉ735Ö×­ }! qÈ›YU½™“þü¹ŸÉîí_E©”à}¨ŠN ½ód $`!/Ê\àÃÆ³årÞ ¥g}0üÄä˜xw¶ð®²¤ª×}ô?òüoÆj8MÚV7ŒWŽU” D®ö(üE_«Ë77·Ž“Wžõ§>8òÒ—¾ì Ÿûä'/ܿɧò_y<dΔîœOüä¿Ú_Ûšò×¾ƒ¥¿;ýµG'Ÿÿ~7w!MÃn_®¨G¥|´”ÜÙΣ9uùZ¥”TJ»K·Rëfàyplý´vô.­¹–̯ú‹“vˆÚJEÆ+´„++! xWæv@ñÅäºcœÇǃ|¸2®‚~bÃfr¤öL<ô‡ï/–ʪ–…Ø…5 ¶[$„ØÅs©¬Zs‘€¡F_E9ÜÌ>uå(¹²…áÀ·!¬ø²¡ÜS4ƒn9›/íª«Ñ!šÊå£J9©”¯}ö3ö;{Eпum¡wg§iÍ=Õujd¤úFª»]ׯ‚$@ð´ÌÅRüX4oj\ÜFQÛ{æÍ=øà¯5Œî²%¥ wjýãn¶\‚ ºp´NÆC7àƒ{˜„,Æø ˜ÝJ¶R ºªÒÅóþî>õῘSÊ™J1 g5Àœ…S¬ŠlJ@è]›vÎÉÝ ê¶ÔI1Ø‚“g“}wOË\Ì%V_EÂÇ‹0ôjÇÝv\q†õ*v¼½_÷¡D"A_Ňed0µCìµCU½°ìÆÕàöH¤âá[{™ƒC˜uÅó»ø-1ëS4[É”*»[¥œóU`ÈÏú(ßõú׋ÅB¡Û0¯ïöÉRBìŠ÷º³§g-­Û£•iHÕ·1~:-xô>à°mIÀë2“×D=D¢ú¥Í“4®:dý˜µÛóé5¿ñ‚í~χÂ3u²´•gš?®(4³XÛßWpªÑH¨~½0—ÊÉh¾¹‡ÅŒ¸¹J)‹Œ•J>P9ûÊ—LŒc="|µ¡qsù"xíy°W­ ä²ýbƒÖ™qÕ!ý'ŽÃFê}tmÔ1v…“ÅÿÔ»ö¼/Ø+Síè]½Ë–iE¼p||àƒC~vKøµ‰ [ðèöì± oUÉäñ>úŸÿ¤Ó Jóžþ}`ðêNZú‚uÖ ËÚcM3ë[Wó×¶·ÐWR—–Õ©™·²‡pHÕe±urìö‹ÏÿžoÿÒÿøa¥4…mìàW(°M‹¨€û¸â`0â£!°þ¬ µ»êgP¾¢ì,\¼ãïúŽ×üÛÝz´øÎƒÍòàЃ.|`ÜE~l ç<«ûóA! ß(Ä7yÙëÉq›ÆÌ–=tJ?‰® ¥«{#wÊØOp-ÊÜã©Et±Ñ‘p2¥*]ùÁ€´^ªJ©#kª ë*¬–µ©-ÖN[ׯËß³ÆEC°RâÙ)WüÖûžùägÖ2§âÁ@©(ûþrN µ¨5>õ ìîQ¥° ¤8åW|÷þÈ;|çÛwÞYËÞÖÿøÃïm|%(J™‚vgàÜ@½ÛAf² ù.$ôîÄø¨mºæôŽÈ7!u ðwrúxØp Êܺ©„|QmºšÒ\¬q!š±{Ýømÿâ[ÞýËû© /ÛÑ€Ár%È­msT|иÂÜR|cwßvïÛßòœ·¿%w=>Øo#á wáÀÉ‹gÔ†½ì…äíºf$Áz÷óà›vk‹ò“¿#Qæºu–9.'àÛœqÖ`·‹•Ë™Œúu\¾s©éšUµö¿Zйv\1œ”NЫã±ýãö·¼ùî÷píÒÕCѼâ[-bàÚC›­É@`$à/”,>[|í+ïyã÷ÜõÐëk9,ø¢G4RÉJ°…ã9—+‡î °ïâÙ‚6X tE`ï ßõi¿iœXÇÜìä‰y˜¡SúONË2? €å(s› ŸX²„uGòš+5.FW*«^§Ñèqä`9dÛ&^ûGz߃/yP‰Žø}GjX°ªÐøüç#a8*(Óã ßùú~âÇFú4 èZaÜE¨2 ƒq7Ÿ/‚¤8Ž@ sqgŸØ³ZSûIqMˆ]¤ÛÔ»¦5òB{FF¢†Œpè盀 _’ÀPPæ6Ç>:Á—r(\–Bª&¨Ô"N·ãŠaã·Ëd*ë,™_xžsé?öœ@x«ˆ€ ªÌ …îÀ¢ñ‹N¿ëO?ôº`þ ‚L›ÏË .²ŽªÆ]È\¨ÞL.¾áPP„'k³*f# à/Á°4²µÞåÞ=—ÅUE+WÒæ1ÅÆÇ¸ÂOb‚†F€2×}|4 ç¹HË•ƒßÛOÎL™R°å…þÚÿñáO|ú Îm—Ã>ÿóG¢¿ý•SïxÇäË_>”þJ㮓!É‹ïC†Ÿ»ð„ÁÇ¡ôzŠ@½Ö:zk½{œ©Þ ˆ93Ñ{…¬H ”¹­àÅ£‡imO¬ãl®±ãŠ!AŠAÊÃôxFF_WÏ‹¯öºNeÙµµM%´O=œP¹|A|FŠ—|¶œ@4ššIŒÄ"Ú†êí‘Éäw÷S›Û‡‡GmGg9Vh Ã#õ·ù8Qï.Ì1š˜¤eAbd„_,ÀÈ*HÀr”¹m!…ÒMLŽ"Lr»Lã ¼½sØfêì=0ëÎÏOŒÇ°(M|ABp†£dbw}óû’àe-°¨w ŒµD ½+ó0a üÜ'¨-•ÎZR'+!è‘}sÛ(”îÎnªXV·¿ÂÃv\ièEX1bù”ŸûG  〢…ŸÜ¡/÷Rû øû.üÅÛ©”yÚ' •.f›Å´_9I€úG€ÖÜŽÙªÞ ‰xHóÓuÆÖ6v;ÆÁ€qwrbäÔÂâ‰HObÁ"~=LfVÖö–Ww±X­Xû~eQ³¬Æu ¶ÄQ?2ƒ}w~vªþ:_õD@ïñü”¹=Ñda°Ž­¹Ý°ôkJw{ç¨,ýtk_äåOϨמqô=¬õZ…P®¨k¡è¡ÛÍ ai8æâ@xù££L2Óµ¨?>Cà™a{·‚˜»øLE:ïZ ÞÙ•Ý\Þ4@þy7³ï6õg0ÖÀ×møzá3n·Üvyf$èZs»ä ¥;73ŽßšQ^ G™ÀIÇi\b©ñòKB,ÖÄÙ…ÏîÙS‰é©¸ü}YÜ`pØÝÜ>¸qkñàØÐS3,ìcmݰ wÅ¡;;Ï-Ðt4¬JÖ@óK„UDY ôJ€ÖÜžBˆ ¼.иK.W\ÛØ_œgLÍžn Ãp‹¦Ü½ƒ4¢ÁOFÜi°ò%3x ÿ™ÑÑ(„#…M³*' ËàŒ«ŽEgßåh}\è]lŸ‰­…úÚ +'8‘eNÈ ”.~ë—ùjÇEÿŇàÆÖ>,ˆì*GÄÄÐ fóìôæß© m±£º$\ñ‘Èöö“.S£ÐÄtfú|Ù¡-ôn”a,Ÿ!Ûf›-[Þ+$舥LG¸šg†Ò… ÔÀe§k\ Kþ—W¶/Þ¶Ð|´<;<ЯØ`G>_„qWn|%ì»Ø:x}sé‰ña^OÙòˆÛ c™¬¾ùF½»8ÏõgzB–¥¡tE]"8±eõ²" n PævK®¾”$Èöî‘<Ý4®Ê"¤eýɺ´¬NÍ|¼?VÝNlò‡H]…hG­«ðø´ºæL—G&Õ.jû¤&'T— >lH¶öùÙqØw{v\ÞNÌ5̽8ðÕk,Ãw0:3ØpûÚ%ù'o¦wûÚº7+ÇKýÀ¡w³™¼B§=¦I`(s-£Ž•ïÐ{û)¹4^T-?rðRŸ¶­Æݾ~cóÁûÏ#Ê•e€X‘ÕðÍ .¹82™üÁütÕßÄ·"´ïî~G8HLá›XÀÏÙ¬rÝÿú÷98qÒ vqu‚ß`%#‹Á ½=›cè\‹à²èenðŠ"Œ?$–pÉ+úÏ}Úæï×p]€Ò½ãvº.ÈÉ´oBì<ˆªb7¯‹­‹/]Ù\yu}¶{˜ç±ïô®}GžuK`CóW¥ ºV¾óÈópké¶–kE@þ´¦×»­ ð @Ÿ PæZ [U-ÎMnlbi¼ütAú´ý5®€¢-lJ‰5vcbu} ç(]X¹»ŸÂ†jÒÑEø§_˜ÆÇFfc¡P ½`•Ã!Íï -ßm¤®}’ç‡ÓE/µ ½KÚ^špŽÕ¾ø#¦õs¿ÉÓ S¡ÐñWýûS4.¸@$][Z‡Y×zF¬±Ÿà&xîôôÅóóÓScpTÐù`«½…Big÷虫«×–6àcÃùíçT ®n×ýq£˜nñ8>¥¥æg1ЀĂ—"h®¬H,J–/™  c)6”æÝÚ(œ&OÍOní!Ð)>fä0¥qÑmh +Ï®Þs×9&œBÆÚùÙ‰™é±££,t-< ·b2•Ã÷kx2$&㣣§ ýlJ@¾ÑÔÅYвʩöÝhDÝ׆~€ØíGµ¬“H ;”¹Ýq;¹”.ÖÂon+ˆá/r;NãŠnf¦jaŽæŸ“'݆9`ÍËÔpw?½wD'å­ˆt©TB¬ð·&A†a—Ú' uV ½Û~mÌÙ61d£Þ5áK ~žõ;6ŽEÃØšU iVAÃui]G¤K¥šGç2 Ï/+DYTŸAgDn;L”­Ë¬\¦Õ}ãæÖx<62BkŸ$í¼"àX˜ŸØÞMîí%ó…¢6†ã›[N¬¬í★C6W)9kŽñFѸ=œ]ƒÞ=wfÖY£³oá)$ÞEåâ3,ϰ·ÙCp=ÊܾO±R×ç[ßÚ‡0­—¡ò3H'TW ¾µÆyàÊÉøb}¿Wúß\ð#ÜÝÞ9€ÓBí8¾ÅJ5äD2„æå~xýŸËZ0Ûž@ήAïZÖ0+ªo§ÉäñÖ˜µ‹üŸH`Ð(sA^gBÓ«k»†0þ¢mù „—v³ãÖzX©ïÙëëwÝqj¼ØFÿ ÀlºÛ;G»{G¥Rõ6”ÒpËÞØÚÃïi‰©ñÉñQîÿ´XÖB ½KÇ\Ë(·¬Hþ)µÌÅ‹$@ý%@™Û_¾²öH8xþììòêvd­³éÊ6Ö¸¢ØhàÖÊΙÓÓº.3élpÃ=µ0…•jØ7x}c?—ž ê ä&y‡GYи»;?3½Î³K{¿º±Ûtdz3Þ4'OöH@:’aaFU±8 €U(s­"yr=xï;{j~ºØˆUäv„W Ÿ—Ë+ÛðÐMLÅåI&\@vj2ŽC ¸»—Ä!5®´HÁ¸»³sˆc$žNŒO'ÆhܵÕÔg³Çqs›vLêݦWyÒBRïf³…h4daͬŠH SŒ›Û)±žòCé"dÁLbµ8N㊑_½¶†5û=Q`a»Pîž™¹ïî3‹ó ¨X©qÕþÖ^¤3ù›·¶¿öøõ¥›[Gô>´ëT¶èW4LáÕ•—2'}÷°²1ÖE$ÐŒ­¹Í¨ôùö©ŠD‚«{âK¿mýq%½¨X*]½¶zÿ½çƒ~G’„\•Àš³ÅùI;{ÉÍ­}èZ©q1ΚÜU¶wqÞ8 óS3Óã4î÷&®P†Ï{µ0G§…F*œáVèZŸB§ xz³Šd:{eiUŽ]oÝy~Q^b¢M”¹m‚²8ÌfçOÏÜZÛÅÒ.Yµb‡‰Îè#>ê5®8kîUî!§Í½‰é©8˜l±»ÄÎî!*5.ÒâëÜyo,oÁ²‹d³3Üzè·Cûzwè]uY¢±°¹ú÷O—‘Ãi‡ÀúöþúÖžÈùÕ'®!!n‰/>vUÊÖý£ÌcÏÜ’·Š»›|°B,»[Û»+Æ«¿©póà׉[«ÛË·¶°Nz—«vWÔþ.¿—Ë· ©wçç땷€6 º"ŽC—x …óGûìÍõd*sõÆæJ!ûù¯\#“”âïNþ•ÙpÜ_¹´Œ^}ê‘˲“ßòâ»a÷}郿áþ;ÆFÝoî¥Ìþm‰pN0}a÷)tEÞˆHÛYãj]U®<»†-.)e† °ˆ±€#É!ÙÖ¶êÉ ÇïûÚ·#±! ÎÍLb/@üvQËÈÿûKàD½ÛßæY»ÁÊ@ ö&9›Jg}r Ý|ä몊ýû¯»`2E÷u6qÂÁÏŸúÒ38*ô)Œá…÷ž}ë·ã«_úÀ©Y׺ìSæÚâfœÁ/‰ðq,ªûCÚ_ã p—¯®>ç¾s£øFh‹Å6‰En¿0PКØ=ÈÖ\Ì ¿ JôòÊŽÄd|nv’߈9fzWþ¼3ÈÎx¡­ŠÞóL XÎÆoï1Â9Šûݬmí¯ÂÍ`cç©+«ûÉê¯RBÍêÍLöe½ûò¥åGTsïŸ@ïþØ_õª?Ç}ö]Ê\Ën—+ŠFBwܶ€PMXàå‹! ÅÇž\zÁs/¢ÿ=`qÇ€'ÃéS [;‡ë{úÝM¥qW”æÌ ûn8š›™P¾àÝbédï¦ä'´tN-H­%ÖÿŸ?;'/1a-©t}>5 |s­­ŸµµIàëO/mlï¯mí]¾¾v˜LÿãמÅß‚üci³6/dƒÞý¡_ûýÄØÈO¿õ5ïüŽW¸IìRæÚè†h¸íüÜêú>úhÝ’OuÎ zoÈûã¢Wu­—Ë8S*–ŸzzùÁûÏÃÁF4Ù•˜Ç‡Ý­­ýÍíCƒÆ•Ée ˷๻HÄ¡wáü /1Ñ ƒƒ”,.?Â[è]™™‰>zV€>ÕÏj%ÍØh»´'Ú§¯¯>uuåxå@Íå@ff¢5Ý£ô/ÿÎ_¼÷ßúoý–Ÿ|ë?mÙ)W)sm7S§&cÑÐêún©T•¹òs }­S™ºßÈôçe&ýÉÞל[×4®À3ÞcOÜxîTº¶»Ù¡ñ±Ž3§g t×ÖwŠ¥²þSF7noâ€Mw~n èqšðNw ƒ®•ï†ó=¶Åâfà™ƒŸ,Ì®ò¼%®/ollï=»´~yiý0•ù⣪™VÞêÇ–!Kój%»‡ªØýøÃ¾çß¼ãî §œŽ2׎3ˆ4PºË+;ˆÂ(ÿ€ÑQ½P°ƒW°½J¥²O>½üÜ.Ø(û4@¯ˆ>†ûZà 'ŸS#C×ݺµ/Hðܽqs ÇôôÄî »½M“|¯0èZýù‹çzk„¥[÷¹ ¶Ð*7¯D–Úk7×ÀëÊÒ6T‚¥V”œ)jOâ×ÓõGžºùÐOÿ§ÿø/ßô¯~QO »0eî°gÀ¤ýh4Œ%>Pº‡ÕŸ#å(JØMãŠA줞¾²rϧMÆÄÓÞ"·‡‡é•õÝÝݪ•«é¯ ðÒÁ} KðÂì½_z¼QôºV_Î×ù“è¯1m)ñv}xHßܰb]ÊõåõÇŸ^ZÛÜ_ÛÜûâc5‡ZêÙ(Z™uï ýƒ¿ú¡(Êw:YéRæZyOX[\u±ÄöN±Æì¯qÅÇçÆæ> PéZ{'8º¶ññ0ܲ»µs ¨îÜêCÞÒRx!ÏÕ««8æ'±ðäĨÈÉç® ˜éÝ®+dÁ4×EoÇ-K-òóÒõåÍkËk[û_}òúÓÏ®bÃEÁD¾9‘@éþÃí§ë½@™k‡»¨Uf¦ÇaÙ½~c³OG»Úq¥RA××÷ aî¹ëL«QñšÇÀR{çÅE¬°Äf(+«;Ùluký#ƒ‘!HÙÚú~$:ãîü$»½ß,RïžšwmtÌÞ)YRƒ”hz½kIÍN¯$•±vãúÍõ«ð¬½¾öô³kâÏ_ÞœN ‹ûÿŽ_øOÿ¿ÿ»CÃ/Pæ:àÎŒFï»û ”.£ÈîÊ7SõLíEíõ\Ó_‡Õ¼ºeARXÔ×ýBÔ]…)ñQ,EÒ6ÚVû ¨ XO/&pll¬oîÁËEr©»µ;a°ÿȵ³3ãgOÏà¯@ff¢kÑH¸ë²,Øý›gG]“ºviyNB×®À¢=HÆqSüì­í?ÿÛ/½ã ÿÄq=G‡)s1kp`¸ãö…5X¹6Äfiºn×Þ3jÿ«—†¨qÑ:z"6Hƒ)N×Q&I J`~nÝZÝ£K£Æùð•¬X,­­ïáÀ$çÎÌ.òŽ2¹‰CŸ_ÄÆ5ÉÄÓ}&äaý‚[!üHŸ›µKõðJ‚½öÚÍGŸZZÝÜ]YW}Øh¬µËôôÖÿò‘OSæö†¥Û €Ïø‘XøúͪƒZ¢¦mkÿ«ç†®qÕN(Ê¥gnÁ*G]"h𹑠´pã¾pnæÿ[+ÛP´úÛ¸îg‡Š‚ uÏŒ]÷ðÝéÜ™™X”VÉF¢ŠüÂ`¦wá Ò¤OYG@ª:¡wqW[W·íjRuí­ë76¾vié™kk¹V°]wÙ¡À ûÌÒª=tiÍíaÚ‡Qtb|侻Πj`:“·³ÆÈ”KÏ`A*ÝaÜ(ÎiAs±ÔòÌ©ÄöÎ\à« n9½öÍç‹7—·qLNž?3;73.³1¡'`fÜ]˜Kè³1m!ñ±}m®T{iÍ¿ö‰gn"ÈükW6h¯ÕϹËÓO_[¡ÌuùÛdxápðÞ»ÎÜZÙÁUtI/lbÇU{Uó¦ÒµÉmcónÀmW °0 ±{sek¿Y½rÕmw×Þ^lº§¦ÎŸõø2µýý#Æà²p¢q׿w…³º‡›°\©ø]·ôì©Ë7—–7½´tUÓµÕ?BõMžo¸¥ùL:nÌ´æ:nʪƯx<*#0ଠ5.zŽßš‘ ÷Buæø_K3Óc8à¶»¼²½ºV]³‚eÆ•à7«×7pœ^œ:µ˜À6Tò’§r1ŸTfz×SX†2X(]Ѯл¸EN nqãÖ&tíµåu¸Ø^¾¶.äJãôPî6:`”¹nes,zÿ=g¯^[Ã;©m5®0”.Þ%ax³rü¬Ë½à¶‹Ÿ,n;7¿º±»|k¾ b¬òW¼¬É õ –²áÀZŸógçæ¹Á„ÎÒfл s\*n¥¾? ½›ÎTcÁö½½€+L¶ˆbûØ¥—áb›}–_šz¨šEI`Ø(s‡=½µ†ûî9‹ý#‹TÔ¤ÿì¯Ó5c²Ÿ×½é v$šõk®W!0Å=yIµéRéö6áÞ*†n??蹛ۇ׮o¤³99þº»®RÝs«ÚòFaËN%°²Í;ËÔðw,Œm†eþÀ%ÿÄ…Þe@1y YŸÀh÷eã,XßVÏ5Þ¸µõÔå×àðäÒªp±Õný_VϰWxɃw8q<”¹Nœ5cŸˆt<»üìj±XÛcJ¯e‘¶Æ=¦Ò5Î_·A.øv„cu}ûÃ%WÿI\©i\Ô$Îcë©¥›[×ol!fÙ™SÓ0î¶ÑˆK²™…Á4*-©w]2T£Å, ±×ªÉöŠêeûø¥_{b©R³óëþ€†Ø;6í§œ¹€•2×÷V;]‹=ï9·!Ü ZÈ_gUµ‡Æ½zâÒM$hÓmgN™Ç@@ˆÝÝýÔêÚΊæ¶Û¨qE¡w± ŽX4táü<"9ÀÊk¨ÐÅ/›*-m2³˜…á~»¸±²uãÖF50µuËp;d“‰a7:'pñÌÌ©YGºRæv>Ûv--$î½ûÌúæþÒÍMÙG›ØqÑ©¼¡tÒ˜*;É ´O 19Šãâm X÷ +â’êÕD}ºÏu¸†_¹º:77ïÄêH¥Ð‚}÷ô"7&lÿFë&§¸÷ô±vvŽ”‹ÝTÕu™KWo]BÀ/x# n,«{r±mÊ•MXmúÆÚÆAm,Ç·zí ÿ'‹ ü«ï½Å5°:ÊÜÂxS³3ãðD|úÊ­T:§·*è4Àì¸À WÝZÙ-JÞwÞã»X üÖpgƒª€?b,#ŒîŠb¯©ÆÕßÿbë`lHqîÌìÙÓnðdh¡w§¼º}Ænwq“ù|i¼÷öð€´}úêò“Ï,?öÔR2¥VEUÛNí†L¹/¼°æÝtÓ´ e®)w\ˆDBÏ}à6Õ+ñÖ–‘þ3~Xv\}O°Šè‹™+/þ†;]òó±;î'"1Çq×í‹Ï<»º¾±·]©ü0,ýý/_`‡a„æ}ê™[çÏÎ\¼° 9,&âBýÔ"DU'OŽº…}÷ÿgï;Û8޵QØ»(ªP…ê’%YÝr—c;v\SüœÄvÞKuœòÞÿ’8í9½ØŽSœòÒ{qœÄå¹7¹Ù*–U©ÆN‘{'XÑþofo÷ @$@‚Ôž¨»¹ÙÙÙÙ¹îÃÜìÞT¾ÎSÁv¿ 0·¶¾õDYí‘Ò¬üår(Y]Í©Ðmmã´òÀO¾ôÁ)Ý s§ôå‹Ôx„©r³Óñz›Á·ª“WÓÕݿ筲sÎÒHW]MŒ×éé)Ï\ì>Ã[y² ¯–sÔBb\´$_X5x¼ô”»È÷ÍÍɯ[_ÅùÂá݉5'lkn—«£¬,lñ°ÑÌÂÂŒ¹s‡&C==oúÜ8m–Ö;‰åPѧ㶑»OKÆÍßùÔ»¦nV®ðІ¹q ¦8'' ë–UÔ#s¦%ÆÈËý¾¾ûÄ– KO·õžl˜L7sðˆ`Õ²yXG í(=…ÅÅŒZ¯‚&(13¬‚¿Y3s-œU´ `Ê9EàÝ °‹^àõàqíKgYù «ÇÝãê8^Іzëê\µµ¢Åæg_3›¶›g IåÃmÌáüÌ•‹3— þ¬óÎ…Xrvvî+AdÎt@¬ÕxW@Ûc€¶'NöpBŒ×à–œ ·ÄðÀÖ5EÿuÓ‰aËØ­Ð0wì¾›r5“°°îÊÍ-]Xp±±Yn÷ø‚Uñ óÅiaLY€fó$@‰É6óqZðto÷ÞÒs·®ÔHwÊ ­7`+ˆáÙ;ÕM]]½Ê`GÀ x.ì·a'þ °»bIa‚g2Àø äõÙRqFn–êøxˆŽ²ò!WOÓ›û¡¤q×.ì›$ŠUmŽOÓªnoiu_iµX¶e;0´ÙÍþòÛ’gåånY—’››·fuÆüÂŒyórW,OΊ”£Öa@Û,þUZ‡id”kký6U—И@ÌÈÍøÙÿLítá- s'pÔ$FS³gå"²[Z~ª««ÏúO%l + n¡6O”˜ìÑ1®@x² ¤»þÌÅsgŸF/hMŒqqZXìüµµ÷œ(;…|\+ ¸ÂxpŒé›HcÀjeóçÎX³jaưE£ÁqUô‚+Õ…pxwl¦ÔºÚ—´;æ:Y×¾ç€Ðc Ä*Œ‰}HzlM§–»¥³uû@ÞÛ“Vƒ Þ±-£hAæ‚ù3·nAÜ7=¦‰!/AIÅ©ÚS-Çʵ­éu cdœa<]Ôuµâèîý«Ï‹c¥ZÃ܉òt"µ“–š¼~í⓵-'kä¼´Iãª{œ„eü÷(߸nñi¸€"‘élËÌüì Î9£«»¯¼º+- «Ö¨> ÖäH÷§º¦³ r–/—ào«VÝÞm/+kØ»¯íø WM]㳯¶ªÕ±¬Ð6ª!b…¿QUŒ¹pës; Sañ”‚ÜœÍëóÎ\ƒ„‡ü-_“­—à·÷lÇRw1Q«•hLŒ>þî ÞuéÖ‰i+Þ­h˜o'®~<ŠÅý¾¤¬ÞÕÛ¯¬T/N›à8®0@E×WãÕ>ȪT†iB{ ¶À ³-ë—®^±àxim}c¶#ýò„ãZŸ,7µtã/3#uí çÍÍO˜LÀªà¤êü ¼.iaÈåªß¿¿~Ï[­GŽ6\˾tØìþ1c[VbgÁ¼xþsõ!Z Ïr·vµ=·£ý¹|í¶ä™¹¹[ÖœwnþÖÍù›6†¯¢¤­£‡ÆBÐ,BFªu4K{ ñ<€”ÜïßúijkŒi˜;FÇMjY™iÎ\T]ÛrªžMŒK–øýÀß@º›Î\2=\­{‘˜À’þ[6,[¿Æ[^ÝP^Ñ(Àn8Œ«ð 2öì+Æ]²höÊ¥óðÞÁDèÂSAA\؆¢…ó ¬SÐmOíÛjÏ[§^£õ̓Hr<£?¹M„.Åß…Kái#ÔÛñÜëܲ¿àåŸwÎŒð·`9 %å§°HBÕÉæë®8OýR »ñïŠnA{ Æ}àGŸ¢„Q¡anÂ\ŠI2„_—:·`fΑ£'=> h©{9Ñæwv?†ù¸¢ß*ŽËÑÚº6÷wÓú%zI]á%½“XÖ]¾¸³3ñ«^§"6ˇÁBjD90qiyCIi=Àî’Esð6–8™­Z+Þº=kãò5«Šòrh™…ºýêßÜ[öôöÖ=Fe\ <†cèM¡ÀÐÅcåÆIíXÍ ®§b̈òR —Ý3ç}×äŸsö¬‹·¥ÉtÞ®ž¾g_Þ÷ÊÎ#=ru[Ì.0¿¬Œ¯±`åú\{ a=Ÿñ³/0;3-a-ƒavõ…8†ÊºÊtò€ÇãÅŠK˜Z®:5¹f`‡Ëœ³Ê¼y(û4¡=œ¬kÅ+U{{ÙBhd8Æ-« 8ÍËËXµ|þâ¢Ùñ1j$­¿¿g{ie½Uèvë¦kV!‚;èrU¼òJÝ®½¥?†gôÒÚ‘Ž`¹Öh.a_ÖÅ…wR5b¾YÁ±R‘ÐVdmÕ Öê²YÓÅ’b¥fšõ•Jˆ)ª¨emÈ”1l¡BJ ”I?9 4K3“ä²Ï^?ã‚s ß}m¶LäÝõÖ‰í/ï¯<Ù|áÙkgÍþµS\RU¢®ŽIÆ4y*í5-7)Èu§ YæŠ#$e=$…H1WX YDl~9N|á+=Ašƒ 0†œ¥ñG± '&ŽШß`Ûçž‘›=Å–ë×ãiJ{€æhÖ6ãíhÖñ¯n4DC­1‚,Ó»jù¼ää‰{V¦`îÌ9go^±eýrnË_y¥üÙçKï{T@ì6‡Aƒ¹èÃY;$”<ÈD€¹°G˜4¢æÛ,7Ì-ÁWi+\sðnãݺ†¶ÊêÆÎ®þ!·‡i˜t¢‚^ifX.“†¹pˆ¸ËX?SÂKÁмÊ%”S%ßZ_꧆¤qT-J6‰²˜Á0ùN{˜;]1..«†¹4¸õfõ0îác';;µEÕd&ã Û€t7­_Z8'Ïjª¦µâí–¶îc'jvѺ; ãªKJrÒüy3Ö­YŒÉjñ¶úï{øÕììŒ-–Ï=§Gž|²lûó%÷="@*Ж\DØíŽã æ¢bh˜ ¾Ø ”$¦þÉòHi¡ˆ¤©®µvà‰`ýB’o¹¬‰ùs…­ø½¶¢hÁ'>Vpñ¶Ô¹s‘·€_Ge•*õ¥´¢NÃ\yÅè¨>&æªp’ÖêKFp&&šË÷ÖU‹ ­—iÚÐæN›KãŽ`!ýª“MÆôsÖ=‰í‹O;^“6ßJãk£ÕM¸vñÁºúvÑòÈ2~ù$Ëô®Z¾‹UO€ÉÍ¥e{ÿzOÉC´µÆåX,ÓÔ>Ã`.øxS—x²-`.Ä®•Jæ’… X2øj#ÔË›OK! %˜ƒ­A43ÓÇ|Å|#±Í(xÿ5s®{çÌmÛPØÚÞS]ÛŒEèJ*j1Ajb“OGsÉü“I;vé$š—Ø „[i(–ú-^7~¢˳),&b38Ó8š›G¹ Óãâ*j˜+³>óÀÀ€¯€aÝDÀ¸ÂÀ¢315~˜±š¡=wàE}GJj«ªšTK¡îÄ&Æ…˜¸ççe­Z9É ªb ¤Þ~ìñÝ¿ú]WIÔr2‚€ns‰cEoc‚¹„ðÒ±&ãÆ/µRW¸l‘ÐRb2¸:ë3˜J^1A€9ÌeyS¢H +5ü%Ôo4˜Ë­0—'ØRWͽé}ónz¿3+ ËÅ,®|ðéMͼt®†¹òCçi˜k~ð$ŸÈ">fñŽææg§?:­1.}F•O¥“õQ{ Àë–W6"“ApÕǧòóH%*|È•„€qwĉúèrE“oÖ5©ÂXœHi ¦vMiL”ð0úèñ¬¥> –Ñj~`N ßõû–-™³jŤ4ÄÄØ®††Wñë=:ÐÜ…ŒÅ×:6Âj¡a.Â¥R†ÃÞÍ%yeH:`.¬•ß+Âráp+¤}ŸzÇŲ‚C*؇ªïRŒ…¢k8ÌE9~Z8 rg¾ûª…Ÿº™ à]ó³7\ƒ –§*¢^ æÑŽB3|0Ê! 9\¡´È³FvX‘ñý¤EAªTEÙ²4UhaÒ’ c«fQuFÖiqÑY så`ÑÇÑo`©-W´|riÑNX|žͽèü5XnÌlISÚë»åõx• &׫L°Œbó¾d^g}ƪ…s¢LÛ-yê©£ü_åö—<>¿Çç‹Ì%\kü1&sâà`|VCFFYÆì(W2N­´P$ ¬z‚ª+E¨P]_}uXDÈZÉ–oK)$%\,ûH§¢§ØS¿ ÎcáÈa.+ñÜ|#"»ìBÁÎ·Ž¿²ëèá£Õ¬Lkš­a® å¥TÞŸ/ÅV·ƒ#?~Ã5`y\.Á—WfšÁÜ-«þôKœöq\ñáÒ0WøAï#ò€ëv÷X^,§ÚÈ/ÒH«ï¢Xb\a.î[7-_´  "ëµö@|<À`÷Teu“‹—Ú 7þ­«d÷¹³s—--\¶˜žk¼58ðÒç¿Ô^RéõûnqÝ>ŸKÿ˜,–Ñ\éÚ3h$øvZá) ¶l’¼¹Yi"‡ë'@LÖ3,ßü‚1Eb s‘½`äA¢Ã$òµf™ÃG2jËC€¬2žÿ­/̹‘rvIÈf«­o}ö•ý»÷—â«Up$¬’Q:Ù» fc†„âIY¦KÔd¯·Amʯp´LeJý$'È’¤Ú´©¢HNY^ª•&ÉgÆpªÚFªjʃ#û0\ƒ–'›¨é|ÙËésqïûág¦Ù; Œ¡ê an(¯hÞˆ¨¨j,ç°® _ÉoªH«/¢¸`\a报s7¬],h½×˜D`q’ÃGO ° 3Ô]3È$…q•Òv7c‘…³œ"ó °BóÁù«SÏ¿2D\þæxð‹ hz$4†-TÒ󅘨K`ŽÿñRE<ãCÍ´a(¸j‹„ŠD«p¬Õ­:ÃòÍïS„Œ–|¢åfmK±AZHŠSÑSìU‘)ÆÚŒS’#&•L8˜ 'äÝþÍ™W_)²õ í/.¿ÿ‰7hšš4;Ñ¢¹ófçÎMë9  g͘3K.ï(¿ôÏ–ƒ¬¬itõ™XtI•ñÆü8V.h£¢P ´¨ÏQ@1™Ä0΃åa ¥,š@IDAT†àK Óæ^éÆïßúï§ÆÅµÕ0wøÇMsF÷¾wŠU‹°®õ++VßBqĸd«ß?» ç¼­gèIi£_9-Tžl*>z²Çe>ô°¶„q³³Ò–#š»dnÈTÝþÆÆwÿèäÃOzü>\7ÿÒæ øE{ sa’SÏØ2É×0—Ü!}…£1˜ {•»”ÜÑa.éÄF?6D´Í–sù¶Åw|[å0p¹­¤âÔŽÝGŸí0N'æfg¤-ç' ø¡µ´ÈX díª"aϬ™¹³òƒ_ê&Š&eßÛ7PYKëœTžltõö×·tÖ7wœjj¯U+ý ³ä}HÃ\øC݆â?ö®ó¿÷¹›&åÚMb£æN¢ó§|ÓåU eªò»…êg1èp)¶¦¼I…6?¬ê –uór2ÏÚ¼SÓ[ïµ&×»‡T«È®0FaܬÌÔ¢³–-)œ‘—ÒNËUuÿýGð#F·¶ha.€c3¢€Ó0Wº[@Oœ)ð*P¿„¤8Æ æ2NÆ«ƒM˜‹K“TSøå[gßð>i‘qDp÷¹Wö¿ðÆáFKpW}£ Ô"¿öPÅ€1Š#$¸Y¾dvVF:Pì’…ôêÅ gg¦ÓÜÇÕ+íM‹CskWSkGEMcCsgIå)D»]ýæâÚª‘ðû¯è—œ5-®vtÐ07:ié  d…§´ëª/Y¨odЃqEëˆæâM§Xn,ÈH}ª=0YhnéÂ4£ÆæN 0.êM×ÓÂm‡å+ÝåÕn¥(¸}&Ì1]Žæ¢Èëõâ6Fh ªÌ•p ˜K:E¨’aš°V @Ð¢Ñ &óöJ8ˆ¶V¶ê #´AU•`|u·ˆ`•|^Ek[J¡ °'BJpÔ•Tˆð«øÅ $¦ yjaĤ’CznÌÚò®¿zÑw¿©²u!ª¶G*xbgy…Ô—ªè–åû–ËÏÉÌHŸS‹çZÁÌÌÅ*4‹æÏRªNCÀ·¢¦¡üdÃ[ÅGËõ’ÙAÎ$„àËa4¥“𒳿ßù‰-kOÓõæ5ÌåQ¯wãó@Y¥ÖUßP9‘Wô­¯]½píªi¨ßÅѵ'ß»‡ŽT54ØÅݲiÙ™gÏ…ƒŒóöºJnÿnÓãOS~‚ßç¦ä‚¹^М•+9œ¡;90ðL … ©´Y‰hkM ,I 6¥GœŠ=˜aù†-U xJ>Ñr³¶¥Ø‚Àž)1Ìe)–ò!`.­×ægÃò°0Ø7eÅÂ%¿ýEúòåÒLóXq²ñ¶;ÿŽsñ½ºŒà,eŠ]8 qÙ¢ù³ôºŠ¦¿ÂS•5M‡ŽWî;Rµë`yWOŸ”cÄ-êæeòå0šº0wóê…øÖÇ‘KÞ7Ó¼DÃÜi~'¬{è"¬ÛÕm|} ÝIÁ¸¢¿ æåc†ä-Â?a>Ô Mo4ìW¶u¸Þÿž œN ímÝGU~õk®ÊjàZµ6‚¶Ê¥dܘkÄtG„¹aüÌbè&`™5iPÌU’ ½ï—m%1\èh.40@bBêa>ÞtÀ·Ô´T#@L¨`fX¾ ILž’O´Ü¬m)¶ °'BJŒ s!ËÎ¥†Ƶæ¢áeY‹Ï0/-oþí_Ÿa™—&Lð*¯nDо ?²ú8.>Qµcïñw9Ù`¼¾[Œ–és?ú®óo»å=ÈÀ—¿¦xe s§øL0óÖ­ªnv{¼“ˆqá¿Ï”dz·¬ÈË ø˜`nÓæœFðù|ŽPË)ÔßwÏ©ÿý™¯×ƒeÂ&æ¶#˜ËPo¼0×R@=qQ­âK4HŠÚmlXN‰/ᬵÙ¹†…l©‘´+CÁ\êˆÝ¶ð×wGºT[oññry·¿ºÿ…GjxÛ4ƒ¹wßú¾\;RrT|œšpZ5ÌM¸K2Õ êï:p¤º­½GtD}qàÔÌ'3©°A_ŒAEcÒ±Ôx¤³€VŒÇK6DsÏ9kÅüÂ|!¯÷Ú‰éo_où]_ïÙ¹ÓßïÌõxÜÍõˆÈ®ˆæú©ˆ‚»ÆŸÂársœFæŠH$V8˜ËJ¨Xá@:‘N¦ §‚«¶ÑiKM I ¬u­ ÃòãsÑ>j©e°µ8L£S²^Y ÂN‘´Àå¢GáÜ\®UKè$× t¶w9SÓQ[oñðÀÎ}ÇŸ|yÿv^ãúÍ1%É©•´0#'ýáŸ|ö4yûèãAÃÜQ]¤Æâ, ZRÞ€WC©Ê&²5©8b\´+¦Ùž¹¦(\¤²MÚ“åþºêªï} ºÊ×ï!˜ÛçñxæÚ°‰ ”´€<]ÞàâÔH` · Ya.úÀ Œ¡¡+ÆRft–±”±n.d Š1¸À""T4UX*Ö0W¢:ávj_n&%98’å–SEß„$¦AFÉðQT ×éa vQÝN<Ìê?,¦ëwzzaUR¶þÑÎ×)>»¦ÖÎ??øâƒÏ¼)Çš1È)s/ݺò×߸9ëôNT° s­ÞÐt,=Ð×?t°¸ª•ú&²5©‰À¸¢? æÍ»Ý‘V´ÊîL²úAÓ1÷Òv¿óóŠKë„æÄæbÕ°¿ÞqË–5§éªa# €_#Èë"íè<°pÞÌË/Y_8'o1.,îí|á•CH¥ˆÎz-­=tîãÔ_~JHJâ ÂEtJàˆÓ ‚F§`~äç–G±¡+ ˯ÑÐb“ i|HfüÌ›ÈæªoøˆÏå}¡ß2X!Ù‡E’½¾þžÞÒƒ~¯™¿þžÎš—ͽçîÏ|îÃWN '¼}ëÊ]÷~[cÜKÃÜnÑÌXz 9 omXÎiô¬-Ü" 2 ŠšÛœ3TT¯½!ÚrS“]$ ïÚ[²ë­j@oÚ“箃»îý¥‰p ÀÒl1Ë€ mœ@ÅF|0´H|¸£ZŸf§„VëwÎø VžöµuúÖw¥B;½\Äç¡Ð½×ëëíê-Þå÷¸e©>ÆË¾þÒ¿þàÓ¹Y =ù{ïß¾÷_:7Ü Ð07œg4?Ƙ;'ïòK6,]L/œ›uyë>W¶h«¬jzæùý½}ƒÒ }Ô˜Pô×T4Üÿ[jRgiÏ\`X|[¶Ô’ 5kŠX¹² 'IFðÑoyÌ\6µÏGíúXº76¥c«d_ÏCO÷¼þ˜HQð{ݸ´V"bºíötöì{ÅÛÝTEŸÆÜV/¹ÿç·®_9?æšÇ¯péü™/ýá¶\£W É—æŽä][ ¬»nÍ¢mç­Æk{&ãŠî´wºžzö­ºú¶ØöNkÓÕCÍõ ÿü‹™`uÔZÃî*ò9òf}¬Rr¸ÀpNÈŠ‰À Ù}«ýV:öGƒgCÆ}GVÐôï!uÁîHB4×Oa]>OW[çÎg°}§´Æ@Ì)ÈûÍíŸ\4/±–¹øï›.}ò×_Ò«†^«gæ†pŠfÅÕùÙ—n;sõ*ùãØò5×8®ê6^yýȾƒåŠ© í˜yÀ‡÷—…Hô 4=ýß@?Åléo8ˆ?:#žHÌ5JY$Ú]H8eUbùÌYÙ#Ññ‹#µ<Ö²P´zf N›)#74r©»¬¦ó©gìÉ)ÈX ¼ÊÐõÙ éÞňj{éOGËØ Óµ"÷R~úµ$Höf›Ýû½[¾ô±wéD…H® †¹‘xIËÄØÉÉÎÕ+¼ý¢uy9Jõ„a\ÕâñÒS˜—f]ÜWiB{`lðõ¹›«<Ý­~÷@†Öçj¨×€¶V(F© r¢¾¥¦!Bc¦-Rã%ž®ÄZùx›Øú#ãΉ²Å´¢ãE£vg2s)¦KI ÐÒEò‚°¿åÙûÝíÍeØéÛ&¥}ÿK7Nzÿ¯»dÃë÷~뢭k'Ý’©b€†¹SåJMC;ss2.½hÝú3õN<Æmlî|ôÉ=M-]ÓпºKî__×PÉ[þî6oO+.&Å+úªKúJsš-Çlæž&ØZ΀k?u•º( 4EYQ‹ XÃÀìt];Þ°'§a™ âbš»œªë÷õ÷7?ö·Þ’ClØiØÜù[V_¸yùdu—@ºÝv›ÃÛ×ã:ò¦Ä­Ä¢„t)«À®ÿ• A*´ÖŸ#ô±ø—IÄÒ£ àk­ß{AÕ}í]Cµ§h)1ÊX Ô‚¼´ðºôgóú± 9²šþKÇžW‚ªëÓØzàºË·ÆVáÚ.ÑAܼY‘~a`d~ÒRâ$énX»xÞÜüCÅÕ]½qÍUPq\ôL544äÙþâþë–l8sÉ„ôX72å=ÐwðîÇþèHMs`Ý~¯×Ž×SñʦÀ">¯'eõ¼®ý¯ P‹®ªR ŽÐ­ì¸ '0¦JRx/áQ\UÖ‹öˆÊªÍhëžòAþ :·èÚg,-OZQèíë£÷ëð‚b*c²_,©KE-ÞÛ_S5ï}OsºîX¾¸p„ÒXåå¤ù#Wë,…ñûSÃÜñûPkˆ±fÍ̹ìâõGKjKËëÝn/´Ç/W”DQènt°¸ª¶®åâmë³2ÓbÜ7­nzy ÷Í—;ÿþGz:.Эƒâm@·x†ìõ{¼)3`y°þÚÒH; ° PË`XmCÀ# ZE’ Šæb Ô"íÄÔ–æ5øÖò£dìóËß8Jۦ¨$$|wC}êúeäòÏ'¤(ðz ôÝ…°.†œ˜—†ø.¾Ï|];_ò»=ó?p‹jK1ôòb¨-¤ª‹ÏZyççnš;+/d©fFå s£r—ž8¬]µpÉÂÙoî/kj6—A°Þέèßì²@&î!¶q\–3å[Úz{z϶óÖ-(¡B³´l6׎çÚõ]{z*žÛE×ëEL×ÎX:7yáªújÿÐÅQ)^kT¤+øF%O2ß,L çG] ûÈ„5…бù2N3IQRVÞe)pà‰ "iÁÃI øâCþ€ƒ)Á×µã9 Ýþô8ÖÕ'Ø"ˆ{ƒžj;¿‡O‹]Z“öÀØ<‘‘zñ…g^xÞêädú=6aWà`$0¼øÊ¡7÷EŠ['u­©éž—··|ãK¾®ŸkÀ×Óëëîõºú|}½x¬ìësù{{lÎÔ¤‚yƒõ•Ü?¹ ìJ@Ëã\±$axÅr*HÚ£ž…oHŽé`ýLE£ÀhÞZ=fˆ.;&Kv\SJtßî7éY”•ËèV¼ ÓÎè”ÿÅÉ ’ãïxù™êŸßåíë,/év£õÀ».Þðêß¾©1n´~Y^GsGö.|Ì/Ìç•[Žœ¨))«Ö†lcÇ—â[ÙÑãµMž·&FÖäûB[è~i{Ë·þpÓÑïÆ¬ Ÿ\z7ç-Ð$x¤.dm|Œ¬¯2â¸bú˜°ŸA/C[¯sцµô‘i⌬"ºyDÐÒd,HتZµÒ±Ð@:‚ºÓð-u“óŒþ:sr©éxKF—ÌÊõcì!pK L0Ì%°KK/pþn÷ÎWËëj—ûGÎŒÌrœ6e˜–ÌŸùÍO_·í¬5ÃJ4c¼ÐÑÜñzPן š»iÝÒK/Z?#/s"1®èZk{÷ÓÏ¿U^i€ì è¯n"‘=Ðýâö¦o|™Rºéá°Í?àõuàÏh.º®^_ S—¬q·7ŽÞB²ÍÁZfI® I›â2ÉFodt ©6M^3 ‰¸*ÂŽ(D¥_¸ÊìC•Ö¥®9|Gf6X#ˆk¼͈æ“6”@º|!ëï+9^ú•Ïy{uL7¤_Ǭ8Áç:ÅŸ¾á’G~ñq£ñY²æFá,-:¹À+$®¸tÓº5E)"‡êx ¾¡o+fŒ1kKÌ”±èe‘ÀðÚÎc/¾zÄä:A·>¹èzq{a\žÝNK8aÍïñû{eCŸ·Ç•ºa›=5ÝÓÝiBXO¶5€£Û5zÏ„¸«2ì¸ÀÃäL†e°›L+%4 TãÍÒð¨FƸéÉVgézt¦$͘Å?­ €+B¶¼”áZúc°Kßqø:£<]Zk¬ÿè±·þ·FºÑù:¼tùɆð…Ñ•l\µàŸü¿ÏôúÅfÑ9.i s£ñ––Mœ¹ºèÊË6-˜g,”m…¬øÕ´Õįc¸Bª®iyô©Ýx?°©ZS§“:q¿*1.C3 ]Œ Býnw?¥êöög_p%ãwÓä3¼ÏW: P‘ÎÔe>ãG+OJU/ †+•õîcbÑ7ffÑ1¥HÕaEÄÀüa?9 ycÓœ\8“óf!FÀYšj&²rñgÐ4)cC¹ô ã“8¾þ#GŽ|à½ck]ײzàåÝG¬§c£s³Ó¿|óUþïç7­Y:6 ºV„°|FXC‹iL¶23R±ÂEç¯ÍÌHS¶„»yÇ ãŠ†z\Onß{à°¾[(ÇŸ.Dç Ûë¿òeÀZÁ‰~/1„`Ac ]¯¯s ý‚«ˆºa(JZ0P,ÇE‰»ì:*2|d!…@¨Ø-®0lÿoñX‚?‹ùqRkia\$]ÔÉÞ” ©+—Ãgv@+!W±çÄ\ v1 9šK‘2„¸Á~·o¨¼æØ é-/Ÿì>Míö]};÷ׇmYñį¿øñ÷]6µ}1E¬ÿäq„6sÊy`Á¼™W]¾yýÚE°œpF¨-¶W5´ï`å£Oîvõâõ­z;-<ÐñÜöºÛ8—d„t)YÁÀ»„r9¬Kî  ¶Ah9N+ŠDÌ–h…ƒ)NëÀ+Ðh`{U ,º‘èkDÝD *$•c6exÅ̳ÎR¾Iš5+ny)1»x9ÇwÍ)hõ2䥌¿ Àc”7 ÝÃo¿®ù©íJ§&"ôÀÎ}ÇkêÛ#¶Š½mËŠ§~û¥[?r­žjfuËÄÐzÝ܉ñ³n%îXºhÒŠV/=5Wôø¦êdskÛ®‹·Y8ǘ÷®ê&ÊÕ߯½ßæ´9À«Ë|M §â°v;¡ÄaóÙýÎܼœK®PÖ93²XRF^©¦*¡"³àRiҵȰ¡£ªD@¦ øG—Uïhè Ö-ÛpŽ¥0±È Ö’ýÒÌqö…®¯TãÈú3ss¯¦bKÎÍÆ¥-A[ >ø™%ã»Æü3NcI Œ€!NÁ]ÞÄ *ÿäm¿³Í¾ÆÔlëCxÜõ»Ç†.Á[;õéë®|ÛæÐÅšèhnü}¬[˜( š»eãòkÞ±¥pŽ‘Ã Â®²}‰øQžÁ4y+æ î‹j³* ¤ ‘nWßãϼ¹kï UEÓÀUß»³íŸ÷ÑaZ¾‰gžQÈ›H]0¨CømyÿþQkÇñÚ*:D"”JH‰p®'™Ò$À†4f“!d†í…"RJˆ{Xq Ã:žK¢8‹‰’(Ú‹hÀÇ<&MX¾+FÕgm}Ta!ÿéY%SD4Wb\ M~[ Mú£S¾ûÒÀÅÈÄ: ´ƒÅP†¼@º:¦kõíÈô_z)ÚPî'ßñóþšÆ¸#;6Þ¥æÆÛÃZÿD{`F^Öå—l¼àÜ3’“–¶Í¯xÜ ¾<âÔzû±Þj”’@Zé0=ùïlëèQòš˜º¨¼óŽÖ{Oð€ŽC‡€nÁ H`@9Ænþuï·v9eÆl j­ìiÖaßÊ ÄAðXn&%9òhÏ’p4‡u{z„÷ÏÈýŒ¹sFV8B)B¹3o T°<)6GÓň`—.ÁYh$­±Àé HZhD}••}ò‹µøóÈÞÐ¥ð@Skç_þïÕÈ]µÿÍ?«³"wYÜ$uÒBÜ\«Oª–-ž»p~ÁÞýeå•XÔÉüŠÆE_qçhmë~ðÑ7€°×­^<©½×ËåwÜÑ~ïý¤‚S衾a]$0àHtXCöûnp¾RÕ™3ƒ–D[Ð`ŒUA‹?e¬,VŒø H;BkŶBèQ¤CëÐÜz€®Xþ§ovd¿f<­páà©*ž…†X vù·ÿ ãLw9¦‹w—ãe,X­¬ùÎONÕ¯øö×­LMyà‹wý­3²ÍËÿ̯¼ò"¥äÂI;Õ0wÒ\¯Ž·ÃpÁ9«—/)Ü»¿´­Ã…æâŠqUw^ßu¢ººùâmë²³ÒSSÅå·ßÞú÷òÈzE&.’n €(a³{í„tEª.ý|t4ö3¯¿1¨ö¤¬çïiª‘¨â 錫1ìôu¼…c³€]ð¿ )ç£èXœ™2êñ놯ÛÄœ¼¢¨`X(Í'åÏ¡$‘· `®xÖ€½Gd,0ØLÌO#as|™ÀH£Amkþã}8¬ÔH×tMõË{ž:\z*€æä ½êýW_ ç™…qÏä°‡=›3t«ÚñòÀœÙy×^yöÙ[V$%ÉË>EéäÆ_øÆ‰z¨‡ó@Z T VR×ÐŽ°nIyDߌ²}}œ|”}÷öæ{ Q!€޹ ø"É©º ̆Œ ¶¥-Y6¼iK×R5⸲J° i…hAš÷ ÝZ‚iݸ‡‡QUXl-ÖtÌ=`~ÊMÕŠ§³l|ÎÿÑÃC¹Ðš’?‹Æ%2e€q1.1òrd—N91Wd,pi`Æýnãê ‚‘nÉ·ï§zoõÀs;ü)‚t…m[V¼ð·¯ì½o××ê½D u47®‚¶!îX½rá²%…oî+-+7_GNØ@nò ŸÎÕ·ÿ0Ú¬ZÉÀ ûÅWWŸlºdÛú”ýA3\—ȇÒïÞÞò·(À…@.‡î|tDæxFÊ,3B$0ä]óî]K[dONõ …,5˜àÒ CÙðÁ"e‚a36ÊÆ’£È‡\² Pät>ã«¢w|¥3?ûñÌCà•¿ù³±–°¬ÌXà._|3!ŽK0×(⌅ P®õûMé‡Íˆéž¬[ó‹»“†¥I(±Ó¨¨iüÞo¹×Eóòï¼õÆ«—Œ,¦K'Ëá¿P'Ë"Ý®ö@|<€† Ï]sÖa˜K+BU³Ië= 6d+šX#$P®¨núÛ}/UÕ4› h*!=P‚8î_îÇÅÅ%À@SÍh%ž÷ Á±]ú! %÷ ûlÉ‹͸Ü\GÌÚ?{rJÖªMà 3A€XƲ0Ñ^¥ëZkL‹Ê#Ë„,5«,F§ô6Qv¿õ›6ÐÀ“"i[×Þú¹p†ù<žÖ“]½Í”†EÐD+éò[ЈCÁ]‘¨À 47©>Œb¿­ë¹×è‹R¼ôŒ{óm¿ág¹Yéßú¯ëžúýW4ÆMäÑ¢ƒL‰|u´m±÷Þ—våe›Ë+ëw¿U*^ë n-hŒ`Üiƒk½3…R048äyê¹·–-žséERuXWº7¡Ž'¾ Œ{LBàÓË( K甀@ƒ K`âÖËE v¸¸”ªk³å½çßH8Ì–¹b}ÏÑݶ¡AQŽŠ4ÈpPpUЊ¸<IÁ$£ Íñ)´¼‡´jddI] ¹+ètü.¢§W0dŽ‚Ü%ùÃÍ9’’êwõ×6ù6g~fjnZÞüÜì¼ô€¥ÄhÑ\ü“¿Ò”:õÆlAûÙl½{Š}è– ÷üá4éöö |ç猀qo¸ú½‚V‰Lh˜›ÈWGÛ/,_:¯hÁìƒÅ•ÅÇjT°•nbSÐw Wê°•W56·v]~ñÆysóS“î®ÊîþiÓŸî#‰×=øä4#NÀëB$0H´‰cŸ××Þçq)) ßtsÖ_رó†¶&ìDsŒ˜‡÷ØÁÂÙ„Ax½æPT˜ZH’ä­ƒS‰Å„ÅЖŀ˜4’HJ†u˜û;A=vä.½ïoÎÑÒœg,ë¯mHö9ü­½­½mõx‰^NzJš-kFZfJF2'ì†]J,àë.Ðý®Óéã~ú›¿/3íìÂÍË?ó»–-šè6}– ÐI za´YñöòeÏÞ²òºkÏ'r˜¬  C¬0"¤ä¬|z¨-7Áïîéè‰]¯ï>†ø®,ÑÇÉô0îþÞÒÈÓÌq¹p™Ä‚¸"¸¦Ã|¶~·ÿT¯ûÈ€­ºsÈï¶gÏ/ðt6‘h˜-sÕÆÔÂÅf¡™©€ÊlƪB€p«u³œ*Y„­RNf|.&܈IlÐüx‡7"Ú_΂<`ÜôåËë4Jæ^—ÏëµüÂê¶Îþ¡Æþöã'‹[êêššû{û=˜1)¶Q –Å⤻ç‚+\åå£Z2ýFÀ¸HÃýÍw>ú«ï~BcÜ)tÝu4w ],mjì=?#ëªË·”UÖï?XÙÃË" H*ZRH5à^®¸„kM“¬‡c\%w ¸ª¢ºñ²·mœ_¨ÃºÊ+“@ãîûà-®=‡Ñ¶ëã 8*jGF#g %0 ø|noOròPïÄÓì¾l;-ßQ°f™·£ÁÛÛ•œ7Û‘i¼OèSûü ¯l8éAêB0ŒU"¡ ˆÃ(óZFËZpèºàbèJ(ZfTÐÕ¢áÂîHLFe¢Èu||•B™ÊÃ+¨qÜe÷ÿ5Œ‹Š)ÙYh§Ûïͳ' ÷-AÞžü˜î²y;ðp =ÅÙçÎp:2ÔØaýò²˜¢Ì÷´v¼þÃú[V°Û¢`j“À¸ÿ*Ž›—•þ™]qýUçOíî–ÖëhîiyÙu§=°bé<„u·l\j…ªê.CŒ+šíꦰîÖ ¼ yfŸh3v°áŠ«?3~ìK!ÚŸ·qȃ¸VEï`Ûg¨·ÂÙ§À¸öôäìÙù¶~»µÎÓ|Òï6ÒpI©ÜœY¹W~ÀÄ{„^Å™=(Â+˜“… %\R@GÚ>–cL”Œ¥áÄ«‰+€q—ßQWô/õ*xíƒKEkÃt×Þ;„Þ.·ÑëiNs¶ù¼}òÉlÁ-rˆþ\q°¬lEæ]¸BL ]ÂÀ$%‘§I”â2I²ãÛF:B±ø¥í#øFÚVÈZ“Ê po<ìO?{]TÞÈ.4²Áü¾>škÑF·oü×çk¶y[2“;’ ;¼wî–΃ÿöáÎ#j`* ã~ü¶ßÖÔ|!_¹mýö?õÿ}è½îÔ½¶´hÎÔµ^[®=44u¼²ãrbǵ~Ú0™_¿yýRd §¦$Ç£/ZgBb\«ŒÇîdzàþÌÔ¡ž>+_Ѐ<9gŠÄ¸`nøòfo^‹Åqí))6ì““ýÉ)8u¤¤9‘ÖÍxÕÔÔsló#ö z}CCX‰Ã?èö bïò!™²ßíëóx<~·Ïï¶aïáá÷[¹ý>¼åÊí§‚Úçñ2x—Ð7MbßøGú£3ù‡3±`8ÆŒ7ÂËp]%}à°”ÙmVfÜ;˜6:IµED[„Âé±*´ˆ+6lÞÇLú¡ ùDË-\CR¢ïgGâÈÙ+(åbÂtJ¤©1ò- 5C†^M«F­ìË/\ö³»Gs&*Y÷œk¦ðæŽI«X$4Vl°g¤9ÝÞ”!ošá²c„V+ãíŒ?ü¸ðš+#Ñ6ežßqà®ß>Þ)?òèó›—ßrÃeôj¸SñrÚìüö·¿ÈÑgÚ§»ð’ÞukáÛ¾­½Û‹uyðuoÁ§2€?B>®ph`E㢨¾±£¬¼~ö¬¼œlýràøŽ½0îÍDÆvÄ·9ýÞ!÷pSVòìÎd€˶òÆKIÈíźc€š ¯Ïcó÷:ü}éɃX/ÏçK†BåÚZžx.íŒeÙ+Ml=††³ÊÃÏîúÖÿ>¤fcžÙW?õîÿþð5sgÑ ëz›êÐSЦúÔöÇË[6,[·zÑ®½'Ž—Ö©6¡ª¼0ø°È˜| S‘@D&Æ »zú|ì-tX×ôRÌ©èÖeód¦ öôR‹2œ3¼u ÄÌ’Ì€&‰äo^â@À  ŒY^å*øÖÅý„b}^Äe‡™¹NLM“`7ûÌ­ÀÁõÿüµ"ê:ôGç‘oîVÏ­1¶`xäŠF”ʎάµZ²¹ÌQUM¼@$v"wÅŸ~m}Ï`fO»×3äLÏrdäŽjvJ^Ž’A‹Ý~ß zÉX6TO®ðu„ù—þÞA¬áÐg·õø½ŽŒT§Ç(o†Í~ü–/Øþ`›N1]L8ûÅ=O?¸ýMá5¼îá#×_ôáë/‹uDõ€Žæ&ê•Ñv%€œNÇâ¢ÙóçÍt¹ú)‡w¹Yã»cŽã(DX·©£T‡u¥‡c{ ¸"vÛ‘™Ò16vk5 ÉnŸáHrJ©ÀDÑ¥ë3gÑÒ ”þEÙ( ;,¬‹¬‚!ÿÐÅG“RŠM³ ëÌ­Ýûw"Ó 8¤(cïÁ+'|6d' žKo àð­µÅ ×(¸F]æcüà§Sd4—ŒáØ#í$£dR·`?qˆÂD³€dŠ®N2B^ž2GÔf9*76“âZ’m‘ä“RÈBKñe¹q É·0MÒè ×  -ºMinQœ²+¨N…UÆ^JbB3ËA ˜)ª3;qdÂ>ã½×¬¾çiEE¬€vž¦Oåaow›ß=€G ~ÏôÙ“FŠòv”W4ïÚ«4` Å%-ðQƒ* Iˆï3D‚¢ADÒ_T¶ßíõzÛ|.¿¯7#¹î‰çzOÕÌÇe!N-fSkç­wüåå7O³?û¡+îøÂM[7¬˜Z½ÐÖŽê sGu‘8Ý=€†UËç#£ ¾¡}xC¬0®ðòàûȉ“n·gîœINZ¬Joã÷€Â¸Ñ¢[Ñ40nŽÝÉ0Å=‚ΊwnqÐjd€l" †éâ”Ó þÚ÷ Ãé9 IY9¹[.è-?áio%€ °‹@Ü€¹xb<<9`.!]…zÞ˜ ¬&¼ ÁŸôƒä`θb&7<ßêÐH`.tZÕ-0Íre-Äh‹Sš•ˆS1‰4öÌÅN•r‘q.%É(% Ú•Uìi+‹–þâ‡ó?q³JTp7×õï}ÁSUìì³yý.¯© Íi/ûǃA<$×:¶t0H@W 8,©Â·bŒQþaò‚â.X‹Úöš{ùÛ²æNÕ×€ýêïOcÂ’qÏß´ìÇ_ýð»Þ¾U/¤4N¦Ó)=j›NýÑ}ш·½°sÏñŠê¦8a\Ã~þ\®[]tÑgêEÆ|M‡\®G.½ª§¦alRíŽÌÀؘ‚/P¸òšõ³ÎX€wùÚ“œ´ONÆSf;VÌHJq¤$3'ÅAk/à/Å–°ƒ-9-)#Çž–%pP]uͯØw!=7­´àBB¯—YÀœ4^r³Ô°À‚ŸhÁÁžÿœAÐÞ!ðrsÑT~F^Ø †ÌMa?¡.»]È£,@Â&±2+ „&’=Iž U¹Ÿ¬É¸wH­¤Aè'*2šô inB’ÁÕŸ-Qg&A|óV¦TšÊ!*'¶)J|£Àð—Áž¥ÚBƒ)ÆíðS¼¤2l†Â¤Âc¹—_¸ü{ßI•¸ Ïõîx¶÷gl>=-Õ‘šîHKaOÏá }¦#=Óž–iËÈÀÞž‘ëÌÈJØm/+{xÛU¦ ,Ô »3)pÜ ßÐ&ÃKÆ‘€,WÄžÿø á[tRòq”E蜡Á™›õþ};RF{)±¡%a•5M·ÿò¬Œ{æŠùŸ¿ùÚõg,IÓ´!ñò€†¹ñò¬Ö;½=Pߨþ«‡ðþ^tSÝ:¬]–·â‰­( à[*XeŒ;kNMM¹ê²ÍËOÕÀ‰¥‹MÆ}ï¿÷<:¶†ñðW`\yÇ7ÕÎÙ7ŸŸ”žNè–.í—%)¸˜ˆ–LË,`q±äTˆÐ)¼ÜŠÒ°âᛌ\Õý£ñ_õ4wø\n¯‡Ö ³þÅæŠ5Å¢‚¹è¸„z 4=dRÄ7·p´µ²UjZ«(E`†åæT%k%_X.TYÛR •rH &s°;ÌÍ>gÝâoÜ–k™jÖ»û宇îñ·6Ú““°Œ—= ©ìSÓh˜ ÈËx×™‘¼kKÇ_†=À7£…8r³®)&yt„Å3É¢ ¢÷žâ뇺#~¡H–‚`2àÊR‰‰ !jEs®¸èê¿ý‰N¦Èöȳ»~yïó¹Ù韾é²Ë·mš"Vk3Çë sÇëA]ÿtöÀácÕ»÷–"¡6È Xvغ BXÜB Ú"cÜyè^dЬXVxÅ¥›uX7ÈÏáN]½GOÔœ¸ûGî—_'32?ÃáH•΄¤ ªVþ’+/^å@2Y€hyàb#¼‹ø.!]†¹„t±ž®À»bm]ð õÒÚºé6,¯›ŠH²){¨¥éÔ½iùÇ¿¼ˆæZ`.Ep9šk^#¬ëá•tCFsa0‚³´'hJæEs‡Ã\ñr®¢çTYD%¥ÒBY§ÄH¤ŸX¼™ɘ[8ÚZÙª5­U”"0ÃòÍ‹)BÖJ¾°\¨²¶¥¤AZö‘NYr,07ueÑ¢/|v¶e­Ùþ’£íýÍ}xVD ”n'íi)6€ÝTü¥8Ó æ–áHOwÝRp7ÐÖž‘é'f¶H7#?“Бû/º¼§´J9ÇJ ¡ï¸”¿H°Coà `/ ÊOÀfàª"ãÁq¸*ˆKîýíÒË.³¶›˜4VT¸ë7ï>Xþ?Ÿx§¸‰yâg•†¹ñó­Ö|Zx ^{÷—(®R½µ SÜ!ŒÉ( à+iâ›2Ƈ˜ê¶bðRS“ß¾mÝšUE–ªš ðÀЧ¦®ùÈñÚ¶öÿkÏÚžx$ 8â“ »#…‘Ž ‰Ú^v~ѬÅ6àÚä$GR’ èZú pÌÅžRhð $3 ¬›îÞˆIÁªMÔBwñ¡Úßý¦í•×­) fðî˜`.t›°•ò¨1k4§æÂÿ|Æ €¹ÈHÀ §ñhûáI ˜g¶8àº[››þòëþ/Údz¼ÅG§)& ¸éi¶4øSp© ñã7ÝIÁ]Êaà4† [’rœ™9î>õ±O6<û*ÛbG)7tÁ¯’p׊n¡E¢X3?A|1ŸÊ­§ÎŒ´ÿ8¼;ÁSví?q÷ŸxÏegýÛ•çefÐϽVÐSÐN«Ë­;{$9E f­Yµï’@ƒà׾Ŋ1.j`‘‡ÒòS§ê[.˜ÈkÑ¡I[M]kñÑê—_/>YÛÒ×?d;Ya»w,S\ÒMŒk8v8ØEò튳" ×@ÐF±Çn"ˆo@.2£y=àcÏ€VCŽ7cašbo#ÈãL3wöÕ׿^xþ@Ks_u˜‚†C¨J4Ïz£Yh”Rþ­$L5Qd ¨)¾@fĤ".¥2"° aA°ˆb2\Q0Eá4qÄfJ°fɦVÌMXÆç’ÎÄd0#à›"FÇ„~“MÝ‘*M ,ÁµÄ©Ä^aÐRòÿ¼Ë/\õ³»–ÝöÅÌ•Æ<3o_oëÃ÷×}íóƒUÂX ‹&¯Î)—§˜‚6ä¶cþ$0«/cÉ1)hš—†uøe"X{nÈïÄ’ÌÍGKÚ‘V±êl¥wF ‚ÄE“C4ÀÇ&dl!“ªT˜Î¥$Au½CžÞ®¶%—'h@AÜÛñðÕÿ¼þ¬õ+ôB ₞n{Í=Ý®¸îo=pª¡ýùWÊ„]ÆÜšqë´¥ýÈ1.*ñ²¬TÙºž»zóúeM§)‰ä„c%555-=®¸@ÜšýýþïÝæâ×=DãÜñ‘«à”€FTe`hQØhÖÒ¼åçÙŠ#§ÏNä*Ø’ÊX@dI Æž²uÄ¥RÖ¥œ]{Š‘ÃÀ© É~𯉠"¬‹ÍÔLвòÖ~è`å½ÿ¨{ä Ds)cAd/p4ë‰ùg´0ƒ—ð‰°PLAƒåΈÅ;œFÍ%øëA_QÕÅj3Áá†""ý†ƒX *ÚZÙª‡û¢4™„°Á<—ñ sÀ²ØRò©r³¶¥Ø -$Å©è)ö\àhøA5~ò̼‚ë®Zø7e-7Эh§íÅçîþ¾ÏÕM\NQàP.–B@ä.P@*)¸Ka]¦0ÚÓ1 9 2aùß”¶K »Hca]åìfyü¥?üìSèc&iáú€ð×’5‚«Š@ˆo*é0òœñ™’^¤"¸,i|±ýÇÁ7² nòÀ ¯,«n@wN­l­·ÓÖæž¶—^w<^8t´j×›%*a7¶F‹›–»ú²-³ F[R¼ú9yz‡ÜžÚS­G× 9¬·eã–üçŸû‹Ö:€qUE†5ÆY m_uÞ¼s²éíª„qvñèÙŽô\ÎÐE-Ö[H¨W`Yƾ”’‹t^‘ºÀ+0€K³ÓPÄ)¼i"[×–’N‹ŽÉ­¿±ñèïWýø“ým»CÆ2 1€¹h 7„=Á8 sÙä úÃKé">çr*H[±¨è“+¼öª¤À5ºªûñûs–‚Í‘D?‡°g\Kˆ–P/c_A;Á¡Ñœ°‹Ì]ž—–Ô˜°K³ÓêËj^¼õ.9FBa$68½ ‰bqÁ9Êl~’6¾ºXŒ”a|ÖŠfl\sÓ³ODÂlHTXVT8û´üzL˜‹(†h˜›(WBÛ1<Œ{èHÕ®½%ò®@3nÜϱÅqƒ”àaÝ-–Ÿ>SÓ€nkêZÊ+i0<çg_šž¥»õ«Ïú£OÉPM'ˆalĈ“á´3ɹõK_(ŽK8 ÒUa]¹ö‚ÖeÔ‹ü]ëšËñ" 4 pJÀ" ÎÔ B½Ø#¾,7·ËU»ãµâ?ý¥iÏ~‘¶m4Ý1þÎÐMÃ\ëµ&ÿðUçHV†¹ßÎzÏUE¼);0| =ƒMMÕ?þiç#OÛÔÒž"µˆà2®5‘®ÍÅÛB†'ì88dÂ.2wÓŒ„ÝÖÚ–çoû¹aØÈÓÝŸìéÃÂ5ÄÁÂW‰ÏD‘ó@ÆS˜•#¿óá¿/ºà‚°èíÉ󀆹“ç{Ýòt÷VØ}m瑲ÊFtTÜDc…q…¶¼œŒ«.;káü‚iìÎÞÞã¥uÈ»E–‚òåp˜ëk>åÿáw£õƒÀ¸ˆ½ÐŽ.\’»hU>…ré¡3Çq9'ú ëRÈVweX—ÖÓåESX7…Ò8¦kì) Ë‹Ž‰°®=“Ò€€Ó±ôXP§ÚËËN<úDÉãO¶—V"¸ëAÎ219èIØa?E)Q°z#Ì'|®anÐ…WœüÔ8…÷Ä‘43wÎuWϾìâÙÛ¶]œz{{î æÎŸ¤ôqz2`(9ÁÀ¸´´‚¾>xë%*pˆ—øbDÑl]¨ètdbá^Š×Ã"t”Ò@ëŽÑj ÷}ôÎá– çÀ̪”ðT¢XŒ) Bœ1A\*²\!i–ð¥Å„®ÜUK?ôÚ R™>j$4ÌM ‹¡M™–@Âî+oiní½‹-Æ…Nö6¬]té¶ Ólj’êêÛ**š:ÑSãÁª¼5‡¹Þ_Ýe«ª~ŽpoŸªŠÀ7ât8½þÜÂŒìÊ¥…Àk¬a] ô:t9”‹=Ð-ÿ1Á`a]¤($Ë·H„^„Áž’Ž?'0./²ò¥¯uû÷yøÑ£=ÚÛØ?˜ W0V&Ä' 8Ê3C‡s×È|h ©Çª_hPz”|0_1âš"d­ä+ËYÂ"# öDHÃÝæÝνì’üM›‚’dU[ó3ÏV~óO{Wg&ØÒňÀ-™,a_Žã‚#ýnºòè‰Çžì<^m4—R‹ h'¢¼8Åf¸Fô=ÌE‰q-$&äjÒ&å4Ò%™A´B“Ì·JTQµ! $ ˆo~HL‘ñÀÜŒ‹ ßyeþÙ[愊ÝÊ–m‡U~ï®·ƒcÍ{QãŠüó(^ks$#Tk#, à;bÂ.-¹ØË‘Ý vör1_@IDAT9a—–C”÷§‹›vSÓ‘l\–× Þb‡ÉÈ®8µ„o¡PÊ0ÁN ¸'1^8¤èÛ®ÿÇ=‘˜¡e´&ÒæN¤·u[§µ°{ ¸rß¡ŠÁALš7\!¡JÓX©JnV¾äÑÑÄyî¢×¼ckNv†…7eÈÞ¾ÁºúÖã%uœœ`˜­º)}eøCñá8g‡ïŽÛ¢êg?ÆU I’ %&bb€µ`qÖ‚E9ÒDà` =wf¤‹3#¬K!;1/ {ÊÖa]¼—וi»ÖÅËÒŒE.qˆàlÝädze`.­¶;JXW™ÝÕÐPúòË5;÷œø×CÔ)îáXØÏ4zDØdn.õƒ!ù®<¨;˜K-*³,´• uj!©šâ[t3,ßüœ˜"„0%Ÿh¹YÛRlɹ—^XpÎÙs/¹(]¾›WV >" ·ôG?n{ø)Ø„J»†WUXBvíödÞ3MI Ô2“Ñm9ÐËQ^Îj ÁE€—–h wó »œÃ°ï­†ÚWö[þH…<•¾!Y®ñ" U˜ŸÀ²R\£5‡íãwf§ú =Ð071®ƒ¶â´ñ–ÛóÖ‰âã5è±ÄmÔyy/fz¬WdD¤¥¦œ½eÅg¯!]SdCrBUucÍ©6Øku Nœ•|ÃUŠßùhu…(^ê ˜‘lÅK¡ô#ÏLß)ÎæÍ3Ð5—#°ËH—ð.!¾PC „ÄÓ[$è5i¼ƒÀµ”À&²rA¨½e†$~‘…uA¯Läåà.€op¶®i«…ªÙ¿¿vÏÞš»jžylXŠŽ!a. P 'ËÄ æ’%ÊH6IœYHb˜2JXoa$l~„̪„=%ßÄ¡¤Ç”I)ÈÍݼ¾àüs ¶n™¹iãpåÃ9ž¾¾ªßÿ±ög´˜H}¼ÇjÉY-ìRL•xRÚ¸vÓÒ*ÝÇÛ)›Šè( ƒW„cˆ0\ÙŸ®QhʉWŠn3n¶¯¿åC—ÝñˆŒÐBÚå s'ÊÓºí‹ZÚº_y½‹žyÃÀ½d|W)œ;{ÆåoÛ˜àSÓ¾-)¯«¬jBr‚¼×F sýÕ¾_üÐâÝQH$*ˆ˜ä¡:òD` yfjËÊLZ¿6¸„£amº%PK&(¬KØ7 ¬Ë³Ód¶.ÖI%à+º´ÜÇnEL—¦¦¡H.¤KyºN¼"‹²uÓ­‹0˜V†¡j÷ïo9QR»kwóâî’ mær— sá ‚k„䌽dŒ\¦_J˜%ŽÕŸ´å$œ¥²qÅ&fT07ïœ ¹ëÖæ­>cæY›sW,vk* CÕ<ð?ú©·i¸d‹h7$صø ¢,¬"»¯AÂnC¯cÿQDsEŸÄeÞ?ttF4—Á.ƯJÁ‘¥t&òXÐHÑW ß”¼ìÿ. ûº £–>hL¬4ÌXëÖ´,@sû‹û;»ÍÄ ãªFÎÙ¼òÂsÖ$ÚÔ47æ–5´WU75µt©9yê¦j¹½R?TÔVò›¯à/^8«éί»EºP.â¸ãò­Üð“•f4¢øÖ mùâŒÙ3Ó(^KHÈ Ø÷fX—@mø°.Ö[pÒªºôŠ`éRª°.f§ÆåÕv)šKH¡_,¯›$úxe@r:Öd€­ð …^#Þ]®–ÒÒSo¾ÕzôXçÉšÖ=ÐÔÇ"Œh.(f²Z”Ni˜›{Ά¼õk3ÌGȸ69p™Û=×~èPñn,?)|MÞ!ØM‡ °+\'Ô†»äj®e&ìr|w¤„]ú5|æ`}òćJ„oÁ3?ŒTD…AW [âóû÷2ÆéÏ<²`óæÈ-Ñ’Úñö€†¹ñö°Ö¯=0Šð¯w#a7æï‘EÛÈaxÇ¥×­^<ŠRÜÙÕ[B¯,nòˆÇs-œÄ‚×,Ÿ|îÙWoþl„¶§).1·p´UH@@ÔÙº6©@·¤†´À•`ÐEnQcXXR,ÂPë®å·HÈ·¦™aÝ€EŒEÇèý@½œ­‹õtÖMI“‹0a]Ç›”d.²kv2êÔþ=õõ=§êOíÜ=ÔÑÙ¶ç 9б˜p26³€6ð:¢"ÕˆIEìjU%œ«r%¬˜ À´Fsg]¹-9'7oíê¼3V¦æE¯µjô@SÓ¡¯~«ýÅ×DëÔœì]ص†uÉcR—òýZ@] !±è„†'ìr¶®‘°KY¹à #í›ö”ÈK ^Ÿí…+e#Qñ =\<ñ‡jÑæ'[bnÓ6Ûª÷½û]¿üyvhQí8{@ÃÜ8;X«×ˆÀ˜¶ÿPÅÞ僃CW÷Œ ª*®iå+˜TQ`\! …KŠæ\ûŽ­¹9“35ÍíöVÕ4•–Õ#KÁÉN*ûÍ’¢ØzÕkÜ— çä-[ZˆL õzúû/º¼§´Êêpt2eËš›Â`…£­3³“VPÈ_òˆ2¬ \ DÃ8{ZF—^LËŠajâµ{Ü|²äÇQ_: ߇ hv¬ ß =¶´™¹Ÿ9éÊæè3í¸x@Ãܸ¸U+Õƒº{úv½yâбêuÚ³–*Œ¦ºQ­ÞÈ¿øüµ[7­œÈd!WÕ4WŸlV&ææÏÈZ¾d.·Y™S¯N¾öÚóïÿ˜Õ!!iÜ‚1Û‡oÄT®ˆiQáŒÂÔÙˆÂ\ tFÖ%0B˜U€Mpe‚ÖÁ¥µueX—æ¢A?¯Æ`¬ªË0ט£–Ja]LGãwa]ÌHü¥Eä[$ø•iýCéi)!]fGYù «nlzÓÈ m?v|¨ËXšÐ𞃢¡H\ ÷*1Ef®\œ¹¤Hð—±vµP8këfÁœµiSLú2²’ªû,ùÁOÜ­¢QìÉBüS†ªÜfŠ’À®‚é†6èT‘]ŠÔš »l¼ä‚Èg`\k ]Œ(Žìâètw¥781rG•š9Aan¸ü„ €‹&ˆc·}úÀî½ÞB8kþ„{@ÃÜ w¹nP{`D´´v½´ãðI9;MÈÆ㊄»¼Ü¬w]uvÑüY#Z1Þ¾þÁj ÛñÞ2Ò6˜ t»tñœ…ó 2Ñ­2î©ßÜðì«ê4$0ø—*RøÄdE|1ßìì¢4žvF!4[²ÓåÈ® ë ,‹½@±üX™×d ˜k ]»–°.¿E ëHx—aÉ»´Ä¿J1î°°.®ÌÖ%Ô‹Ùi”­‹-Þ`W´ù¾·±ÑÕ@oiƦœŸ’•=þŒ¡3¶ûÖƒ|á+}eÕÂTìAöóˆ »†B‚]Žf]…tI9Ð-XtL_¹Â.ñ éRê#`»G{ÒZ—­ûÌò'X–£´–_Ërý£`X~‚ðˆˆ €+€ïU¿üñ†÷¾wlö V}KÇÞâòùsòÏZ»lÌJtEíå s•+4¡=@Àò±O?ÿVgwlŠ!Æ…6q+Z½bÁåoŠGC}cGums}C»qÿ“C#‡¹™© çωìÎÊJZ6“Ñ2´á 2R$#ëÒš hÐvA“’aa]$00¢µ†uie8D¶ƒë¦fÔf¤ëtâUkIAnѧ#x ¿©ißW¿Ñòìr!¦haÏÃEŒµ'‚Œ•iÐ|%ˆìZvU(°œÃ€š”œ Á®¾àêelIØ­OšQ¶3Ò)˜Ã;Ž%N¬_1lS$ù B•à Ίw_uýï~;¼¡Q9¸¼ðæ‚9ùï¾të¨ÂZ@{ B诿¥Å´&Ô æ|âÃW-9¹cç1v­ÍG›« &N Œ UÇËê*O6·uÕ¶s×Z5™¦ðmmËÉÚ–ÞÞ±)AB‚ù3—.ž;#73 GÿþÏ‘Åp¿NP2¢ïâ\$NK2IV Ðsrˆ{9h^ºßæ¡ÚÈj´'ùwýÔ†`ÞNÉŒv˜~Šƒ´õÛA+Ñ"Â’‚D‚ À.3é§Œ/‰æ ú|vÌ*b‚&Ö|^{’×çKq˜×æõÚ½^‡—Aû½^Ÿ×có¸m^Šl>/-7–”,RP™œÔ½èwoïñßý¡ì'¿1€«Ì?Å•’¤YWQ"Œ\bŠ! ›_ ”ÎÊ.#kiP1[¼f6 ÌNs#îï·c˜Ú"…CÅlj¹^»¨×çG4× ]@½vc6'WŽzðŒW³ a°Éð-Tp².wõ‰ÞPߨˆ÷ØÑ‡!`§x¿K7‚“·ŽV<øÜž 6¬ø¯›®ˆ@\‹hDáÍÂYZT{`â=€ö*sÙÞÆÛø1.Ô¨9'…sò¯¸d–,sך:€n±@˜¡AÜÕíPÊta`6ÀÇÊZ@·€õ æÍŒÊ†{ÎüB¢_a ´%~5Q,[à*1ã£m³}­±fô&Yâñ—öþëÙ]7]qÞ»t7B—i±(= an”ÓâÚ“á€Ý—v:tôdl1.º"ðîæõKßqñ樦¦!|[^Õx²¦«(@ùÖO…kùî§ðôð¤d&,Y4g~aþ<:òä3 _€%TIˆ ` x!™t\8#iN&e,‹0hcBTæžDC1È Š°.Tâ”8v¢ t±6A?Ærc@·ü~`‘›KóÒhv/CÆ4eëò¢c¼ö½˜–#àK/¦"zYš#5/KCX·äÁ‡ßõãö¦¶¤Ô”™‰Ÿ¸‡¢¢ï i¡„i*„Q81:¥Ð%môHê©:ÌMˆ_äŒrœ©AEü“€ýÁKblÅC‚ë²hš»”–a¬OpŸ_œA+sù=É´ò’Sh1 ~?œƒr6Rí©ió'cŸêHÍt"…ƒ¼‘I ³!æŸç_6ÐÓ›žœ”‡†©‡²§†¸ö0°kxƒÕŠ!'<&Ú¡cÑA¨ »¨¥ÌR—“!¼èˆ\•°›Dh /¸½þý¥òG¦h8ú=>¬½~<0ÂÎreËäšžJ,Zp1tðIÿÌ7Gž…ÖÓ;ð÷'^}ý@éWœ«nô—K׈£ÿÆB™ÕЈ@¯ºì¬ ÎYó⫇N”סuƒ!ZJƒøÆóÅ au×’µö®>O†»2ߘC‚])BD u™T”“æ$&2PŒ80=><6¦ìä! Í QˆÑÃe ë‚™ðÅŒtQ¸9išÃzè—hWd6.'’ð@šSh$3ø¼ D>ƒ²89ÁGù Ÿ¥Ì¡¬Ð>‹·åà¡Ý_ý^å)˜ï±ù‡³œ˜¡F-¡Ë–¡gÝR—™æNÃFðÉ¡,ÏuhÇ™¢‚‰¸Ø€¡¢.7%ÉSbà;Zóøé¸ßŒ KÁ¤º,È¥¤k“&z;J¿¡ðþ…s)A„ÿÏg÷¨‚SH ìMÂ!?BØë`¸ß†po¨íùïüÀÑ7€KÐçõxìΙ Sïi$¡¾Qð“-…ÉÂj«6qy ° 7‚B‡RŠZÐ¥à),^eu8ƾ@íªJ_¡áðï€]œéÒà µ:¸Þ¸vP‘nw¸(o†7V ça3úÏŸ#Q¨˜Ê9t ;¹~gCC8˜‹Ü_ücûÁÒšO¿ïÒþà¿•BMhÄÉ¡?óqjL«ÕÐr²3®»ö¼ÚS­;vÅ4/¡jüzp'zú…}‹«®¸tó¢P9 }ýC•ÕHÀáÛh;2#/sñ¢Ùó gb†Y´u‡ËW?ñÌp&8ÀFØ£;Æ_Ü¢q‡æ›4`†:“õ¥‹Û6”(fV/¶B*$)a/ÒÀ‰ºÔŠÈÖõ»}ŒknE¶.ãHBZ„wY/76€ &žöØ# F4‘yIÙ ¸@›µv_2hìEÚ®²ÈÍĵ!‘Wfè:<”³kó¦‚ÓÛÔràÿj|v'Yi³a…TaJ—Ó6ÛkøGpx–Ñ*!]ê Õ ¸"  @/d;ANè´yÁ€jŠì`8ƒ(ÓPr HÞK.âRRìó!šMxÀâÔ]br]öê ÃÁͤFaý ‰Ú# Æž#tK(B(W@ ¥2+¿‰ªHLàÝ”Ld2Ù–­½¬¬í‘'ÀÀ«5м¦¥ÅãŸáD®÷Æpà:ÔÚ„Ë­öÔe va·p•ðUc‡Ú œ!Õ>a¿+ÐQ]œ°›·jqgI5©dž™aKrq¦/ a¯ôP,zÀEDÒ\!¸4b£±_~Æ™õ€Ü??òÊ’Ú¯|ìÚ»>w“µHÓÚñ󀆹ñó­Ö¬=àå¸þme•õÏ¿z¨££Gµ!ï3Ì·)yc2 u ñZ©°ÙN5´ýùÏoY¿ì—nNK5Aí©6„o[Û¨- E³ÔΟ—¿r鼌X [Ñ21‡{%„€kVw[yB’ÊðÛ°¡ {v³ÓœðQò"ÐEáZ ;ºŸa]`, -9N%Á»@®A°'Œ8B õÉ"ðhG§Ô6#¬ËgfX—áÅ;ѶÜ%Z„u ø摌Ö…Ï{{+^Úsìp'Dw(”K”Í64äîs$eM®P g¶€N ¥?Ô Fº$ uü*-ônÀÀ\õ'ÛGÆNC×|È=ÕQʼn(3Ò¨*yÈ•ºì%4Eˆ ý!ÂC`ÏäÉø ÿš$ÏÂÿô°LúOD Ü Eð§ôE+° ž¡æˆ \4¤¶çÿ盂ÆÌ./dȇϛmw¤çÈ#h‚6PC2ŽÿDÜCŽÉÐÏê<דuÑ ˜0”بAÞ,`Wð„<Œ!9ÁBÿ2Gu ?þMES½vgÚß~g4-@öé6g|_xY";OæS!ýÇ寇BÙÏ%`ô÷˜ßK|âå·~ûàK=}·}ìÚ_ýf¥SÚà s'Àɺ íØ{`ÅÒyø+>^ý–bèrÑ]Gmt˧ÍÊÄýQ0‰o¥—nP†Ì¾ÃÿŸ½÷€³ì(ÎÅo¾“Ãæ]I(g HPFIH"ˆ$0² &Øæý ¶ÁÏØï÷“¶ñ³±ýLxŒ± ¶IH(¯²„®´+iµ9‡ÉynüUÕ]§Ï 3÷ÎÜ™í£Ñ9ÕÕÕÕÕuÎÞóݺÕÝ6íÂ^íím;wõdsÍUÉd2¾fÕ’SO^Ó5û®í{ÒìJàvOñA†žòfta<Àhº/o~¨ Ì)á‚ÈC^Ü]M&P!/q`Ö%lÇàƒ *Å,Ik¶€YðÄ- ë2À5}ƒÜ º|G!I´ côO]sX—Îøãl:êx‘¤%4¬»ç‘uÏþèžì>¹Þ3üðAIq XhAn d±BÊ™À®`,Sfiô)#UÖGo‘A¿e#ø1T0ð¥ßÖ²¡ZjDßð?9ZÁô'}(/XÖ…JˆÇÐ_€âòϲ'GìRä<͈NŸûI ¹ „†AwÎdž!€>ö=ýôðÃO!ÓÐä\,Q®j¤M‘.„È"ú—ÀW:ÑA£–”ÒDî#gbx r,ñ¥†ë@K»’°«òç§ÚàA¤áà_$†N§ÈwG{s/*q4ÁåÑâD`1VƒèÎäRÛž~áYÆ^<í’K‘€{ËÏÖÞrÛÃp"¸×_~ž­÷Wïù󀇹óçkß“÷@Ã=ðŠ3O8í¤cžxæ¥G½ Y¤ŸÞÂ|•‹Ð–‰Ò´2ÝíK—têÅŸÓÔÑX<áeË׬ZºfUwu‘ÙÖôm,]±ˆ~Û`ĉ·/ …¾•0 ¨nm0$#)ÀngsosÈA3‘€Tá4S†/Ü]Ö¢¤ØmiX7š€q”Û@7HQ/Å?‹'¤€;Cs°Èx °ã&8¬ ˆd“¤s>Ia]ŠçBCa`oÏs?{¸Ãvreó \t<Íu`N\ N !p&®C0 ;•ªð'®…Q$ÇÂ8…[Gr—@kì+â’ ã"¸KVº Þ8bÝÖRf/WS‡°ãå z©õè0IE#Y¦¡\P,y‰¬ KýI®W%¦ ¼LöAb‹Eä[&¥=zó_sïæDai.Ü8Öi‹F:M€†E|rš‘a“\Œì.ÛéØ5‚¢COólñ3Lž fä €1zˆ£_Šoã@ |äáåh~l†«ø±®ÒSk$Žo.faîd,ß(¸z0À‹”bhdô³ÿ÷û·ÞûtwgËÿü ¸®o<=ßð0w¾=îûóh¬0;í¢ Î:ÿ7N}ð±‚k]毇Íæ6×û޽è€Ý+.9÷<€ÝG7<õìVÕL€À!Ú2qÅ ¬»«}ù’NìL  ž©·'Ÿ´ ±Û–æL,«±çÞ'׉$lÆÅVba°]0jgv~mI51¼Cj'ýºNcBo\W9¬ËŒÃº@‹´gÿÌNZä ÀãAXFÛ€&Z ë"{–ij„ûr/¤FÙº´ÀBrǺ­[z);2Á€„¼"÷OÎRÔÄ\ª&@B`l4íÈb$Õ®6Bºä^nh‘t]“7ˆBêô™MJ£$¤+P?Ô9W¾SÀ:L°B‘c祓Ò×’' ÝRô“PÁXüŠQ2) !^–$ax˜‘.eî"þäßý,8á» ´•ˆ£F£í±XŠÓIL­ Þú|€!à⺬DÌß,°Ë_è¶aܨ¶Ï–mé€](Æ!òùEXô°Y;X¦!§ŽH¢9(0 ‘ŽP0>u~Lt1ò‘¾ó}ùMG“Þ‡Íæ6×û޽îlÞ{í›Î?ÿ•§ýê¾§·í<@¯~{„hËLÄã+—wàÖ»¶B¶/;vd˜‹í‚­uU¯²+b€æ-Ï` Ò‚>1hÂÜz6`·«9N/sžHF8S.QB4èDÞøu„u¡©·åa]X ¬RÖôÃf@Ú š9¬Kí±ºŽÁ}/=¹sxO¿2iâ±+A³ÂPÖØd¦‹ aÊ&ÈÄ'•#ÈF ŒÎtDáÀ+Eºiɤ4x‰(Š]ó¤4Ƴð8M;#GxAATž”Fwc²”H K,%‚æ º¥ /Ñô‡¶=÷ÝlÚÎÂÁ ]âOT€+£¦êbq8ŸÇŒ43)MZˆ âvêD~rœöÒ€%©y+ÚÈ3LàÕhã‹<ÊRÇÒìâª<äø‘¶¦8bþ >ðý±­˜ÆÏrпº1%ݘ29}›"‘‹Î;³D̽—<Ì=\ž÷ýzÌ•V,ï|ÿ».ÃÚ÷?üÀ.º!,`¡:Ú[n—-éWÀ V¾ööa¾ËåŸÝÕQÓ–¼•µÌ‚‹åŸÐ7Ï(4Ù·½hmØíHÑ PN(Š -c.À%,—„®kë20(FM¶.pŸ ëÄa‚PXÚ iŽpX—¶X ð`ºʼnÑÉÍÚrˆDí•«-)›¦*‘Â@É1.A¦ÅPÑ-GäÌIš»* –±iF³"Ì'Þ&ý tPMð7(ž”>KÞò¯IÏÕIiðÏ?CKþò‚"øò¤4 &Vœ”+²¬–´„b)îˆÑPÄ–âðèϼ<ñuRZfdtÃ7h=ºb˜^_†%´q´v´0~ ¾øÉ|`ÁiÁ.~ÉUhJÏ÷ˆ3õåjç± #¬ž°ÛrÌÊÑ=ô½GºËFã¼Ä˜ñ YL=ˆ™Dá& ÀeaÂÈt[;UùÃ{`xÀÃÜp¼ Þsàìß{Ó»/ß´eÏíw?Õ?8"=Äãñ%]íX¼6…]µê9Æ'&÷è´~ ˆM[v_|ÁYœw†.:V²YÉNŽŒ”a28à¼V àEKØÁÂÄ <#Æ?ûˆGzG[%ÒЈFšR4g C¤%˜ÿmX—~vf„2mXWÁqi¶.ÆÕ°.£Ø* —À®›­‹™[Ü VÀŠÅ»wôíÙ:”-ÍR€ùb»œ¹H$cN›5Ñrd2¹±X¼… „t o‘SI8Í9S…À-HCâNB^¬Úèç6„t!Mýò$'ñ?«N ‹·lRä0é‰&¥À¥IiÔ–O™»PÊ —î,•Öàe¿™IiiM¼–01аŒ°/ø p‰à+høÅ_=’é$ûÊúCmƒÃ¥±ªÅP4ָΟGÅÆ’Á0S.L[àY’ùRI²Ä¦Ñ° ÑR´QwB±bêžÃÉaCïF˜noy+Ûkk1ŽoY|]’ƒïa@³Ñ8Ñ¡UÅÈÊSOž?{vx˜{Øo7À{`=pÚÉÇàoýÆm>±©¥¥¹»³5Ž_Ìñ5¯¦iºÆ2«=}C‡z&3æ·K‰ûŽOd~uÿ3¿^·åÚ7wÆ)ÇN£¥ÑÕˆãâÝO#`%C\‹½ )„9°Û‘į dqáZKX© ° ø]d¡eÈÖPX~ä- -Äd´Y„V"C‘/TQ¯‹‘¾ƒc[6Ž÷ò7{ûäjKÌÄëˆæ²íæ¸4Xc‰hs–B˜ºÀ©F¤‹¶ca$t/8ç€Æk±e P¯xÜ’4ƒÎl@&“Ò(jK!<Þ)LÐVžÒz'¥1vDsÖEsëR '$4[È;ÖÓ÷Ì¿C¶U:б JŒÅ9‚Æ5-¶Æh·]¨ŽùE8“ü„²Fðnzdá4z`¸%9Óêà{qK1 UØä[ÚÚz­ $;Љ~zFáS>ØzZìCFw‡©Ž4-éä²?y,x˜» nƒ7Â{`î<°wÿd¦püq«ÐÙ¦ï !ÛþÁážÞ!, $¸VÚ¸48}Ãßùá½'Ÿ°êÍWž·jÅ® Vn±¼ax£wk£Á.jk‚ ©à0š„48œ Xaú©–d뿦tÄëŸð ýO §Êa]dA˜l]ˆPè‘.‹00ôOLä_Ú2Ò¿g€™tÂaA…!œ¢’T%ØÄÅ!.ËäF£±VJ3¦V X p¡ Iç C¨‚@U8@‹¡EG¢…ZIKHp^0&2Ѫºäy ÓÎì.¼S(ÅGI¢´å“Ò¨Vð¾™”`ì”Fî Ä9ŒárÀ!š†ës·?ÊæW=‘¦R¾ ÀNÑÅÈh>ß„Ii4~q†­“–ijÎ#wðáúΰä«@À1ìBé6Úø»¦¯G|¦QÓ~¸u#OíÅÄ`4ƒÂÁb’Øezä™Ã]vúô†7Ò8¯Ë{`Jx˜;¥{|¥÷Àë\wîîÙ³¯/‡Íj>°Ó2¾•ìáÒ–G×Í[÷}ñë?»äµg]vñ9Mé”[5×´A»-ØâÁ.”KȤΰ.ä LÖEȨ‹á/”ëR¢às.Wܵr÷æ>ãI{7 Ȱþµl %‰âîIH¸‚¶”b J°ׂó颕40½ d®j@EnÜІÑÎHCíÆÀÐëüfƒIiâa¾ˆ¾FMLvJã1`+ï…†®(æ|qˆuRZ’p&zÅNitPhš×U ˜ÏЖàoŠð-»·ü×fLU.ôõ 6„¼ -àI¬æVŒ´ ÿ„‚›â*ŒÀ›Öe$æÖÑ.vÁ¡î]m vá;¨œç„ÝÄÁ^ç««·4í\Œ`“8Q×Á¸d='_r©¡üÅ{`xÀÃÜp¼ Þ õÀ¡Þ! ÛC‡† ÕÅ=St‚ä„ýûû†&lrµu^›.íê!ÃÇÚG7>þÌæ7^ö¯;ï W`ŽhôjߪfŒMнô™ÜAœ` $ AŒyUoQCŠ"q,—K‹v!›@ÇA,Šîâ Ÿ1º`°˜Jüzºb­u؆Ÿ½Ez‚Çô³0¥.˜ãáÁƒã[vçÆeטH‡X¤„ST2rˆ¯D´K`¥´át¢û·‘(‡+#]‚y å$M¤œidf ¤ÉcÜõb{¥@.`fX–°¨ì”Æ1æÒIià¬vRílŒÜêÃÙ) æÒ¤4…åžeJZ€QÏßÿ,[=Õ Jyh<Eq䄌ä#-˜”f†NÏ—øgñš}É1 eIÜgüãh¦†ìBZT‰6²B(jÇ€_ï.ç0ðËéÏÑØ82‰ãëò(bïrÐðø.ÑÙð˜yù›ß”=å=p¸=àaîá¾¾ïyQÛ}ví>4>‘J«QkOïྃ½£¼‹’Û°@5¸´2A(Æ%[FMd~zûã¿~fóõozÍ /[áJÎ-öéVÞñ³» üfΈ™|Èéð„@[`4¡„@jÉÖ…C¶.G™ è+ Øp ™ÜÖSî6~ã¡êý¨D(/„tø)‘(‘+!ðݦ5&KRÉX!K;)Ÿ‚kË'¥q-  ( sË&¥»â†ÐT3ö¢3ÙÇ(¾,Ÿ”ÇòRbˆõÒÑ·¯ÿÀ£ÓÃ\ãvñûÍpÊ.<”âh$ÒŒÅßPkÁnHB¤ŠþEáŠ?þ.ÆæK9$ÍÈVOØ%ŒŒƒFÌJè‚<}ášÓ£¹ÏÆ0Ç 4_ C—ûN$S+OõI sz¼òú<àan}þòÒÞ Ð#£»öôìÛßO/ÒÚŽ•+:W.ï:fõ’Á¡Q,ŰáÅnS׺´«»ãJ„÷ìëýê·~ùŠ3¿öçwu6~ѱöÕ«C¦rÇüÂ'jö`·#M BæŸ)N5Ž¥!ð¡Á¾î" „räzÀ4&é×t ‚JÙº«¸aÝD6ïÊØgVÆPÐ*CÖ;„’*Ë~GÀJò‰€)’ä" „, ›ŒubÓ+ðÙl‰áÒ¨7¤è!)—&ö,áHxHŸ¤ÓÒPAƒãœnÅmèd'¥E“´™,MJ#£"má$,ÂÀ½Ày¬Š|‰È6œÍЖôÔÆâ1laFw€üÊ¿  {ÑPñ%"Ø)õãQåPn±øÔ­PµèŒY.•6kÁEã‘"6HÁ`XA‹ØåÁq+¡H‹4¢çǨÃPAÚ’aÒEn!yºPAôÀhã õcê’m™!ûä·ñG[!1Ïdkå CObÔ ¯¿°ñ½zÞ³ð€‡¹³pžoê=p¸=°áÛ==##ÕLgOsS qV,¬ Bd;;Zßóö‹wì:xïƒÏnÙ±LÂ9öpiË£k5Œ«2Ï>¿W]þÊ×EÇ™°Û¶ŠçÒ1Ò·­yïÛî @˜Qæ)Ò# $åàTÀ ‚%”/ÊRá°. £ŽÒµu. Ps Ò@È€@3 ‡uwöæöGsc“f<* £Ózåµ$i2:2MìRœ&Í”sr"“‰ÇÒÓò]gd Ug+MJcAk é”{špõ@jdsÚOJÃJ¬X§€Ð'a€(c\™”ãI e`E “Ò¹ (ÇÛXpwð OJ£®‘`ÂÃt öJ¸Z‚?OBºûv ŽîРȫðð˜7LLfpwïéÁBªÒ©¼kèÕʇ&-?‘ˆ¯XÖqüq+ÚÛšŒD¥ Àî=®ß²À.Žc\i.g,¬ûÖk.xå+Nv™³¤ÿ핯îíá—>½öé ïX®3¿“œ©!à…‰€Üª¦h*Ò<4`´¥pƒ ÂpŒ<(¬‹ƒ„™B94°­e@RÖ-$Ftž,l‹O “"ö>ÊÕ–”@ G–ÛYQ\ ÜÙ"‹¡D=‹v­çD:Ù3°K˜H³™0œKÁ‰§šÿs%u`iæsµTjáä³&) ™¼š¤"ýÅ£âš&ÒîÈ”¯,ò(š’a© ç8Ñ\„.b"u‹ÿCKD'“ùbôá;·Œì4Ï6Y9Ýal‰ ,õŸ¡Ôè¾™ñ=„ä1à‡‚´¸ ÃUT_ÂbÔÎúfš‡“«Ñ5ýgž²ë©õ\9·§l´0§,:O¤RŸÛ²}nûöÚ½êô€æÖé0/î=pX=004¶{oOO/«Åîî¶cV-ÆÒV8øƒï½òÅÍ»qç¯{û+‡…¦ãº½g!a÷?~àÁG7^wÕkN|ÙJ·vÆtûË^˜+H†ÞµØ¥¢ PôfFm‘ÝÖ$­¸ AØ !@(²€ 0Ëú€Ä'4 q7[|´£æ0 u ú”eëf³ÅíñÁþ‰Àd¯e„ G…YÖ”Ô*‡‡ÍUÌb—(Ò…ÁAB17™ˆÅšÛÓðE€ÇOãÀr`‚؉o›Kor¦!ØË”Y¬‚´4al äâ'™”&Ç»ˆšÉ¤4€n»S[v>T®EKÐÇ®¥ #d;‰‚3)M¢Ål l¦Ii;vŽÖ…qÉbc8]ÅpæÉ‰ãp;ë‚ r8Û#us$б–bb45MçÒçéW¼qî;÷=xÔçÍ­Ï_^Ú{à°xÓËzûF¶ï<8äM¼×šøÐ·š`-¦SÉ5«»W¯êÖä„zÍ~æ¹­w¯]•q݆Ú/˜ú> Å i—/ÂçœyüuozÍìvýÂ?<öÅ/´T¥Â»bˆ#`¨QÙei æcˆþ™˜ÁS:ˆ ²ÍcÅ™02$ajˆƒ¤˜B9\„ÏXIÑzb‘ž|rÏA'™ÒúT®¶ä¸: Šõ‹C¯è „-:ÄDÿ¦F.zFtïKU"ÜJ[N ¢$U—hª*9O|Å•J3Ÿ\dh6Í)ÚJQW Ä&)èMˆ§£([œ±Åh¹Ê2)d«Ñ\ÔŸdˆOµÔW*æóŵwoÏTùæf*½ÂB¾ÄWËK„à!v,-œh AjnGNcªMZ>udDÐHzR¸{p¹wª¶fÈsfÔ2Ÿž´HddY×Ö]{˜1§‘D~‚2ÓƒãOžx²kÕê ì)ïàsÀMð&xT÷ò0©ëÀV ¥×¿P«Ã\@ÛåË:–/í¨®²ŽìÎãJ¯À¾W¿áU¾æÌÙ$ìî{úé½õ /8Žk•`7²+D€´ º2Uv›bÑ¥€¹€J®ХрÑ/騥öNúÕ2_Ä“%m Ìbþ€gýã…½“Q³Xie ÍIK!÷Ê|˜± Íå¡<åóƒC þÂ:ªq„ ݶÑö^t˜3 a¸ƒ†cò¬É‚&â[{CˆoijËßl+î\“‡ œ¨À•¡-ã]É"¯¤‚Á+A^IW >òß2 Üb‹ 4d¼»udËÏ‘5õ° 7ìžòÀ8x(t²4sh—hš5ˆsvtŠrrSâ=s‡Á®­"#y*P 'eŽ [&mÞ ‰Ïù1˜Èæì >þ¼ó?þãŸÌy—¾ï:=àanóâÞóå¾þä' Ž¡CËUƒ¹­méãŽY¾|i{-É õŽàÑ'_¸óÞg~ ù¥N¤¯uuº|våc~Û5¼êœSÜVuÑ_:ö$ü€ˆì.OÄ‘› ª0Š-Ê‚$SHŸµ‡u%ŒV¬˜0ßX>ÒM‹…¡?ë#¹Ú’²A(Ï¡BO…xB"µ$kµÂra®v.28cÐÝ€ X¥9sµÐRCžË!1b¤ Jª ÆÒĨˆt ¼&Ëb¡1B´„bmL×ÔÂ&B´\‹jÈ£È]_¹d8·¥æÇÅ%“É?xû&MݧD0sU…þ“îaž-&!¶ãgÀœ­>ñ’9óž5WnB´ƒe¹ÄÚØ±…´4Çì¾ôq1oF:ÊòØ#Ÿºo튓gþ/zÞlömð0÷h»ã~¼ ݹ|áà¡Á½ûú&'±ü­ùMPß©%07¯ZÙ…n[ëTsËf?f$K<úÄ <ºqLÁ®ÚÖ>-Æ…¸È,ín¿ñí—Ì,a÷{×\wpÃF¨’¼1a`7™H,'È@šp"èÀ$¿ST¸Ä§*’"5‡uebýƒN.Ô2F `K¸ g­ ˜TkÙöÈIXHb|[v‘®ðÜs*jÏQ¦±(1g–Zj$¨-B!Iª&þ·òJ3ßz’dT­@Û$cY€W„u5?yº^uRn¡+MJã.Ý>Fº/î+î{r†0»Ñ(ð¿ØiÇcü·8Žë™$†ðèL7ƒ‚ºXU7øæÀJH'ùG®ÆQÄß™*fàT–ÃÀ‚ÚŠÚ@×a ßy=ò±âP2·êŒ3ÿàλçµcß™÷@mð0·6?y)ï¹÷píÎ==}}Ã’Ÿ€§€¹Ë–vàwîí z°‹ ÏÆÆí¢WA%Qµc\mwÚIkÞýÖ‹º:Û”S ñÔ7þuíçþ ¯9è1#°ÛµQl°‚ èk`X·o {§5ÙÕ|§µ632òÏgC¿Íã`0«”˜UwÎîJúœ°„à¢X!¡,Щ%¬+m)zGÒ‘Él±§˜ÌŒ„“&Ùfk¸ŽÀ ¤Ð\eˆ¶{ jÝ&4 êYµ´RÕ®hN¶¦;&h­:UehÓ1†Š:!ÿ˜<Ó©tmÏte7àJ‡¥™/8Žùäa!€+ͤ4J` ç3„¥D[ß !]Ëhˉ h`„7îÎ÷>¿ƒOR¯ª(LÂ42¹¡Ž±T/w‘.š³âYš(…¿éX +‹r\ŒZf@¹©·òÙíWz'e¾^X±FR‰¬K¦¢£Òż/ù‹?{ýÇ>:oÝù޼êò€‡¹u¹Ë {4Òyä'ô b÷2Y?Të{’ûqa.ö-Cøvé’öFZ0 ]°ù¶;ýøÓ/‰ŽÙ`\Ñ€„ÝË_ÿò /8«F°‹¼…’· ]UR2#«-²›Š'º IP‚¡c  .8¬K?¯s‘€š€„à¶ŠÙºù|d0‘éwÖR@[k§\mIÙ ”çPhgÙzdèÊ‹z@¥+iô˜"_¦†¹ÐÓj†Î¬9t"/UFº¨5ÝB¼é’b ¾Å¢\´ó2Ã\muR"ï4à êÇ%ˆ 1š‹ÆÙºy'¢Ýƺéd†¯åÚ¤kÃ<û SE•AºÎ­QDk¨Wvµé˜¼Å<2vÔwú¹,›ïºë§úˆ}×[€`»ˆ`:šìvDcM€K, ¼„+þ0a …QW[X7RˆŽ'’ýýáù@Ö6{5ЇÆÎ]å0»àV7’l¹ ö‘V«™êM¿|aì…QV‘zL%º°§‚TÔ\ücάDh©Ñ†5 ”Xyv¯U)~7­T-\]>) é vÕì‹F9&m«NJ[÷ÒèØþ^êgêƒ;-Ñr  ,ÑÀ°<òš4"7:·m ˜ mÒ  ¼ ómBHÙœí³lª iŸr\ÍA<ŠAiÜÌ/Ì}×n9õÒKíhüÕ{`ÁyÀÃÜwK¼A‹ÛCÃãûô÷ P„O—è ^”üòÄ‹3!p‹]y;;Z¾Cvï^û "»òîƒ]\ëÒ:œrŒk"§²æªË_uÒñÓl'ñÕ—Ÿ;6Æi .®uiÂp\ÚyÌç¾ülÜ]}vÚúï~÷ÎÏþ¹3»é|´­tDw…á’ÀN0D˜†ƒ:„í $t¾™hï;ØoGÀW;tØk)áÀ¤ Šäm{5µ®<+ZA¡GŠ0©)þ r¶P“€šgdD/-.FÁVA_à1-uLiø*§BºÜ\d DSý,uä^¦¼JÞ‚ÉÓåiï*𥰮Àb¦­ìÖoÊV]v@}+ÝM}Ö‡ì“Dx60p›£1ÐÚ;uÁ}˜³)Q½t0àbpá.þ’‘)^˜¨:jí¨nBº7k^¾ä=ìÓÂ^ñ¥çsÜ-ñ-2d2¹C½Cˆàéê˵æÔ.én_½jIkKúˆöÀî]kŸÑ4Âê¸Ôà¸.ÆÅ¶¦"ÿºWŸþÖ«/¨–°‹€î(ºÐûÞ¢Á Àø½©Ènw{BNŒ€um‘tQ)̡ڒ°.:™lií mGr¶w¹Ú’²A(Ï¡È-Ô‡^ø¹òN­ŠEd’ZqC:‰ËÑ ô€‘…TÓÅt:ݚ˳?È`Zš@Û»A @Îä)” s’!ØhK3ŸN¶• E€Z”k1î“ÒNÆwlØk{¨ë*Þ 5EŸ0­£*u&nü¨m4š+:S­¹™ÒÊV7«Õ,À`z”.Ìóf¼!%ë4ÁƒI‰G#ÏŽ—=„Fwƒ/ïøá¹ß@IDATþÏïžæÓìT¯®ñð0·ñ>õ½ÄÃ#½}Ã=½CîL2©’7£Ds;:ZV,ëèî>ò·SÜh€ÝŸýêñu¶•˘w>WL‹qIªinI]qÑ+.ºàìr°‹€î]Ÿýs5@¤f°›lJµòFŒÐ\b¡µ„u)+òÅH&_œL¦òcÎba¨°6Ù«a8E%UÍ,& hÃ@žä¬€ráX@FBp˜I'©u϶â°¿ŠŒÑâJv‹à!s-QÖáv™ÃU‘.j ¶è–”XšÚRô¸L­¶˜Æ“Ò$%L“› JÓÑ̤4¤»oØ3‘å¼ Ò:Ä!Ö´@ë=tЄ"ÂxOé)`®´ÂÙ¦–¾nwRuE7ûÀbXã2°+¸–L²—{6+Ïù,´×ýñ'ßø™?¶žðWï…ësî½ñ–¹ºÅÒpea.²o—/í\½² “ÌŽÜ‘Nmù¶î¼ïéM[ƒ¸š4¬ãJî.ëî¸æÊWwî©%~ëò+mÛbÊT)(€Â"ƒ ÄPH¤%o¢è±A²Zúøq<×Ù1ÙS¶„“`™ÓHÚ?+aeDBüÔè%ó\y.–)ä6Œ s››ÒYY\Œ`”¸T\:³ÂkªnHŒ†(±òÄešN‘.¸ÓNJ£$ÝXt_¤uÿÆÆAµ]‡Wh›°ê­>K"a0®sc Ä0‰°7ØYP •Iég,IiîŽkÒ;D1,üc.jMS íM!ö†æda¨O4ÌÑyõ¯þÈOý¾¾sä]¯¶Áð0·ÁõêŽfðaC=}C™É,ü ®æv´7/[Ö±|iÇQâ+»êv޼åÉs¨ÂæéjxXŠáýï¼ì¤ãW‘}/½ô­+¯Ê3έì"T™‘„£ŠBv : ŒI‡AQT/Åb$ßÒ<9T–i‡e¯î8E%-âÎÕ9Z-„ƒ£Œ‘–o‹Ú R” £eÐÕ6|¾0ÌÂpªÈˆIön™myè6#\e<q¢Y3ùˆº*Ò5e+/2ÐF­H˜KCœT Ø7Ù·”Æ@°3H` uÇÇ¢ÙBqãÖpn´uwRßÉx _‡¨¿ÒƒnY­ÛC¬h³gsà “ÒŠÑ&N.é†ÜÂ}›³)‘U±´V¡´½¥yxà³çäÔ´¬û“?âSrçĹ^éx ~óÍ7ÏZ¯Ò{àèòpwïíݱ»ghxLÖsÇ/aK„o±rÂ)'¯ÆÖeGz®;ºiiÌ!Ãa§ž¸™ ½ý”8XoW»4Ï<ú䦭;`%Š%]´ZgóÒ¥ãîöYóÚ·¨TZ”` A€­š›šS ¥YZ0‰ |1m\WhJgã‰ìHx½0´c¯¶¤lÊs(ru¯u¡dSO˜†_ïmºZšÚV:h0µùT2éu8l Ç#Ê£Z­—T]´1<®Z÷Œz–1VX:aÑK¢ˆŸ«&€9ìCï.¤Çà Ý.¦e…šR4² šDÝ/°Œëª Ó"jj•N±˜)àë²#̈K-Ð2{}WcÖ@"99YödjóÙÀ¸úÉw®^=;5¾µ÷ÀüyÀGsçÏ×¾§Eé‘щƒ‡°™¼üd [»€ÑÖš^¶›;,”ãØ¶ãÀ÷>¥i uÅqÕŸäj†pžwÖëîjæh·\ze_Ïš}ÿ+â xá4†Žl<‰Ðd¥£ZX6D»:²}e¹°Ø«˜NQÉúÔAiµ. -ߘ« Éü?pâ›RN…†¶›º¢¹ÐƒeðBà•xM ¬¥©7ÐÖíDgT j~&¥æò[׎• «ý¨Ø ‹5…㹎ÿiœÜÊðl‘¸š­ >ýPA-¸•ðIE|㠇ñ3_È¥â[4U £ZS,7W0÷†o~íÜ뮯`œgy,Tx˜»PkÁ{;ôꆷ…á#xó1…Eª°ovvH¥°Î§? û«{Ÿzq³“³kÁ Ù«›«ø–ÀÀ’ÿŸó¦Ë_5ðü†^ÿŽlÜVY¤à*6<»˜úÓ=a…HS…°Î :L.ëžmÇqGÉ –ÚUmÈ[õÚ¦>tÆ5ñMcQ¸ •ÔTôŒ!QsQážY|×åX¨,Ö]0@Ïø„å*ƒ-ø5Zÿrâ‡Mv¦=“ªÄÊÏdRÀáž–öþ­¼V®Œ¡ÒYFZ©f* ”_.…¬“N–f=¦ÆÏ!>‰ßrCyåò#º¢qþÆRÞc[ùæ€J»ê4!&Š…—²e¹44ÕÍzÇ¿yŒ[·Ó|ƒÃîsû-ða@NBOïp_ÿ°¬€ ëËan{k~R_8ó.LìRdwó^ÎÖ‹qeh-Í©+/:§{ÃãþÝßæ°™„ä(»íM­MC™i=#aÝä’Î \4œb¯¶¤l4ÚE@AÞìÕȹòÒP1¥¸…–@¤~*DZÎaë~©ŒÔØzêY¡˜Ê´475MæÄ£é¢€THšZRPŠtÁ)IÕµÂ!%¤æF1_KU ‘Œ«;¥Å¢ÃÍ©ûhê•; ë:ª÷IöÉ‹‡u9N#ÿ¦Ô‡R%µ,I÷_ŠLب¯a‚íŠ#Z¿¶„;ç°;ôFˆs b}¦ñkŠ]øÇŸºúO>]j‡/{,xx˜»ào‘7pÁx “Í88ˆìÛ\Ž&ž+RQ˜Ká[l]¶Ì‡oë¸g[wìØ}q GvëŒãj7’ì çŸöÀ¬{’¦£a-¬äAì.År¹S€«:ÑÖŒOÉÒŤ–qŠ€0*Ê jI²jÃ@¾²BS¾p×7XJLì’³êRBŒp1®ö"2$éÔÜ{ü{ºt£ ²êjT©D³FË¡k ÒGjí™´ -ULÓ ¡*Gó´3ÎÕˆG·5¥ÆK6æ@³ðQà 7 ›e¼‚íØ\Üi}EW¡Ý3¹“©½[¥ŽU&ÉJƒ‘DjÕK´•BëÀ<öLè×xH˜ëã…Èx¼´™)uæÛ®ÿÍùúL[ûvÞ‡ÓæNïû¾ŒŽNêâ\Ø,o>zñ˜ÛÜœZ±¬ki7͈òÇ <@`÷“ÆàwÕÉÐIhÀ!¾SˆONž}ë×Gò£f•°*`·)ÝÜ1LÛÑMq1¤W.Íì­ c ‘«-ö…LuÚ«¥%M\y/Õ¬ ¸-)¸ŸüÌ­WÑ\!M›±Àâjl0®TksÛ8­"‚#³ ‡xø_ª m Å€c‹døL%7ŒÉ´mè*¤ N":Ô’ÜÛ?4Ë#˜ê+F*®„ ãsÏ(þSŒ ¥¨¦c…cð-_¬ ² ˆÄÿÍÑDg¼rª®Øj\—â+"mLŒç°¦Ø`¥çVÚÔy>ægÿÞ=wÕÙÈ‹{,x˜»Pî„·caz``pìPÏàø„¼ÚÍkHa.æ‹tv´,_ÖÑÜ”Z˜öYVìÞ°»Å¤W8‹^ù€Hó•à “ƒÁ̓=§üò{£‘1Ätå­!C@ŽqAg¢¹it*˜ÛT àB÷®&”®VÖX'f—ȳŒòHR B8ƒ55%Ò¡\A<¤‚£’-(ürx¦ÒŠˆxЭò…èŒÅu…WÅXhch¾ZšT¶AôY"]ÓIIôã+ͶæhvÄ,SM½ÚCc±–1«+ÒsehÐRâ–€Ãü$…ÿERÎà(„µµ¥ |PiÆcñå´^ÚT‡Ô¿òlimë?8UƒšëËV¿éÛ·\xþY5·ð‚Þ Ëæ.¬ûá­Y È ¸ØÀ,›©o(CàÝ \‹éeÀ¸@º ÄæEc†€Ý6s‰\ìà/à·`€ª–ná¸û~>”ΛÅtƒY° L°"“¬æ®DkeÍ—/†öA«-)„òŠì4½éU‘®¼Hˆ€ JßßZ¯]ˆJ9%]¢Èø £7"rqÏV«H–*€$4$[›;ǃo ° mèJH—j¹'‘A‰0™ýöaRü…ÄT€oå5¾KŒ¤;°´uÿÁj<ÇòÜ™aâ:ôi¾¸NCªŒ;ÐåT 岉Hâ¹Æx—ÅR%I)åc%w±¿v´6 ðª#åBaŽf›Rñ„³·Ÿ÷f<…¯8ëøßzçåÇ­YVQÌ3½²<Ì]ÈwÇÛv<\ÛÛ?200Jð–áI ÌÅòUẊoçúÞìþònŠìâ­¯})^§Æá¤ ¦ è‹íÝ-½¦¢!¤–V™jFý‘b5¥„ptň®ÚPuTÐìŒÔˆ©t9oZX1—´¸‡Ê‘ÙTÐ\¦ITE”`¦ÓyXFô´EMNwÒ±0\ U¨2µÔ[)Ò§$U× ãZéZm$¥H7[,îj‰g‡+ÜP겞ÃuBÅvH Я"4a þQ'KÎ*õÔΩ* 墶,ÜK Ф;žh­žª+öˆ‡Š¹í³^S,súù{ϹÌ<¾¬ý-Wÿ¶«_ÛÒœ–¾üÙ{àˆð€‡¹GÄmòF·&&³X#l`hÔ®f€”ÀÜT2tÛÝÕê÷óq3l[Æp÷“/pƒ ¾¦Æ¸h áã¿sÉóë†ÓùœýÕ|à°%™xªXƒO/ïÎöTZ,ŒtkHÙ²„„dŒ€•ÐkøÒÀb¿i;3Œ# ;Ãl”KZ(ƒ”V`¬E-cÉäš„:ƒ2Ȫ†t!M2¬‘…QŠt —…™&Y½[¤e>¡;Ðýk–Úþ©²Ê¡c©R_•­ ÑBý¥r¶šý* g[ILìÖ2ÝP®m‚ÇÖ<æ! ìzœðãÑÒXÕ"¨>héÜüÌq¬?çâ}g\`m!¥b–ÿàW\äsÄÑþ|$xÀÃÜ#á.yçØØX«§oxdÔäö•À\d&`·­ÖVØãÛP]=Àî/ï2`Rµ`\Q¤»ôùu£©ÂdÌä4$"±å“¡eŒÁÍ•o÷ Æðë]ÁJ ÁðCEL£ˆ¼DžŒ¤¨a‰€6ÔP1· Ñ ú°É_I¡{H_‚­KB¬\33¬ŒËÙ‘˜ŒU¾€Ø`Á.Â@”À¨šG´ AQ ÖÊ ]Z:š‹·ç'HÈ1UеŸ]ßNÛ*emÃBŽ“&¹àìj†˜ò¡€kk åª<”¤âñ•±”ú3lKPz6;ê¡’±Ä૯8xÂ9Ö^jì…sÃð.ŸÃP[½ìá󀇹‡Ï÷¾çàÁáqJÀå ƒ„æ&“ñ®ÎÖîÎV ÀRoBdËöý?½éÁÇŸ|aîXPåÂ4âžÒ]?‘(Œ%Hº9ÑÖ5j–ËM´·D …Ê‹…‘"Ó‹N6ê­D KMÔ[ ÁW>¬‡ZáІ¢Ï6ºQŽ‘°S,"gTeYFBä© K•F§cE‰ŒQ.>OÄ–abÙ!ýUDº5µÁíš-Ò=°¤eè­•;Å¡£˜B¦bU‰3E&‰X6u£µâW©sû…¼Ë­ÎdZtC¦\LE© µ*Fâ‰øòh²$}¢dÏ'"¹é—….i•Ž'÷\~ãH÷*kÕ»q o¹ê¼·_ó:ŸÃPâC_\hð0w¡ÝoÏ|xyýƒ£ƒƒ£¸ú!®0·¥) €ÛÕÙ2¦ø>êô@ÿÀÈí÷<ùà/à7`sØð Š&p…}éfâÅÑd~ùd è x+ßÑž®¾Š>?úl”„5ìPNïÊt%©¥„pÌ65†o{q›-€‘z,â'æ ‰¹¦¡öôèª ªYž”iY"f†Ì>—Vé¦dG0-hU#ÒEƒ’†ê1]¨¬ª;Y,ì.’+E`Ê””{§ U"?$äP=+%„ÑX½ªÌŠé t³r¹È]³¡b-™‚¯–ÄSåun@§ XSl¨¾5ÅÚMÛ¯üÍ‘ö%î¿"µ™”:19 ÿãƒ×¾ê'S­?¼¤<Ì]·Å5g®Tâ fô±­Ýx—Ý"?Á‡oçÌý SlÀîc/èOàt+õ^@È1Ý|SS 6¯kkMVÏ\´íäjKÁs"€CF¢µnï– ò¹ò\”¦ŽBÛ@F-•ÒR0®ó¢J~F78UžÒJµ!ÿ•Š™Q80·‹.%*Dt5jË€—ÃÌ6#«˜m#»l„p¤]ɤ4؆ZW ÉäýË[GöWEr%n—1ÖrÖœ¥jÂHذ^‚°ø³šW•‚l³ž´|<-æ‘‹‰(µԎî>_Ál%—&*§ênjkžì¯i±èÁ7¥Ž¶®ÍßPÆ%³ppÃïþÖÕË–tß½”<Ì]P·Ã3‡ÀíëÅfŠ„Àë$NÝ"2/Í»›C{¼êÙ{`÷—÷üú¡Ç_€*Ö–b\éèô{ÿ»cÿnüÔËU B’ c‘½*Ä.ìPN×Ê•—v¥Z¶šmCÛM`qàጿ¡Òa*PÏ|-*¡â0Õe–Ðf ™I+ȤZ›º&Ë&£Y¥„GÙ4¤¢’ø® wf9t­ˆt¥!ŸIf¼-µwpD½Ç´(vZ…ôÉÀXT}¥„hp]ªU ș֓–çÿ ‡ÅŒvÓDš;AJD²9™Z‰UÎÊŒÞWÌöä*,$\&ˆIuñ–%«×_òŽ\"eµ’”è7òNÁ„¢¥Âòñ@þæ _uÙ«|ƒñ˜¿,x˜»`n…7dÎ<€Í€‡FÇ&¥… 0½¬£½¥¥Ùoî0gÞŸ{Åvïþõƒ vÑ›Þ_¢ÝÞ‹Å—ÿü[]ƒý嘀¤¬¨\mIÙ ”çPÔéC¯uqM;Ûƒ¸bºF(W0¢µ±òÕYZ+£skKh3|gh,µVÆ\1ªeÊm Šå‹¡%dËæXJ&¥C ¡†„êö4ŲÃcÜzV';º•¤0éO3H¸õžD/®¥SÛ5ž#ó(YŽ amCm©9þƒ„²7BDí͉t§’K쪺ùHqc¶ê Ëöh¢+ž:tòÙ/`ú4«fºÓCãÍı|÷«—åQ}ksúmW¿æ†7¿Ž þð8¬ð0÷°ºßwÞhËb†Ùàð˜Î0Cø,FÔ¶ y„-ˆã6ºO¯oÁy@Àî÷?C‘]çŒ+¶6Ÿ~Û·;39FÆ~©Ó·5! {” ”)„+/í,ßê×Vs‰äÐ ï\$aÍ ÄJ~=W%\…Ê—ÔºEÐÁˆII­#C$d¢éäŠü1eê‡2Mª®‘á„–v%©º£KÛî¯ik_ÇTq­ç¢Í¢¨Öy’+".*éÈ-‚6n¬àCøßÜmÂòÔ‡´5ÍÍ…´©0`®b\ª/Fð·*‘–›Qqé\ âb±ˆ§œ5GWí;å„•ºñŠ3N9¶š=ß{`<àaî<8Ùw1Èå ££“C#ãÁE—‚¸†µo[[ÒÎôèù°Ç÷qØ=@`÷¡õwÜ¿n\²VôõË–Å3“§®½µkÿ^¼ø78„’„6ô ‚d„AC…/ÏP+•µ`\tl  é¶Ö‹X[Ú£ÓUÁˆ|ÛŠ®ª§½µµu²ÊÄ>G­²Ÿ‰! ƒ.†bÂ‚Ì A‘n.RØ âôÖ§ÈiQl5ú•#†ÕsƒåqסZ<9Ái…Ù½\Àɺ—®ʵÍ)]‡À\#IN-&c±c’Mâ[òcc…à¦`9…öx²+J+3ì9ó•›ÏäPk`w­C ºANÁ’ê ´°ÐÜ«W·¸<°~ã¶»Xÿü¦Ý‚'0¸x&sÆ=?Œ<€U™Ö•á ÑW¿C(I‚ZC…/•$MGÜ¡>ÒÂ4U¶ ÊÁ€Ù@¸µ$溭¬&º–ð¥¨Þ(Á¸Ž¼iIWƒÐM]íÝ#Aâ¬Û]9-.¶1]‚r婺F†µOF ûrµ*/ï®ÇE5™Š|Ø–(_V,ÿFC«ß\]¿ g­y¹ tÆäþOÅ T’®€*3wÚðý§5™hŠÅ5ë<µ¬ëí·þ`É©œ«‰<ýÜ–¯üÛm#£“¦k¡S˜#Œ+ý¬ZÑù¿sý™~jš¸ÃŸçØæÎ±ƒ½úÆy³æ‘€›Íš]—ð©Çය»o6®?¯i±{à¥mû~ö«Ç7nÚ… ô’?ù©»[6®Ãúÿ-ѸDJõÕ/AŽðaù†ë ?ªQérB@ ŠðÌY›€­Q€q¹©­¨ùªª´…pTóÌ0.´Av‹hŽÖ‘,$CÀHãV@ºP Ät÷·¥&‚¼?5Q>ة姭ub²Ùo¡­´U%äîÁ½Êq Có'¹ öln¼ÛVºÓ>IÿqÐÍñT ‚ÛžH*À…U%WììíúÂ×~²u»ÝØØA•sŠqµŸ«.;çïºÂOM“ÛáÏsçsçη^sc<8 €;:–Éå àÊ ³t*­ËZ|~Bc||Tkؽkí3¿~f³xaÕ–u+¿·/`mŽ4ï½ /fΡ…€0Tøb° µTIQS ÆÕ&nïØëK~1wÌ™†T=®œ0]Í ÚTÞæ aË!M%4þY®È(s»ªJ+Ò…„¡ùJèÖ6Âf½ù ‰¿nïVvV׺"7Zên+—÷ˆ{•ï†æ NV’Êöbr=‹]«þ%yüÇ3ÏPM7ž,Ù¯"ÆU}ïÇ÷ÿ Aó„q—·57}ü¦7^rÁËÕOx4Üæ6Ü¥^aÃ<€‹ ÌFF2òs}¢G"Mé$·I|˜ûÃ{ qèëþùOÜÿð¨ìèÛwÒ=ÿ™›Ì?à—_ä›Ê³çö&À@áƒDˆðm壀ÖcÈf¶À9[ÝS]KúuE¥*𢧠öÛÞ]È刉©"„dÐvg;.·Çj´ŒÄ&0”›ª µ=Ý-ãûª5¯o†Q{+Y±!M ˜’øV«”€VÐ*d‹Ä0·ÃÞ• ¡z—L?q\w!~EyåËOøÿ>xŸšVíyþ,=àaî,è›Ï‰à"‚ BÞëÈOhnN"|›áOµsb§WºÈ< `7žÍœ}çw ýý eâvöÁS°"D À…|‰€ËwÕ‚q%J"³B`’¿µÆ0긨: ¥¸­ÕìÔªNÃ+\* 9ÐZŒ%«±;[Gé¢d@¤}##µèSjvefÖ·ë8z5%¾‚ŒÖ04_„¶ò†fÚøÙ%“‰X[“ÄV’¯µ`\iÐÛG ›·ïÚ‹0µüùf!‡²•&yG‡SPv Æéö¶¦®¾à×^4ö”÷@ƒ<àanƒéÕ4ÈùBal,31™-Ìçy2‘hnJ67§ÔƒWã=0°Ôî=®ûå=O÷%·n’74¶¦4¼³•â7½–Ê é².€‹&‚~ˆPtÊj åJ§zv¬R2”Zª\%ÁX¦Êh#¦ _ZšÒÝ&…>Ÿ–ßÚ˜.J„t1î©XnÔlíë6­¾@`f­ÐÞÁi6—ÂSÁi±†Wî%Râ4mŠ|Ú¶2¬0Ó6æÀ} R˜™OT¸hS;ƵD¾ûß÷Ý*+0ˆ4|K©Ù,í°Qvd²rÛŠ—TrÃSO\õ¾þøc—s'þä=Ðx˜Û?z-³÷píèxfbÂdà¡ØÜ”B®_þvö¾õf໬{úK_mì^ÉòJÆcÁ‚7º¡”QN w¸D8-Õªò& p©‰‹n¸MíÑ\ÕLzDBjµa1îƒN†mq˜òm3 ¤rF"Ym·œ ÚÔF)Ø•Ii£­}=Ó¤+¸Æ×Ö‰‘ªt+êR@+ºÅÙâŠ6¸LÐA‘))ZßV˜i cÜ©.ÚœùÑ›.ûÜͶq×§žÝò¥ý…$0¸ªX%ŠÂN j\~ŶSc\£<y×›/x×uù©iuÜ6/:¥<ÌÒ=¾r^<€mÌ&&(‚‹ÞðYÅššÁMa§yéßwâ=0•îùÁO7~êSÙœA…x(±’”€].úª/'Do£‚¸j%O}ªé_G)´À£ŠÙ† *`†£vpÛ –))6·6/­s.šj•á_¾XÄ"b~•¨(µ»¶VuIÁT¹n«ƒQ 8LI±àB—©¥‹ÈZ‹q±|¶^kAþ–~gr{µôŒ1®(èAÃWoݼ-H`,UnÁ±ÑåÏ㊠kVt}òw®?ëÔãì˜üÕ{`æð0wæ¾ó-gï\.up³9úމ8n “Ìf¯Ùkðh ²##ßzíeÃzU'0 Ö:ПŒÝ·ˆÈÆ·¶"$fë\TZÄ…Z™éý¶I×0ºmÚܱ' g†qYsqU"­+k/5â¶‘%mŸ—´u¡UIÕ\Ý[ãêÇ E P]¶Á€®+¥Z8ua\$Ë4ÇãMÑrDê…Yb\UwËÝwëí£ØOϰևj\þì1.©æõ’ Îø¼Ö‡u]§{zð0wNóMà¸Yœåã „¥Óɤߞ·®õ*æÊ?ÿoo¾c­û®°«K8¹U0¢±A\Un&=¹sŸ¦q´%ÃÂòá¢)Yu%AEKÉÕü£nk]1YŠ®í0S,ÌUXDÌÖ7ø*6Ï@)²sÝ[a=àhªäT›q±0Y8Vœ4$¢1ÜT ÛÝAø¢ü«W¼ïFjÖˆãÇ7|ã{wa QæbÙÐwÌm Æ•NÛÚÒ¿wÓU—¾Ö¯8Öˆ;z´êð0÷h½ó‡oÜ€¶ÈOÈdèý‡8òÒ)³Îúá3Ê÷ì=P“ÖÿË7ïýìçJ #P æ„îèl$ýUÙ}ñK*`¢‹±ªq­}X&Îäp»–öaNP*Ç[ª™Š–’«ŽIJxª%V÷ª bÛžh¤˜1k&£ ·Q«ÂìéKÓ6ÄíÐu/¬'X­S(÷ I@µ¸Râ3Õ /Ë67c³šï56ò=íºk©qãŽ{}ùßoÛ²ýÀaÁ¸êy¬8öÉ_¿|IGãFæ5Eð0÷(ºÙ‡}¨™l>“ÉæŠ%Xí*Qãœ3«94ÕR%»½µéïºôÍo8O…=á=P£<Ì­ÑQ^lVÀ½¬F€´ i«„Íäå7+#|cïy©ºß}ýåýûz*ê“eJpоûÑDi}—³$D̪I(V˜[±ë©™ªÍ ñ\¼¥2! 6>àXÊ^ ¼¡a0®b¤»­­ºQ…µ»ŠÅh.ãJ:]îtôÌZA«Žhº¨> íÕá¶U” ï”qñmè6¼­ñû‹± ›œ]óo¬yÕ+k±sÆ2wÜ÷Ô×n¹ËõŠßkŒkÍ.¾ê'~ô½o<þØ–ã¯ÞÓ{ÀÃÜé}ä%fãÜI¸Ñ(V2÷ù ³q¦o»p<¤û«ÿþ¦;ÖV3 hEð®iBàIqOOÄlšfhÈ…\aSC5bLˆÅÒ.Gè€c){5èVÇ%x»ÈK–€þ°%¥%líÛWikßR9O—×MÉQ›§”*«äfåmù7©Ð œà ®H=ˆÌÓbÌØiOӻ˺œŠ1õF¾Sµ¬¿î…Í»ÿú‹ÿi× ÚÏÆÕ.?ø®ËÞ}ýEZô„÷ÀÔð0wjÿ,æÚž§Ÿé{âÉ‘ÏG‡1ƒ7A3Ç#Kßxå’k¯ÉôìJ,YèèšÍøpñÃ.¶{ÀËsËR)™‘<•¾­÷ÀÂòÀãówüýÿ«‡ ì°¼«ð(„Ê«TèϾ& *janÐA}”«žZŠ1¥\â‡)LKÙ«ê± Òutuv…B³!Õáü±;ŸLj“ë«°àT%kÄT2ê¸Ù Ú"‹8—˜E­páÝT,žŒÄ¾­`Fm¬ùĸbnþûï¿´í€8ÿW¢È§´ê?ò–|XWï„'ª{ÀÃÜê¾Y¤5/mÞüïí½õ¶|Ï~ KD#Xô'‰s1šÆ9M/ë:ö_>ßÿÐ]“=Ãíg½¾ûÒ‹Ò«VÕå dßNNæ Å"VxÀM&}~B]þóÂG’¶ßy×møÝÉJ©º%à J?nUWWT!øg“ÀÜTÒIy±2lSV^]ð-e¯Sa\2(]¯uq±þHq8;Q> —£ýºÌšhvMÒ*4}‡È©…t©zn') ‘UØí,Ñ­Ø„MήùÚ—ÛV×÷ɬ㙠ñÕoß~Çýëh°Nâ‚:H¿˜‘g©™¾T|çÉuÿ¨÷ŤÆh •¤Þ?üžË}X7ðˆ§ªxÀÃÜ*ŽYŒìƒO?ýì¿ÒsÇø<Žñ’¤ Â@ @ºØ‰!!°›Bä;ýé'2-c<8|ÇKù|qòÄ5í]pþç?7µWð„­Ëð¾Ç¶xº̺‰¯õXزåÖ·ßX-U·|€„ˆê ⪆z7µ¡’PV˜p€UH1`T€>D§j– M?~<Ùtœ;O+Ü©–à•]Ål$WazŸÊLE°yŽSÉ:uõ·àÆn3ZgC4Š ÉáS_m°­C2J[Š8ΜœÁF¾3ï¬RËÛð÷_û™Ö¨æãJïǬìú£½õìÓ^¦ÆxÂ{ Äæ–8dqû_ÚüÄ_ýÍ¡;ÖâSV>ŽéRh©$  ¼›ŠEÖü¯?<Ð׳í[?,ŒNF[#‘ñH>Óš~ÓÞ²úÜsË}\6U˜D€«Ÿùåžã=°ø<€TÝ_ÜxÓ¶Çž©khŠz*7xÅzU%Þ wúÞôɲÚQIËŠ|aU–²WZC*Q‚qÑ‹TAnu¢©iºßèD#™ñÛ‚"÷¦½üi¨ú[°ÂºšáÖȇµâÿ±x:‚¬d {÷¾Mcë´Õ‡㊅Xk쳟¿©ºê¥ùǸÆÓ‘È×¿îÆ·\ì7’˜öá9:<Ì]ü÷ýɯ}ãÙ›ÿ>j Úòg†®Ð=響P<õäÛ.¹¶%ŠE/£ã…üX¤8)[›>²î±t[›z Ÿqùþ+à“=Ïõ¸®§¤"žð8Z<ðÀgþô©ûAY ¶Öá+Pp–Æ&\¸äÒSt (¤šLEa†ªlÁ^ ~…ÚZ0.ÄbÉÔñØ6®úŸöd'TuÁòš™4šI›òžÃ¬,\›Œ"ï¶Æûn?]é¤÷¼åò¿þ\Êùž®ÅÖ#U÷}á{›9UW]ô7×¹ :$÷®YÙõiÖU×xÂñ@üæ›ovŠž\T˜ùå}fÃWþŸ¸˜d†ÿä£×„Z…C,bà:£Ée]ÇÿÅŸµ®^=^Ìîxø±l¤ˆ_Ç‹…ÉH~"›8õÊ+ÅMù|õBoûô¤ˆãÚßí•ý`¼jôÀño¼²ëØU»î¹ÿ4jlâŠñ¿P$ߺ¯oª—rcqSiÖá‡j‚’j¤b¥æ*°Ù$4)ä±ðÖ+´¤&'+î¡:¬•5\gÒ¦µå"¸kørßM´'’X3É 3[6¡\s ù^ùwƒÚþá*b×Ê«.}åÀàðK;ö« ‡ãâ^NÜ~ÿ:l;túÉǦ’S}›RS=q”xÀGsíƽåÆßì}ì¼WÒ‘xÿvV-  >ÍBCÆB$zæÿ"ÿØcíí…¦æû~øøÈNšW›-G"¹Éh¡yÍŠ?zêI¼ÅñX h‹ó¢u¢˜÷@ý8´~ýÏoüàÀ¡¾ú›-( ìŸ~VÐç 8ûkð¿xéÀÀÞñ£ý›‡Š[ú;ŽY™‰'"üAî” /ÆfXBÁcÜEøÜø!5Èɶ¶wß×Ëß~uC>aiç³"T¬#o¥­H«ý‡<1õhDƒª „µÂö"UŠkA(îk‰ã’ˆæ2áÀ(ÕŒòã™LɈ¨¢qPìÔ%]Q¼Y¶ñhS<ÞœÀ¯a´Æ-–þ.Á¸@¼iÀsx`#ߎq1øãYþÅ¿øSOäÎp#íqX0.:ÿþÏù½?ûÚ†M;­!þzôzÀçæ.Â{_˜œØõÕÏv÷ç ƒ“YZN¯œCF¿J0ÂàTúÑ-šZÑuþ7¿4±oß¶¹°) Ž‘•[LŽMôµ¤&&&²Qð |ê«N?}zÍÉ{ Ñ8ùúëÚ»;vÞÿ ls={õÙb¤3_–HtÅ-HÅ–Dy§îÅA „CG¸ì–Pâ¢9á+ªb–ᨷØ×L¤ÐŽÅµœc?aß ‘iH@X‚ÞÕÿ¦n  °Š<Ì0ÀïXø ˆàHZBµæHWhÔ2a»Æ=íºk+V-4&:¸ø5g8Ø¿sÙûpa\ñÌÐÈø/ï{&›ÍúlÝ…ö¨Ì³=sû5tžã»ä†zã­íË›ºR èæ#EÄk±\7^&öϼWÖ¼ûº«ºk<›ýågÿb"~0“ËÆòEùËŠíMMÅüd!ŸKÄN¹øbïgïï=pöG>tã?n먜Z£W¬7—+8ˆÞ=&‘<>•~Y*½2‘lãÜ$ù+Mì¿tý'"µ"gËnIp£ÕVÄÆ…ª±\_˜mo‘Á|?7i±"1u µuxíae³D, 8k‚µ¯WŒ×VÔ,.Bø`ŽVT@§ØäìšýÛ‘‚qÅK@ºŸù½Þyí(^Œ«9 ßÿéÃÿ³¯ú°nÅÇø(aúÜÜÅv£3[Ÿ¤[öþðëCO>ÓûÔž­#»‡Ç%Cðà÷57CwÕÕ—žý;7u¯YRŒ6üâÁ_ÿï¿Çû 8%Ö‚8E<>2_ëPÞ¹´µoß¾“^wÁ‡zëbs™÷À{ 72òý ßг÷P£úYJà2´xº‡”pÆŒ.ü&3Y,‚ÀWÜÊ80Ü–´9ºøqPŠ,d@Œm µ–4Ô0\Òñø±IÊ›Dvg?;9ò %)£ÕÁá-ºòš33è¡|\ð~ b¾3ÐUC“ùßÈ·£êYûèsûµŸJ÷á ž“Cƒ‚û<+T…ž@¡]׸Šü÷¾åõïõÙº®›ŽÚÃÜÅv«w}à-]¿õÁ‘C»Ÿzbä±çwîÞ621žÍ´Ê’ iþ%îøw_â…祼˜Û±1±¤;¾dù–­CÏ}û6¸C~ƒCº^“øyÙ½±ÖæüèX1ó©G\zÊÉ‹Íe~<Þóâ;núÀÆÛïoHWÀk@ºøUÝÕæBð¼ L9Q L$üDƒ¬$Å–*)Ú‹T(²¨Ä厌‚=ÔÜöa¯¢¶W§šgÜŸËõåB3ÏŒDÙwBf p^%ц¼S§BˆWŽ£Ñß9JW8Ò1®8iÇîCÿóóßÒIiäOûœ„<ÜØ…ª„sS\ç¶à‹Ÿ+Ô€ÆÉ«?ý±·ŸxÜŠ€ë©£À>7wQÝäÁG:ôí[¢'Ÿ±âºwMìÙšî-/'(C·iY÷‰×_uÎïøÌ·_“âþ‘îžØµ#36™Ê:480ѳe?>!ùÀëoD¼™ð—ÇŠ¹“ØÁ·pòy¯|í|bQùËÆ{`=pÊ oëìîØvïÚ*/â:LÁ¿ÓÑ|¡•SHæð@¯þA—ðåŒ"-5Çb—ñx|‰ŽDœöxÿäñ“= *²!P¨¸„(ã$ê˜fž¥L=ɇŶöjjDíD‘2tdƒm´‚†e`=rgaLD²O‹k-²i±/þh‘/š%6sŒŒ§Ì—‘ˆàg1Š 7üh?ýÄ·|ÿß—œzjÃ5ϳ®ŽÖK_wö†—vöõ k}–Âào—ïBÕ@ÂyÆ\w\Só{úG~zç©Tì§ï¶òôâö€æ.ªû»ù/ÿrïw~0ØÜöæûoëÛµ-?:>™Í#„Ó¾beÿ†çr;÷îøò7 =±b$ÞŠi,ñx+²ÒâÉæÄöñ¦C·c: ÞIø=:Ø"‹Ÿ>#œñ |Ç}ç„K.YTþòƒñ˜wô¬_ÿŸ×¼c<ƒMWf{ð›Lmqx5À¥°2¨¡µ¤„Ë,¡QÄ&ˆ8Ë1Y(ÀnÉ…Uà2A4£ÌÕ‰&àã ³´• aP ³Š-ñÄp! äŒ*üI,€ë¶QEЛ£Å”œa(g¦D©æéôÀ¢9JWX ùNç€:ê±SÚç¿ü_O>·MÚØÇÄ”T‘Ë×g µî­QÚP $ìjq*Êù>¬ë¸gñ“æ.ž{Œü¿ÛO? )Ñ>ž»øó¿këHttÆ;ºcí]‘Ž%ÛîzäÞ?ùË–Öæî‰<^3x5Ò^9EÄ%b‰ÖøÁ+nÜ‚w>M01¤ôå8Ã/‹¬<ãÔ÷¯½kñ8ËÄ{àðyÿTpá5"U9HkÒŒt- (¼´™óú')+)’Ë«FsÓ Zƒ‚u&8%LWÊ­BóL±8D°¹êáÊ“Pi¹jÃi+f£iŽÒÆÕ»ðåÿÅm÷>ã<†¡{éòKŸU«Bï—+`+éZ??òÑ÷¾Ùº®O/J„VuY”#tϯ>ü±ïyx–ÃÁjÖ{²YÄtMГR‹.Å»Ÿ‹6J]Q ×)aHIÎ &Ô*ð• ‚õÙJ¬åkIA*,¨· U Ò–’æ„•N5W•–Kåk/7JS2‚µÐÜÕnÂT’Ç\}ÙÕ_ù§T[ÛTBGlÝ'>píI/[ù¥¿ÃŽ ¸‡ ãÂ’¯ÿž§6nûôGß¶bi§5Ì_¡|nî⹩O~ýc[v c o²%ñl<3Q- å{{×?º}|oøôÒÊçGpbüŠü‰Õ‰ÄÝsè.2q%+3Ï “Ž"u/Ž)oøÂçÎ^ê‹çžù‘­ˆ¥R§¾ëéBv÷cO¸oúZüA›¢á_²üQö|q²PÄÎ’ Œ*ŒË$ðÐXƒy挮ÝZ-*hfI·5Zª*‘w[iÃPÆÜÈÐ Úà(- w&çÆi2½c åÊpfbP•6ØÈ÷ª/þãâþ€=õÄ5Ç­Z²îù™lVÝà>ùn8Ö½qJ»ªDý|Ó¿3ì=ÐûÚ§Û›Ó§Ÿ|Œ«ÓӋɡ߳ÓÀŽÂ±|cÕ)˜G"‘†“–%W´Æéó8ß•ìÜõü^,š‹¹Õ„rù½ˆ0m¢¹©3“ãyVٙû’s!•'èÁÁ²‰å¹üû¯ÿô….õCö˜kì¾ë®ŸÿöïNª+›ýNm `îªT‚£µœxäDJéß½…f ,Jr(Êë*&¼j¸2Ui'ÌJ:Ž$H)ÊCPe‰DX¾®Rã4UèßùñW…ŠY°€q/ûÜͳPp$5ݱûà§ÿúÛ²'°ûŒ¹PÕ½ƒJ»î€ëç›Ö¡\šbñ ¯?û?ò¶Ö¿9°ëÝEB{˜»Hn$†!0WƳº-± ÓË¢‘ñ|dkoJ´å´0Î@µ©DwȘ>¹÷Ì¥t|² .„–0›kAáMÏ<Ô¶šwq\<Þò#ñX(ܲåç7¼ïàÞƒ®Aµ@[Wt§ ]º¹¨àÀPMqF]‰… Ê{\>W ôXzo¶«‰•è3~Æ4ÜT…<‹YõsF€tÿá?}qË~uœ UÝ[©´+ ­@ÔÏ7­ÝÇP•´·5ýù'ÞñÚWú=>]/ÚùÊ¿†sT¡iÍ Þ—àìx¶04Qè/ãÅ‚<Dsé>ôíÉg2r“Ã…<~:ÄFD´öõ‰ÆÅG fžaõóÓÞóqêË~Ž=ÐyòÉïyèî“^ýr@[ý›AŸƒ…<öH‚5<Õ”2$£™òg“ŒçÈjÒ¤ñVÐ?ÚìVë¤Õ/2Aw_™…ÓšTaåù™™½ðéäþÍÀWõ6Í Ç¸ØÈ÷(ü•ìøcW|þOn:í$7q^G¡¯@óŒqñ< Æü'óÝøÆOFÇ&ë}<¼üBö€ÏÍ]Èw§>Ûö<ýTï¦Í˜ZVÀ‹ÞgѱöŽLÿ0g)0Òå¥pññ!Ù·»¥Ì¸±B»%‰u(ÝÙX\[ ½þïþ²uõêúLñÒÞÞõx©ºg¼ÿ}ÅžûÖmÐ|= Œ,öFv~/ÇÆšìÀlåä^ÀŠŠé¼€¦‚MqU%B SÇTtþ¤X‘ 1æ­ÿN`@ð½›…ªœfã–**ë`·ÐZ½7êhYE÷ÈÚÈ·Ê8fÂN&—¾öì‘ÑñM[÷i{÷þ*í‚`•Q?ß´®Çu5¿¸uß½>wÆIkV,ërùž>r=à“ŽÜ{WjùÈß¹ôŠìØ*–®>&Þ7„EsñA~â»ôg¿-ãÇL,†\š†øQ$Šu汸hù|ÁÔ)étëi'\}ï¯J{òeïï¹ñÀ¦ïýÇ=Ÿùó±L0Mgý¬I&»ð[ ‡<õ,z@ï¥V@IDAT|Îm ù6²j>™òGi Ž©#†Í‰J·†8Ú‘.S郹,Ö⥕·m¥úyâáÛ~ËÒ8½U£‘©È£ãº~ùâ7þ‹{ž§¢?íëÈmAtý|£aZŒËÊðÇßwÅûÞv©)øË‘ìsä»WfûÈý?z÷{û¶o_¾te|><ãÒä3JÉ¥h.§ßÒ+Šrp±8Ng±ü"Íç{ó´†%øx—a=ÎÓšÓçþóÿ=æÚkÊúñ ïï¹ò@ßúõ·¾ë¦þÁÙtð²d²‘®*$!gaV Ë /$]Ô«(·®t^íH RËF`³_$M‰=rve\þá¢ñW&žÙC<àY¶-B×ű‘ohH³+üðg~ã?îUêÌú±¬6UeDO¬yâ„905ŒÏ:eÍçþè}~¹1rÙ‘|x˜{$ß½J¶zÖ~æOy:?‰­‰æ Æ¥·X¡\‹î&üàóW²å^ŸÌðÇ>b–'⧯YùÚµwaÏJýxž÷€÷À\yûGüøêëvmÚ>ã°çí‰ÉTåÙÒ »dB›¼äÝW}ÚÆX (T ôbê(/[àÄí}0Ÿïço×®ÀB ÅHŒ¬› [ƒ\/'(eZaphã†ýaJ÷=òì_åVÔ] ãŠqí­M{ï•o}Ó-÷Ì#Â>7÷ˆ¸M5™ÉävíémiNu,_zú;o8÷“¿üÛ¯t¶Ž Œ dsHIÀZìnmc!…(æU`1ïwmÅæ‘)GŸ6+“É—ÿÞ‡ºýî¾5ùÞ y4Ìã™§žß±å˜3ã›7EûõÝ_Wh5X(tÄcIΞ¥óüGJ@M™PË"¶Dg‘ÎKZЗvO¥Pïø">NË.ˆ£ÜÕ­±xš‚4Ô–ú­Ò¸Ü†è¶–wþüGKN=uA u!qÂq+[½dí/ˆQ ãžÉLîá§6íÜ{ðüÿŸ½óp£8ß¾®÷Þ{u9wcÀ`z¯ !¡HBB •R öÒÃ?I=ôÆÝî>—ó5_ïý\ï{wG;;»ÒÞIw’vWzdù4;õ߬´FïÎ,¨ŒŽÂvZV:o<¶³¹£²pF¸-m½ÑÑ‘ù¹iFf¶¬[Wóô³Íë6ôÔ7³{>è“;-<‚öOЗו§Cšªé!¥ë?51á” ïEå`1#¢ˆ_ u»eç·ØX½×;{ubõ‡‡µ?ëóT£÷A¤wtEt ›Ó•2ó¹¤'³¼r!9·³ˆüââÛàœÙ•U¬TDŒÎ…ÌœiRAž¥”±ãã-lé\¹âÀÿq•¶ÜòÇ¥ÛpÙ¡.›äý%<4J÷)ÇÎËϽï×\s®PA úƒ_ÿñャšXåÀ{íë,)žòÆ•(Íhß"™;NËýìÞçÏ*Q³"d¹6(3;ÞÚÖ;84RZœmK½ç_O׿ùfýê C”–^E¿Í ;þöÀ EÞxÃÊ¢G©/‰cŸèéܺ³®fóÆ-Nu«Û,³·½üÝgÆŽNrSšx9 Œ '¥Kz—Erá5©ä¥ü,³ZD‰ÑTå"y¥‚TF+y¥HŠ„“¼£$s}±t.3É“¿bw&ÈOÆfED‰xA`©t¨ƒ¯Ë0–›ßrÉ ç^xò9+Š"¬#@J÷k?ú;Û#ÀÔíê»ë»BðK¬NæÒ5;úèá“Þ||`HúR*>x1Ò5LJwF4mR+¥ˆêÕ[ªˆŽe*ë¶i¹óª5)ÊVŽQõÊGÆÇëû`‡×^‹1jOÅØ Ãi´97X§dÅ Å0U©›èËË;xÑ Çcc/8k1dî„È¥DW¥k,Ouàuó!߯•¨ióóxµV3Ý—öà7¯Ç}iõ¹Ö#7’Àmi뉈/-ʦSÜäð>ªgûöúÿ¾Tÿޮîãá7m•ÖyÁ@À‡š[»×mÞ½k_sCS‡$,%Aé|𫬫Ìe9–¯}a¸©žgSÊyô*)ݘXi÷oÖ¨|S•‘䥹UrØ»;ØÔâ.½N ¢•¼{yÔ/3‰]ð²¨#.<“¹¢©²õSùC_²"ɃKãbïÅÊù 0:š$¥MÒ¸-ŠÆ¥8È\Ìä¯Ã£‡¾õðã5ûÕÍ#Ä2“ÊVͨ©C%Ö¡üÈ ÇióólꨊuðØsOwÏíŸHˆ÷Í4oŸ€Ìõ9RU84<ÖÜÒ3<:FÒ¶0?3# ë|ù 5êŸض»nëŽúM[kGGñK©ªbå &¿jºÉ Á/±,Cv_{Å»ÿ9*-qíöÁ+t¦ Ç™‘’Ò奨fä¥$R½â,¯£²ÔI^žY-"ça­äm<|˜6oãxòª kfÎ9;2RrWsˆõó¢Mr´½£ŸîV¡XúôLOK,ÈK÷“£‚¦a€xC §ohû®ºwÔíÚÛ$–ãBŠË©ÉÜeK*—Ì/?ei«üØÐл·Ý¾mՇζD%6ï.\M˪H+€J!*!è”æº‰ÞÉ$/U »ÜÊRg=—¼-‡ôÓl„¦¥¾Šæ©±S ñq-M«‰ç“_‡0WK™]›¦]¤˜«‰4n¹^ãR[¹®À'•®55.;N^Tñà7> †IÔ” ¹¦`Ÿ¼QZH¡«g°½£¿·ósÓ³2“'/‰ "ÐÜֳᣚšÚ–Fº¥L~È»°¨ÍsQÅ•W2·´8{ÅIs–ŸXåöœm?ûùÿ~þ;ÚÐ[mϳPEL4MëŠyEÉKñb’Ôã VN˜Xòê‹O&y;ípçƒ!Ú š:…0òr ¢¢i£15Šd•è¬b‡<²éÜ+ºÝi\*™+‚õ<Ì”îîý-n‹ð‘ÕŽM!ž™bµùy6µ 63Ï@§Gv$'Äþ¿ïÜ8v©‡ %@æZbtFtuÒJa¤t)žÞTÒŠ ÅÙ‰ pu×qÂ!˜C`ûîúm;ëkö¤ï¢Î‹žrñó‰Ì¥/´'.ª¦C¥7Ò±˜Jñ:É+e˜†;/UÞ!È\±-Ù–)þí7¬B#hiùðˆ4·X ®ÂHÌp,6¦öüks Yf­Z–ânýô¹sf³TüõŠ)Ýo>øww~ºÎj´C#‹ÚŽxJhóóŽ\o+Ï9}aa^¦ç=4~lÿ¡C¬ oÿŠö¸/k kÅÌ´¢ZqTt$¤"!7˜âÄ0Íãîºø®qiQ¡¼ó6È\•ÆB¢Òåã®Õ¬â°¨-ðÌ¥ÍÏ󨵙y:Ã…Ì`£®w!s9óéHéÞýcÉOW«YÅ3N­^U85ï6RÈ*\š©^5·tà<2¨Yʼ|1Ôá0+™kyGßÀ-¤pô¨óC•_VIæBãš6*h8ô´´÷ìÜݰeg]cK—rå¢K˜rEcoP_ÈÜÌŒä¥ *N>avaž¥éß¾íùknìêîó|$ÃÃÄÇJ¿Ú+V^¥:è*.LôJ),•3³TžÄ3S@ S]\*ÅÈ·á£a½Ìk`eÝüåU¹IS£Ô¡T㜡ˆ°°JydÞœd? 5×´E„Gê²…ïÍ¿`è¸Þ#½{×m—b6W‹sŠG²ÒýÛneç£ñË@‰*§ fÌù›@2O¬\Í-'0ë jV+INŒûå}7.˜]Æòãoà @æž¹cdôp[GïØ¡#Ô6ßpˆ¿R’ã1k¨ ÉP"06v¸¶¡uÇîrK ÷£ôN”/LüÒÈßÓŸÍ‹‹9qaÅÉKgÏ(Ë crÕý¿Å§ õõzÞ)ÝE‰q4³«rP®êÊ«T¥úPòJÊ*qרm„Æáš­—”†Õá3Ì"%GÇ$Éû¥KM+•s3&¼%·]¿à›ßøæOÿ¦Êv}K:½{çm—–ÃiAiŠÇ\é 4DjÀ@‰ªçµ6³j’X¹š[ªÑydP³üQ¢TÃ*ùòMÜ…I€_5K'¸ílîÈÑcƒÃ䦛&pÂHKI,ÈO A2è2€@k{O­ä–ÐPSÛÌšS.X~iœ–¼]8·tÁTo,›²M‰‰¯ž~íù½q¬¹ÑÃUu‡Žß24zbb|˜,÷$ñ&Ë>éBN×tõ"¯Þ`%G;ÃäÙnŠaZ‘Qe‡jí†,+ËOÛŽËá Q”xÝ‘A M8»æÚŠ ‚kz®˜X|ÛõK~øÖßÃUïò) ÞõÄ6䙘@B\Ì/¾{Ë7~üWî§+æWJŠ3P¢tn:ÚÌJ¬$e…Í4.Tb¦Iõ.¦rE\Ó“Òý÷ÝúõJ—ŸoÔ„E4®l‰ãÍÕÛwïoþÅ·oª(Î~÷Qƒç s=g5õœ´.m÷ ,¡à¾žØØ(ÌãºGƒXðž@k{/¹%ÐÄí^yÿ$®B¼¯ÉÓÅ…Y§ž8{Ù’Y&ª[­äV•%eŸXýƈ´÷äÖ#GÃcsâbIéÑS÷p#y)‡3ŸF1'¡«'z¹‘”$Ïáp$D„÷Ÿd¿_Vßt¤­b‘ôZM+ˆ‰rXT·î$ïìïkæçoS‹±ÛîýÅÓ›wøòÍ—ÀÁoç…¦bÈ\ nOïpÿÀð¤uF„‡fbˆIA!¸%@·»ö4ÔÖ·‘[»Ôù\¹¶›™ž´d~ù§.°¦ºYš·iëföpDÔ?O¼êÁ˜¦u¯ÿϵ#®:”nZäÑü(õêàä¥6dm«´¥ÎìÊÑn$oœ8µ+óß’§B~d›j%%ʺÆþº¢pv!ܱð^r‘Ò#镯t®FN¦wÕœùŽSºw~ÿ/ƒÃÊœ®ðåEоêð ‘BV:m…57™ªÄ+ßç$ë•89,ýq>Œ+Q3<óúFº=àg÷Þ”“™ª”뿨dþj!$ëííî飛:4ï#YYÉ´£¯Q*âA\ ôõhh=Pß¶uW=mÃëšÁO1¤nÏ/?iɬüÜt?5á“j4.¶TçiOü-ÿ/ýï½Ðþ“~0í ‹ÍŒ”ïÁÒdŸTòR[ÞºóÆÒžÃ“å0ŽÊؘHºL’74¹ìì IÞȌԅ¿þEΊºæ©<›¯å•¨ ô®š!Ÿ ¥ûõÏ^òÃ_=Gµ(QõO45V’­ê‘’jtÔì¡Pvv˜·²}oóu_~ôÑïݼ°ªÌ§0P™žd®žÈ4GÇŽÐvGÒΚwŠQµÉIqiVü­ÓÈ`〉êÛwïiÜW×z°µ›Ìà× ›Ms·g._`qu«r„›tħR;ºûËo»õú¹Uϯ¼±_^ÍPÍì.´mdÌ›MŸr²t‘'Q¨ùX›XòJ­{v›òó¾;;|—!WÉmg}r/y£ÒS—=óTre¥«Í-ÒH‰œ w#ÿÿ=çÔ…ÔÈý¿z–7¥¨SŠPOZ!Rˆ¥B‚š[*ê<ò­Æe6õ ~æž?~õæ n¾úln6>'™ë3¤$m»{‡‡†G=¯‘Üòó°|˜çÀ3 Ð"Óäq[Wß¶mw»æˆ×$¿‰'u;¯|þœÒy³KüÚÏ+ç³¹ÊeÚÑÑÕ—‘’uò)7mþð•‹.¯;Ø>i£»G¥DF$ÊJy<\zñDòRµ4LNu ´áFò²¬‡¸×®PÂÇÁø°ð¨h©Mr¢å”ŽÅ+Û피‘)KŸý‡[K…†åå–E=Ò»b„}J€”îþ†¶¼ø!ÕÊO{ñL"5ç§øy¢9o•þи¼ë>þFÍ–û¾´21^ÿ σÀt@æN‡žZ¶·„Üp=œÁåŲ2’IéòC@òI¨kl«kh§…ÀÈ'A¼©ÛÅsËì¨n9œ2ãE‹ârs¯ùxã{×]¿ñ]I=èØ1¾n`ø”Äø¤HçfÀLh$¯$)H'jäÕÉ¥#%èÓø,¯œ4ÏldÌôãiÃ³Š˜ÉPIn æ±`®zS’N\0÷§&¹›ÇeÆŒŽRT:eÎ’\õnQAæô»€&%pû§/{á­ÍJNõÔãƒEIj,……1ž+e¿j\fË«·lï¾ÿËŸÄZcÊÀùò2wº4i3³ÎîÁ#ž­×#6F«+¤Ã]A$‚ph uêÛIÚÖÖ·lí < R·‹æ–ϯ*±ÝÜ­[VüòLºÎ5Ùÿ~*õ­úÍ_ÈU—§ W|gÜ‘qǺ¡‘S’¤¤ÙÜ0š eÕ±bãaô ZpAŽZ•Ä$¯S*¥P¬&AŽgæÅ……ús]Œâ¨(Z¶ŒÃÌ`’WT$/iÜÿKdb¢b¸›WÚšÇrnÜE„%q½K§ÏŒ€_ |ãsWì9вKZFP=×øQÓj,……1>—ÑØ¶§ùÖ{þððÝ×-?¡Ê¯|B°rÈÜ©:ùßv÷ ŒšZY)S+ˆR Lê›:êÚ4´ï¯kÕ\iØÉÅóÊHÝÎ]b%o}Ø{¦w]Ù.úþ÷2-zõ‹_ë›ÐU—6%ß<4rFRBTXØqEã’yìÖ+>Ëê×Lôz#ycÃÃF=Z9×;0¬ïäzANÆšÛ%dé­Ñß$·å>Æ]2™Æ%#¨f&ÐEƒ˜jÒ‰]9³˜ aÿøå÷nùÚþ*+]©!AÊZTã²3“\u¿xÿß¾Ç'®¾h¹…Xí¹SðþÑ¡QòÇZyšÊMMŽŸZY”»hëè«o’|vÔ4R_Æ5$p#Ï„yòÜmll°M¶ÍŸUâ ÇÂË/»~Þœÿ^~MS›ó†*©WJ#ÇÇלš/nWFšÏìJ…\'z½qçuiSiÛûW&my¹È°ðYÑ’×£¸j™ä¤À„9˧(ÖÔsWÌûÕ#ÏãR‰–ö¹gJiV—ª«\õ®3^üI€Ö£ýöWßñý?ѶvѸʩãxàw/ÖÔµ~å3—ÀU×Wçd®×$i¯òÄ=t˜æ8¦þHMžè簩׋’ `U´ ­“@n ä“02ê\áÒcÍ+›7§xÞ¬’àS·"O~gb‹|ÝjßÄòŠëÖðîM·T¯Þ(×…û_#+]šÓu& 3»£›èå ˜)AÍ,¯4ÁF•ˆ2Ó‘Þslг:]«³|vlt¬ìZÌPêû³C¶%çÖOÍþÁ÷uÅÝêÖ°ãé]·• Òh‰±ŸÝ{ãîûoB<۬㫠ù‚¯˜øŸ×6ìÚßôØ¿¥Ë‡o:È\/èÑfƒ#|_A/JºdÅT® D!º/SòIhlß¹§)ðw’é€.¢»ÊªŠç»ºÕõš™¼ã‹ç»fOL<ïùg’¿öõ5O=O6ê2pMÐwôØÆ¡ÑIÒÏP.2U³Ø$’—¹óòv$‘¦ªg]ó‡\Y¤;£3##3"«’íÁFŠ›¤{ö-Ÿšå™Æ¥ªÙýg\ðs¸Uлœ‰YúR÷­Ï_ö³ÿ{™ àçšÎp1žOÂóA”3«æ‹™+qæ7Ì ØâVãJ:ÆiUÝ‹n}èï?½£¢$Wµ¡)€Ìõ]¤iÓ‡cÇø¹žtÍAN ®ñˆ À¤mCcÇÆö¶ã®©½Z4¯”<æÎ*î¹[WÆ…¹iÛz]ãbNúå#y'ô߯gøÈQñ"-æï6ŠrÕY8UŽŠ’÷ߥ‹óãJ.®©[0»L,îyxR½[gé=ó<ï©ír~ñ† iUZv;šøåM=)¨KÊø‰'›'õXÌl\‰“a¡š æqµÈ’Ò½ûgÿjéè½eå9<o @æNBŒ\††ÆhO³Iòy“ƒ­}½Á…¼Ö$ÐÑÙ×ÖÙÛÐÔq ¡£·ˆŒ4ëN2‘ÏBÚÊ¡ªxÎÌ›»!¸„ÙeZ¼X»dQ"’,¸é£5¯]qõŽ-»•8ý+)ÝDš(‹¡“£‚ä¥ “ K^*Ë5.5Àç‚E©¡o؛㒘èli³bgÕRµ û«Lë’Æ]“Räxcã3¯oœ?³àúËO£è¦‰›ÚSÛÂÔŒ´ššðàÚH-ä@0°h(úæõ7Ýýºkœ·ì<ر2fÊù!Å*qr˜e“ÿJX¥Fà Þk\Ö,Uøÿþözs{ÏWo¹ ®ºÂPx„Ì5„uäè±~éV3ŸMâ¶„° ŽÎþ†ƒ²´m§enÙgºò oZh0R·å¥¹sÈ3?•(ã”§¥×ÖÎ>ñp‚pxBâ¥ï¼™õÅ;V=óŠQ¶cc´ mI´Ó핲‰n 4ÑKg…üßPò’gƒ¨“##DaÔî¤ñìl¤UxÙf<¿d’"É©! ŽFD½P0o5i\zÈÅÈ!òÞ_<œ{õ…Ë®¹xyNf*/nà²zבéñ´ùßîZùõŸd–h>¯=+ž{Jœ”]ÌÌÇZÏ3fà9èm¢©‘YÄRxˆWøï×6ì¬mþnJSy‚Ìu‹vRñÉ­fnk‡c®[,ˆ´&Ææ®Æ¦öö޾$mÉHþák®Á¤nT•Ì™-ÍÝšk‰5[ŸYšûΚÌ6š\li7ôCpkÿIø}Þ‰KŸýö,€°axÄáˆ/vº`…‹×ravÖUòRs’Ìäs¹ù˜iÌjk’ª[-WHI®©dRxZòÀ]w7¬¯u´öˆ9èܦ_Šÿúìûô\¾¤òÓ—I“»²š?ÍšcáMa¤wuùqH§,™}ó•+aµædPô¬Å5."³·í9xíWùõwo­ÄMi^ž:¹z`‡¥_7Ž|²ësOéøÈ‘)®›3¥ÖP¼#@KæÑUœÖÿjhê¤%À¤Âòõ@s…ð®J_æ&u+må0«¨ êÖc®ÊÝãrÆâ[oýÜÒ¥ÿºìšžaõ_± Rº$Oó£Øœ®:9;ä¥ât"M|›Ø„Qx‚³qflL†àéËÍ¢"¬TDzÊÌ?±¤¢ò²›Ûjê^[õñ[n'u+~£œkª÷Ó³8?ýªóN¤ûÅŸŒG†¥ï{ÒƒßàÆ¥÷ŠÓ4ÞUÒñj/Üpᦵ;÷ÑîhòC&[h\frCKÏMßúÝïï¿uQU™³xñ€@Oz9ȳŠ¡¡CÃ#Ò®füÔ§EĤCþ–PÇåKuŸÁ  U—žš˜™ä4Ñ=[ •ò¸´muÞ·äÔR?ä³Ýyõvy;¨ñšäX9ùí£ p}±îÔ«V¥¼ÑœÆÇÓÓ’*É-avqÕ ùWf¥N¼xé­ l5%–á¤E|÷£ÌÄzñì ÷Ö6ºÍC“¦ç¦$¦FD°zÙòq¤"ü³T '•\ÏIÙ>¦•ܶÂÊ%‰ñ´áÙŠÄ)FjX–ÓJ2k‹4n忟ˆ¯¨T¢¥×ᑱ5í~ùÝͤké[%çq]sáI—œµdaU­ºs÷þ&' \ô.O#½ûÉËO]qò\ƒ€):ºúoøÆ¯†ÆØÙ 99…Q‚êÕ_Î/®dâkú Ây¤ùhT ê Pê6ª(>rϧ/<Ë/(¼&{Ål®“Ðá#GGñå­fFð‡§º?°Q…ˆ)hjîêèêk:ØÙÚÑ××?$|öN¡2IOM¢Ån/¨ÈÍNóWAZoyI.S>£9…¾’«îU>Üpó-«^}×µ89h¿Ó?t^J"[*5$J^ÁJ;ýc¥ü䆑#óV¸ýûc~8åÀX{Û«_±·A¹•G¨(=2òüÔ$ç~fÊžÎ+~j ye÷UòJyvŽŽmó~ÊY®=*,üœ”ÄxÚ BÛs%H¹éºÂï}WlÝÛpmcÛk«>¢µuéNµâœ´¢Ì4åëƒKM:±+§ý‹WT”b×VV&E¬«®ùê§Æ¤‘âä§²ažCû#€MAõ ÁCFYÈî¢.,šUø—‡¾¥;Á©¢2÷è±ãCC´œ‚óT ¼Ì¥“ãŠòá°5Áɉ$:|¤Yš²í'_ÛöÎ~¶æ•ç_Þ´ÕXGæÎ£ûÉfJê6¦hÇÈWG¢Ì¥:×=÷ ¯j~wå5ß[ïZ›¤tÓ“å9]áj>™ä¥zhŠ¡ãèÑ·]ët£¨åÕA.¹•1Ñ’Â$Ië:”4nþô4®R™ôJÎ ÿzñÃc‡e….'x¢w!sE†V¹z;·„ŸHc¤8¹:5ÌÀsJã2ûK Òÿ½Û°ÐM] è>Y¶œ‚ŽE€‡FéGäÔäø·‹æìN€tmW÷`SK'MÙ’º¥MLXÄ_Ëö1.6†Ö›=³°´(êÖßÃDoAòù²µsž}&ûÁ¿õ«?V¾M±Ú{ŽÝ<4²<%Ü%œíÑ„*¹ìÊ:‚¢ÂÉK©ü®- “;/óèu–r}Q”ˆòªæ(ŒŽž#oÉ&w˜ék&y“oö¥Æ¥&É“asõþšý²ƒlŸoÓë]Á™!?›ýªãe…¹.¬ûØéº žQ⧨Ϭaž#°—`64÷|êîßþëwBéº=µBKæÒ<íû@Û›¹eøHúY™®ô¸Øž¼½Zdº–\ººûÛ;ú%]kÁûÆ& š–š8wfQiqö¬Ê ²!É·N^T±~K-«“$&-›5é6¶ž0ÿ¾ï¦/Zôê¿Ú-/ÂÈ î£ðòTZÍ€$AXínFºL20ÉKÉòa¸Vò² x=‚lƒj: E‡…Ÿ,ï÷¦ÈjRö’À¤ÿ9¿ùyòEê Lû¸þ`‡Ü1Þ ³Æ ô.-ö<ífQ/ ÐáK7œ÷ðÿËNLVµ¡„U2fÎPá¤vžçÎÊ…KùÉFJ÷¢Ûö«o_ñ'X¯ul ™KgçÈÈa’âG¡EÆ€)ÝÜœÔÔx/XdLL0ƒˆRX4H90Ì d7e—ËäÍW~Šb t9 ¿Ì=vì8Mâ=*º‰Ì“Òmní!á¼Ìx™?± »gtmw‰Úr±•¾ƒù_‘øµk±1Ñåä“0£Ô-~ð+jÏ+_:_uZP§=/ïYΰ„ÄKþûRö7ï~ÿ‰gS?i7ô EG†—'ÄJ Ï2ÇU tÍá~»²ä•5ù6HÚ7#2²ÛãåÃ#NHŠc«Õð )Â3’³ûmÜÂEžÙîu®ž¾AEù(Â]©ƒ¿…]õ.eééyêÕõô¤[ã?så+0¹«p3ñuÁìÒ•œøÌ¹ |p¥倬ÇJ(9LÇ•­R-ù2”.åoËÜC‡Ž’|T:kéWÒ=ä9——“–/-ýˆG0 e=‡ÇZÚº‡G;»;»øç¦[_+õ=-%‘ÜJвgVØÈìP4ÕÏߣNüù/ò–-{á«ß<¤~ä®îpä8$¥Kv!ÖI^Š%ÿ]J•%otD¸Ãp»_>hÎ+ú©ÉñÑŠÔd·¯Ed¤d?ù·híF¾¼˜O£ÂFB\Y8'ª•ø»›éݰð°ä¤Ø¾çZi[öüêOžJIŽ»dÅÂë1¹«@3ëõ3+Ïæ2—¨dŒrÀGSˆcÆ*9¬¤q™MPºl„Øß •¹tjŽŽ9|xòL‡¹á±±#u )Éñ9Ù)ÑQA;4æB@ëtÖu÷ÒL-í 3 Š ²é˘Ó¼X˜À¶šúÏ}Gr=d»n¼à†+ÏTŽüõ:><üÂe—ïÞº—7@s´§§ÅDÐ9LB,;Wã§ìññm}#Õ}ÃJAž D(¯äÛpi¹xÉä?Ñ‹æ¦?úHdŽß·`xþÕµo½·Åi“ìŠU⫨wgÏ(üÊçœj£­³ïƒM;Ÿ}kã–šƒr´·whhdŒ“»0ÿoaºÊPIRQÌZ_ã²Þ@éÓ9ŒŽ!wz7(çªúë˜íœx'øû>Hiñ´´DÚ8 z×·Ÿy¤hûú†™¢%iK‡-m½JÒÙÄÎ)F9·t2W&gváã_ë… r5ÊuÑRN ´ZBiQöŒŠ<¸%HƒeW~›÷㮛οñʳøaC;·?uŵ]½ÎE¸2â¢.*ˈâZPy“8-wtŒ~µAšÝ4zdÄD]–—&¥Êï³øO®L½óË´ÔƒQ~ŸÇþî߉uêõ.Oã}t8NXPþ¹.à)F×Þÿèu;^Z¥xDÈ]\<»ð¶+Ï<}Ù\¬¹kÄÍWñ?ùÃólB—VSÍÊç=kD=²‹ÆevÓUæ¦ËNyà®OúŠ•½ê™ü«³-úsôè1šÇUµˆ-ŒöÞHi›â–®ƒ-’¹©ÉäÌ—”A÷&ãá1Z•–òÒþsô—v^ ›Ãz”k0Åý)ä–¹%̬Ì/.È‚[‚[>A¹ç@k€û’8wþÍkß{uåµ5;¥ÍغG¿^×-)]òO Í@ZPú+E’—,l`etxøÙ¹©’oƒ¬7⯽:í›ß1Èë—h×u{ø×T½ÞU¾ÇR‹ò3=±†èùÀ—?ùÁÆ}á½jÙy÷㚃w>ü”¤ØËÎXtãå§Ï(Éó¤*䙋ÏZL27(5.ÑxâeÉ{!4•n0È\Ú¼—Ö(˜Âimß"äÚÞIû¾JŠ->6*..–ôn\\L|¶””F•VJ¡-rööKÓHýtÑ!\ü¶-~ ?Ô¤’¡ô(-ÊšQ‘_T·„ v.#©´faà{›sõﯾåÆþ»ŠZ—”n}÷å3²$Kè·7I×Ê¿yÈ’7;!FŠ7x,ÉJ¤ïõì¶ø•W§ÝPKFÑÆ„¦9=)õb—rÓg ÿ¸1*,ÄÓ¬íÅgž@OºYí½;þôÜ{µ»zFI¦Ð“&w?{ÕYg`rW æ«à‚ÙeEyi-ò"!A4ËøÐçÀã/¯+ÌIÿüµçùŠ˜]ê±·Ì¥O’24•kÜþ°“Ö” 'ÝéÏ>Kb¢££hñ]R½11Q1ÁëÎKkO’³Ã£ct¡ìì’£íí&çl~+·à3àöö«“6n˜Qž7£¢€f˜èô°_`±—–/®Xû±4“jîcÅßžÌûÓ_¸ïáÃÇŽu^ÓÜwjam„&=ä©Y) ñ8“"ÄG^BLUze¦;Ø’îøRÒõŸS›¸!ÃÉ݉‹¹K¥›Õ®»ä4zîkh}éÝM¯­ÞZÛÜMS¼w<ôdzrÜ¥§/º‰&wK1¹ëŽÝTãnúÄé?þý‹TšŸ’rMê‘í| ÞÿüjAvú%g†ÖnÀ6–¹¤êÆI«†Mõ”Îr´O,mºÞÕ­Î ÄÇG“cCr¢´T²´Ôx||l¤µ]¤›½äÏR±#£‡H­J‘ÃÙ×?|舲²2MÂ^Cyjvâ³™V·%ÛeùY¸ŸlbRHõÊÏ}áÖE‹iUÝ®þѽ]´jXØi%iò{Vòc•–V$Õ;îHЉ<¤¼ÁchI²sŠÓtûÚøxêýÆŸs¾’Ð׿ÃÙ\>Ô»ä¨p÷­—Ó“V"{g=­¼»¥§_ÜýÜÕ˜ÜÕ±Ÿúá©K«Žµ’B=Òh 5šÎYõ€‡Ä‹$Ë”K–d¤ÏOÑzmf5»’*TÔ}gTâÅHjòŽŸü½ÃRJ×®2—Ô-ýp+¾%ŒÂô >%õ÷Ë¿W6 ïÉq¦z¥7-ƒÊß-©) ¬*öö A<µÍh–}`HÞøGxŸŒæÛQ‹l*š½õIÎËB–¨oTå«ù`0ê0âe11ѳÈ'¡0³¢,/&·!zZ?½ÑغÎ÷£y$2N<éæõ>É¥uZ÷v Ñê §‘x¥‡4GË.Øa‰Ñ®2÷Œ¢´¨ÈpÊ–úÃãÏ2Gã’™ÒWnùÓL¸Álšô!–––4I&Ï’O?q.=ɽ’ôîÛëvÐoÐ4¹ûÅŸ¤ÒtƒÑ•ç.=aN…g5!—{´²Ø¼™Û÷6+Éê¥+84.ëW¨)][Ê\YãáÊG9#ñê5IûI ð=2;YEìKªê ¼åù—W6üˆ.Þ#¬ÓB&©Ý¨X¯{€z9Y)•åy•4q›‘¬OÃqè˜U–ÿæêíì'\¿MA®ºŸÞ´éÝë¯[ÿƇ{;†ò’c+Òâ%]eá3ÚWg\ij|aj\xRRê}ÄžxŠ.5‡ Ê¢¹üêã‰ÞÍHóñ;‘éÝ{>{Åûw¾µvÛs«¶üýåµô¬(ȸ}åY—Ÿ}"–e˜òY±lA¥ò6Q.xǪ̀PŸæ—´Âpk{£ä0Ì gWO%?¯Å¨ Ëh”*ÙæR¯SNU’•Wž:IAµÓ¼„& öE-ÀÒÅ+‡Ó(¨T¡ué›6Ã$ÉÆ&OZÐÒ$EàÅk;4•£I ’ª4ʢƓ—휙…KV\xÎ’% *Èï–œ³§b Ê­»ë7lU}s?ݹVèbùÕ+ÓÂÆê6TèN‰J‹–V]ômØð‘c­ª ,ù0\0#+2%9ãÑÇbæ,0×øwVoë—§\͘@¬*ÝGºb»´žúÌÒü‹V,þüʳæUäµvöî<Ðööú]¿ý×;õMmt;riA¶˜aOÐÝ,/¾³YüÔ >Ë8¼¹fÛ9'ÍÍHõÍO ž°5+ÍfsIãÒº fÁB» `)Å™…™¥y˜¸µÔ¸Xʘ¼¬Tú>¤Ÿ µ€‰ó¿õô‹^¹ã«ïíïr̫ȈwŒËJWkëéå1i)éÿïQ%æÏ<5ìàä˜*ç‡ü›ðz—göm€æn/=s)=Ié®Ú°ãé77Ðü.=+ 3>}Ñ)Wœ½4/Kö ñm«AZ[¥´d›:ƒ¬—F¯{päê¯ÿê­Çî úÓÃN27H?XÐ-/¤$Åd»mA^:¶(?½I^V,ˆ5îqù#¡wpô ü婟ÞÜ^.¶‘¹t?÷5:AÁJ ²,· ?ƒ&n“サèWÔ6¶Uç !›H()»yÝš×o¾á•ª/›Ÿ—•žà\ü;)6êÄ3NÊxèWañΛb=¬ÓOÙº{éFW×áIõneY —ý"½û…OžGϽõ­/¼»ñ•¶<û¿Ó~õÌÍ—-¿òœe3± Ù„§Hq®$sƒ^ã2ínúÒþòøÃ_š‰½í!s¡qí}–Áú)ÈÎL&i[^’K·Sª…@À‘“™æœË•†GäÅO¬†TìÅϼóÀ÷ßzìÉó«rØ¢dà…žœû³ßZDã’=ݽÒBÝü–\Ïõ®‰°IÑÞsÛôdz÷å¶üò©w–Vݾòì3—ÍKJˆ5Ñ6Ë6=»¼`õGûUó„ŸBøWJåÑâm-~ëå˯>oÙ s± U)@kð©Ç»&(5.ëéß^^{ò rïV;D!«Ë\hÜ :ÙÐC¥9ùyéy™™éÁß«!$„6‚+W®œ=û­ÏßžY”sîK¯Z FÃÁ.q^œ›ç‰Þå™MH󻟽‚ž´“ð[k·ßðíÇÒRâo¼dù'Î91èoEò~hh\ÖËÛüäªÒ‚ th±´Ì…Æõúm‰ö!@Ë#ä§—çäçÂ'Á>ÃfCKi¿ß5Õû™3@{gŸc¶uûX5ïªÕkºëê,h"í á´Š«í¢nõn-—A)@IDAT¦U—¯&§z>ôÕO‘Þ}síö3o{øœe³.¬è݇þúÊg,ºêÜe³JóŠwü¦mûY*—Æ”^øâ~ò'wÙøZôB+k\Úã°=r±-+ÉÉËMËËIÇ: ¶Nv )!Þ†V[Îd¶k:™¥Õ´²Lïº$Ðü®8çg¹.i bz—âh~÷o/¾ßÐÚyÉi‹®8{Y¨Ý©ÖØÚÃÁ„È<.ïï;›öþáßo}ñ:ÓöÓæ–ø0`E™KŸ |ãYvU@ÀÐL-¹"HÒ67=à ¬#h(Ì*Ï{}õ6 = \öháÌá ÷ÞÛœ5×»«6îxðÿžOIŒ?yAåY'Íã‚8ÐÞÕ×(/šK} 5ËNìþôʲùÁtc¢e.¹äñ»] bù¹i¹ò¬m^¶ âq¶eר5ÌN ä;2¦8æ Æy¢wããl¼íöYËæÑ“zL›«ýî_oRàÊs—åõžj[vÕ±MËú~ãwÛðÏ‚fßr2ó¸ì<Ã_»pJÛì´\H[»ŒYˆÙ™—­~éjnW 1 ÓêîÁæ.®{tÛžQ½èÝ’‚Ìi5lÂ4•ËfsIï¾»~ûu%lVg }cÅ“/~@ñ±–ÃΚEÿ>âRá@Zn}\Ö n¡qwÆ{G¿ý˧~ûÝÛœ=·ù‹µd.¹äŠgŒÍÙÂü %‘ž”›“Jº¶¸0+h;‰Ž yé\vu³ù¯éæHW´7{p ä…ÞUÊÚý5¸]Ö~´{ûÞf>¾4XˆBuHyfŠ"-£&(!1Îm+”QÔ@b¼B1RµO0UjÝ —5j…Ç?û¿-+ÏßAî+Ší6~µ–ÌåˆmL¦)§´ÍNÏÍNÅ" A:ÈAß-ºÌñ+]ÐwÖ—ìèî§ûÉt;Ÿq¥2Þõ¥¨ËŸ†FÆ~ì%>¦Ô«ˆÊ„GJ„!h{Ë0ßñàÁáº`!™+žIþ<™Q7xJ #-1‡fm³ÓrHÚFYèÍâiŽŠ’<Ž¡± N †úFi51·+ãJñŠ"rÕ»q±6öÍõý³þø·Ï4´tó~pÙ**) ºp ƒDãRÉu²ïý윉MV¹r‹g’MQÂìà ž–Hóµ¤k!mƒc@Ñ Zïý¸|s4)w‘‹Wøjb¬”çz·0?|s½beÇÌþþ¹×>ØÆ-ç²UT&<’²½Æe(~ùÔ;7_qºÝ·Ç³ŠÌå§ x²®MÉÉJËβúZƒ€@jb\ßÐ(»AÐwa¯°š˜®éIõ®.?­F€|îùÉ««÷qøœ qˤüÝ¿x꩟Ú{ÃKÈ\ñdâ§ àW¹Ù)ÙY©9Y©¶~åŒÊ­@`ÞÌ‚«÷[Á;ÚÐÝ«Þfd¿‘Þ5Êx+ {Îîýù¿û†F¸1и Ÿ®~gãžÍ;k—έàˆl°„̵5lGä\›•ĤmjJ‚»›A`ŠèêÍ.àaZ_^{aŠ5…`±îîÉe.Ç¢Ó»qv^7—wÊw>Ü24<682º°ª¬¢87!>Ö­ÕI÷©—VÓw?îWM9¡q.®q“GžxýŸvžÐ…Ì5z >$ÄÇÐd-MÙ’®…´ †E¦D`v…2›;îhëì…ÌõŠbCs'¿ð‡y¼&Ó»…y^µ:™Ï=muvxdl]õî7Þ¯®©mÎÏɘU–WQš—›™V^œãµm«7îzî­l«3h\WÈüT§$¦ûí>¡ ™ë:ʈ±7´”„ÌÌäìÌÒµ$síÝX¾ ”ç‹jB´ñþ3.<×»!JͳnÓ$î¹§-¦'e_[]³egÝ/þürS«´ȼù‰ ±'ί¤í¸*Jhº7Ž&}=«UÍE®·µ ­ûë[÷Ôµ®ßº¯¡Y]iWŤ„øéM|n›ÂϾ½Ñ¾~ ¹ÊðâÕ¶¢¢"R“²2“³2S²2’mÛþ"@r]Ô]W¼òW“ATFWn\@ïúj¨—/™MÏ;n¼è@cûÖÝ^zgóºkéIõ‹’kþŒ¾íÒùn|F7mwº¡¯©Þ¯¹íR¨×uÔø)­N¬þòÒšû>w%ÇîZÖÊ1¹VØfH€¦iIÑÒ“¦lS’ã ó!@Àá˜Qê\:—®Xûê[ÉT<$ÐÝ;H9¹*2Ò»nÅ.~Mò².y,ÐóÊ N!—r¢]µq×ú÷÷JÙÆ´Q™ô*‹2²rœ”¢!È\ûŒUÈ[J¢63#‰tmfz2Íà†<©–åÂTІb&syÏô.W ¢Þ--Îæ˜ri8oÅbzRÙm5u«7î~gÝr«Wg5œ¤‚•4.#¡™†Æ%à¯~¸2W9¹ð >"šŸœŸ•žL󵘲õTTŠr³ÒØÕÎã¨B‘’Û>75w„Å+Ëæ•Þu[3"½"°`v=¿tÓÅ´TȚͻ7o?ðÆêm¢†ƒÆuž™ü+—Hdz—j~{ïÆË:™1›k±€%ލÈš¯MIŽ£ùÚääx:éàK+heÁô+þºzd§œWzWÐÁ*`=¤“ùª O¡çCß¼ž\ªwÖ½½v{£°O/æqÙX(ç¬t$΋#%ž¢šüʼ¸XЦ èBæŠ#ް 2Ò“’“H×Òßøø¸h,@“ Rã˜wcñž^!€Áë.Ö7uŠe¸,ðDï–f‰eö9å'TÑóNyŠ÷ÃÍ»hŠWܳW‘jR³|ö]; 5œFä BÐqœ¿³éEŒsÛŠœG­F 9Ô ÅH­ÙjKÇ xYãîð,jm.–«I¼b…Ôø†mûí¸Þd®:´†‰Úô´Dµ g`E+ âæÏ,Xý‘´£é€°çSˆ3ñ¤ûuMm’F’.n&лñØÂľÈCS¼W_¸œžÓAS¼í8°aë~v³UÏu›v¶'j8Qò‘3S8Ä5®“š _ sm8hv3™´l’¤hã“%k7óa/€@è>¤tžk!Ïõ®R¯$À¦xïrHþmÙU·yGílc?eð!„Æå™P ÿ> òq~Ës8Ûºy) sm4X¶1Uµ‰±I‰’ºMO…®µÍÀÁÐ &PUáœÍu.ÌÄ]õ]×öÖJkW¹<¸0ðTïºÔ€ˆ@ )Þ N_LÏûîXYÛÐöñ®ï®Û.mð+LØò±$ƒ„h.í$;1ˆÑò[¹~CJ§¥%¨¦ùÚ´Ô„Pê:ú ö ˜Ç®èÛö´‡Å°²«w€KWçÅ™ u¯wgUZ 0A"@û¨ÑsåEË)¼ewÝÇ;Ðk[…÷hÊ j_h\ ŸÌ¤8×–;WCæ²Ä_/DFF$&ÆÒžº±±1´- …½(Œ¬ fà;‰—p3 ±S›ÝÝÜ\.ƒ<×»¼,–"°¨ªŒž·¬<‡¶Þ²ëÀG;¬ß²ŸK^ñ ËŽ1¡i,K£‡Æ@æz*¤³%$ÆÆÅD'$ÄÒLmlLtllTHã@çAÀ†f”æÛÐj“MÞ¹·‰~àÓ [è]“GÅwÍ'ÆÇž¶t=¿r³ƒIÞÍ;¬ßꔼиŒ4×ýËæWúŽ}àj²„Ì¥ÑW&p½GKîDF†“¢MLˆ¥¿ä‡@{4¸Ë…8›àú¬­«/73ÕfÖ›an{W?5Ë/OÞêÝŒ´$3¬F›S!À%/&ÉK޼’äݲo‹¡c—'~¶P=jÁÁWŒsˆñ¦¯Æ r«* 3gÙó«²%d.…ÒågUà´ClLTtt$í£K›°“OBàm@‹ ~%PY’Çëoëì…Ìå4&ttJ2—?¸‚ñPïBærtö ä]±t=Él’¼ûê[ªÉ±aëþ÷7KKòу¯H ‡å(ù?Ctñ|b˜«F)»p Ô¸dì}·]*ÙlÇUd.¡£Ìêà¢]sc¢£bb¢S’âbb(„PG `2ºr›lÝšßSÛÌćæþ2¹LÍèÄ.¥ðùr­›ƒÝz{ôÆY<§œž·]s.EÓ,ïÞúVÚ(aǾƒuÍÝ¢< b{ÞI³®8ûDŠ‚’¹„-<<œN”cÇÄ3ÇN4­fkDD8ÍÎÆÇÇ–¥…Êc¢#!j­6F°F 8?½¡¥'`ÍÙ½¡îçýgü‚¤Ó»\ÖL wíöë0ÉûÉ‹O¥ø¶Î¾} -›¶×îª=¸jÓ^ž“Ÿ0ó¸i)ñúÁçyïl°–Ì%|ôyA?š—â©b;°&LKz‘®‹‹&ENkÖš`š°*’¼ &s«w ;Í­j¦UìêêÑx,Yüšä‰ÞWUl•žÀÿÈÍJ¥'óm ¤‰Þº–]Zvìoú¸æ ÅÆ%—Ü'¼¯Óâþ­Õr2—u—¦uÃät%µË?Zü‹ÂNµ'%Æ ø¸Xr¨ŽŠŒ‹&k§ÀV°6{šœ^..ü¢ä‰Þµv/aϰ‰^^]µSõ6oß×T-«^)‰Ÿ:š EýqÉWæqm­q ¹Ee.;QÂÃÃÂÃ#臡ջ¤c B\lŒä~CXhA@À+ËT¼·YýiÕ«²!˜ù@c»³×|®Å+½ËK… ;tÙáX2§œžœ©ÞÖŽÞÝšwì?¸¥¦©gp”'Yðž3šÄ¥{ÎìëËÙRÀÒ2—Jn ô”Ýv¥ùÝñããÇ‚é$"<œV¢%9K«wQ—â$9K1˜ e'þ‚ø–ÀÁvxèNBtdôÐàð!ýodüÂãÞ--Êž¤ $‡IòÎq\ræ ¬Ó­½ô$¿Þ¦öž¦¶®êš¦^¾îæz¹ 8ÒÕuîtùIªÏ¯”+Tâ¤:Xå4ƒû© O ËÈØ@æ2Cé¯ä¶æ Õ®¢œS¼Çd^6Ý˳Y0ÁVé¢;ÀÈÙ "<,&F"O‡¤q-h0L>3Ëœ;Dlë¾Þù¶GM-]Táq¥RýÇ4—Æz—î‘PJãôò²Òè)N÷ÒÊe{ê›iÆ·¹½wçþƒ}C#Õ{šzúGxI¿jÜsOšuÉŠEçœFW3AÌ"™ky´  æ(ÊI'9×Ô†Ù\•WÏ@«æþ3¦`5b—r{¥wÕÚ0‰d®IàÑ,€˜D )1ŽZnjë6©}+6Ûp°ƒ$¬ËÍgn§k%û'лU3ЬØCØ!I27$‡a³ÊœkŠ…0}×IæR”‘x5rf˜°ˆ¾ ƒždnà™£E0“@R|ÍRö Ž˜i„ÅÚÞ^Ó$Z4½ß\‘% `&È\3é£m<¥Ò~¿Õ5ß´e[üxGÙæºÝÃônqA–e» Ã@ Ô`A±Pqô@)IØ$B= hcv ¬~Ë]rÕ<¤wÙSr†(3{º¤ @Àl¹fÚ€X2»è¸c|hd,à-[±Á]{ufMYïV–fëªÂ!€€‰ sM„¦A@À)‰ñÔðžúfsš·X«uMFS²ÞêÝ„i <@,B2×"3@@ pæV®1Ë·´uW=·ÑWz—Wˆ€€‰ sM„¦A@À<ãŽÖŽ^óš·JË#£‡Z:û\­™šÞ? ‹æº²D ˜F+-˜† ƒ€€Y–Î/§¦›Û!s»ö5Šñ0’µÒ#lÜeç3–@IJ€½’? ¸®Ï Íˆ#Ó@暆 ƒ€˜N`×^특“é]Ø%ûE½›•‘bz`€'™ËQ  ¡Bà„94ÙÔÖ*6îçþ†¶ñãÒ¼lX¸FÁÍï:§p]&w©Ò»™¹Æ¨‘'™xæh@,A ±­Ëv˜jÄÇ;êYûnÅ.%MAïšÚ!4  €ÌUY  ¡Càì¥3B§³F=ݽOã±@٘إ€nrWJ2ðgçw«*±„…l〠°Ò‚ ÐÑ$€˜N 5)¡®%ÔgswÒÆ¤RÙS;$¤wÙS-‘ÞeO]×»ºx‚˜E2×,òh@Ì$0·¢ ö`·™X ím»T+¦­wó²qÿ™Š!°8-Xa`€š@R"öërTï¬×ÜwÆÏÊjÓ&õgÈÉJ ô(¢= `6wB€˜D`IUñÀШI›ÜlÃÁŽÁá1\éNm~7!¾¹:¢8“ @æš<h@Ì"‹-Њ¹ãÒz¹Ò#ŒþiSÓ»YØéW‹G `:8-˜>0@Ì!0¯²hÍ–½æ´mv«k?R;Nz—=]bÎ \õò ný2Ó“y@¬@³¹VØ &(ÌI7¡Uk4ùÑö:2$L;;éü®Î™jà÷«%ÇÃcÁC +@@ ™+À@@B‰@^vZï`(.(¶k_gšÅeõ.ŸÖuÕ»e¹¡tî ¯ `¹ö'X  >'P¾y—Sðù¼r+W¸sO£Î<¦wub—òÍïN wu5ã@ÀD¹&ÂGÓ  `&¼¬43›7¯í-»ë%+=4^ F“»”oR½[Y’#Wˆ? "€[Ð,40@Là„ª¢ÖÎÞ7jns#£‡ªeÇ\Ù »ì©1ÊyKšâÒ ¦±›Õ¸êåIXMŒ£@¬C2×:cK@@ ÐR“â›;zݪ©íÑRbîÚŸ®ÞÍÎLqW-â@Ì$§3é£m0—ÀüEæøÖwÔ4Làœ 83]Þù3dbÑÜÀ%ZÉ`6w2BHà%’[s ´öû]½©†çÎ Š3ƒÞqÁ¨ö†àTë€ÌµÎXÀ4eó+†ChM±Îîþæ¶Þq>«ð6¯rºGþ YØB‰W°8-Xg,` €€€ lTv}ãJ7L»ŠÀÚhfŸÙÕû3$%`oÿj©ÀlîÔ¸¡€¥s+>üXÝö6º4a¶înÐ¥“Þe—xçÀºxùP?¿;£{C¸ã„80›fsÍ´ ¦HIŒ3µý€6þÞúݬ=Í|¬Eb×™¤ÈU¢õ;³Bò_×ÊXMø  `2È\“̓€€¹Šs3Í5 `­oܪÎ[»÷?Mñ^ïŽ/ª* X/Ѐ€ç s=g…œ  „ú†Bå´í5¤nuS¯>Õ»Axz K `k¹¶> Ó%Pœ›1Ý*lR~õFÉcÁH×ÅKEdÇÝÍjr¼³çsg•8Cx°Ü‚f¥Ñ€-  pE9é{êƒé\i)±ö>‘.éZö#)lÏnU㾺b1·‘b„AÌ €Ù\3¨£M° üœôÁáQ˘ã/C6lÙk8)+·©sf 8Ò»ì¡KruÞ3³XÉ‹W Àl®…¦€€@à Ì*-|£oñÃÍÎÍÏ”9Y.b¶MâR²Q’QUïZpK2×-D‚€@¨ ­ 6lÛܽ=´y[®F"ÕHÔRq·I³°h®Ž,AÀ2à´`™¡€!  `“TšÔr€šÝ´eÏ-¹:!°Ì$jÙCç´@‘bR"¶@S@á¬F2×j#{@@ Ð’‚|‡ˆ5›Õs'€;5½[Yš7AH0‘d®‰ðÑ4€X‚À¬Ò|KØá7#6m¯% ëº"˜Qƒ^éÝ„øX£z `.È\sù£uÿظeïàеa$^'hÞ¨ˆè´PVœ=A H0‘d®‰ðÑ4€€€ß ¬ýHï˜k$^'0ŨéÝ„8ÌæN@I `&È\3é£mxoÃ.£&ŒÄ«Q~Šw-RZ”3A~$˜H2×Døh@@À¿hWæ±0q3®âuâü”ÊŠ¿oB\̤™‘@ÀX7×ìh@@ Ö~TÃ%¬'íQföð$3å™YŽ©\Q!˜@³¹&@G“  !ðÞ:Éc”+knú‹-èÌúµØtýÅ!Ø‹d®½Æ Ö‚€xJ@òX–ÖXà)ë]#}¼¸ª”WŽ€€Õ@æZmD`€€€oÇ‚QEÞê]oóµ‹x@€Ì $m´  8Ìcaâö˜~5š¬u-«Ó»óf—¸æA €€E@æZd `€€€/ ÇÂÀÐXX˜GuêÄ«'eXlæ +ä³@æšEí‚€ø‘ÀÚÍ’Ç»÷ÌC±+ç÷îfµÒBlæÇADÕ 0M¹Óˆâ  –#0Ô»eÅØéwzC…Ò àg¹~ŒêA@Kà߯¬å N°RØôõ.Vãœk€Ìµæ¸À*©ر§¡¹­×µ¤?ônYfs]I#,D2×BƒS@@¦Ià­Õ[&®Á‡z7!.fâ¶  `.È\sù£uŸ9äzó™QíÓÔ»K”ÕŒx‹€ÌµÈ@À é–Ëcµød'æ¿«[|—ê§õwãã¦k.ʃø™d®Ÿ£z@øÏ«âÍgÎV§¯wÝÞ¬6£47PÝB; S$>År(  Œ¶×Ô8'DíÕ¿º¦ö]û[¸$åÆÓÌ+{ò˜IäÏÀºœJMÒ–9X4WG‡ `=¹ÖX æÈÉLÛVSo^ûSoùù7ֳ¢«ó­ÞÍÎH+G@À‚ s-8(0 @L#™²eWiÍOµaš~ñíͺÒLïê"éÐ'zwÞ¬ך `)ð͵ÔpÀ©xñ­ $^ÙCçŒKb×ïÓUmTD—M<$g:LJŒ#°&ÌæZs\`€˜F`pxÔvî¹/¿ûçe4YkäÌ@Šð:uÙùº‚Xd®&€€™ò²ÒÖ~´ÛL ¼lûÝ5[¶õ¸2¯Ó×»ùÙi®Í!@Àj s­6"°@L&°pNYõÎ:“ð¦ùWW},g'wöÔö¹ÞÍÅ2 zÆ8+€o®G6€€‰hãƒÛjM4À«¦·ïiظUg­ä>+?×L›´mwtõ?ÿÖfÚ“Œ=´‰¾œßuÕ»9XML‡‡ `U¹VØ æ(/Î¥™Ñíû¬ë·ðøsš©\Eîên'ßuÇØ}!®w³3SÝ•B€€å@æZnH`€XÀòÅdÆKn‡FS¹ÏÑT®;LÞê].^ÝV¦øýjçÏ*Ñã@Àª s­:2° @L%@‹-Pûÿµ¤ßÂß•©\÷ó®27·Î ”bTÄC½›”ˆsM=/Ñ8xC2×ZÈ  !C ?+$!ù-Ô6¶YªÓ´oÅóonÒ™d,^Ó»ºüth\ÄÁ$¯k*TU‘ï.q V$™kÅQM  `:EsK%Æo¼Wmº1¢¿þû+²aò‚¶b‚6¯¾Ñ»³Ê°h® tD€€U @æZud`€˜J G^lLxÎeêÔD»¶×Ô¯ßR«`ìjà'½›K“Üx€Ø„d®M f‚€@` äd¦Òü'µÙ?4úöêÛ¸ak?üÍ3l[2}Ž@éÝòiEa<@lA2×Ã#A@À§.©d¿ôÿã¥Õ&4ïÒä“/¬jjíaÑ®{ð:³ûYï–叨…‹€ÌµèÀÀ,0À¬òfmü»uw¹öÐÎÃ?ïFmRï&%Å&Äc¥sO´^€Ìõ²‚€@HÈÏN“¼äÇkf߈ö›Ç_5ž«¥›åœ‰ŠÉÊ«qoýw«*œº_©¯ –&™kéáq  `" Ù•iÁÿ¼¾‘æSÍ2fmuÍ[n[7Ö®~Ô»XfA„AÀú s­?F°@Ì!°°ªLlø¯Ï¼+,<<2ö½_þÇxæÕp™Û)Ïïºvù(Wâþ3W4ˆ €ÌµðàÀ40›@Q¾º~–YºÿáyrWà$ wš Õ'¸€XŸd®õÇ‚€€iæVŠû…~Bwmõî7VocK›é(‰Qú3蚘?»TgA¬L2×Ê£Û@@Àd³ËŽmÇÿóú†@.¹@ÞÀß{ä? sð­Þu×@#“Þ-ÌS'¶ÝD€€õ@æZoL`€X†ÀŒÒ¼ã$ñ„ÇŸž~[8òoðžŸ>Ù'¸+°Æ|¨w w©%½[“îßÞ¢v_€Ìõ5QÔ AD ¢$zCJ—‹Ý5ÕûŸ{cmºø“?>¿}_35¤óàMOªwyNpÑ®ÎOôîÒyå¼@lA2×Ã#A@ÀtÓUjbk›‰]úû›'Þô÷âb´½ð3olÔõÙ[½k”Ÿª‚ÞeË«éLÂ!€€• @æZyt`€˜O`Þ ýž½ƒ£üÆé2ëû¶ÕÔÝû‹§ gq•ù]צæw}¢ws2á›ëŠ1 `i¹– ¦˜M[¹èÄÉuáu¿¸.Ô6¶}õGOhzíÒ:K5ˆ–ý¡wË‹s4Vá@Àò s-?D0@L%0³LXlA–üþEŸ¯º@÷³÷þ±op„éT}¿…ÖÅ$ƒh)‹¯ôîÉ‹*İÈ\[ ŒÓTÊw¡é›—¥å]?ü; S}ÒT™Æí–Vp/v©~ak-4M½‹e¦:ª(f€Ì5“>Úë [¯Œ" IúƒGŸ›~/œó¸C£$Uu#…*e3¶Ñr ¥:}+Jeºx©‘q-¬æ‹€ÌµøÁ<0ŸÀiK*™®zwûÞæ/|÷±i.¼ðÖêWÞùK¾D®‘HUª«V$ªKŠQUÔ£ÚÜa «™?°@À¹ÞÐB^Iù¹º~‹z—”î5wþ²¶a*Þ 4üО»ççÿ’…ª®£¹ZC…*•w«R £åŠàÕ5/Ö´Ûüêèàì@2×£A@ÀT³ËòEÍ'ÚÂônßÐÈU_zäïÏþOLš4Lw°}úë>óú%§Q#FÚÕ/zW1F};C¸ OF@Àê"­n ì0›@¥à™JR”=”{%½ûÈß_{í¶o}UeÚDý Üÿû÷Û´*K×Õ%ÉZöð4&dÂôEŒ*3jõª‚ýd¶b^A,M2×ÒÃã@@À ¹“­ne"90ÜøÍßç§æÊ3Ï)×íFŽ [vxüÅZzÄ~ñ„¡w=•ÁÒT13rfî?‡ a° È\Û   ÌŸY°mÏA2 Ìeº”‰AQ=6¶ô<𻘵T051¾±­‡"õö‹eä´@è]·ò\nÝ(eÑœR½å8°È\;Œl³ Ì©pÊ\>ǩӻF‘æw¹ía­°5*ãpXJïVc6—! `'¸ÍN£[A@À,Kçë·#½Ë:“H»²§.žÅõ4©ÆeHï²§&¿t`Xưuƒk’RŠòÒâc]ZG€€ `6׃A@Àt•%Òb ôÐÎÇJ1¤¥g¬Û"’€”‹èê3.ãíü®qM†+Fi,®ª,`¦â/€€í@æÚnÈ`0€˜@ ²$—µ:ù8QEZzëÏàr³Yç¾÷±rgŒºX-¦fn4  à pZðEÔ !@`Å 3Ä^’|dO1’…ï®0Y&*Bs¬òS_›AcgªÀ}÷±r{FSM¸ÿL?"8û€ÌµÏXÁR0•@Uy“¢:+¦ '*b1½‹ûÏtÃC°8-Øh°`*€˜I`–òó½â‹K‹‹iì!ñÊÚh)ÎÈ=`¢"²ë€Þ™Aª‹5¢ñ ¥(cç]Ã25Iõ3ƒi`Ü&áÀìI2מã«A@ àÍ-×µ½Kž ¬QSôîI +u]Æ!€€ÀiÁFƒSA@ÀL¹™©)Éq|T4ÅéWë’Fì)ffaæë&Þ ˆábdT…A3Ó÷ß娮v"@Àú s­?F°@¬B`ÁŒB2Å@UJFz«w ïý2n%zW·Y±U†v€xF2×3NÈ  àpœ´@ó#þ¤zו™QËè]É «Ê4Ç8°øæÚj¸`,€˜J`ñܲã²Cn¸öî3¯ì¡»ùÌÈy—2q¦è6ž¨ˆR™/üwU»æÏÄÆÎaÅ Ø”d®Mfƒ€€ f”:÷J`b—,°™ÞÕÉð‰Ög_¶@¿¿± ÄÑ$€À4ÀiaðP@BŒ@b|ì¢Y’{.Þå’—GR€&EÙSŒ”â×Z]ü„Eœ ^QÚÑ12KÖ»ì–5^d¦²€A@À^ sí5^°@L&0§R#s™5Lì™Þ…c®É§ši€Ì6BT ¡D`Ùü‰~Ê·ˆÞuÿßÞÄÈuÔqŽsÊ;xâDı‘-¯I<Ž·ñ;Îxl'$$cB;!+Q „°K’"Ö„„qâÆ BÜ8°H !A qâ (q"TÏëî™~ïUÛÓžéêzïkYvw½¥þõU?Šê×½EäþÖÛÞ)‘õÝë§ÞuËÆÞIþ%@ K{s³œ6E @ •@{îðú+»¥Í»áª~Ò,m”]Åï«ÅºXì½{°ü}µÁkî9¼{ø%@`ò¬æNþ©$°kÛm7­Ÿºú‚Öb}·Ú{ìyd!»j.º÷s«dZä& ææ6cê%@€@jûŽìòM²Xu«˜w‡…×^à-•1ì’º¼Vºƒd' æf7e &@€@b;w.=Pv-ònux±^†…×kË»¾V-²°77»)S0 Ù·#|£«´·uÈÎÚX¹±ý»!¼¯ÒæÝÐëeè%݃¥ß›rÉ©Ãþf׫οLº€˜;é3¤>LšÀ¡»v„’BÒ- k^Þ½cgÍCÓ&mÔC€ÀlZ¸"‘ @ ,07»ô ‚سºb; Ê÷Zö9¶7êâϲs»oc½ ½¤þ÷&ú—ž±1·*­…@~bn~s¦b$8q`)æö‹iLÞ=xgg¹Ú‹ÜlZÈ}ÕO€‹Ûs»ýÖì ]ÜÏPÚÌÎŽí¬2€qîß-6ïÞ½gKøMã!%9D€@.bn.3¥NL@±=·((üýÅ«”wc›wÃÉ“™wÃV†PÛñ»ºãñ™ Ø´ù*Ÿ‰掔÷-ô÷¶–*Šmf§ÅvÖ–î°üãÈûw—ߤx_[ðá}v,T©´ÈR@ÌÍrÚM€äûvm-¾ÉU­¤6>†ÓÒæÝ!‘zyÁŸ#Q”²s³›2 @`"ŽÎtW={¿Ã²bùµ<>.?6±ywÿÞ­6æ.Ÿ)ï d-`onÖÓ§x$8}t_©ïbokh,ýChéGà1ìß½~]©“xï½²úWœ°1·4©>ÈYÀjnγ§v$˜›ÝS¬×–ªH»¾Û¼ŠŒ®.÷–—Ã$Jcñ‘|ÄÜ|çNåH,pOïé¹ñøØM¼ÕB£—ô¾–VsÉb­¶ÇZFÈ»6æÆ0µÈQÀ¦…gM͘ÙÞöÜ~5!¼¯Ò¾UÜϰŠ# ¥./ø€¹½éó/fˆ¹Í˜G£ @€@ðôÜâçV²¶,cûwKù8Œ*¬ác+ýÞĪç]OÌMðß. ¬¥€M k©ëÞhºÀ£óÃGØÛ¿"mñ§*×Û@ÛM½ý†<)¬NéMmÁG*‹Ó¥«|$@ /17¯ùR-&KàÄÝ¿V‹ŠcùuròîéÙ»& W5\›€M ׿çj´[àÈÌÎbqµ´Ù ØÌlbûJç‡3cûwû‹·5—¬Þ~†Ó‡òz»gÕè 4DÀjnC&Ò0 D`÷¶Í;¶l ]Çkcë»±ó;·ê½J#vIäù W¿ŸáüÉý¥î|$@ w17÷T? œ>¼gyE]ÞR¼Ÿð¼{xßÎjÍZÈZ@ÌÍzúO€ôÇ÷ïêíX*fÈÊëæÝm[nÞµí¶¥ê½#@ öæ6b ‚éæŽ-þêo¶Åkp m¤¹sjlÿîKFÞ¿[zYè}ùóÈNX.Æáor°š›û ªŸ‰Ößxá;¶.YÈ4w®Ãúnìad¡÷wÏžXLêKcðŽ&ˆ¹M˜Ec @€@Z‡î=PS@$ØFš;79ïV{õR›wÃï\Tï …ÜÄÜÜgPýH/pöøL,VvŠ‹‹4w®XiÞí=›!ܲüŠõÒÏ»s³»Ã‚tù2Ÿ È_@ÌÍ€©voï>V,‹•#Ç"Í+Æw=J¬íE ‰bngÕ˜ 0v{+ú^cdž\RäÝê°b—\ýúîÜQs«®Z4A@ÌmÂ,’ ÜÏÌÿ®{»øS*&–D;§EŽE𣋻ñ;El¢¸dû–M·Ýº±S‰s7¥D€aMtzÃTÑóèy·RùZç݇ҧ" æ6d" ƒÉæg÷–jXqÞ¥Úè²ïµ®ï.œ-Õì#s3•B€ÄœÜßÝ„P)d2óîöÛoÞ½ms¥X 4DÀ¯ 5d" ƒÉΛéÖe‹×à/¢…¶wÃß×_W>½"z`ñF‹½”Vt~ýºÒ‘ò%§ùñ³‚Êßš)`5·™ójT¿@xúìûçôgñg µv‹?ƒÍO‘+†ˆ^{Y¿—ó~ü¬:Z4H@ÌmÐd R ‹-î†ÁôCjy`ÑѼûøÇË7ñ™† ˆ¹ XÃ"@€@j—>x®(¡6ì†C±ŒºvywzÃÔÃgޤ†Ñ?csÇ­´MàÂüÀC»F¯#\ÍÎ×uÖwŸ|äž¶Í‚ñh³€˜ÛæÙ7v¬¡À†wÜðÜ…“ÕF¯#\R›wŸ\8]­G Ms›:³ÆE€ôÝlH#„×.éçÝs¾|6d2"ÐD1·‰³jL˜ #ûvîܺ銵Œ^G¸ä¹÷¹b%N @ Ibn“fÓX 0q_|ö‘«¯i„ðzÅKŠÞCÚž;ºïê+q& s0‰†@€É8slfzýÔÛo‡‡ã® È+†×êÍb—Ïsxñó+èÞ©4B@ÌmÄ4&U |í•Ëç‹êа»ºy·:îjÞ¾iêÂÙÇ>T¯ÒB€@óÄÜæÍ© @`²ž\¸¯TÐ*æÝØÃwCý¼ûò‡Î­¿ñ†R > Ðx1·ñSl€H,Ðy²ØÅ“E-•2ž¼ë9b%v ´D@ÌmÉD&R |ò‰‹îc‹¯k—wŸ½pÒRnʹ×7tbn:{= @ 5·ß:ýüÅŸŠ[Þ}ùò{ZÃl  ˆ¹> @€À „Ýð¸…êÍk73„ÓVe}÷Ó—Ïm¾uºÚ©Ú æ¶a–‘étO->X¬“`KÅwÃi#çÝéõ7¼tÉRnIÚG-s[4Ù†J€´¯<ñàÍn,jCÞýä¥ó<`!í”ë@R17)¿Î  Ð&° û©ËçJ#^£¼~ö¬ú ³R×> Ðl1·Ùókt˜,,ÌíØ²)<ѶZÖêæÝð#ÃáAfÕ^´ Ð1·=sm¤H/¢ç¯<êèÿvCµ¦kÏ»çí]˜Ÿ­ÞY ­s[5ÝK€ôóÇfî?¾·_ÇZäݯî‰þý½!@ µbnk§ÞÀ  Là›ŸÿÈôMÝï¢õ‹X­¼ûÚ‹ "ÖWõ†@›ÄÜ6Ͼ± @ @ø.Ú«/,tž*Vü¬âZòîìïþø‡¼ŸO´T@ÌméÄ6Ò „Ç <~þP·†QóniÓ¦¾÷ú ¥F h­€˜ÛÚ©7p$øÚgŸÜ¹õ–"V˜wK_VûîWž ëÄ7ô ˆ¹-ž|C'@€@RðÔ…}õÅï,oÒíU·™¡ÓÜ{• y÷µ9sl¦Ôî#msÛ<ûÆN€Ä{·ßþ½/?YÃí…Ýp¸òêÅÝî±ç/žzéÃ~׷¤@»ÄÜvÏ¿Ñ @ µÀüñ™ï¿úLQÅhy÷ù 'ßøô¥ÔãÐ?'°.üâ‰+JA Ð2Ÿþò·Ï½þƒê ×U›Š–Þ^<õÆg.ÇÎÒN€@›ÄÜ6Ͼ± @`‚ÞüÛß~åÛÿø×jkêÅÚƒ¯ìÂ'.Ù«0`â}1·Oá $xëßÿý·~ü“_ü¾6ÔŇÂ#¾ó¥§f÷íL\±î ˜`1w‚'Gih¥Àïþô×oüðg?ÿõ›aôÕ¼îÓœ´ˆÛÊÿ4 šÀÊÄÜ•y9›Æ#ö0üæùÕþüÏ·ºÛNÚ{׎-á+kã)@/ä. ææ>ƒê'@€¨ð@±M @€¹ ˆ¹¹Ï ú  @€jÄÜM @€¹ ˆ¹¹Ï ú  @€jÄÜM @€¹ ˆ¹¹Ï ú  @€jÄÜM @€¹ ˆ¹¹Ï ú  @€jÄÜM @€¹ ˆ¹¹Ï ú  @€jÄÜM @€¹ ˆ¹¹Ï ú  @€jÄÜM @€¹ ˆ¹¹Ï ú  @€jÄÜM @€¹ ˆ¹¹Ï ú  @€jÄÜM @€¹ ˆ¹¹Ï ú  @€jÄÜM @€¹ ˆ¹¹Ï ú  @€jìíø]íIDATÄÜM @€¹ ˆ¹¹Ï ú  @€jÄÜM @€¹ ˆ¹¹Ï ú  @€jÄÜM @€¹ ˆ¹¹Ï ú  @€jÄÜM @€¹ ˆ¹¹Ï ú  @€jÄÜM @€¹ ˆ¹¹Ï ú  @€jÄÜM @€¹ ˆ¹¹Ï ú  @€jÄÜM @€¹ ˆ¹¹Ï ú  @€jþ´?ëÐOìQ.IEND®B`‚concurrent-ruby-1.0.5/doc/promises-main.md000066400000000000000000000052571305460430400205400ustar00rootroot00000000000000Promises is a new framework unifying former tools `Concurrent::Future`, `Concurrent::Promise`, `Concurrent::IVar`, `Concurrent::Event`, `Concurrent.dataflow`, `Delay`, and `TimerTask` of concurrent-ruby. It extensively uses the new synchronization layer to make all the methods *lock-free* (with the exception of obviously blocking operations like `#wait`, `#value`, etc.). As a result it lowers danger of deadlocking and offers better performance. It provides similar tools as other promise libraries do, users coming from other languages and other promise libraries will find the same tools here (probably named differently though). The naming conventions were borrowed heavily from JS promises. This framework, however, is not just a re-implementation of other promise library, it draws inspiration from many other promise libraries, adds new ideas, and is integrated with other abstractions like actors and channels. Therefore it is likely that user will find a suitable solution for a problem in this framework. If the problem is simple user can pick one suitable abstraction, e.g. just promises or actors. If the problem is complex user can combine parts (promises, channels, actors) which were designed to work together well to a solution. Rather than having to combine fragilely independent tools. This framework allows its users to: - Process tasks asynchronously - Chain, branch, and zip the asynchronous tasks together - Therefore, to create directed acyclic graph (hereafter DAG) of tasks - Create delayed tasks (or delayed DAG of tasks) - Create scheduled tasks (or delayed DAG of tasks) - Deal with errors through rejections - Reduce danger of deadlocking - Control the concurrency level of tasks - Simulate thread-like processing without occupying threads - It allows to create tens of thousands simulations on one thread pool - It works well on all Ruby implementations - Use actors to maintain isolated states and to seamlessly combine it with promises - Build parallel processing stream system with back pressure (parts, which are not keeping up, signal to the other parts of the system to slow down). **The guide is best place to start with promises, see** **{file:doc/promises.out.md}.** # Main classes The main public user-facing classes are {Concurrent::Promises::Event} and {Concurrent::Promises::Future} which share common ancestor {Concurrent::Promises::AbstractEventFuture}. **{Concurrent::Promises::AbstractEventFuture}:** > {include:Concurrent::Promises::AbstractEventFuture} **{Concurrent::Promises::Event}:** > {include:Concurrent::Promises::Event} **{Concurrent::Promises::Future}:** > {include:Concurrent::Promises::Future} concurrent-ruby-1.0.5/doc/promises.in.md000066400000000000000000000641031305460430400202160ustar00rootroot00000000000000# Basics ## Factory methods Future and Event are created indirectly with constructor methods in FactoryMethods. They are not designed for inheritance but rather for composition. ```ruby Concurrent::Promises::FactoryMethods.instance_methods(false) ``` The module can be included or extended where needed. ```ruby Class.new do include Concurrent::Promises::FactoryMethods def a_method resolvable_event end end.new.a_method mod = Module.new do extend Concurrent::Promises::FactoryMethods end # mod.resolvable_event ``` The default executor can be changed by overriding `default_executor` method inherited from `Concurrent::Promises::FactoryMethods`. ```ruby mod = Module.new do extend Concurrent::Promises::FactoryMethods def self.default_executor :fast end end # mod.future { 1 }.default_executor Concurrent::Promises.future { 1 }.default_executor ``` The module is already extended into {Concurrent::Promises} for convenience. ```ruby Concurrent::Promises.resolvable_event ``` ## Asynchronous task The most basic use-case of the framework is asynchronous processing. A task can be processed asynchronously by using a `future` factory method. The block will be executed on an internal thread pool. Arguments of `future` are passed to the block and evaluation starts immediately. ```ruby future = Concurrent::Promises.future(0.1) do |duration| sleep duration :result end ``` Asks if the future is resolved, here it will be still in the middle of the sleep call. ```ruby future.resolved? ``` Retrieving the value will block until the future is resolved. ```ruby future.value future.resolved? ``` If the task fails we talk about the future being rejected. ```ruby future = Concurrent::Promises.future { raise 'Boom' } ``` There is no result, the future was rejected with a reason. ```ruby future.value future.reason ``` It can be forced to raise the reason for rejection when retrieving the value. ```ruby begin future.value! rescue => e e end ``` Which is the same as `future.value! rescue $!` which will be used hereafter. Or it can be used directly as argument for raise, since it implements exception method. ```ruby raise future rescue $! ``` ## States Lets define a inspection helper for methods. ```ruby def inspect_methods(*methods, of:) methods.reduce({}) { |h, m| h.update m => of.send(m) } end # ``` Event has `pending` and `resolved` state. ```ruby event = Concurrent::Promises.resolvable_event # inspect_methods(:state, :pending?, :resolved?, of: event) event.resolve # inspect_methods(:state, :pending?, :resolved?, of: event) ``` Future's `resolved` state is further specified to be `fulfilled` or `rejected`. ```ruby future = Concurrent::Promises.resolvable_future # inspect_methods(:state, :pending?, :resolved?, :fulfilled?, :rejected?, of: future) future.fulfill :value # inspect_methods(:state, :pending?, :resolved?, :fulfilled?, :rejected?, :result, :value, :reason, of: future) future = Concurrent::Promises.rejected_future StandardError.new # inspect_methods(:state, :pending?, :resolved?, :fulfilled?, :rejected?, :result, :value, :reason, of: future) ``` ## Direct creation of resolved futures When an existing value has to wrapped in a future it does not have to go through evaluation as follows. ```ruby Concurrent::Promises.future { :value } ``` Instead it can be created directly. ```ruby Concurrent::Promises.fulfilled_future(:value) Concurrent::Promises.rejected_future(StandardError.new('Ups')) Concurrent::Promises.resolved_future(true, :value, nil) Concurrent::Promises.resolved_future(false, nil, StandardError.new('Ups')) ``` ## Chaining Big advantage of promises is ability to chain tasks together without blocking current thread. ```ruby Concurrent::Promises. future(2) { |v| v.succ }. then(&:succ). value! ``` As `future` factory method takes argument, `then` method takes as well. Any supplied arguments are passed to the block, and the library ensures that they are visible to the block. ```ruby Concurrent::Promises. future('3') { |s| s.to_i }. then(2) { |v, arg| v + arg }. value Concurrent::Promises. fulfilled_future('3'). then(&:to_i). then(2, &:+). value Concurrent::Promises. fulfilled_future(1). chain(2) { |fulfilled, value, reason, arg| value + arg }. value ``` Passing the arguments in (similarly as for a thread `Thread.new(arg) { |arg| do_stuff arg }`) is **required**, both following examples may break. ```ruby arg = 1 Thread.new { do_stuff arg } Concurrent::Promises.future { do_stuff arg } ``` ## Branching, and zipping Besides chaining it can also be branched. ```ruby head = Concurrent::Promises.fulfilled_future -1 # branch1 = head.then(&:abs) # branch2 = head.then(&:succ).then(&:succ) # branch1.value! branch2.value! ``` It can be combined back to one future by zipping (`zip`, `&`). ```ruby branch1.zip(branch2).value! (branch1 & branch2). then { |a, b| a + b }. value! (branch1 & branch2). then(&:+). value! Concurrent::Promises. zip(branch1, branch2, branch1). then { |*values| values.reduce(&:+) }. value! ``` Instead of zipping only the first one can be taken if needed. ```ruby Concurrent::Promises.any(branch1, branch2).value! (branch1 | branch2).value! ``` ## Blocking methods In these examples we have used blocking methods like `value` extensively for their convenience, however in practice is better to avoid them and continue chaining. If they need to be used (e.g. when integrating with threads), `value!` is a better option over `value` when rejections are not dealt with differently. Otherwise the rejection are not handled and probably silently forgotten. ## Error handling When one of the tasks in the chain fails, the rejection propagates down the chain without executing the tasks created with `then`. ```ruby Concurrent::Promises. fulfilled_future(Object.new). then(&:succ). then(&:succ). result ``` As `then` chained tasks execute only on fulfilled futures, there is a `rescue` method which chains a task which is executed only when the future is rejected. It can be used to recover from rejection. Using rescue to fulfill to 0 instead of the error. ```ruby Concurrent::Promises. fulfilled_future(Object.new). then(&:succ). then(&:succ). rescue { |err| 0 }. result ``` Rescue not executed when there is no rejection. ```ruby Concurrent::Promises. fulfilled_future(1). then(&:succ). then(&:succ). rescue { |e| 0 }. result ``` Tasks added with `chain` are evaluated always. ```ruby Concurrent::Promises. fulfilled_future(1). chain { |fulfilled, value, reason| fulfilled ? value : reason }. value! Concurrent::Promises. rejected_future(StandardError.new('Ups')). chain { |fulfilled, value, reason| fulfilled ? value : reason }. value! ``` Zip is rejected if any of the zipped futures is. ```ruby rejected_zip = Concurrent::Promises.zip( Concurrent::Promises.fulfilled_future(1), Concurrent::Promises.rejected_future(StandardError.new('Ups'))) rejected_zip.result rejected_zip. rescue { |reason1, reason2| (reason1 || reason2).message }. value ``` ## Delayed futures Delayed futures will not evaluate until asked by `touch` or other method requiring resolution. ```ruby future = Concurrent::Promises.delay { sleep 0.1; 'lazy' } sleep 0.1 # future.resolved? future.touch sleep 0.2 # future.resolved? ``` All blocking methods like `wait`, `value` call `touch` and trigger evaluation. ```ruby Concurrent::Promises.delay { :value }.value ``` It propagates trough chain up allowing whole or partial lazy chains. ```ruby head = Concurrent::Promises.delay { 1 } # branch1 = head.then(&:succ) # branch2 = head.delay.then(&:succ) # join = branch1 & branch2 # sleep 0.1 # ``` Nothing resolves. ```ruby [head, branch1, branch2, join].map(&:resolved?) ``` Force `branch1` evaluation. ```ruby branch1.value sleep 0.1 # [head, branch1, branch2, join].map(&:resolved?) ``` Force evaluation of both by calling `value` on `join`. ```ruby join.value [head, branch1, branch2, join].map(&:resolved?) ``` ## Flatting Sometimes it is needed to wait for a inner future. Apparent solution is to wait inside the future `Concurrent::Promises.future { Concurrent::Promises.future { 1+1 }.value }.value` however as mentioned before, `value` calls should be **avoided** to avoid blocking threads. Therefore there is a flat method which is a correct solution in this situation and does not block any thread. ```ruby Concurrent::Promises.future { Concurrent::Promises.future { 1+1 } }.flat.value! ``` A more complicated example. ```ruby Concurrent::Promises. future { Concurrent::Promises.future { Concurrent::Promises.future { 1 + 1 } } }. flat(1). then { |future| future.then(&:succ) }. flat(1). value! ``` ## Scheduling Tasks can be planned to be executed with a time delay. Schedule task to be executed in 0.1 seconds. ```ruby scheduled = Concurrent::Promises.schedule(0.1) { 1 } scheduled.resolved? ``` Value will become available after 0.1 seconds. ```ruby scheduled.value ``` It can be used in the chain as well, where the delay is counted form a moment its parent resolves. Therefore following future will be resolved in 0.2 seconds. ```ruby future = Concurrent::Promises. future { sleep 0.1; :result }. schedule(0.1). then(&:to_s). value! ``` Time can be used as well. ```ruby Concurrent::Promises.schedule(Time.now + 10) { :val } ``` ## Resolvable Future and Event: Sometimes it is required to resolve a future externally, in these cases `resolvable_future` and `resolvable_event` factory methods can be uses. See {Concurrent::Promises::ResolvableFuture} and {Concurrent::Promises::ResolvableEvent}. ```ruby future = Concurrent::Promises.resolvable_future ``` The thread will be blocked until the future is resolved ```ruby thread = Thread.new { future.value } # future.fulfill 1 thread.value ``` Future can be resolved only once. ```ruby future.fulfill 1 rescue $! future.fulfill 2, false ``` ## How are promises executed? Promises use global pools to execute the tasks. Therefore each task may run on different thread which implies that users have to be careful not to depend on Thread local variables (or they have to set at the begging of the task and cleaned up at the end of the task). Since the tasks are running on may different threads of the thread pool, it's better to follow following rules: - Use only data passed in through arguments or values of parent futures, to have better control over what are futures accessing. - The data passed in and out of futures are easier to deal with if they are immutable or at least treated as such. - Any mutable and mutated object accessed by more than one threads or futures must be thread safe, see {Concurrent::Array}, {Concurrent::Hash}, and {Concurrent::Map}. (Value of a future may be consumed by many futures.) - Futures can access outside objects, but they has to be thread-safe. > *TODO: This part to be extended* # Advanced ## Callbacks ```ruby queue = Queue.new future = Concurrent::Promises.delay { 1 + 1 } future.on_fulfillment { queue << 1 } # evaluated asynchronously future.on_fulfillment! { queue << 2 } # evaluated on resolving thread queue.empty? future.value queue.pop queue.pop ``` ## Using executors Factory methods, chain, and callback methods have all other version of them which takes executor argument. It takes an instance of an executor or a symbol which is a shortcuts for the two global pools in concurrent-ruby. `fast` for short and non-blocking tasks and `:io` for blocking and long tasks. ```ruby Concurrent::Promises.future_on(:fast) { 2 }. then_on(:io) { File.read __FILE__ }. value.size ``` ## Run (simulated process) Similar to flatting is running. When `run` is called on a future it will flat indefinitely as long the future fulfils into a `Future` value. It can be used to simulate a thread like processing without actually occupying the thread. ```ruby count = lambda do |v| v += 1 v < 5 ? Concurrent::Promises.future_on(:fast, v, &count) : v end 400.times. map { Concurrent::Promises.future_on(:fast, 0, &count).run.value! }. all? { |v| v == 5 } ``` Therefore the above example finished fine on the the `:fast` thread pool even though it has much less threads than there is the simulated process. # Interoperability ## Actors Create an actor which takes received numbers and returns the number squared. ```ruby actor = Concurrent::Actor::Utils::AdHoc.spawn :square do -> v { v ** 2 } end ``` Send result of `1+1` to the actor, and add 2 to the result send back from the actor. ```ruby Concurrent::Promises. future { 1 + 1 }. then_ask(actor). then { |v| v + 2 }. value! ``` So `(1 + 1)**2 + 2 = 6`. The `ask` method returns future. ```ruby actor.ask(2).then(&:succ).value! ``` ## Channel There is an implementation of channel as well. Lets start by creating a channel with capacity 2 messages. ```ruby ch1 = Concurrent::Promises::Channel.new 2 ``` We push 3 messages, it can be observed that the last future representing the push is not fulfilled since the capacity prevents it. When the work which fills the channel depends on the futures created by push it can be used to create back pressure – the filling work is delayed until the channel has space for more messages. ```ruby pushes = 3.times.map { |i| ch1.push i } ch1.pop.value! pushes ``` A selection over channels can be created with select_channel factory method. It will be fulfilled with a first message available in any of the channels. It returns a pair to be able to find out which channel had the message available. ```ruby ch2 = Concurrent::Promises::Channel.new 2 result = Concurrent::Promises.select_channel(ch1, ch2) result.value! Concurrent::Promises.future { 1+1 }.then_push_channel(ch1) result = ( Concurrent::Promises.fulfilled_future('%02d') & Concurrent::Promises.select_channel(ch1, ch2)). then { |format, (channel, value)| format format, value } result.value! ``` ## ProcessingActor There is also a new implementation of actors based on the Channel and the ability of promises to simulate process. The actor runs as a process but also does not occupy a thread per actor as previous Concurrent::Actor implementation. This implementation is close to Erlang actors, therefore OTP can be ported for this actors (and it's planned). The simplest actor is a one which just computes without even receiving a message. ```ruby actor = Concurrent::ProcessingActor.act(an_argument = 2) do |actor, number| number ** 3 end actor.termination.value! ``` Let's receive some messages though. ```ruby add_2_messages = Concurrent::ProcessingActor.act do |actor| # Receive two messages then terminate normally with the sum. (actor.receive & actor.receive).then do |a, b| a + b end end add_2_messages.tell 1 add_2_messages.termination.resolved? add_2_messages.tell 3 add_2_messages.termination.value! ``` Actors can also be used to apply back pressure to a producer. Let's start by defining an actor which a mailbox of size 2. ```ruby slow_counter = -> (actor, count) do actor.receive.then do |command, number| sleep 0.1 case command when :add slow_counter.call actor, count + number when :done # terminate count end end end actor = Concurrent::ProcessingActor.act_listening( Concurrent::Promises::Channel.new(2), 0, &slow_counter) ``` Now we can create a producer which will push messages only when there is a space available in the mailbox. We use promises to free a thread during waiting on a free space in the mailbox. ```ruby produce = -> receiver, i do if i < 10 receiver. # send a message to the actor, resolves only after the message is # accepted by the actor's mailbox tell([:add, i]). # send incremented message when the above message is accepted then(i+1, &produce) else receiver.tell(:done) # do not continue end end Concurrent::Promises.future(actor, 0, &produce).run.wait! actor.termination.value! ``` # Use-cases ## Simple background processing ```ruby Concurrent::Promises.future { do_stuff } ``` ## Parallel background processing ```ruby tasks = 4.times.map { |i| Concurrent::Promises.future(i) { |i| i*2 } } Concurrent::Promises.zip(*tasks).value! ``` ## Actor background processing Actors are mainly keep and isolate state, they should stay responsive not being blocked by a longer running computations. It desirable to offload the work to stateless promises. Lets define an actor which will process jobs, while staying responsive, and tracking the number of tasks being processed. ```ruby class Computer < Concurrent::Actor::RestartingContext def initialize super() @jobs = {} end def on_message(msg) command, *args = msg case command # new job to process when :run job = args[0] @jobs[job] = envelope.future # Process asynchronously and send message back when done. Concurrent::Promises.future(&job).chain(job) do |fulfilled, value, reason, job| self.tell [:done, job, fulfilled, value, reason] end # Do not make return value of this method to be answer of this message. # We are answering later in :done by resolving the future kept in @jobs. Concurrent::Actor::Behaviour::MESSAGE_PROCESSED when :done job, fulfilled, value, reason = *args future = @jobs.delete job # Answer the job's result. future.resolve fulfilled, value, reason when :status { running_jobs: @jobs.size } else # Continue to fail with unknown message. pass end end end ``` Create the computer actor and send it 3 jobs. ```ruby computer = Concurrent::Actor.spawn Computer, :computer results = 3.times.map { computer.ask [:run, -> { sleep 0.1; :result }] } computer.ask(:status).value! results.map(&:value!) ``` ## Solving the Thread count limit by thread simulation Sometimes an application requires to process a lot of tasks concurrently. If the number of concurrent tasks is high enough than it is not possible to create a Thread for each of them. A partially satisfactory solution could be to use Fibers, but that solution locks the application on MRI since other Ruby implementations are using threads for each Fiber. This library provides a {Concurrent::Promises::Future#run} method on a future to simulate threads without actually accepting one all the time. The run method is similar to {Concurrent::Promises::Future#flat} but it will keep flattening until it's fulfilled with non future value, then the value is taken as a result of the process simulated by `run`. ```ruby body = lambda do |v| # Some computation step of the process new_v = v + 1 # Is the process finished? if new_v < 5 # Continue computing with new value, does not have to be recursive. # It just has to return a future. Concurrent::Promises.future(new_v, &body) else # The process is finished, fulfill the final value with `new_v`. new_v end end Concurrent::Promises.future(0, &body).run.value! # => 5 ``` This solution works well an any Ruby implementation. > *TODO: More examples to be added.* ## Cancellation ### Simple Lets have two processes which will count until cancelled. ```ruby source, token = Concurrent::Cancellation.create count_until_cancelled = -> token, count do if token.canceled? count else Concurrent::Promises.future token, count+1, &count_until_cancelled end end # futures = Array.new(2) do Concurrent::Promises.future(token, 0, &count_until_cancelled).run end sleep 0.01 # source.cancel futures.map(&:value!) ``` Cancellation can also be used as event or future to log or plan re-execution. ```ruby token.to_event.chain do # log cancellation # plane re-execution end ``` ### Parallel background processing with cancellation Each task tries to count to 1000 but there is a randomly failing test. The tasks share a cancellation, when one of them fails it cancels the others. ```ruby source, token = Concurrent::Cancellation.create tasks = 4.times.map do |i| Concurrent::Promises.future(source, token, i) do |source, token, i| count = 0 1000.times do break count = :cancelled if token.canceled? count += 1 sleep 0.01 if rand > 0.95 source.cancel raise 'random error' end count end end end Concurrent::Promises.zip(*tasks).result ``` Without the randomly failing part it produces following. ```ruby source, token = Concurrent::Cancellation.create tasks = 4.times.map do |i| Concurrent::Promises.future(source, token, i) do |source, token, i| count = 0 1000.times do break count = :cancelled if token.canceled? count += 1 # sleep 0.01 # if rand > 0.95 # source.cancel # raise 'random error' # end end count end end Concurrent::Promises.zip(*tasks).result ``` ## Throttling concurrency By creating an actor managing the resource we can control how many threads is accessing the resource. In this case one at the time. ```ruby data = Array.new(10) { |i| '*' * i } DB = Concurrent::Actor::Utils::AdHoc.spawn :db, data do |data| lambda do |message| # pretending that this queries a DB data[message] end end concurrent_jobs = 11.times.map do |v| DB. # ask the DB with the `v`, only one at the time, rest is parallel ask(v). # get size of the string, rejects for 11 then(&:size). # translate error to a value (message of the exception) rescue { |reason| reason.message } end # Concurrent::Promises.zip(*concurrent_jobs).value! ``` Often there is more then one DB connections, then the pool can be used. ```ruby pool_size = 5 DB_POOL = Concurrent::Actor::Utils::Pool.spawn!('DB-pool', pool_size) do |index| # DB connection constructor Concurrent::Actor::Utils::AdHoc.spawn( name: "connection-#{index}", args: [data]) do |data| lambda do |message| # pretending that this queries a DB data[message] end end end concurrent_jobs = 11.times.map do |v| DB_POOL. # ask the DB with the `v`, only one at the time, rest is parallel ask(v). # get size of the string, rejects for 11 then(&:size). # translate error to a value (message of the exception) rescue { |reason| reason.message } end # Concurrent::Promises.zip(*concurrent_jobs).value! ``` In other cases the DB adapter maintains its internal connection pool and we just need to limit concurrent access to the DB's API to avoid the calls being blocked. Lets pretend that the `#[]` method on `DB_INTERNAL_POOL` is using the internal pool of size 3. We create throttle with the same size ```ruby DB_INTERNAL_POOL = Concurrent::Array.new data max_tree = Concurrent::Throttle.new 3 futures = 11.times.map do |i| max_tree. # throttled tasks, at most 3 simultaneous calls of [] on the database throttled_future { DB_INTERNAL_POOL[i] }. # un-throttled tasks, unlimited concurrency then { |starts| starts.size }. rescue { |reason| reason.message } end # futures.map(&:value!) ``` ## Long stream of tasks, applying back pressure Lets assume that we queuing an API for a data and the queries can be faster than we are able to process them. This example shows how to use channel as a buffer and how to apply back pressure to slow down the queries. ```ruby require 'json' # channel = Concurrent::Promises::Channel.new 6 source, token = Concurrent::Cancellation.create def query_random_text(token, channel) Concurrent::Promises.future do # for simplicity the query is omitted # url = 'some api' # Net::HTTP.get(URI(url)) sleep 0.1 { 'message' => 'Lorem ipsum rhoncus scelerisque vulputate diam inceptos' }.to_json end.then(token) do |value, token| # The push to channel is fulfilled only after the message is successfully # published to the channel, therefore it will not continue querying until # current message is pushed. channel.push(value) | # It could wait on the push indefinitely if the token is not checked # here with `or` (the pipe). token.to_future end.flat_future.then(token) do |_, token| # query again after the message is pushed to buffer query_random_text(token, channel) unless token.canceled? end end words = [] words_throttle = Concurrent::Throttle.new 1 def count_words_in_random_text(token, channel, words, words_throttle) channel.pop.then do |response| string = JSON.load(response)['message'] # processing is slower than querying sleep 0.2 words_count = string.scan(/\w+/).size end.then_throttled_by(words_throttle, words) do |words_count, words| # safe since throttled to only 1 task at a time words << words_count end.then(token) do |_, token| # count words in next message unless token.canceled? count_words_in_random_text(token, channel, words, words_throttle) end end end query_processes = 3.times.map do Concurrent::Promises.future(token, channel, &method(:query_random_text)).run end word_counter_processes = 2.times.map do Concurrent::Promises.future(token, channel, words, words_throttle, &method(:count_words_in_random_text)).run end sleep 0.5 ``` Let it run for a while then cancel it and ensure that the runs all fulfilled (therefore ended) after the cancellation. Finally print the result. ```ruby source.cancel query_processes.map(&:wait!) word_counter_processes.map(&:wait!) words ``` Compared to using threads directly this is highly configurable and compostable solution. ## Periodic task By combining `schedule`, `run` and `Cancellation` periodically executed task can be easily created. ```ruby repeating_scheduled_task = -> interval, token, task do Concurrent::Promises. # Schedule the task. schedule(interval, token, &task). # If successful schedule again. # Alternatively use chain to schedule always. then { repeating_scheduled_task.call(interval, token, task) } end cancellation, token = Concurrent::Cancellation.create task = -> token do 5.times do token.raise_if_canceled # do stuff print '.' sleep 0.01 end end result = Concurrent::Promises.future(0.1, token, task, &repeating_scheduled_task).run sleep 0.2 cancellation.cancel result.result ``` concurrent-ruby-1.0.5/doc/promises.init.rb000066400000000000000000000000651305460430400205530ustar00rootroot00000000000000require 'concurrent-edge' def do_stuff :stuff end concurrent-ruby-1.0.5/doc/promises.out.md000066400000000000000000001071411305460430400204170ustar00rootroot00000000000000# Basics ## Factory methods Future and Event are created indirectly with constructor methods in FactoryMethods. They are not designed for inheritance but rather for composition. ```ruby Concurrent::Promises::FactoryMethods.instance_methods(false) # => [:zip, # :create, # :delay, # :future, # :resolvable_future, # :resolvable_event, # :resolvable_event_on, # :resolvable_future_on, # :future_on, # :resolved_future, # :fulfilled_future, # :rejected_future, # :resolved_event, # :delay_on, # :schedule, # :schedule_on, # :zip_futures, # :zip_futures_on, # :zip_events, # :zip_events_on, # :any_resolved_future, # :any_resolved_future_on, # :any, # :any_fulfilled_future, # :any_fulfilled_future_on, # :any_event, # :any_event_on] ``` The module can be included or extended where needed. ```ruby Class.new do include Concurrent::Promises::FactoryMethods def a_method resolvable_event end end.new.a_method # => <#Concurrent::Promises::ResolvableEvent:0x7fcd849824f8 pending> mod = Module.new do extend Concurrent::Promises::FactoryMethods end mod.resolvable_event # => <#Concurrent::Promises::ResolvableEvent:0x7fcd8497a690 pending> ``` The default executor can be changed by overriding `default_executor` method inherited from `Concurrent::Promises::FactoryMethods`. ```ruby mod = Module.new do extend Concurrent::Promises::FactoryMethods def self.default_executor :fast end end mod.future { 1 }.default_executor # => :fast Concurrent::Promises.future { 1 }.default_executor # => :io ``` The module is already extended into {Concurrent::Promises} for convenience. ```ruby Concurrent::Promises.resolvable_event # => <#Concurrent::Promises::ResolvableEvent:0x7fcd84922a30 pending> ``` ## Asynchronous task The most basic use-case of the framework is asynchronous processing. A task can be processed asynchronously by using a `future` factory method. The block will be executed on an internal thread pool. Arguments of `future` are passed to the block and evaluation starts immediately. ```ruby future = Concurrent::Promises.future(0.1) do |duration| sleep duration :result end # => <#Concurrent::Promises::Future:0x7fcd84903860 pending> ``` Asks if the future is resolved, here it will be still in the middle of the sleep call. ```ruby future.resolved? # => false ``` Retrieving the value will block until the future is resolved. ```ruby future.value # => :result future.resolved? # => true ``` If the task fails we talk about the future being rejected. ```ruby future = Concurrent::Promises.future { raise 'Boom' } # => <#Concurrent::Promises::Future:0x7fcd848d9a38 pending> ``` There is no result, the future was rejected with a reason. ```ruby future.value # => nil future.reason # => # ``` It can be forced to raise the reason for rejection when retrieving the value. ```ruby begin future.value! rescue => e e end # => # ``` Which is the same as `future.value! rescue $!` which will be used hereafter. Or it can be used directly as argument for raise, since it implements exception method. ```ruby raise future rescue $! # => # ``` ## States Lets define a inspection helper for methods. ```ruby def inspect_methods(*methods, of:) methods.reduce({}) { |h, m| h.update m => of.send(m) } end ``` Event has `pending` and `resolved` state. ```ruby event = Concurrent::Promises.resolvable_event inspect_methods(:state, :pending?, :resolved?, of: event) # => {:state=>:pending, :pending?=>true, :resolved?=>false} event.resolve inspect_methods(:state, :pending?, :resolved?, of: event) # => {:state=>:resolved, :pending?=>false, :resolved?=>true} ``` Future's `resolved` state is further specified to be `fulfilled` or `rejected`. ```ruby future = Concurrent::Promises.resolvable_future inspect_methods(:state, :pending?, :resolved?, :fulfilled?, :rejected?, of: future) # => {:state=>:pending, # :pending?=>true, # :resolved?=>false, # :fulfilled?=>false, # :rejected?=>false} future.fulfill :value inspect_methods(:state, :pending?, :resolved?, :fulfilled?, :rejected?, :result, :value, :reason, of: future) # => {:state=>:fulfilled, # :pending?=>false, # :resolved?=>true, # :fulfilled?=>true, # :rejected?=>false, # :result=>[true, :value, nil], # :value=>:value, # :reason=>nil} future = Concurrent::Promises.rejected_future StandardError.new inspect_methods(:state, :pending?, :resolved?, :fulfilled?, :rejected?, :result, :value, :reason, of: future) # => {:state=>:rejected, # :pending?=>false, # :resolved?=>true, # :fulfilled?=>false, # :rejected?=>true, # :result=>[false, nil, #], # :value=>nil, # :reason=>#} ``` ## Direct creation of resolved futures When an existing value has to wrapped in a future it does not have to go through evaluation as follows. ```ruby Concurrent::Promises.future { :value } # => <#Concurrent::Promises::Future:0x7fcd84290c80 pending> ``` Instead it can be created directly. ```ruby Concurrent::Promises.fulfilled_future(:value) # => <#Concurrent::Promises::Future:0x7fcd84250fb8 fulfilled> Concurrent::Promises.rejected_future(StandardError.new('Ups')) # => <#Concurrent::Promises::Future:0x7fcd84220340 rejected> Concurrent::Promises.resolved_future(true, :value, nil) # => <#Concurrent::Promises::Future:0x7fcd84173dc0 fulfilled> Concurrent::Promises.resolved_future(false, nil, StandardError.new('Ups')) # => <#Concurrent::Promises::Future:0x7fcd84208628 rejected> ``` ## Chaining Big advantage of promises is ability to chain tasks together without blocking current thread. ```ruby Concurrent::Promises. future(2) { |v| v.succ }. then(&:succ). value! # => 4 ``` As `future` factory method takes argument, `then` method takes as well. Any supplied arguments are passed to the block, and the library ensures that they are visible to the block. ```ruby Concurrent::Promises. future('3') { |s| s.to_i }. then(2) { |v, arg| v + arg }. value # => 5 Concurrent::Promises. fulfilled_future('3'). then(&:to_i). then(2, &:+). value # => 5 Concurrent::Promises. fulfilled_future(1). chain(2) { |fulfilled, value, reason, arg| value + arg }. value # => 3 ``` Passing the arguments in (similarly as for a thread `Thread.new(arg) { |arg| do_stuff arg }`) is **required**, both following examples may break. ```ruby arg = 1 # => 1 Thread.new { do_stuff arg } # => # Concurrent::Promises.future { do_stuff arg } # => <#Concurrent::Promises::Future:0x7fcd841624a8 pending> ``` ## Branching, and zipping Besides chaining it can also be branched. ```ruby head = Concurrent::Promises.fulfilled_future -1 branch1 = head.then(&:abs) branch2 = head.then(&:succ).then(&:succ) branch1.value! # => 1 branch2.value! # => 1 ``` It can be combined back to one future by zipping (`zip`, `&`). ```ruby branch1.zip(branch2).value! # => [1, 1] (branch1 & branch2). then { |a, b| a + b }. value! # => 2 (branch1 & branch2). then(&:+). value! # => 2 Concurrent::Promises. zip(branch1, branch2, branch1). then { |*values| values.reduce(&:+) }. value! # => 3 ``` Instead of zipping only the first one can be taken if needed. ```ruby Concurrent::Promises.any(branch1, branch2).value! # => 1 (branch1 | branch2).value! # => 1 ``` ## Blocking methods In these examples we have used blocking methods like `value` extensively for their convenience, however in practice is better to avoid them and continue chaining. If they need to be used (e.g. when integrating with threads), `value!` is a better option over `value` when rejections are not dealt with differently. Otherwise the rejection are not handled and probably silently forgotten. ## Error handling When one of the tasks in the chain fails, the rejection propagates down the chain without executing the tasks created with `then`. ```ruby Concurrent::Promises. fulfilled_future(Object.new). then(&:succ). then(&:succ). result # => [false, # nil, # #>] ``` As `then` chained tasks execute only on fulfilled futures, there is a `rescue` method which chains a task which is executed only when the future is rejected. It can be used to recover from rejection. Using rescue to fulfill to 0 instead of the error. ```ruby Concurrent::Promises. fulfilled_future(Object.new). then(&:succ). then(&:succ). rescue { |err| 0 }. result # => [true, 0, nil] ``` Rescue not executed when there is no rejection. ```ruby Concurrent::Promises. fulfilled_future(1). then(&:succ). then(&:succ). rescue { |e| 0 }. result # => [true, 3, nil] ``` Tasks added with `chain` are evaluated always. ```ruby Concurrent::Promises. fulfilled_future(1). chain { |fulfilled, value, reason| fulfilled ? value : reason }. value! # => 1 Concurrent::Promises. rejected_future(StandardError.new('Ups')). chain { |fulfilled, value, reason| fulfilled ? value : reason }. value! # => # ``` Zip is rejected if any of the zipped futures is. ```ruby rejected_zip = Concurrent::Promises.zip( Concurrent::Promises.fulfilled_future(1), Concurrent::Promises.rejected_future(StandardError.new('Ups'))) # => <#Concurrent::Promises::Future:0x7fcd84b94430 rejected> rejected_zip.result # => [false, [1, nil], [nil, #]] rejected_zip. rescue { |reason1, reason2| (reason1 || reason2).message }. value # => "Ups" ``` ## Delayed futures Delayed futures will not evaluate until asked by `touch` or other method requiring resolution. ```ruby future = Concurrent::Promises.delay { sleep 0.1; 'lazy' } # => <#Concurrent::Promises::Future:0x7fcd84b7e888 pending> sleep 0.1 future.resolved? # => false future.touch # => <#Concurrent::Promises::Future:0x7fcd84b7e888 pending> sleep 0.2 future.resolved? # => true ``` All blocking methods like `wait`, `value` call `touch` and trigger evaluation. ```ruby Concurrent::Promises.delay { :value }.value # => :value ``` It propagates trough chain up allowing whole or partial lazy chains. ```ruby head = Concurrent::Promises.delay { 1 } branch1 = head.then(&:succ) branch2 = head.delay.then(&:succ) join = branch1 & branch2 sleep 0.1 ``` Nothing resolves. ```ruby [head, branch1, branch2, join].map(&:resolved?) # => [false, false, false, false] ``` Force `branch1` evaluation. ```ruby branch1.value # => 2 sleep 0.1 [head, branch1, branch2, join].map(&:resolved?) # => [true, true, false, false] ``` Force evaluation of both by calling `value` on `join`. ```ruby join.value # => [2, 2] [head, branch1, branch2, join].map(&:resolved?) # => [true, true, true, true] ``` ## Flatting Sometimes it is needed to wait for a inner future. Apparent solution is to wait inside the future `Concurrent::Promises.future { Concurrent::Promises.future { 1+1 }.value }.value` however as mentioned before, `value` calls should be **avoided** to avoid blocking threads. Therefore there is a flat method which is a correct solution in this situation and does not block any thread. ```ruby Concurrent::Promises.future { Concurrent::Promises.future { 1+1 } }.flat.value! # => 2 ``` A more complicated example. ```ruby Concurrent::Promises. future { Concurrent::Promises.future { Concurrent::Promises.future { 1 + 1 } } }. flat(1). then { |future| future.then(&:succ) }. flat(1). value! # => 3 ``` ## Scheduling Tasks can be planned to be executed with a time delay. Schedule task to be executed in 0.1 seconds. ```ruby scheduled = Concurrent::Promises.schedule(0.1) { 1 } # => <#Concurrent::Promises::Future:0x7fcd84b0d7f0 pending> scheduled.resolved? # => false ``` Value will become available after 0.1 seconds. ```ruby scheduled.value # => 1 ``` It can be used in the chain as well, where the delay is counted form a moment its parent resolves. Therefore following future will be resolved in 0.2 seconds. ```ruby future = Concurrent::Promises. future { sleep 0.1; :result }. schedule(0.1). then(&:to_s). value! # => "result" ``` Time can be used as well. ```ruby Concurrent::Promises.schedule(Time.now + 10) { :val } # => <#Concurrent::Promises::Future:0x7fcd84ae7960 pending> ``` ## Resolvable Future and Event: Sometimes it is required to resolve a future externally, in these cases `resolvable_future` and `resolvable_event` factory methods can be uses. See {Concurrent::Promises::ResolvableFuture} and {Concurrent::Promises::ResolvableEvent}. ```ruby future = Concurrent::Promises.resolvable_future # => <#Concurrent::Promises::ResolvableFuture:0x7fcd84adff30 pending> ``` The thread will be blocked until the future is resolved ```ruby thread = Thread.new { future.value } future.fulfill 1 # => <#Concurrent::Promises::ResolvableFuture:0x7fcd84adff30 fulfilled> thread.value # => 1 ``` Future can be resolved only once. ```ruby future.fulfill 1 rescue $! # => #[true, 1, nil], :new_result=>[true, 1, nil]}> future.fulfill 2, false # => false ``` ## How are promises executed? Promises use global pools to execute the tasks. Therefore each task may run on different thread which implies that users have to be careful not to depend on Thread local variables (or they have to set at the begging of the task and cleaned up at the end of the task). Since the tasks are running on may different threads of the thread pool, it's better to follow following rules: - Use only data passed in through arguments or values of parent futures, to have better control over what are futures accessing. - The data passed in and out of futures are easier to deal with if they are immutable or at least treated as such. - Any mutable and mutated object accessed by more than one threads or futures must be thread safe, see {Concurrent::Array}, {Concurrent::Hash}, and {Concurrent::Map}. (Value of a future may be consumed by many futures.) - Futures can access outside objects, but they has to be thread-safe. > *TODO: This part to be extended* # Advanced ## Callbacks ```ruby queue = Queue.new # => # future = Concurrent::Promises.delay { 1 + 1 } # => <#Concurrent::Promises::Future:0x7fcd84abe3a8 pending> future.on_fulfillment { queue << 1 } # evaluated asynchronously future.on_fulfillment! { queue << 2 } # evaluated on resolving thread queue.empty? # => true future.value # => 2 queue.pop # => 2 queue.pop # => 1 ``` ## Using executors Factory methods, chain, and callback methods have all other version of them which takes executor argument. It takes an instance of an executor or a symbol which is a shortcuts for the two global pools in concurrent-ruby. `fast` for short and non-blocking tasks and `:io` for blocking and long tasks. ```ruby Concurrent::Promises.future_on(:fast) { 2 }. then_on(:io) { File.read __FILE__ }. value.size # => 26689 ``` ## Run (simulated process) Similar to flatting is running. When `run` is called on a future it will flat indefinitely as long the future fulfils into a `Future` value. It can be used to simulate a thread like processing without actually occupying the thread. ```ruby count = lambda do |v| v += 1 v < 5 ? Concurrent::Promises.future_on(:fast, v, &count) : v end # => # 400.times. map { Concurrent::Promises.future_on(:fast, 0, &count).run.value! }. all? { |v| v == 5 } # => true ``` Therefore the above example finished fine on the the `:fast` thread pool even though it has much less threads than there is the simulated process. # Interoperability ## Actors Create an actor which takes received numbers and returns the number squared. ```ruby actor = Concurrent::Actor::Utils::AdHoc.spawn :square do -> v { v ** 2 } end # => # ``` Send result of `1+1` to the actor, and add 2 to the result send back from the actor. ```ruby Concurrent::Promises. future { 1 + 1 }. then_ask(actor). then { |v| v + 2 }. value! # => 6 ``` So `(1 + 1)**2 + 2 = 6`. The `ask` method returns future. ```ruby actor.ask(2).then(&:succ).value! # => 5 ``` ## Channel There is an implementation of channel as well. Lets start by creating a channel with capacity 2 messages. ```ruby ch1 = Concurrent::Promises::Channel.new 2 # => <#Concurrent::Promises::Channel:0x7fcd84c15dc8 size:2> ``` We push 3 messages, it can be observed that the last future representing the push is not fulfilled since the capacity prevents it. When the work which fills the channel depends on the futures created by push it can be used to create back pressure – the filling work is delayed until the channel has space for more messages. ```ruby pushes = 3.times.map { |i| ch1.push i } # => [<#Concurrent::Promises::Future:0x7fcd84c0e1e0 fulfilled>, # <#Concurrent::Promises::Future:0x7fcd84c0de20 fulfilled>, # <#Concurrent::Promises::Future:0x7fcd84c0d4e8 pending>] ch1.pop.value! # => 0 pushes # => [<#Concurrent::Promises::Future:0x7fcd84c0e1e0 fulfilled>, # <#Concurrent::Promises::Future:0x7fcd84c0de20 fulfilled>, # <#Concurrent::Promises::Future:0x7fcd84c0d4e8 fulfilled>] ``` A selection over channels can be created with select_channel factory method. It will be fulfilled with a first message available in any of the channels. It returns a pair to be able to find out which channel had the message available. ```ruby ch2 = Concurrent::Promises::Channel.new 2 # => <#Concurrent::Promises::Channel:0x7fcd84bef218 size:2> result = Concurrent::Promises.select_channel(ch1, ch2) # => <#Concurrent::Promises::ResolvableFuture:0x7fcd84bee390 fulfilled> result.value! # => [<#Concurrent::Promises::Channel:0x7fcd84c15dc8 size:2>, 1] Concurrent::Promises.future { 1+1 }.then_push_channel(ch1) # => <#Concurrent::Promises::Future:0x7fcd84be5808 pending> result = ( Concurrent::Promises.fulfilled_future('%02d') & Concurrent::Promises.select_channel(ch1, ch2)). then { |format, (channel, value)| format format, value } # => <#Concurrent::Promises::Future:0x7fcd84bdd810 pending> result.value! # => "02" ``` ## ProcessingActor There is also a new implementation of actors based on the Channel and the ability of promises to simulate process. The actor runs as a process but also does not occupy a thread per actor as previous Concurrent::Actor implementation. This implementation is close to Erlang actors, therefore OTP can be ported for this actors (and it's planned). The simplest actor is a one which just computes without even receiving a message. ```ruby actor = Concurrent::ProcessingActor.act(an_argument = 2) do |actor, number| number ** 3 end # => <#Concurrent::ProcessingActor:0x7fcd84bcefe0 termination:pending> actor.termination.value! # => 8 ``` Let's receive some messages though. ```ruby add_2_messages = Concurrent::ProcessingActor.act do |actor| # Receive two messages then terminate normally with the sum. (actor.receive & actor.receive).then do |a, b| a + b end end add_2_messages.tell 1 # => <#Concurrent::Promises::Future:0x7fcd84baceb8 pending> add_2_messages.termination.resolved? # => false add_2_messages.tell 3 # => <#Concurrent::Promises::Future:0x7fcd84ba6450 pending> add_2_messages.termination.value! # => 4 ``` Actors can also be used to apply back pressure to a producer. Let's start by defining an actor which a mailbox of size 2. ```ruby slow_counter = -> (actor, count) do actor.receive.then do |command, number| sleep 0.1 case command when :add slow_counter.call actor, count + number when :done # terminate count end end end actor = Concurrent::ProcessingActor.act_listening( Concurrent::Promises::Channel.new(2), 0, &slow_counter) # => <#Concurrent::ProcessingActor:0x7fcd84b7d640 termination:pending> ``` Now we can create a producer which will push messages only when there is a space available in the mailbox. We use promises to free a thread during waiting on a free space in the mailbox. ```ruby produce = -> receiver, i do if i < 10 receiver. # send a message to the actor, resolves only after the message is # accepted by the actor's mailbox tell([:add, i]). # send incremented message when the above message is accepted then(i+1, &produce) else receiver.tell(:done) # do not continue end end Concurrent::Promises.future(actor, 0, &produce).run.wait! # => <#Concurrent::Promises::Future:0x7fcd84b4fab0 fulfilled> actor.termination.value! # => 45 ``` # Use-cases ## Simple background processing ```ruby Concurrent::Promises.future { do_stuff } # => <#Concurrent::Promises::Future:0x7fcd84aecc30 pending> ``` ## Parallel background processing ```ruby tasks = 4.times.map { |i| Concurrent::Promises.future(i) { |i| i*2 } } # => [<#Concurrent::Promises::Future:0x7fcd84adec70 pending>, # <#Concurrent::Promises::Future:0x7fcd84addf00 pending>, # <#Concurrent::Promises::Future:0x7fcd84ad7a38 pending>, # <#Concurrent::Promises::Future:0x7fcd84ad6fc0 pending>] Concurrent::Promises.zip(*tasks).value! # => [0, 2, 4, 6] ``` ## Actor background processing Actors are mainly keep and isolate state, they should stay responsive not being blocked by a longer running computations. It desirable to offload the work to stateless promises. Lets define an actor which will process jobs, while staying responsive, and tracking the number of tasks being processed. ```ruby class Computer < Concurrent::Actor::RestartingContext def initialize super() @jobs = {} end def on_message(msg) command, *args = msg case command # new job to process when :run job = args[0] @jobs[job] = envelope.future # Process asynchronously and send message back when done. Concurrent::Promises.future(&job).chain(job) do |fulfilled, value, reason, job| self.tell [:done, job, fulfilled, value, reason] end # Do not make return value of this method to be answer of this message. # We are answering later in :done by resolving the future kept in @jobs. Concurrent::Actor::Behaviour::MESSAGE_PROCESSED when :done job, fulfilled, value, reason = *args future = @jobs.delete job # Answer the job's result. future.resolve fulfilled, value, reason when :status { running_jobs: @jobs.size } else # Continue to fail with unknown message. pass end end end ``` Create the computer actor and send it 3 jobs. ```ruby computer = Concurrent::Actor.spawn Computer, :computer # => # results = 3.times.map { computer.ask [:run, -> { sleep 0.1; :result }] } # => [<#Concurrent::Promises::Future:0x7fcd849e0030 pending>, # <#Concurrent::Promises::Future:0x7fcd849d80b0 pending>, # <#Concurrent::Promises::Future:0x7fcd849d1418 pending>] computer.ask(:status).value! # => {:running_jobs=>3} results.map(&:value!) # => [:result, :result, :result] ``` ## Solving the Thread count limit by thread simulation Sometimes an application requires to process a lot of tasks concurrently. If the number of concurrent tasks is high enough than it is not possible to create a Thread for each of them. A partially satisfactory solution could be to use Fibers, but that solution locks the application on MRI since other Ruby implementations are using threads for each Fiber. This library provides a {Concurrent::Promises::Future#run} method on a future to simulate threads without actually accepting one all the time. The run method is similar to {Concurrent::Promises::Future#flat} but it will keep flattening until it's fulfilled with non future value, then the value is taken as a result of the process simulated by `run`. ```ruby body = lambda do |v| # Some computation step of the process new_v = v + 1 # Is the process finished? if new_v < 5 # Continue computing with new value, does not have to be recursive. # It just has to return a future. Concurrent::Promises.future(new_v, &body) else # The process is finished, fulfill the final value with `new_v`. new_v end end Concurrent::Promises.future(0, &body).run.value! # => 5 ``` This solution works well an any Ruby implementation. > *TODO: More examples to be added.* ## Cancellation ### Simple Lets have two processes which will count until cancelled. ```ruby source, token = Concurrent::Cancellation.create # => [<#Concurrent::Cancellation:0x7fcd848b9260 canceled:false>, # <#Concurrent::Cancellation::Token:0x7fcd848b3d38 canceled:false>] count_until_cancelled = -> token, count do if token.canceled? count else Concurrent::Promises.future token, count+1, &count_until_cancelled end end futures = Array.new(2) do Concurrent::Promises.future(token, 0, &count_until_cancelled).run end # => [<#Concurrent::Promises::Future:0x7fcd84880370 pending>, # <#Concurrent::Promises::Future:0x7fcd848737b0 pending>] sleep 0.01 source.cancel # => true futures.map(&:value!) # => [83, 79] ``` Cancellation can also be used as event or future to log or plan re-execution. ```ruby token.to_event.chain do # log cancellation # plane re-execution end ``` ### Parallel background processing with cancellation Each task tries to count to 1000 but there is a randomly failing test. The tasks share a cancellation, when one of them fails it cancels the others. ```ruby source, token = Concurrent::Cancellation.create # => [<#Concurrent::Cancellation:0x7fcd84b15428 canceled:false>, # <#Concurrent::Cancellation::Token:0x7fcd84b14f50 canceled:false>] tasks = 4.times.map do |i| Concurrent::Promises.future(source, token, i) do |source, token, i| count = 0 1000.times do break count = :cancelled if token.canceled? count += 1 sleep 0.01 if rand > 0.95 source.cancel raise 'random error' end count end end end # => [<#Concurrent::Promises::Future:0x7fcd84b0c0f8 pending>, # <#Concurrent::Promises::Future:0x7fcd84b06c20 pending>, # <#Concurrent::Promises::Future:0x7fcd84b055f0 pending>, # <#Concurrent::Promises::Future:0x7fcd84b043a8 pending>] Concurrent::Promises.zip(*tasks).result # => [false, # [:cancelled, nil, :cancelled, :cancelled], # [nil, #, nil, nil]] ``` Without the randomly failing part it produces following. ```ruby source, token = Concurrent::Cancellation.create # => [<#Concurrent::Cancellation:0x7fcd84ac43c0 canceled:false>, # <#Concurrent::Cancellation::Token:0x7fcd84abfd98 canceled:false>] tasks = 4.times.map do |i| Concurrent::Promises.future(source, token, i) do |source, token, i| count = 0 1000.times do break count = :cancelled if token.canceled? count += 1 # sleep 0.01 # if rand > 0.95 # source.cancel # raise 'random error' # end end count end end Concurrent::Promises.zip(*tasks).result # => [true, [1000, 1000, 1000, 1000], nil] ``` ## Throttling concurrency By creating an actor managing the resource we can control how many threads is accessing the resource. In this case one at the time. ```ruby data = Array.new(10) { |i| '*' * i } # => ["", # "*", # "**", # "***", # "****", # "*****", # "******", # "*******", # "********", # "*********"] DB = Concurrent::Actor::Utils::AdHoc.spawn :db, data do |data| lambda do |message| # pretending that this queries a DB data[message] end end concurrent_jobs = 11.times.map do |v| DB. # ask the DB with the `v`, only one at the time, rest is parallel ask(v). # get size of the string, rejects for 11 then(&:size). # translate error to a value (message of the exception) rescue { |reason| reason.message } end Concurrent::Promises.zip(*concurrent_jobs).value! # => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "undefined method `size' for nil:NilClass"] ``` Often there is more then one DB connections, then the pool can be used. ```ruby pool_size = 5 # => 5 DB_POOL = Concurrent::Actor::Utils::Pool.spawn!('DB-pool', pool_size) do |index| # DB connection constructor Concurrent::Actor::Utils::AdHoc.spawn( name: "connection-#{index}", args: [data]) do |data| lambda do |message| # pretending that this queries a DB data[message] end end end concurrent_jobs = 11.times.map do |v| DB_POOL. # ask the DB with the `v`, only one at the time, rest is parallel ask(v). # get size of the string, rejects for 11 then(&:size). # translate error to a value (message of the exception) rescue { |reason| reason.message } end Concurrent::Promises.zip(*concurrent_jobs).value! # => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "undefined method `size' for nil:NilClass"] ``` In other cases the DB adapter maintains its internal connection pool and we just need to limit concurrent access to the DB's API to avoid the calls being blocked. Lets pretend that the `#[]` method on `DB_INTERNAL_POOL` is using the internal pool of size 3. We create throttle with the same size ```ruby DB_INTERNAL_POOL = Concurrent::Array.new data # => ["", # "*", # "**", # "***", # "****", # "*****", # "******", # "*******", # "********", # "*********"] max_tree = Concurrent::Throttle.new 3 # => <#Concurrent::Throttle:0x7fcd84bfcc10 limit:3 can_run:3> futures = 11.times.map do |i| max_tree. # throttled tasks, at most 3 simultaneous calls of [] on the database throttled_future { DB_INTERNAL_POOL[i] }. # un-throttled tasks, unlimited concurrency then { |starts| starts.size }. rescue { |reason| reason.message } end futures.map(&:value!) # => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "undefined method `size' for nil:NilClass"] ``` ## Long stream of tasks, applying back pressure Lets assume that we queuing an API for a data and the queries can be faster than we are able to process them. This example shows how to use channel as a buffer and how to apply back pressure to slow down the queries. ```ruby require 'json' channel = Concurrent::Promises::Channel.new 6 # => <#Concurrent::Promises::Channel:0x7fcd84a2d6c8 size:6> source, token = Concurrent::Cancellation.create # => [<#Concurrent::Cancellation:0x7fcd84a08080 canceled:false>, # <#Concurrent::Cancellation::Token:0x7fcd84a035f8 canceled:false>] def query_random_text(token, channel) Concurrent::Promises.future do # for simplicity the query is omitted # url = 'some api' # Net::HTTP.get(URI(url)) sleep 0.1 { 'message' => 'Lorem ipsum rhoncus scelerisque vulputate diam inceptos' }.to_json end.then(token) do |value, token| # The push to channel is fulfilled only after the message is successfully # published to the channel, therefore it will not continue querying until # current message is pushed. channel.push(value) | # It could wait on the push indefinitely if the token is not checked # here with `or` (the pipe). token.to_future end.flat_future.then(token) do |_, token| # query again after the message is pushed to buffer query_random_text(token, channel) unless token.canceled? end end words = [] # => [] words_throttle = Concurrent::Throttle.new 1 # => <#Concurrent::Throttle:0x7fcd849d0400 limit:1 can_run:1> def count_words_in_random_text(token, channel, words, words_throttle) channel.pop.then do |response| string = JSON.load(response)['message'] # processing is slower than querying sleep 0.2 words_count = string.scan(/\w+/).size end.then_throttled_by(words_throttle, words) do |words_count, words| # safe since throttled to only 1 task at a time words << words_count end.then(token) do |_, token| # count words in next message unless token.canceled? count_words_in_random_text(token, channel, words, words_throttle) end end end query_processes = 3.times.map do Concurrent::Promises.future(token, channel, &method(:query_random_text)).run end # => [<#Concurrent::Promises::Future:0x7fcd849a8180 pending>, # <#Concurrent::Promises::Future:0x7fcd84991f98 pending>, # <#Concurrent::Promises::Future:0x7fcd84981080 pending>] word_counter_processes = 2.times.map do Concurrent::Promises.future(token, channel, words, words_throttle, &method(:count_words_in_random_text)).run end # => [<#Concurrent::Promises::Future:0x7fcd8496acb8 pending>, # <#Concurrent::Promises::Future:0x7fcd8495bce0 pending>] sleep 0.5 # => 1 ``` Let it run for a while then cancel it and ensure that the runs all fulfilled (therefore ended) after the cancellation. Finally print the result. ```ruby source.cancel # => true query_processes.map(&:wait!) # => [<#Concurrent::Promises::Future:0x7fcd849a8180 fulfilled>, # <#Concurrent::Promises::Future:0x7fcd84991f98 fulfilled>, # <#Concurrent::Promises::Future:0x7fcd84981080 fulfilled>] word_counter_processes.map(&:wait!) # => [<#Concurrent::Promises::Future:0x7fcd8496acb8 fulfilled>, # <#Concurrent::Promises::Future:0x7fcd8495bce0 fulfilled>] words # => [7, 7, 7, 7] ``` Compared to using threads directly this is highly configurable and compostable solution. ## Periodic task By combining `schedule`, `run` and `Cancellation` periodically executed task can be easily created. ```ruby repeating_scheduled_task = -> interval, token, task do Concurrent::Promises. # Schedule the task. schedule(interval, token, &task). # If successful schedule again. # Alternatively use chain to schedule always. then { repeating_scheduled_task.call(interval, token, task) } end cancellation, token = Concurrent::Cancellation.create # => [<#Concurrent::Cancellation:0x7fcd84bfdb88 canceled:false>, # <#Concurrent::Cancellation::Token:0x7fcd84bfd6b0 canceled:false>] task = -> token do 5.times do token.raise_if_canceled # do stuff print '.' sleep 0.01 end end result = Concurrent::Promises.future(0.1, token, task, &repeating_scheduled_task).run # => <#Concurrent::Promises::Future:0x7fcd84bec2c0 pending> sleep 0.2 # => 0 cancellation.cancel # => true result.result # => [false, # nil, # #] ``` concurrent-ruby-1.0.5/doc/synchronization-notes.md000066400000000000000000000037301305460430400223360ustar00rootroot00000000000000# Concurrent Ruby Notes ## Locks Concurrent Ruby also has an internal extension of `Object` called `LockableObject`, which provides same synchronization primitives as Java's Object: `synchronize(&block)`, `wait(timeout = nil)`, `wait_until(timeout = nil, &condition)`, `signal`, `broadcast`. This class is intended for internal use in `concurrent-ruby` only and it does not support subclassing (since it cannot protect its lock from its children, for more details see [this article](http://wiki.apidesign.org/wiki/Java_Monitor)). It has minimal interface to be able to use directly locking available on given platforms. For non-internal use there is `Lock` and `Condition` implementation in `Synchronization` namespace, a condition can be obtained with `new_condition` method on `Lock`. So far their implementation is naive and requires more work. API is not expected to change. ## Method names conventions Methods starting with `ns_` are marking methods that are not using synchronization by themselves, they have to be used inside synchronize block. They are usually used in pairs to separate the synchronization from behavior and to allow to call methods in the same object without double locking. ``` ruby class Node # ... def left synchronize { ns_left } end def right synchronize { ns_right } end def to_a # avoids double locking synchronize { [ns_left, ns_right] } end private def ns_left @left end def ns_right @right end # ... end ``` ## Piggybacking Any write executed before volatile write based on program-order is visible to the volatile read as well, which allows [piggybacking](http://stackoverflow.com/questions/8769570/volatile-piggyback-is-this-enough-for-visiblity). Because it creates synchronizes-with (JMM term) order between volatile write and read, which participates in creating happens-before order. This trick is used in some of the abstractions, to avoid unnecessary synchronization or volatile declarations. concurrent-ruby-1.0.5/doc/synchronization.md000066400000000000000000000003261305460430400212060ustar00rootroot00000000000000# Synchronization [This document](https://docs.google.com/document/d/1pVzU8w_QF44YzUCCab990Q_WZOdhpKolCIHaiXG-sPw/edit?usp=sharing) is moved to Google documents. It will be moved here once final and stabilized. concurrent-ruby-1.0.5/doc/thread_pools.md000066400000000000000000000326011305460430400204310ustar00rootroot00000000000000# Thread Pools A Thread Pool is an abstraction that you can give a unit of work to, and the work will be executed by one of possibly several threads in the pool. One motivation for using thread pools is the overhead of creating and destroying threads. Creating a pool of reusable worker threads then repeatedly re-using threads from the pool can have huge performance benefits for a long-running application like a service. `concurrent-ruby` also offers some higher level abstractions than thread pools. For many problems, you will be better served by using one of these -- if you are thinking of using a thread pool, we especially recommend you look at and understand [Future](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Future.html)s before deciding to use thread pools directly instead. Futures are implemented using thread pools, but offer a higher level abstraction. But there are some problems for which directly using a thread pool is an appropriate solution. Or, you may wish to make your own thread pool to run Futures on, to be separate or have different characteristics than the global thread pool that Futures run on by default. Thread pools are considered 'executors' -- an object you can give a unit of work to, to have it executed. In fact, thread pools are the main kind of executor you will see - others are mainly for testing or odd edge cases. In some documentation or source code you'll see reference to an 'executor' -- this is commonly a thread pool, or else something similar that executes units of work (usually supplied as Ruby blocks). ## FixedThreadPool A [FixedThreadPool](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/FixedThreadPool.html) contains a fixed number of threads. When you give a unit of work to it, an available thread will be used to execute. ~~~ruby pool = Concurrent::FixedThreadPool.new(5) # 5 threads pool.post do # some parallel work end # As with all thread pools, execution resumes immediately here in the caller thread, # while work is concurrently being done in the thread pool, at some possibly future point. ~~~ What happens if you post new work when all (e.g.) 5 threads are currently busy? It will be added to a queue, and executed when a thread becomes available. In a `FixedThreadPool`, if you post work to the pool much faster than the work can be completed, the queue may grow without bounds, as the work piles up in the holding queue, using up memory without bounds. To limit the queue and apply some form of 'back pressure' instead, you can use the more configurable `ThreadPoolExecutor` (See below). If you'd like to base the number of threads in the pool on the number of processors available, your code can consult [Concurrent.processor_count](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ProcessorCounter.html#processor_count-instance_method). The `FixedThreadPool` is based on the semantics used in Java for [java.util.concurrent.Executors.newFixedThreadPool(int nThreads)](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html#newFixedThreadPool(int)) ## CachedThreadPool A [CachedThreadPool](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/CachedThreadPool.html) will create as many threads as necessary for work posted to it. If you post work to a `CachedThreadPool` when all its existing threads are busy, it will create a new thread to execute that work, and then keep that thread cached for future work. Cached threads are reclaimed (destroyed) after they are idle for a while. CachedThreadPools typically improve the performance of programs that execute many short-lived asynchronous tasks. ~~~ruby pool = Concurrent::CachedThreadPool.new pool.post do # some parallel work end ~~~ The behavior of `CachedThreadPool` is based on Java's [java.util.concurrent.Executors.newCachedThreadPool()](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html#newCachedThreadPool()) If you'd like to configure a maximum number of threads, you can use the more general configurable `ThreadPoolExecutor`. ## ThreadPoolExecutor A [ThreadPoolExecutor](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ThreadPoolExecutor.html) is a general-purpose thread pool that can be configured to have various behaviors. A `ThreadPoolExecutor` will automatically adjust the pool size according to the bounds set by `min-threads` and `max-threads`. When a new task is submitted and fewer than `min-threads` threads are running, a new thread is created to handle the request, even if other worker threads are idle. If there are more than `min-threads` but less than `max-threads` threads running, a new thread will be created only if the queue is full. The `CachedThreadPool` and `FixedThreadPool` are simply `ThreadPoolExecutors` with certain configuration pre-determined. For instance, to create a `ThreadPoolExecutor` that works just like a `FixedThreadPool.new 5`, you could: ~~~ruby pool = Concurrent::ThreadPoolExecutor.new( min_threads: 5, max_threads: 5, max_queue: 0 # unbounded work queue ) ~~~ If you want to provide a maximum queue size, you may also consider the `fallback_policy` which defines what will happen if work is posted to a pool when the queue of waiting work has reached the maximum size and no new threads can be created. Available policies: * abort: Raise a `Concurrent::RejectedExecutionError` exception and discard the task. (default policy) * discard: Silently discard the task and return nil as the task result. * caller_runs: The work will be executed in the thread of the caller, instead of being given to another thread in the pool. For example: ~~~ruby pool = Concurrent::ThreadPoolExecutor.new( min_threads: 5, max_threads: 5, max_queue: 100, fallback_policy: :caller_runs ) ~~~ You can create something similar to a `CachedThreadPool`, but with a maximum number of threads and a bounded queue. A new thread will be created for the first 3 tasks submitted, and then, once the queue is full, up to an additional 7 threads (10 total) will be created. If all 10 threads are busy and 100 tasks are already queued, additional tasks will be rejected. ~~~ruby pool = Concurrent::ThreadPoolExecutor.new( min_threads: 3, # create up to 3 threads before queueing tasks max_threads: 10, # create at most 10 threads max_queue: 100, # at most 100 jobs waiting in the queue ) ~~~ ThreadPoolExecutors with `min_threads` and `max_threads` set to different values will ordinarily reclaim idle threads. You can supply an `idletime` argument, number of seconds that a thread may be idle before being reclaimed. The default is 60 seconds. `concurrent-ruby` thread pools are based on designs from `java.util.concurrent` -- a well-designed, stable, scalable, and battle-tested concurrency library. The `ThreadPoolExecutor` is based on Java [java.util.concurrent.ThreadPoolExecutor](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html), and is in fact implemented with a Java ThreadPoolExecutor when running under JRuby. For more information on the design and concepts, you may find the Java documentation helpful: * http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html * http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html * http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html ## Thread Pool Status and Shutdown A running thread pool can be shutdown in an orderly or disruptive manner. Once a thread pool has been shutdown it cannot be started again. The `shutdown` method can be used to initiate an orderly shutdown of the thread pool. All new post calls will be handled according to the `fallback_policy` (i.e. failing with a RejectedExecutionError by default). Threads in the pool will continue to process all in-progress work and will process all tasks still in the queue. The `kill` method can be used to immediately shutdown the pool. All new post calls will be handled according to the `fallback_policy`. Ruby's `Thread.kill` will be called on all threads in the pool, aborting all in-progress work. Tasks in the queue will be discarded. The method `wait_for_termination` can be used to block and wait for pool shutdown to complete. This is useful when shutting down an application and ensuring the app doesn't exit before pool processing is complete. The method wait_for_termination will block for a maximum of the given number of seconds then return true (if shutdown completed successfully) or false (if it was still ongoing). When the timeout value is `nil` the call will block indefinitely. Calling `wait_for_termination` on a stopped thread pool will immediately return true. ~~~ruby # tell the pool to shutdown in an orderly fashion, allowing in progress work to complete pool.shutdown # now wait for all work to complete, wait as long as it takes pool.wait_for_termination ~~~ You can check for current pool status: ~~~ruby pool.running? pool.shuttingdown? # in process of shutting down, can't take any more work pool.shutdown? # it's done ~~~ The `shutdown?` method will return true for a stopped pool, regardless of whether the pool was stopped with `shutdown` or `kill`. ## Other Executors There are several other thread pools and executors in the `concurrent-ruby` library. See the API documentation for more information: * [CachedThreadPool](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/CachedThreadPool.html) * [FixedThreadPool](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/FixedThreadPool.html) * [ImmediateExecutor](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ImmediateExecutor.html) * [PerThreadExecutor](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/PerThreadExecutor.html) * [SafeTaskExecutor](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/SafeTaskExecutor.html) * [SerializedExecution](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/SerializedExecution.html) * [SerializedExecutionDelegator](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/SerializedExecutionDelegator.html) * [SingleThreadExecutor](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/SingleThreadExecutor.html) * [ThreadPoolExecutor](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ThreadPoolExecutor.html) * [TimerSet](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/TimerSet.html) ## Global Thread Pools Concurrent Ruby provides several global thread pools. Higher-level abstractions use global thread pools, by default, for running asynchronous operations without creating new threads more often than necessary. These executors are lazy-loaded so they do not create overhead when not needed. The global executors may also be accessed directly if desired. For more information regarding the global thread pools and their configuration, refer to the [API documentation](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Configuration.html). When using a higher-level abstraction, which ordinarily uses a global thread pool, you may wish to instead supply your own thread pool, for separation of work, or to control the thread pool behavior with configuration. ~~~ruby pool = Concurrent::ThreadPoolExecutor.new( :min_threads => [2, Concurrent.processor_count].max, :max_threads => [2, Concurrent.processor_count].max, :max_queue => [2, Concurrent.processor_count].max * 5, :fallback_policy => :caller_runs ) future = Future.execute(:executor => pool) do #work end ~~~ ## Forking Some Ruby versions allow the Ruby process to be [forked](http://ruby-doc.org/core-2.3.0/Process.html#method-c-fork). Generally, mixing threading and forking is an [anti-pattern](https://en.wikipedia.org/wiki/Anti-pattern). Threading and forking are both concurrency techniques and mixing the two is rarely beneficial. Moreover, threads created before the fork become unusable ("dead") in the forked process. This aspect of forking is a significant issue for any application or library which spawns threads. It is strongly advised that applications using `ThreadPoolExecutor` do **not** also fork. Since Concurrent Ruby is a foundational library often used by gems which are in turn used by other applications, it is impossible to predict or prevent upstream forking. Concurrent Ruby therefore makes a few guarantees about the behavior of `ThreadPoolExecutor` after forking. *Concurrent Ruby guarantees that jobs post on the parent process will be handled on the parent process; the child process does not inherit any jobs at the time of the fork. Concurrent Ruby also guarantees that thread pools copied to the child process will continue to function normally.* When a fork occurs the `ThreadPoolExecutor` in the *forking* process takes no special actions whatsoever. It has no way of knowing that a fork occurred. It proceeds to process its jobs as normal and makes no attempt whatsoever to distribute those jobs to the forked process(es). When a `ThreadPoolExecutor` in the *forked* process detects that a fork has occurred it immediately takes the following actions: * Clears all pending jobs from its queue (assuming they will be handled by the *forking* process). * Deletes all worker threads (they will have died during the fork). * Resets all job counters (these counts will be reflected in the *forking* process). * Begins posting new jobs as normal. These actions guarantee that all in-flight jobs are processed normally in the forking process and that thread pools, including the global thread pools, remain functional in the forked process(es). concurrent-ruby-1.0.5/doc/top-stock-scala/000077500000000000000000000000001305460430400204265ustar00rootroot00000000000000concurrent-ruby-1.0.5/doc/top-stock-scala/.gitignore000066400000000000000000000000001305460430400224040ustar00rootroot00000000000000concurrent-ruby-1.0.5/doc/top-stock-scala/README.md000066400000000000000000000054411305460430400217110ustar00rootroot00000000000000# Top Stock - Scala This program determines which stock had the highest price in a given year. It as an example from chapter 1 "Introduction", section 1.2 "What's Scala?" of the book [Programming Scala: Tackle Multi-Core Complexity on the Java Virtual Machine](http://pragprog.com/book/vsscala/programming-scala). ## What It Does This program takes a list of one or more stock symbols and a year. It then concurrently obtains the relevant stock data from Yahoo's iChart service for each symbol. Once all the data has been retrieved the program determines which stock had the highest year-end closing price. http://ichart.finance.yahoo.com/table.csv?s=AAPL&a=11&b=01&c=2008&d=11&e=31&f=2008&g=m ### Run It This example can be run from the console. From the root of the repo run: > $ bundle exec ruby top-stock-scala/top-stock.rb The output should be: > Top stock of 2008 is GOOG closing at price $307.65 #### The Ruby Code ```ruby require 'concurrent' require 'open-uri' def get_year_end_closing(symbol, year) uri = "http://ichart.finance.yahoo.com/table.csv?s=#{symbol}&a=11&b=01&c=#{year}&d=11&e=31&f=#{year}&g=m" data = open(uri) {|f| f.collect{|line| line.strip } } price = data[1].split(',')[4] price.to_f [symbol, price.to_f] end def get_top_stock(symbols, year, timeout = 5) stock_prices = symbols.collect{|symbol| Concurrent::dataflow{ get_year_end_closing(symbol, year) }} Concurrent::dataflow(*stock_prices) { |*prices| prices.reduce(['', 0.0]){|highest, price| price.last > highest.last ? price : highest} }.value(timeout) end symbols = ['AAPL', 'GOOG', 'IBM', 'ORCL', 'MSFT'] year = 2008 top_stock, highest_price = get_top_stock(symbols, year) puts "Top stock of #{year} is #{top_stock} closing at price $#{highest_price}" ``` #### The Scala Code ```scala //START:PART1 import scala.actors._ import Actor._ val symbols = List( "AAPL", "GOOG", "IBM", "JAVA", "MSFT") val receiver = self val year = 2008 symbols.foreach { symbol => actor { receiver ! getYearEndClosing(symbol, year) } } val (topStock, highestPrice) = getTopStock(symbols.length) printf("Top stock of %d is %s closing at price %f\n", year, topStock, highestPrice) //END:PART1 //START:PART2 def getYearEndClosing(symbol : String, year : Int) = { val url = "http://ichart.finance.yahoo.com/table.csv?s=" + symbol + "&a=11&b=01&c=" + year + "&d=11&e=31&f=" + year + "&g=m" val data = io.Source.fromURL(url).mkString val price = data.split("\n")(1).split(",")(4).toDouble (symbol, price) } //END:PART2 //START:PART3 def getTopStock(count : Int) : (String, Double) = { (1 to count).foldLeft("", 0.0) { (previousHigh, index) => receiveWithin(10000) { case (symbol : String, price : Double) => if (price > previousHigh._2) (symbol, price) else previousHigh } } } //END:PART3 ``` concurrent-ruby-1.0.5/doc/top-stock-scala/top-stock.rb000066400000000000000000000014751305460430400227050ustar00rootroot00000000000000require 'concurrent' require 'open-uri' def get_year_end_closing(symbol, year) uri = "http://ichart.finance.yahoo.com/table.csv?s=#{symbol}&a=11&b=01&c=#{year}&d=11&e=31&f=#{year}&g=m" data = open(uri) {|f| f.collect{|line| line.strip } } price = data[1].split(',')[4] price.to_f [symbol, price.to_f] end def get_top_stock(symbols, year, timeout = 5) stock_prices = symbols.collect{|symbol| Concurrent::dataflow{ get_year_end_closing(symbol, year) }} Concurrent::dataflow(*stock_prices) { |*prices| prices.reduce(['', 0.0]){|highest, price| price.last > highest.last ? price : highest} }.value(timeout) end symbols = ['AAPL', 'GOOG', 'IBM', 'ORCL', 'MSFT'] year = 2008 top_stock, highest_price = get_top_stock(symbols, year) puts "Top stock of #{year} is #{top_stock} closing at price $#{highest_price}" concurrent-ruby-1.0.5/doc/tvar.md000066400000000000000000000245731305460430400167330ustar00rootroot00000000000000`TVar` and `atomically` implement a software transactional memory. A `TVar` is a single item container that always contains exactly one value. The `atomically` method allows you to modify a set of `TVar` objects with the guarantee that all of the updates are collectively atomic - they either all happen or none of them do - consistent - a `TVar` will never enter an illegal state - and isolated - atomic blocks never interfere with each other when they are running. You may recognise these properties from database transactions. There are some very important and unusual semantics that you must be aware of: * Most importantly, the block that you pass to `atomically` may be executed more than once. In most cases your code should be free of side-effects, except for via `TVar`. * If an exception escapes an `atomically` block it will abort the transaction. * It is undefined behaviour to use `callcc` or `Fiber` with `atomically`. * If you create a new thread within an `atomically`, it will not be part of the transaction. Creating a thread counts as a side-effect. We implement nested transactions by flattening. We only support strong isolation if you use the API correctly. In order words, we do not support strong isolation. Our implementation uses a very simple two-phased locking with versioned locks algorithm and lazy writes, as per [1]. In the future we will look at more advanced algorithms, contention management and using existing Java implementations when in JRuby. See: 1. T. Harris, J. Larus, and R. Rajwar. Transactional Memory. Morgan & Claypool, second edition, 2010. ## Motivation Consider an application that transfers money between bank accounts. We want to transfer money from one account to another. It is very important that we don't lose any money! But it is also important that we can handle many account transfers at the same time, so we run them concurrently, and probably also in parallel. This code shows us transferring ten pounds from one account to another. ```ruby a = BankAccount.new(100_000) b = BankAccount.new(100) a.value -= 10 b.value += 10 ``` Before we even start to talk about to talk about concurrency and parallelism, is this code safe? What happens if after removing money from account a, we get an exception? It's a slightly contrived example, but if the account totals were very large, adding to them could involve the stack allocation of a `BigNum`, and so could cause out of memory exceptions. In that case the money would have disappeared from account a, but not appeared in account b. Disaster! So what do we really need to do? ```ruby a = BankAccount.new(100_000) b = BankAccount.new(100) original_a = a.value a.value -= 10 begin b.value += 10 rescue e => a.value = original_a raise e end ``` This rescues any exceptions raised when setting b and will roll back the change we have already made to b. We'll keep this rescue code in mind, but we'll leave it out of future examples for simplicity. That might have made the code work when it only runs sequentially. Lets start to consider some concurrency. It's obvious that we want to make the transfer of money mutually exclusive with any other transfers - in order words it is a critical section. The usual solution to this would be to use a lock. ```ruby lock.synchronize do a.value -= 10 b.value += 10 end ``` That should work. Except we said we'd like these transfer to run concurrently, and in parallel. With a single lock like that we'll only let one transfer take place at a time. Perhaps we need more locks? We could have one per account: ```ruby a.lock.synchronize do b.lock.synchronize do a.value -= 10 b.value += 10 end end ``` However this is vulnerable to deadlock. If we tried to transfer from a to b, at the same time as from b to a, it's possible that the first transfer locks a, the second transfer locks b, and then they both sit there waiting forever to get the other lock. Perhaps we can solve that by applying a total ordering to the locks and always acquire them in the same order? ```ruby locks_needed = [a.lock, b.lock] locks_in_order = locks_needed.sort{ |x, y| x.number <=> y.number } locks_in_order[0].synchronize do locks_in_order[1].synchronize do a.value -= 10 b.value += 10 end end ``` That might work. But we need to know exactly what locks we're going to need before we start. If there were conditions in side the transfer this might be more complicated. We also need to remember the rescue code we had above to deal with exceptions. This is getting out of hand - and it's where `TVar` comes in. We'll model the accounts as `TVar` - transactional variable, and instead of locks we'll use `Concurrent::atomically`. ```ruby a = TVar.new(100_000) b = TVar.new(100) Concurrent::atomically do a.value -= 10 b.value += 10 end ``` That short piece of code effectively solves all the concerns we identified above. How it does it is described in the reference above. You just need to be happy that any two `atomically` blocks (we call them transactions) that use an overlapping set of `TVar` objects will appear to have happened as if there was a big global lock on them, and that if any exception is raised in the block, it will be as if the block never happened. But also keep in mind the important points we detailed right at the start of the article about side effects and repeated execution. ## Evaluation We evaluated the performance of our `TVar` implementation using a bank account simulation with a range of synchronisation implementations. The simulation maintains a set of bank account totals, and runs transactions that either get a summary statement of multiple accounts (a read-only operation) or transfers a sum from one account to another (a read-write operation). We implemented a bank that does not use any synchronisation (and so creates inconsistent totals in accounts), one that uses a single global (or 'coarse') lock (and so won't scale at all), one that uses one lock per account (and so has a complicated system for locking in the correct order) and one using our `TVar` and `atomically`. We ran 1 million transactions divided equally between a varying number of threads on a system that has at least that many physical cores. The transactions are made up of a varying mixture of read-only and read-write transactions. We ran each set of transactions thirty times, discarding the first ten and then taking an algebraic mean. These graphs show only the simple mean. Our `tvars- experiments` branch includes the benchmark used, full details of the test system, and all the raw data. Using JRuby using 75% read-write transactions, we can compare how the different implementations of bank accounts scales to more cores. That is, how much faster it runs if you use more cores. ![](https://raw.githubusercontent.com/ruby-concurrency/concurrent-ruby/master/doc/images/tvar/implementation-scalability.png) We see that the coarse lock implementation does not scale at all, and in fact with more cores only wastes more time in contention for the single global lock. We see that the unsynchronised implementation doesn't seem to scale well - which is strange as there should be no overhead, but we'll explain that in a second. We see that the fine lock implementation seems to scale better, and that the `TVar` implementation scales the best. So the `TVar` implementation *scales* very well, but how absolutely fast is it? ![](https://raw.githubusercontent.com/ruby-concurrency/concurrent-ruby/master/doc/images/tvar/implementation-absolute.png) Well, that's the downside. The unsynchronised implementation doesn't scale well because it's so fast in the first place, and probably because we're bound on access to the memory - the threads don't have much work to do, so no matter how many threads we have the system is almost always reaching out to the L3 cache or main memory. However remember that the unsynchronised implementation isn't correct - the totals are wrong at the end. The coarse lock implementation has an overhead of locking and unlocking. The fine lock implementation has a greater overhead as as the locking scheme is complicated to avoid deadlock. It scales better, however, actually allowing transactions to be processed in parallel. The `TVar` implementation has a greater overhead still - and it's pretty huge. That overhead is the cost for the simple programming model of an atomic block. So that's what `TVar` gives you at the moment - great scalability, but it has a high overhead. That's pretty much the state of software transactional memory in general. Perhaps hardware transactional memory will help us, or perhaps we're happy anyway with the simpler and safer programming model that the `TVar` gives us. We can also use this experiment to compare different implementations of Ruby. We looked at just the `TVar` implementation and compared MRI 2.1.1, Rubinius 2.2.6, and JRuby 1.7.11, again at 75% write transactions. ![](https://raw.githubusercontent.com/ruby-concurrency/concurrent-ruby/master/doc/images/tvar/ruby-scalability.png) We see that MRI provides no scalability, due to the global interpreter lock (GIL). JRuby seems to scale better than Rubinius for this workload (there are of course other workloads). As before we should also look at the absolute performance, not just the scalability. ![](https://raw.githubusercontent.com/ruby-concurrency/concurrent-ruby/master/doc/images/tvar/ruby-absolute.png) Again, JRuby seems to be faster than Rubinius for this experiment. Interestingly, Rubinius looks slower than MRI for 1 core, but we can get around that by using more cores. We've used 75% read-write transactions throughout. We'll just take a quick look at how the scalability varies for different workloads, for scaling between 1 and 2 threads. We'll admit that we used 75% read-write just because it emphasised the differences. ![](https://raw.githubusercontent.com/ruby-concurrency/concurrent-ruby/master/doc/images/tvar/implementation-write-proportion-scalability.png) Finally, we can also run on a larger machine. We repeated the experiment using a machine with 64 physical cores and JRuby. ![](https://raw.githubusercontent.com/ruby-concurrency/concurrent-ruby/master/doc/images/tvar/implementation-scalability.png) ![](https://raw.githubusercontent.com/ruby-concurrency/concurrent-ruby/master/doc/images/tvar/implementation-absolute.png) Here you can see that `TVar` does become absolutely faster than using a global lock, at the slightly ridiculously thread-count of 50. It's probably not statistically significant anyway. concurrent-ruby-1.0.5/examples/000077500000000000000000000000001305460430400164735ustar00rootroot00000000000000concurrent-ruby-1.0.5/examples/a-tour-of-go-channels/000077500000000000000000000000001305460430400225005ustar00rootroot00000000000000concurrent-ruby-1.0.5/examples/a-tour-of-go-channels/buffered-channels.rb000077500000000000000000000004311305460430400264010ustar00rootroot00000000000000#!/usr/bin/env ruby $: << File.expand_path('../../../lib', __FILE__) require 'concurrent-edge' Channel = Concurrent::Channel ## A Tour of Go: Buffered Channels # https://tour.golang.org/concurrency/3 ch = Channel.new(capacity: 2) ch << 1 ch << 2 puts ~ch puts ~ch __END__ 1 2 concurrent-ruby-1.0.5/examples/a-tour-of-go-channels/channels.rb000077500000000000000000000007771305460430400246360ustar00rootroot00000000000000#!/usr/bin/env ruby $: << File.expand_path('../../../lib', __FILE__) require 'concurrent-edge' Channel = Concurrent::Channel ## A Tour of Go: Channels # https://tour.golang.org/concurrency/2 def sum(a, c) sum = a.reduce(0, &:+) c << sum # `<<` is an alias for `put` or `send` end a = [7, 2, 8, -9, 4, 0] l = a.length / 2 c = Channel.new Channel.go { sum(a[-l, l], c) } Channel.go { sum(a[0, l], c) } x, y = ~c, ~c # `~` is an alias for `take` or `receive` puts [x, y, x+y].join(' ') __END__ -5 17 12 concurrent-ruby-1.0.5/examples/a-tour-of-go-channels/default-selection.rb000077500000000000000000000010761305460430400264430ustar00rootroot00000000000000#!/usr/bin/env ruby $: << File.expand_path('../../../lib', __FILE__) require 'concurrent-edge' Channel = Concurrent::Channel ## A Tour of Go: Default Selection # https://tour.golang.org/concurrency/6 tick = Channel.tick(0.1) boom = Channel.after(0.5) loop do Channel.select do |s| s.take(tick) { |t| print "tick.\n" if t } s.take(boom) do print "BOOM!\n" exit end s.default do print " .\n" sleep(0.05) end end end __END__ . . tick. . . tick. . . tick. . . tick. . . tick. BOOM! concurrent-ruby-1.0.5/examples/a-tour-of-go-channels/equivalent-binary-trees.rb000077500000000000000000000023671305460430400276170ustar00rootroot00000000000000#!/usr/bin/env ruby $: << File.expand_path('../../../lib', __FILE__) require 'concurrent-edge' Channel = Concurrent::Channel ## A Tour of Go: Equivalent Binary Trees # https://tour.golang.org/concurrency/8 Tree = Struct.new(:value, :left, :right) def new_tree(n, size = 10) values = [*1..size].collect{|i| i * n }.sample(size) root = Tree.new(values.shift) inserter = ->(current, new) do if new.value <= current.value if current.left.nil? current.left = new else inserter.call(current.left, new) end else if current.right.nil? current.right = new else inserter.call(current.right, new) end end end while value = values.shift do inserter.call(root, Tree.new(value)) end root end def walk(tree, channel) _walk = ->(t, ch) do return unless t _walk.call(t.left, ch) ch << t.value _walk.call(t.right, ch) end _walk.call(tree, channel) channel.close end def same(t1, t2) ch1 = Channel.new ch2 = Channel.new Channel.go { walk(t1, ch1) } Channel.go { walk(t2, ch2) } ch1.each do |v| return false unless v == ~ch2 end return true end puts same(new_tree(1), new_tree(1)) puts same(new_tree(1), new_tree(2)) __END__ true false concurrent-ruby-1.0.5/examples/a-tour-of-go-channels/range-and-close.rb000077500000000000000000000006521305460430400257720ustar00rootroot00000000000000#!/usr/bin/env ruby $: << File.expand_path('../../../lib', __FILE__) require 'concurrent-edge' Channel = Concurrent::Channel ## A Tour of Go: Range and Close # https://tour.golang.org/concurrency/4 def fibonacci(n, c) x, y = 0, 1 (1..n).each do c << x x, y = y, x+y end c.close end c = Channel.new(capacity: 10) Channel.go { fibonacci(c.capacity, c) } c.each { |i| puts i } __END__ 0 1 1 2 3 5 8 13 21 34 concurrent-ruby-1.0.5/examples/a-tour-of-go-channels/select.rb000077500000000000000000000011361305460430400243100ustar00rootroot00000000000000#!/usr/bin/env ruby $: << File.expand_path('../../../lib', __FILE__) require 'concurrent-edge' Channel = Concurrent::Channel ## A Tour of Go: Select # https://tour.golang.org/concurrency/5 def fibonacci(c, quit) x, y = 0, 1 loop do Channel.select do |s| s.case(c, :<<, x) { x, y = y, x+y; x } # alias for `s.put` s.case(quit, :~) do # alias for `s.take` puts 'quit' return end end end end c = Channel.new quit = Channel.new Channel.go do 10.times { puts ~c } quit << 0 end fibonacci(c, quit) __END__ 0 1 1 2 3 5 8 13 21 34 quit concurrent-ruby-1.0.5/examples/actor_stress_test.rb000077500000000000000000000063511305460430400226020ustar00rootroot00000000000000#!/usr/bin/env ruby #$: << File.expand_path('../../lib', __FILE__) require 'benchmark' require 'optparse' require 'thread' require 'rspec/expectations' require 'concurrent/actor' class ActorStressTester include ::RSpec::Matchers TESTS_PER_RUN = 5 THREADS_PER_TEST = 10 LOOPS_PER_THREAD = 25 class Ping < Concurrent::Actor::Context def initialize(queue) @queue = queue end def on_message(message) case message when :child Concurrent::Actor::Utils::AdHoc.spawn(:pong, @queue) do |queue| -> m { queue << m } end else @queue << message message end end end def initialize(opts = {}) @tests = opts.fetch(:tests, TESTS_PER_RUN) @threads = opts.fetch(:threads, THREADS_PER_TEST) @loops = opts.fetch(:loops, LOOPS_PER_THREAD) end def run plural = ->(number){ number == 1 ? '' : 's' } puts "Running #{@tests} test#{plural.call(@tests)} " + "with #{@threads} thread#{plural.call(@threads)} each " + "and #{@loops} loop#{plural.call(@loops)} per thread..." Benchmark.bmbm do |bm| @tests.times do bm.report do test(@threads, @loops) end end end end def test(threads, loops) (1..threads).collect do Thread.new do loops.times do queue = Queue.new actor = Ping.spawn(:ping, queue) core = Concurrent::Actor.root.send(:core) children = core.instance_variable_get(:@children) expect(children).to include(actor) actor << 'a' << 1 expect(queue.pop).to eq 'a' expect(actor.ask(2).value).to eq 2 expect(actor.parent).to eq Concurrent::Actor.root expect(Concurrent::Actor.root.path).to eq '/' expect(actor.path).to eq '/ping' child = actor.ask(:child).value expect(child.path).to eq '/ping/pong' queue.clear child.ask(3) expect(queue.pop).to eq 3 actor << :terminate! #expect(actor.ask(:blow_up).wait).to be_rejected expect(actor.ask(:blow_up).wait).to be_failed terminate_actors(actor, child) end end end.each(&:join) end def terminate_actors(*actors) actors.each do |actor| unless actor.ask!(:terminated?) actor.ask!(:terminate!) end end end end # def trace! # set_trace_func proc { |event, file, line, id, binding, classname| # # thread = eval('Thread.current', binding).object_id.to_s(16) # printf "%8s %20s %20s %s %s:%-2d\n", event, id, classname, nil, file, line # } # yield # ensure # set_trace_func nil # end if $0 == __FILE__ options = {} OptionParser.new do |opts| opts.banner = "Usage: #{File.basename(__FILE__)} [options]" opts.on("--tests=TESTS", "Number of tests per run") do |value| options[:tests] = value.to_i end opts.on("--threads=THREADS", "Number of threads per test") do |value| options[:threads] = value.to_i end opts.on("--loops=LOOPS", "Number of loops per thread") do |value| options[:loops] = value.to_i end opts.on("-h", "--help", "Prints this help") do puts opts exit end end.parse! ActorStressTester.new(options).run end concurrent-ruby-1.0.5/examples/atomic_example.rb000077500000000000000000000006101305460430400220070ustar00rootroot00000000000000#!/usr/bin/env ruby #$: << File.expand_path('../../lib', __FILE__) require 'concurrent/atomics' my_atomic = Concurrent::AtomicReference.new(0) my_atomic.update {|v| v + 1} puts "new value: #{my_atomic.value}" begin my_atomic.try_update {|v| v + 1} rescue Concurrent::Atomic::ConcurrentUpdateError => cue # deal with it (retry, propagate, etc) end puts "new value: #{my_atomic.value}" concurrent-ruby-1.0.5/examples/benchmark_async.rb000077500000000000000000000154751305460430400221660ustar00rootroot00000000000000#!/usr/bin/env ruby #$: << File.expand_path('../../lib', __FILE__) require 'benchmark' require 'benchmark/ips' require 'concurrent' require 'celluloid' class CelluloidClass include Celluloid def foo(latch = nil) latch.count_down if latch end end class AsyncClass include Concurrent::Async def foo(latch = nil) latch.count_down if latch end end IPS_NUM = 100 BMBM_NUM = 100_000 SMALL_BMBM = 250 puts "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" puts "Long-lived objects" puts "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" puts "" Benchmark.ips do |bm| celluloid = CelluloidClass.new bm.report('celluloid') do latch = Concurrent::CountDownLatch.new(IPS_NUM) IPS_NUM.times { celluloid.async.foo(latch) } latch.wait end async = AsyncClass.new bm.report('async') do latch = Concurrent::CountDownLatch.new(IPS_NUM) IPS_NUM.times { async.async.foo(latch) } latch.wait end bm.compare! end Benchmark.bmbm do |bm| celluloid = CelluloidClass.new bm.report('celluloid') do latch = Concurrent::CountDownLatch.new(BMBM_NUM) BMBM_NUM.times { celluloid.async.foo(latch) } latch.wait end async = AsyncClass.new bm.report('async') do latch = Concurrent::CountDownLatch.new(BMBM_NUM) BMBM_NUM.times { async.async.foo(latch) } latch.wait end end puts "" puts "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" puts "Short-lived objects" puts "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" puts "" Benchmark.ips do |bm| bm.report('future') do latch = Concurrent::CountDownLatch.new(IPS_NUM) IPS_NUM.times do Concurrent::Future.execute { latch.count_down } end latch.wait end async = AsyncClass.new bm.report('async') do latch = Concurrent::CountDownLatch.new(IPS_NUM) IPS_NUM.times { AsyncClass.new.async.foo(latch) } latch.wait end bm.compare! end Benchmark.bmbm do |bm| bm.report('celluloid') do latch = Concurrent::CountDownLatch.new(SMALL_BMBM) SMALL_BMBM.times { CelluloidClass.new.async.foo(latch) } latch.wait end bm.report('async') do latch = Concurrent::CountDownLatch.new(SMALL_BMBM) SMALL_BMBM.times { AsyncClass.new.async.foo(latch) } latch.wait end end __END__ =========================================================== Async Benchmarks =========================================================== Computer: * OS X Yosemite - Version 10.10.4 * MacBook Pro - Retina, 13-inch, Early 2015 * Processor 3.1 GHz Intel Core i7 * Memory 16 GB 1867 MHz DDR3 * Physical Volumes: - Apple SSD SM0512G - 500 GB =========================================================== ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin14] =========================================================== ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Long-lived objects ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Calculating ------------------------------------- celluloid 22.000 i/100ms async 37.000 i/100ms ------------------------------------------------- celluloid 239.639 (±10.8%) i/s - 1.188k async 374.885 (± 2.7%) i/s - 1.887k Comparison: async: 374.9 i/s celluloid: 239.6 i/s - 1.56x slower Rehearsal --------------------------------------------- celluloid 3.910000 0.540000 4.450000 ( 4.455316) async 2.730000 0.010000 2.740000 ( 2.736720) ------------------------------------ total: 7.190000sec user system total real celluloid 3.880000 0.550000 4.430000 ( 4.435163) async 2.740000 0.010000 2.750000 ( 2.750706) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Short-lived objects ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Calculating ------------------------------------- future 19.000 i/100ms async 19.000 i/100ms ------------------------------------------------- future 191.738 (± 3.7%) i/s - 969.000 async 188.085 (± 4.3%) i/s - 950.000 Comparison: future: 191.7 i/s async: 188.1 i/s - 1.02x slower Rehearsal --------------------------------------------- celluloid 0.110000 0.020000 0.130000 ( 0.131996) async 0.040000 0.010000 0.050000 ( 0.037236) ------------------------------------ total: 0.180000sec user system total real celluloid 0.160000 0.040000 0.200000 ( 0.186817) async 0.040000 0.010000 0.050000 ( 0.051579) =========================================================== jruby 9.0.1.0 (2.2.2) 2015-09-02 583f336 Java HotSpot(TM) 64-Bit Server VM 25.45-b02 on 1.8.0_45-b14 +jit [darwin-x86_64] =========================================================== ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Long-lived objects ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Calculating ------------------------------------- celluloid 1.000 i/100ms async 14.000 i/100ms ------------------------------------------------- celluloid 139.631 (±42.3%) i/s - 473.000 async 883.424 (±26.6%) i/s - 3.514k Comparison: async: 883.4 i/s celluloid: 139.6 i/s - 6.33x slower Rehearsal --------------------------------------------- celluloid 7.420000 1.930000 9.350000 ( 6.625224) async 2.630000 0.210000 2.840000 ( 1.574823) ----------------------------------- total: 12.190000sec user system total real celluloid 5.910000 1.720000 7.630000 ( 5.995677) async 2.610000 0.190000 2.800000 ( 1.594092) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Short-lived objects ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Calculating ------------------------------------- future 40.000 i/100ms async 48.000 i/100ms ------------------------------------------------- future 640.057 (± 4.8%) i/s - 3.200k async 570.240 (± 4.7%) i/s - 2.880k Comparison: future: 640.1 i/s async: 570.2 i/s - 1.12x slower Rehearsal --------------------------------------------- celluloid 1.420000 0.090000 1.510000 ( 0.523106) async 0.020000 0.000000 0.020000 ( 0.006935) ------------------------------------ total: 1.530000sec user system total real celluloid 0.620000 0.100000 0.720000 ( 0.293182) async 0.020000 0.000000 0.020000 ( 0.007434) concurrent-ruby-1.0.5/examples/benchmark_atomic.rb000077500000000000000000000050401305460430400223100ustar00rootroot00000000000000#!/usr/bin/env ruby #$: << File.expand_path('../../lib', __FILE__) require 'benchmark' require 'rbconfig' require 'thread' require 'concurrent/atomics' if RUBY_PLATFORM != 'java' && ! defined? Concurrent::CAtomicReference warn "[WARN] C extensions not loaded!" end Thread.abort_on_exception = true $go = false # for synchronizing parallel threads # number of updates on the value N = ARGV[1] ? ARGV[1].to_i : 100_000 # number of threads for parallel test M = ARGV[0] ? ARGV[0].to_i : 10 # list of platform-specific implementations ATOMICS = [ 'MutexAtomicReference', 'CAtomicReference', 'JavaAtomicReference', 'RbxAtomicReference', ] puts "Testing with #{RbConfig::CONFIG['ruby_install_name']} #{RUBY_VERSION}" puts puts '*** Sequential updates ***' Benchmark.bm(10) do |x| value = 0 x.report 'no lock' do N.times do value += 1 end end @lock = Mutex.new x.report 'mutex' do value = 0 N.times do @lock.synchronize do value += 1 end end end ATOMICS.each do |clazz| if Concurrent.const_defined? clazz @atom = Concurrent.const_get(clazz).new(0) x.report clazz do N.times do @atom.update{|x| x += 1} end end end end end def para_setup(num_threads, count, &block) if num_threads % 2 > 0 raise ArgumentError, 'num_threads must be a multiple of two' end raise ArgumentError, 'need block' unless block_given? # Keep those threads together tg = ThreadGroup.new num_threads.times do |i| diff = (i % 2 == 0) ? 1 : -1 t = Thread.new do nil until $go count.times do yield diff end end tg.add(t) end # Make sure all threads are started while tg.list.find{|t| t.status != 'run'} Thread.pass end # For good measure GC.start tg end def para_run(tg) $go = true tg.list.each{|t| t.join} $go = false end puts puts '*** Parallel updates ***' Benchmark.bm(10) do |bm| # This is not secure value = 0 tg = para_setup(M, N/M) do |diff| value += diff end bm.report('no lock'){ para_run(tg) } value = 0 @lock = Mutex.new tg = para_setup(M, N/M) do |diff| @lock.synchronize do value += diff end end bm.report('mutex'){ para_run(tg) } raise unless value == 0 ATOMICS.each do |clazz| if Concurrent.const_defined? clazz @atom = Concurrent.const_get(clazz).new(0) tg = para_setup(M, N/M) do |diff| @atom.update{|x| x + diff} end bm.report(clazz){ para_run(tg) } raise unless @atom.value == 0 end end end concurrent-ruby-1.0.5/examples/benchmark_atomic_1.rb000077500000000000000000000050311305460430400225300ustar00rootroot00000000000000#!/usr/bin/env ruby #$: << File.expand_path('../../lib', __FILE__) require 'optparse' require 'thread' require 'benchmark' require 'concurrent/atomics' unless defined? Concurrent::CAtomicReference warn "[ERROR] C extensions not loaded!" exit(1) end Thread.abort_on_exception = true $conf = { :lock => "atomic", :num_threads => 100, :count => 100_000, :count_per_thread => nil, :slow => nil, } OptionParser.new do |opts| opts.on("-c", "--count NUM") do |n| $conf[:count] = n.to_i end opts.on("-p", "--count-per-thread") do |n| $conf[:count_per_thread] = n.to_i end opts.on("-t", "--num-threads NUM") do |n| $conf[:num_threads] = n.to_i end opts.on("-s", "--slow NUM") do |n| $conf[:slow] = n.to_i end opts.on("-l", "--lock atomic|mutex") do |x| $conf[:lock] = x end opts.on("-h", "--help"){ puts opts; exit } end.parse!(ARGV) unless $conf[:count_per_thread] $conf[:count_per_thread] = $conf[:count] / $conf[:num_threads] end $conf.delete(:count) if $conf[:slow].to_i > 0 require 'digest/md5' def slow_down $conf[:slow].times do |i| Digest::MD5.hexdigest(i.to_s) end end ret = [] 10.times do m = Benchmark.measure{ slow_down } ret << m.real end $conf[:slow_time] = [ret.min, ret.max] else def slow_down; end end $stderr.puts $conf.inspect def para_prepare(&block) num_threads = $conf[:num_threads] count = $conf[:count_per_thread] if num_threads % 2 > 0 raise ArgumentError, "num_threads must be a multiple of two" end # Keep those threads together tg = ThreadGroup.new num_threads.times do |i| diff = (i % 2 == 0) ? 1 : -1 t = Thread.new do nil until $go count.times do yield diff end end tg.add(t) end # Make sure all threads are started while tg.list.find{|t| t.status != "run"} Thread.pass end # For good measure GC.start $go = false tg end $tg = nil if $conf[:lock] == "atomic" $atom = Concurrent::AtomicReference.new(0) $tg = para_prepare do |diff| $atom.update do |x| slow_down x + diff end end else $lock = Mutex.new $value = 0 $tg = para_prepare do |diff| $lock.synchronize do slow_down $value += diff end end end # Run ! # # NOTE: It seems to me that this measurement method # is sensible to how the system dispatches his resources. # # More precise caluclation could be done using # getrusage's times ret = Benchmark.measure do $go = true $tg.list.each{|t| t.join} $go = false end puts ret.real concurrent-ruby-1.0.5/examples/benchmark_atomic_boolean.rb000077500000000000000000000017301305460430400240110ustar00rootroot00000000000000#!/usr/bin/env ruby #$: << File.expand_path('../../lib', __FILE__) require 'concurrent/atomics' require 'benchmark' require 'rbconfig' THREADS = 1 TESTS = 10_000_000 def atomic_test(clazz, opts = {}) threads = opts.fetch(:threads, 5) tests = opts.fetch(:tests, 100) atomic = clazz.new latch = Concurrent::CountDownLatch.new(threads) print "Testing with #{clazz}...\n" Benchmark.bmbm do |bm| bm.report do threads.times do |i| Thread.new do tests.times{ atomic.value = true } latch.count_down end end latch.wait end end end puts "Testing with #{RbConfig::CONFIG['ruby_install_name']} #{RUBY_VERSION}" atomic_test(Concurrent::MutexAtomicBoolean, threads: THREADS, tests: TESTS) if defined? Concurrent::CAtomicBoolean atomic_test(Concurrent::CAtomicBoolean, threads: THREADS, tests: TESTS) elsif RUBY_PLATFORM == 'java' atomic_test(Concurrent::JavaAtomicBoolean, threads: THREADS, tests: TESTS) end concurrent-ruby-1.0.5/examples/benchmark_atomic_fixnum.rb000077500000000000000000000017041305460430400237010ustar00rootroot00000000000000#!/usr/bin/env ruby #$: << File.expand_path('../../lib', __FILE__) require 'concurrent/atomics' require 'benchmark' require 'rbconfig' THREADS = 1 TESTS = 10_000_000 def atomic_test(clazz, opts = {}) threads = opts.fetch(:threads, 5) tests = opts.fetch(:tests, 100) num = clazz.new latch = Concurrent::CountDownLatch.new(threads) print "Testing with #{clazz}...\n" Benchmark.bmbm do |bm| bm.report do threads.times do |i| Thread.new do tests.times{ num.up } latch.count_down end end latch.wait end end end puts "Testing with #{RbConfig::CONFIG['ruby_install_name']} #{RUBY_VERSION}" atomic_test(Concurrent::MutexAtomicFixnum, threads: THREADS, tests: TESTS) if defined? Concurrent::CAtomicFixnum atomic_test(Concurrent::CAtomicFixnum, threads: THREADS, tests: TESTS) elsif RUBY_PLATFORM == 'java' atomic_test(Concurrent::JavaAtomicFixnum, threads: THREADS, tests: TESTS) end concurrent-ruby-1.0.5/examples/benchmark_map.rb000077500000000000000000000011051305460430400216070ustar00rootroot00000000000000#!/usr/bin/env ruby require "benchmark" require "concurrent" hash = {} map = Concurrent::Map.new ENTRIES = 10_000 ENTRIES.times do |i| hash[i] = i map[i] = i end TESTS = 40_000_000 Benchmark.bmbm do |results| key = rand(10_000) results.report('Hash#[]') do TESTS.times { hash[key] } end results.report('Map#[]') do TESTS.times { map[key] } end results.report('Hash#each_pair') do (TESTS / ENTRIES).times { hash.each_pair {|k,v| v} } end results.report('Map#each_pair') do (TESTS / ENTRIES).times { map.each_pair {|k,v| v} } end end concurrent-ruby-1.0.5/examples/benchmark_new_futures.rb000077500000000000000000000042421305460430400234050ustar00rootroot00000000000000#!/usr/bin/env ruby require 'benchmark/ips' require 'concurrent' require 'concurrent-edge' raise 'concurrent-ext not loaded' if Concurrent.on_cruby? && Concurrent.c_extensions_loaded? scale = 1 time = 10 * scale warmup = 2 * scale warmup *= 10 if Concurrent.on_jruby? Benchmark.ips(time, warmup) do |x| x.report('flat-old') do Concurrent::Promise.execute { 1 }.flat_map { |v| Concurrent::Promise.execute { v + 2 } }.value! end x.report('flat-new') do Concurrent::Promises.future(:fast) { 1 }.then { |v| Concurrent::Promises.future(:fast) { v + 2 } }.flat.value! end x.compare! end Benchmark.ips(time, warmup) do |x| x.report('status-old') { f = Concurrent::Promise.execute { nil }; 100.times { f.complete? } } x.report('status-new') { f = Concurrent::Promises.future(:fast) { nil }; 100.times { f.resolved? } } x.compare! end Benchmark.ips(time, warmup) do |x| of = Concurrent::Promise.execute { 1 } nf = Concurrent::Promises.fulfilled_future(1, :fast) x.report('value-old') { of.value! } x.report('value-new') { nf.value! } x.compare! end Benchmark.ips(time, warmup) do |x| x.report('graph-old') do head = Concurrent::Promise.fulfill(1) 10.times do branch1 = head.then(&:succ) branch2 = head.then(&:succ).then(&:succ) head = Concurrent::Promise.zip(branch1, branch2).then { |a, b| a + b } end head.value! end x.report('graph-new') do head = Concurrent::Promises.fulfilled_future(1, :fast) 10.times do branch1 = head.then(&:succ) branch2 = head.then(&:succ).then(&:succ) head = (branch1 & branch2).then { |a, b| a + b } end head.value! end x.compare! end Benchmark.ips(time, warmup) do |x| x.report('immediate-old') { Concurrent::Promise.fulfill(nil).value! } x.report('immediate-new') { Concurrent::Promises.fulfilled_future(nil, :fast).value! } x.compare! end Benchmark.ips(time, warmup) do |x| of = Concurrent::Promise.execute { 1 } nf = Concurrent::Promises.fulfilled_future(1, :fast) x.report('then-old') { 50.times.reduce(of) { |nf, _| nf.then(&:succ) }.value! } x.report('then-new') { 50.times.reduce(nf) { |nf, _| nf.then(&:succ) }.value! } x.compare! end concurrent-ruby-1.0.5/examples/benchmark_read_write_lock.rb000077500000000000000000000104261305460430400241750ustar00rootroot00000000000000#!/usr/bin/env ruby #$: << File.expand_path('../../lib', __FILE__) require 'concurrent/atomic/read_write_lock' require 'benchmark' require 'optparse' require 'ostruct' $options = OpenStruct.new $options.threads = 100 $options.interleave = false $options.compare = false OptionParser.new do |opts| opts.banner = "Usage: #{File.basename(__FILE__)} [options]" opts.on('-t', '--threads=THREADS', OptionParser::DecimalInteger, "Number of threads per test (default #{$options.threads})") do |value| $options.threads = value end opts.on('-i', '--[no-]interleave', 'Interleave output to check for starvation') do |value| $options.interleave = value end opts.on('-c', '--[no-]compare', 'Compare with other implementations') do |value| $options.compare = value end opts.on('-h', '--help', 'Prints this help') do puts opts exit end end.parse! def jruby? defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby" end # for performance comparison with ReadWriteLock class SimpleMutex def initialize; @mutex = Mutex.new; end def with_read_lock @mutex.synchronize { yield } end alias :with_write_lock :with_read_lock end # for seeing whether my correctness test is doing anything... # and for seeing how great the overhead of the test is # (apart from the cost of locking) class FreeAndEasy def with_read_lock yield # thread safety is for the birds... I prefer to live dangerously end alias :with_write_lock :with_read_lock end if jruby? # the Java platform comes with a read-write lock implementation # performance is very close to ReadWriteLock, but just a *bit* slower require 'java' class JavaReadWriteLock def initialize @lock = java.util.concurrent.locks.ReentrantReadWriteLock.new end def with_read_lock @lock.read_lock.lock result = yield @lock.read_lock.unlock result end def with_write_lock @lock.write_lock.lock result = yield @lock.write_lock.unlock result end end end def test(lock) puts "READ INTENSIVE (80% read, 20% write):" single_test(lock, ($options.threads * 0.8).floor, ($options.threads * 0.2).floor) puts "WRITE INTENSIVE (80% write, 20% read):" single_test(lock, ($options.threads * 0.2).floor, ($options.threads * 0.8).floor) puts "BALANCED (50% read, 50% write):" single_test(lock, ($options.threads * 0.5).floor, ($options.threads * 0.5).floor) end def single_test(lock, n_readers, n_writers, reader_iterations=50, writer_iterations=50, reader_sleep=0.001, writer_sleep=0.001) puts "Testing #{lock.class} with #{n_readers} readers and #{n_writers} writers. Readers iterate #{reader_iterations} times, sleeping #{reader_sleep}s each time, writers iterate #{writer_iterations} times, sleeping #{writer_sleep}s each time" mutex = Mutex.new bad = false data = 0 result = Benchmark.measure do readers = n_readers.times.collect do Thread.new do reader_iterations.times do lock.with_read_lock do print "r" if $options.interleave mutex.synchronize { bad = true } if (data % 2) != 0 sleep(reader_sleep) mutex.synchronize { bad = true } if (data % 2) != 0 end end end end writers = n_writers.times.collect do Thread.new do writer_iterations.times do lock.with_write_lock do print "w" if $options.interleave # invariant: other threads should NEVER see "data" as an odd number value = (data += 1) # if a reader runs right now, this invariant will be violated sleep(writer_sleep) # this looks like a strange way to increment twice; # it's designed so that if 2 writers run at the same time, at least # one increment will be lost, and we can detect that at the end data = value+1 end end end end readers.each { |t| t.join } writers.each { |t| t.join } puts "BAD!!! Readers+writers overlapped!" if mutex.synchronize { bad } puts "BAD!!! Writers overlapped!" if data != (n_writers * writer_iterations * 2) end puts result end test(Concurrent::ReadWriteLock.new) test(JavaReadWriteLock.new) if $options.compare && jruby? test(SimpleMutex.new) if $options.compare test(FreeAndEasy.new) if $options.compare concurrent-ruby-1.0.5/examples/benchmark_structs.rb000077500000000000000000000112501305460430400225430ustar00rootroot00000000000000#!/usr/bin/env ruby #$: << File.expand_path('../../lib', __FILE__) require 'benchmark' require 'concurrent' n = 500_000 StructPair = Struct.new(:left, :right) SafePair = Concurrent::MutableStruct.new(:left, :right) FinalPair = Concurrent::SettableStruct.new(:left, :right) ImmutablePair = Concurrent::ImmutableStruct.new(:left, :right) array_pair = [true, false].freeze struct_pair = StructPair.new(true, false) safe_pair = SafePair.new(true, false) final_pair = FinalPair.new(true, false) immutable = ImmutablePair.new(true, false) puts "Object creation...\n" Benchmark.bmbm do |x| x.report('create frozen array') { n.times{ [true, false].freeze } } x.report('create frozen struct') { n.times{ StructPair.new(true, false).freeze } } x.report('create mutable struct') { n.times{ SafePair.new(true, false) } } x.report('create settable struct') { n.times{ FinalPair.new(true, false) } } x.report('create immutable struct') { n.times{ ImmutablePair.new(true, false) } } end puts "\n" puts "Object access...\n" Benchmark.bmbm do |x| x.report('read from frozen array') { n.times{ array_pair.last } } x.report('read from frozen struct') { n.times{ struct_pair.right } } x.report('read from mutable struct') { n.times{ safe_pair.right } } x.report('read from settable struct') { n.times{ final_pair.right } } x.report('read from immutable struct') { n.times{ immutable.right } } end puts "\n" puts "Enumeration...\n" Benchmark.bmbm do |x| x.report('iterate over frozen array') { n.times{ array_pair.each{ nil } } } x.report('iterate over frozen struct') { n.times{ struct_pair.each{ nil } } } x.report('iterate over mutable struct') { n.times{ safe_pair.each{ nil } } } x.report('iterate over settable struct') { n.times{ final_pair.each{ nil } } } x.report('iterate over immutable struct') { n.times{ immutable.each{ nil } } } end __END__ Object creation... Rehearsal ----------------------------------------------------------- create frozen array 0.090000 0.000000 0.090000 ( 0.091262) create frozen struct 0.180000 0.000000 0.180000 ( 0.179993) create mutable struct 2.030000 0.000000 2.030000 ( 2.052071) create settable struct 2.070000 0.000000 2.070000 ( 2.080022) create immutable struct 0.710000 0.000000 0.710000 ( 0.716877) -------------------------------------------------- total: 5.080000sec user system total real create frozen array 0.100000 0.000000 0.100000 ( 0.097776) create frozen struct 0.190000 0.000000 0.190000 ( 0.186287) create mutable struct 2.020000 0.010000 2.030000 ( 2.032391) create settable struct 2.030000 0.000000 2.030000 ( 2.031631) create immutable struct 0.690000 0.000000 0.690000 ( 0.695010) Object access... Rehearsal -------------------------------------------------------------- read from frozen array 0.060000 0.000000 0.060000 ( 0.060430) read from frozen struct 0.060000 0.000000 0.060000 ( 0.058978) read from mutable struct 0.440000 0.000000 0.440000 ( 0.454071) read from settable struct 0.460000 0.000000 0.460000 ( 0.457699) read from immutable struct 0.120000 0.000000 0.120000 ( 0.126701) ----------------------------------------------------- total: 1.140000sec user system total real read from frozen array 0.060000 0.000000 0.060000 ( 0.063006) read from frozen struct 0.060000 0.000000 0.060000 ( 0.094203) read from mutable struct 0.420000 0.000000 0.420000 ( 0.468304) read from settable struct 0.410000 0.000000 0.410000 ( 0.452446) read from immutable struct 0.110000 0.010000 0.120000 ( 0.127030) Enumeration... Rehearsal ----------------------------------------------------------------- iterate over frozen array 0.170000 0.000000 0.170000 ( 0.176898) iterate over frozen struct 0.160000 0.000000 0.160000 ( 0.160786) iterate over mutable struct 1.520000 0.000000 1.520000 ( 1.627013) iterate over settable struct 1.500000 0.010000 1.510000 ( 1.525163) iterate over immutable struct 0.990000 0.000000 0.990000 ( 1.006201) -------------------------------------------------------- total: 4.350000sec user system total real iterate over frozen array 0.170000 0.000000 0.170000 ( 0.167927) iterate over frozen struct 0.150000 0.000000 0.150000 ( 0.157328) iterate over mutable struct 1.450000 0.000000 1.450000 ( 1.462654) iterate over settable struct 1.460000 0.000000 1.460000 ( 1.480270) iterate over immutable struct 0.940000 0.010000 0.950000 ( 0.955633) concurrent-ruby-1.0.5/examples/format.rb000066400000000000000000000035561305460430400203210ustar00rootroot00000000000000require 'rubygems' require 'bundler/setup' require 'pry' require 'pp' input_paths = if ARGV.empty? Dir.glob("#{File.dirname(__FILE__)}/*.in.rb") else ARGV end.map { |p| File.expand_path p } input_paths.each_with_index do |input_path, i| pid = fork do require_relative 'init.rb' begin output_path = input_path.gsub /\.in\.rb$/, '.out.rb' input = File.readlines(input_path) chunks = [] line = '' while !input.empty? line += input.shift if Pry::Code.complete_expression? line chunks << line line = '' end end raise unless line.empty? chunks.map! { |chunk| [chunk, [chunk.split($/).size, 1].max] } environment = Module.new.send :binding evaluate = ->(code, line) do eval(code, environment, input_path, line) end indent = 50 line_count = 1 output = '' chunks.each do |chunk, lines| result = evaluate.(chunk, line_count) unless chunk.strip.empty? || chunk =~ /\A *#/ pre_lines = chunk.lines.to_a last_line = pre_lines.pop output << pre_lines.join if last_line =~ /\#$/ output << last_line.gsub(/\#$/, '') else if last_line.size < indent && result.inspect.size < indent output << "%-#{indent}s %s" % [last_line.chomp, "# => #{result.inspect}\n"] else output << last_line << " # => #{result.inspect}\n" end end else output << chunk end line_count += lines end puts "#{input_path}\n -> #{output_path}" #puts output File.write(output_path, output) rescue => ex puts "#{ex} (#{ex.class})\n#{ex.backtrace * "\n"}" end end Process.wait pid end concurrent-ruby-1.0.5/examples/go-by-example-channels/000077500000000000000000000000001305460430400227325ustar00rootroot00000000000000concurrent-ruby-1.0.5/examples/go-by-example-channels/channel-buffering.rb000077500000000000000000000005601305460430400266400ustar00rootroot00000000000000#!/usr/bin/env ruby $: << File.expand_path('../../../lib', __FILE__) require 'concurrent-edge' Channel = Concurrent::Channel ## Go by Example: Channel Buffering # https://gobyexample.com/channel-buffering messages = Channel.new(capacity: 2) # buffered messages.put 'buffered' messages.put 'channel' puts messages.take puts messages.take __END__ buffered channel concurrent-ruby-1.0.5/examples/go-by-example-channels/channel-directions.rb000077500000000000000000000011501305460430400270300ustar00rootroot00000000000000#!/usr/bin/env ruby $: << File.expand_path('../../../lib', __FILE__) require 'concurrent-edge' Channel = Concurrent::Channel ## Go by Example: Channel Direction # https://gobyexample.com/channel-directions # we can't force a channel to go only one direction w/i a function # but we can replicate the actual functionality from the example def ping(pings, msg) pings << msg end def pong(pings, pongs) msg = ~pings pongs << msg end pings = Channel.new(capacity: 1) # buffered pongs = Channel.new(capacity: 1) # buffered ping(pings, 'passed message') pong(pings, pongs) puts ~pongs __END__ passed message concurrent-ruby-1.0.5/examples/go-by-example-channels/channel-synchronization.rb000077500000000000000000000007211305460430400301310ustar00rootroot00000000000000#!/usr/bin/env ruby $: << File.expand_path('../../../lib', __FILE__) require 'concurrent-edge' Channel = Concurrent::Channel ## Go by Example: Channel Synchronizatio # https://gobyexample.com/channel-synchronization def worker(done_channel) print "working...\n" sleep(1) print "done\n" done_channel << true # alias for `#put` end done = Channel.new(capacity: 1) # buffered Channel.go{ worker(done) } ~done # alias for `#take` __END__ working... done concurrent-ruby-1.0.5/examples/go-by-example-channels/channels.rb000077500000000000000000000005011305460430400250510ustar00rootroot00000000000000#!/usr/bin/env ruby $: << File.expand_path('../../../lib', __FILE__) require 'concurrent-edge' Channel = Concurrent::Channel ## Go by Example: Unbuffered Channel # https://gobyexample.com/channels messages = Channel.new # unbuffered Channel.go do messages.put 'ping' end msg = messages.take puts msg __END__ ping concurrent-ruby-1.0.5/examples/go-by-example-channels/closing-channels.rb000077500000000000000000000015141305460430400265120ustar00rootroot00000000000000#!/usr/bin/env ruby $: << File.expand_path('../../../lib', __FILE__) require 'concurrent-edge' Channel = Concurrent::Channel ## Go by Example: Closing Channels # https://gobyexample.com/closing-channels validator = ->(v){ v.is_a? Numeric } jobs = Channel.new(buffer: :buffered, capacity: 5, validator: validator) done = Channel.new(buffer: :unbuffered) Channel.go_loop do j, more = jobs.next if more print "received job #{j}\n" true # loop again else print "received all jobs\n" done << true false # exit the loop end end (1..3).each do |i| jobs << i print "sent job #{i}\n" Thread.pass # give the worker a chance to run end jobs.close print "sent all jobs\n" ~done __END__ sent job 1 received job 1 sent job 2 received job 2 sent job 3 received job 3 sent all jobs received all jobs concurrent-ruby-1.0.5/examples/go-by-example-channels/non-blocking-channel-operations.rb000077500000000000000000000015741305460430400314400ustar00rootroot00000000000000#!/usr/bin/env ruby $: << File.expand_path('../../../lib', __FILE__) require 'concurrent-edge' Channel = Concurrent::Channel ## Go by Example: Non-Blocking Channel Operations # https://gobyexample.com/non-blocking-channel-operations messages = Channel.new # unbuffered signals = Channel.new # unbuffered Channel.select do |s| s.take(messages) { |msg| print "received message #{msg}\n" } s.default { print "no message received\n" } end message = 'hi' Channel.select do |s| s.put(messages, message) { |msg| print "sent message #{msg}\n" } s.default { print "no message sent\n" } end Channel.select do |s| s.case(messages, :~) { |msg| print "received message #{msg}\n" } # alias for `s.take` s.case(signals, :~) { |sig| print "received signal #{sig}\n" } # alias for `s.take` s.default { print "no activity\n" } end __END__ no message received no message sent no activity concurrent-ruby-1.0.5/examples/go-by-example-channels/range-over-channels.rb000077500000000000000000000005511305460430400271210ustar00rootroot00000000000000#!/usr/bin/env ruby $: << File.expand_path('../../../lib', __FILE__) require 'concurrent-edge' Channel = Concurrent::Channel ## Go by Example: Range over Channels # https://gobyexample.com/range-over-channels queue = Channel.new(capacity: 2) # buffered queue << 'one' queue << 'two' queue.close queue.each do |elem| print "#{elem}\n" end __END__ one two concurrent-ruby-1.0.5/examples/go-by-example-channels/rate-limiting.rb000077500000000000000000000026041305460430400260310ustar00rootroot00000000000000#!/usr/bin/env ruby $: << File.expand_path('../../../lib', __FILE__) require 'concurrent-edge' require 'time' Channel = Concurrent::Channel ## Go by Example: Rate Limiting # https://gobyexample.com/rate-limiting requests = Channel.new(buffer: :buffered, capacity: 5) (1..5).each do |i| requests << i end requests.close limiter = Channel.ticker(0.2) requests.each do |req| print "request #{req} #{Channel::Tick.new}\n" if ~limiter end print "\n" bursty_limiter = Channel.new(buffer: :buffered, capacity: 3) (1..3).each do bursty_limiter << Channel::Tick.new end ticker = Channel.ticker(0.2) Channel.go do ticker.each do |t| bursty_limiter << t end end bursty_requests = Channel.new(buffer: :buffered, capacity: 5) (1..5).each do |i| bursty_requests << i end bursty_requests.close bursty_requests.each do |req| ~bursty_limiter print "request #{req} #{Channel::Tick.new}\n" end limiter.close ticker.close __END__ request 1 2012-10-19 00:38:18.687438 +0000 UTC request 2 2012-10-19 00:38:18.887471 +0000 UTC request 3 2012-10-19 00:38:19.087238 +0000 UTC request 4 2012-10-19 00:38:19.287338 +0000 UTC request 5 2012-10-19 00:38:19.487331 +0000 UTC request 1 2012-10-19 00:38:20.487578 +0000 UTC request 2 2012-10-19 00:38:20.487645 +0000 UTC request 3 2012-10-19 00:38:20.487676 +0000 UTC request 4 2012-10-19 00:38:20.687483 +0000 UTC request 5 2012-10-19 00:38:20.887542 +0000 UTC concurrent-ruby-1.0.5/examples/go-by-example-channels/select.rb000077500000000000000000000010051305460430400245350ustar00rootroot00000000000000#!/usr/bin/env ruby $: << File.expand_path('../../../lib', __FILE__) require 'concurrent-edge' Channel = Concurrent::Channel ## Go by Example: Select # https://gobyexample.com/select c1 = Channel.new # unbuffered c2 = Channel.new # unbuffered Channel.go do sleep(1) c1 << 'one' end Channel.go do sleep(2) c1 << 'two' end 2.times do Channel.select do |s| s.take(c1) { |msg| print "received #{msg}\n" } s.take(c2) { |msg| print "received #{msg}\n" } end end __END__ received one received two concurrent-ruby-1.0.5/examples/go-by-example-channels/ticker.rb000077500000000000000000000007771305460430400245560ustar00rootroot00000000000000#!/usr/bin/env ruby $: << File.expand_path('../../../lib', __FILE__) require 'concurrent-edge' Channel = Concurrent::Channel ## Go by Example: Tickers # https://gobyexample.com/tickers ticker = Channel.ticker(0.5) Channel.go do ticker.each do |tick| print "Tick at #{tick}\n" if tick end end sleep(1.6) ticker.stop print "Ticker stopped\n" __END__ Tick at 2012-09-23 11:29:56.487625 -0700 PDT Tick at 2012-09-23 11:29:56.988063 -0700 PDT Tick at 2012-09-23 11:29:57.488076 -0700 PDT Ticker stopped concurrent-ruby-1.0.5/examples/go-by-example-channels/timeouts.rb000077500000000000000000000011351305460430400251330ustar00rootroot00000000000000#!/usr/bin/env ruby $: << File.expand_path('../../../lib', __FILE__) require 'concurrent-edge' Channel = Concurrent::Channel ## Go by Example: Timeouts # https://gobyexample.com/timeouts c1 = Channel.new(capacity: 1) # buffered Channel.go do sleep(2) c1 << 'result 1' end Channel.select do |s| s.take(c1) { |msg| print "#{msg}\n" } s.after(1) { print "timeout 1\n" } end c2 = Channel.new(capacity: 1) # buffered Channel.go do sleep(2) c2 << 'result 2' end Channel.select do |s| s.take(c2) { |msg| print "#{msg}\n" } s.after(3) { print "timeout 2\n" } end __END__ timeout 1 result 2 concurrent-ruby-1.0.5/examples/go-by-example-channels/timers.rb000077500000000000000000000006541305460430400245720ustar00rootroot00000000000000#!/usr/bin/env ruby $: << File.expand_path('../../../lib', __FILE__) require 'concurrent-edge' Channel = Concurrent::Channel ## Go by Example: Timers # https://gobyexample.com/timers timer1 = Channel.timer(2) puts 'Timer 1 expired' if ~timer1 timer2 = Channel.timer(1) Channel.go do print "Timer 2 expired\n" if ~timer2 end stop2 = timer2.stop print "Timer 2 stopped\n" if stop2 __END__ Timer 1 expired Timer 2 stopped concurrent-ruby-1.0.5/examples/go-by-example-channels/worker-pools.rb000077500000000000000000000015251305460430400257300ustar00rootroot00000000000000#!/usr/bin/env ruby $: << File.expand_path('../../../lib', __FILE__) require 'concurrent-edge' Channel = Concurrent::Channel ## Go by Example: Go by Example: Worker Pools # https://gobyexample.com/worker-pools def worker(id, jobs, results) jobs.each do |j| print "worker #{id} processing job #{j}\n" sleep(1) results << j * 2 end end jobs = Channel.new(buffer: :buffered, capacity: 100) results = Channel.new(buffer: :buffered, capacity: 100) (1..3).each do |w| Channel.go { worker(w, jobs, results) } end (1..9).each do |j| jobs << j end jobs.close (1..9).each do ~results end __END__ worker 1 processing job 1 worker 2 processing job 2 worker 3 processing job 3 worker 1 processing job 4 worker 2 processing job 5 worker 3 processing job 6 worker 1 processing job 7 worker 2 processing job 8 worker 3 processing job 9 concurrent-ruby-1.0.5/examples/graph_atomic_bench.rb000077500000000000000000000033401305460430400226170ustar00rootroot00000000000000#!/usr/bin/env ruby #$: << File.expand_path('../../lib', __FILE__) require 'optparse' conf = { :vary => "threads", :lock => "atomic" } OptionParser.new do |opts| opts.on("-l", "--lock atomic|mutex") do |l| conf[:lock] = l end opts.on("-v", "--vary threads|speed") do |v| conf[:vary] = v end opts.on("-h", "--help"){ puts opts; exit } end.parse!(ARGV) result = File.open("results_#{conf[:lock]}_#{conf[:vary]}.csv", "w") if conf[:vary] == "threads" # Vary the number of concurrent threads that update the value. # # There is a total count of 1mio updates that is distributed # between the number of threads. # # A pair number of threads is used so that even add and odd substract 1. # This avoid creating instances for Bignum since the number should # stay in the Fixnum range. # (1..100).each do |i| i = i * 2 ret = [] 10.times do ret << `ruby #{File.dirname(__FILE__)}/benchmark_atomic_1.rb -l #{conf[:lock]} -t #{i}`.to_f end line = ([i] + ret).join(', ') puts line result.puts line end elsif conf[:vary] == "speed" # Varies the execution time of the update block # by using long calulation (MD5) # # NOTE: Thread.pass and sleep() are not usable by the atomic # lock. It needs to run the whole block without hitting # another atomic update otherwise it has to retry # # The expected result is that the atomic lock's performance # will hit a certain threshold where it will be worse than mutexes. # (1..30).each do |i| ret = [] 10.times do ret << `ruby #{File.dirname(__FILE__)}/benchmark_atomic_1.rb -l #{conf[:lock]} -s #{i}`.to_f end line = ([i] + ret).join(', ') puts line result.puts line end end concurrent-ruby-1.0.5/examples/init.rb000066400000000000000000000001411305460430400177570ustar00rootroot00000000000000require 'concurrent-edge' def do_stuff :stuff end Concurrent.use_simple_logger Logger::DEBUG concurrent-ruby-1.0.5/examples/stress_ruby_thread_pool.rb000077500000000000000000000014271305460430400237730ustar00rootroot00000000000000#!/usr/bin/env ruby $: << File.expand_path('../../lib', __FILE__) require 'benchmark' require 'concurrent/executors' COUNT = 100_000 executor = Concurrent::CachedThreadPool.new latch = Concurrent::CountDownLatch.new COUNT.times { executor.post{ nil } } #COUNT.times do |i| # executor.post{ nil } # sleep(0.01) if i % 1000 == 0 #end executor.post{ latch.count_down } latch.wait puts "Max length: #{executor.max_length}" if executor.respond_to?(:max_length) puts "Largest length: #{executor.largest_length}" if executor.respond_to?(:largest_length) puts "Scheduled task count: #{executor.scheduled_task_count}" if executor.respond_to?(:scheduled_task_count) puts "Completed task count: #{executor.completed_task_count}" if executor.respond_to?(:completed_task_count) concurrent-ruby-1.0.5/examples/thread_local_memory_usage.rb000077500000000000000000000031541305460430400242230ustar00rootroot00000000000000#!/usr/bin/env ruby #$: << File.expand_path('../../lib', __FILE__) $DEBUG_TLV = true require 'concurrent' require 'concurrent/atomic/thread_local_var' require 'benchmark' require 'thread' include Concurrent # if we hold on to vars, but threads die, space used for TLVs should be recovered def test_thread_gc(vars) threads = 500.times.collect do Thread.new do vars.each do |var| var.value = 1 end end end threads.each(&:join) end puts "BEFORE THREAD GC TEST:" puts "Ruby heap pages: #{GC.stat[:heap_length]}, Other malloc'd bytes: #{GC.stat[:malloc_increase]}" vars = 500.times.collect { ThreadLocalVar.new(0) } 200.times do test_thread_gc(vars) GC.start end puts "AFTER THREAD GC TEST:" puts "Ruby heap pages: #{GC.stat[:heap_length]}, Other malloc'd bytes: #{GC.stat[:malloc_increase]}" # if we hold on to threads, but drop TLVs, space used should be reused by allocated TLVs def tlv_gc_test_loop(queue) while true var = queue.pop return if var.nil? var.value = 1 end end def test_tlv_gc(queues) 500.times do var = ThreadLocalVar.new(0) queues.each { |q| q << var } end end puts puts "BEFORE TLV GC TEST:" puts "Ruby heap pages: #{GC.stat[:heap_length]}, Other malloc'd bytes: #{GC.stat[:malloc_increase]}" queues = 500.times.collect { Queue.new } threads = queues.map do |queue| Thread.new do tlv_gc_test_loop(queue) end end 200.times do test_tlv_gc(queues) GC.start end queues.each { |q| q << nil } threads.each(&:join) puts "AFTER TLV GC TEST:" puts "Ruby heap pages: #{GC.stat[:heap_length]}, Other malloc'd bytes: #{GC.stat[:malloc_increase]}" concurrent-ruby-1.0.5/examples/thread_local_var_bench.rb000077500000000000000000000011361305460430400234540ustar00rootroot00000000000000#!/usr/bin/env ruby #$: << File.expand_path('../../lib', __FILE__) require 'concurrent' require 'concurrent/atomic/thread_local_var' require 'benchmark' include Concurrent N_THREADS = 100 N_VARS = 100 vars = N_VARS.times.collect { ThreadLocalVar.new(0) } def test_threadlocal_perf(vars) threads = N_THREADS.times.collect do Thread.new do 10000.times do index = rand(N_VARS) var = vars[index] var.value = var.value + 1 end end end threads.each(&:join) end Benchmark.bmbm do |bm| bm.report('ThreadLocalVar') { test_threadlocal_perf(vars) } end concurrent-ruby-1.0.5/examples/who.rb000077500000000000000000000013071305460430400176210ustar00rootroot00000000000000#!/usr/bin/env ruby require 'net/http' require 'json' # http://www.schneems.com/blogs/2015-09-30-reverse-rubygems/ gem_name = "concurrent-ruby" def rubygems_get(gem_name: "", endpoint: "") path = File.join("/api/v1/gems/", gem_name, endpoint).chomp("/") + ".json" JSON.parse(Net::HTTP.get("rubygems.org", path)) end results = rubygems_get(gem_name: gem_name, endpoint: "reverse_dependencies") weighted_results = {} results.each do |name| begin weighted_results[name] = rubygems_get(gem_name: name)["downloads"] rescue => e puts "#{name} #{e.message}" end end weighted_results.sort {|(k1, v1), (k2, v2)| v2 <=> v1 }.first(50).each_with_index do |(k, v), i| puts "#{i}) #{k}: #{v}" end concurrent-ruby-1.0.5/ext/000077500000000000000000000000001305460430400154555ustar00rootroot00000000000000concurrent-ruby-1.0.5/ext/ConcurrentRubyExtService.java000066400000000000000000000014741305460430400233140ustar00rootroot00000000000000import java.io.IOException; import org.jruby.Ruby; import org.jruby.runtime.load.BasicLibraryService; import com.concurrent_ruby.ext.JRubyMapBackendLibrary; public class ConcurrentRubyExtService implements BasicLibraryService { public boolean basicLoad(final Ruby runtime) throws IOException { new com.concurrent_ruby.ext.AtomicReferenceLibrary().load(runtime, false); new com.concurrent_ruby.ext.JavaAtomicBooleanLibrary().load(runtime, false); new com.concurrent_ruby.ext.JavaAtomicFixnumLibrary().load(runtime, false); new com.concurrent_ruby.ext.JavaSemaphoreLibrary().load(runtime, false); new com.concurrent_ruby.ext.SynchronizationLibrary().load(runtime, false); new com.concurrent_ruby.ext.JRubyMapBackendLibrary().load(runtime, false); return true; } } concurrent-ruby-1.0.5/ext/com/000077500000000000000000000000001305460430400162335ustar00rootroot00000000000000concurrent-ruby-1.0.5/ext/com/concurrent_ruby/000077500000000000000000000000001305460430400214565ustar00rootroot00000000000000concurrent-ruby-1.0.5/ext/com/concurrent_ruby/ext/000077500000000000000000000000001305460430400222565ustar00rootroot00000000000000concurrent-ruby-1.0.5/ext/com/concurrent_ruby/ext/AtomicReferenceLibrary.java000066400000000000000000000145531305460430400275110ustar00rootroot00000000000000package com.concurrent_ruby.ext; import java.lang.reflect.Field; import java.io.IOException; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import org.jruby.Ruby; import org.jruby.RubyClass; import org.jruby.RubyModule; import org.jruby.RubyNumeric; import org.jruby.RubyObject; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; import org.jruby.runtime.ObjectAllocator; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.runtime.load.Library; /** * This library adds an atomic reference type to JRuby for use in the atomic * library. We do a native version to avoid the implicit value coercion that * normally happens through JI. * * @author headius */ public class AtomicReferenceLibrary implements Library { public void load(Ruby runtime, boolean wrap) throws IOException { RubyModule concurrentMod = runtime.defineModule("Concurrent"); RubyClass atomicCls = concurrentMod.defineClassUnder("JavaAtomicReference", runtime.getObject(), JRUBYREFERENCE_ALLOCATOR); try { sun.misc.Unsafe.class.getMethod("getAndSetObject", Object.class); atomicCls.setAllocator(JRUBYREFERENCE8_ALLOCATOR); } catch (Exception e) { // leave it as Java 6/7 version } atomicCls.defineAnnotatedMethods(JRubyReference.class); } private static final ObjectAllocator JRUBYREFERENCE_ALLOCATOR = new ObjectAllocator() { public IRubyObject allocate(Ruby runtime, RubyClass klazz) { return new JRubyReference(runtime, klazz); } }; private static final ObjectAllocator JRUBYREFERENCE8_ALLOCATOR = new ObjectAllocator() { public IRubyObject allocate(Ruby runtime, RubyClass klazz) { return new JRubyReference8(runtime, klazz); } }; @JRubyClass(name="JRubyReference", parent="Object") public static class JRubyReference extends RubyObject { volatile IRubyObject reference; static final sun.misc.Unsafe UNSAFE; static final long referenceOffset; static { try { UNSAFE = UnsafeHolder.U; Class k = JRubyReference.class; referenceOffset = UNSAFE.objectFieldOffset(k.getDeclaredField("reference")); } catch (Exception e) { throw new RuntimeException(e); } } public JRubyReference(Ruby runtime, RubyClass klass) { super(runtime, klass); } @JRubyMethod public IRubyObject initialize(ThreadContext context) { UNSAFE.putObject(this, referenceOffset, context.nil); return context.nil; } @JRubyMethod public IRubyObject initialize(ThreadContext context, IRubyObject value) { UNSAFE.putObject(this, referenceOffset, value); return context.nil; } @JRubyMethod(name = {"get", "value"}) public IRubyObject get() { return reference; } @JRubyMethod(name = {"set", "value="}) public IRubyObject set(IRubyObject newValue) { UNSAFE.putObjectVolatile(this, referenceOffset, newValue); return newValue; } @JRubyMethod(name = {"compare_and_set", "compare_and_swap"}) public IRubyObject compare_and_set(ThreadContext context, IRubyObject expectedValue, IRubyObject newValue) { Ruby runtime = context.runtime; if (expectedValue instanceof RubyNumeric) { // numerics are not always idempotent in Ruby, so we need to do slower logic return compareAndSetNumeric(context, expectedValue, newValue); } return runtime.newBoolean(UNSAFE.compareAndSwapObject(this, referenceOffset, expectedValue, newValue)); } @JRubyMethod(name = {"get_and_set", "swap"}) public IRubyObject get_and_set(ThreadContext context, IRubyObject newValue) { // less-efficient version for Java 6 and 7 while (true) { IRubyObject oldValue = get(); if (UNSAFE.compareAndSwapObject(this, referenceOffset, oldValue, newValue)) { return oldValue; } } } private IRubyObject compareAndSetNumeric(ThreadContext context, IRubyObject expectedValue, IRubyObject newValue) { Ruby runtime = context.runtime; // loop until: // * reference CAS would succeed for same-valued objects // * current and expected have different values as determined by #equals while (true) { IRubyObject current = reference; if (!(current instanceof RubyNumeric)) { // old value is not numeric, CAS fails return runtime.getFalse(); } RubyNumeric currentNumber = (RubyNumeric)current; if (!currentNumber.equals(expectedValue)) { // current number does not equal expected, fail CAS return runtime.getFalse(); } // check that current has not changed, or else allow loop to repeat boolean success = UNSAFE.compareAndSwapObject(this, referenceOffset, current, newValue); if (success) { // value is same and did not change in interim...success return runtime.getTrue(); } } } } private static final class UnsafeHolder { private UnsafeHolder(){} public static final sun.misc.Unsafe U = loadUnsafe(); private static sun.misc.Unsafe loadUnsafe() { try { Class unsafeClass = Class.forName("sun.misc.Unsafe"); Field f = unsafeClass.getDeclaredField("theUnsafe"); f.setAccessible(true); return (sun.misc.Unsafe) f.get(null); } catch (Exception e) { return null; } } } public static class JRubyReference8 extends JRubyReference { public JRubyReference8(Ruby runtime, RubyClass klass) { super(runtime, klass); } @Override public IRubyObject get_and_set(ThreadContext context, IRubyObject newValue) { // efficient version for Java 8 return (IRubyObject)UNSAFE.getAndSetObject(this, referenceOffset, newValue); } } } concurrent-ruby-1.0.5/ext/com/concurrent_ruby/ext/JRubyMapBackendLibrary.java000066400000000000000000000231601305460430400274110ustar00rootroot00000000000000package com.concurrent_ruby.ext; import org.jruby.*; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; import com.concurrent_ruby.ext.jsr166e.ConcurrentHashMap; import com.concurrent_ruby.ext.jsr166e.ConcurrentHashMapV8; import com.concurrent_ruby.ext.jsr166e.nounsafe.*; import org.jruby.runtime.Block; import org.jruby.runtime.ObjectAllocator; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.runtime.load.Library; import java.io.IOException; import java.util.Map; import static org.jruby.runtime.Visibility.PRIVATE; /** * Native Java implementation to avoid the JI overhead. * * @author thedarkone */ public class JRubyMapBackendLibrary implements Library { public void load(Ruby runtime, boolean wrap) throws IOException { RubyModule concurrentMod = runtime.defineModule("Concurrent"); RubyModule thread_safeMod = concurrentMod.defineModuleUnder("Collection"); RubyClass jrubyRefClass = thread_safeMod.defineClassUnder("JRubyMapBackend", runtime.getObject(), BACKEND_ALLOCATOR); jrubyRefClass.setAllocator(BACKEND_ALLOCATOR); jrubyRefClass.defineAnnotatedMethods(JRubyMapBackend.class); } private static final ObjectAllocator BACKEND_ALLOCATOR = new ObjectAllocator() { public IRubyObject allocate(Ruby runtime, RubyClass klazz) { return new JRubyMapBackend(runtime, klazz); } }; @JRubyClass(name="JRubyMapBackend", parent="Object") public static class JRubyMapBackend extends RubyObject { // Defaults used by the CHM static final int DEFAULT_INITIAL_CAPACITY = 16; static final float DEFAULT_LOAD_FACTOR = 0.75f; public static final boolean CAN_USE_UNSAFE_CHM = canUseUnsafeCHM(); private ConcurrentHashMap map; private static ConcurrentHashMap newCHM(int initialCapacity, float loadFactor) { if (CAN_USE_UNSAFE_CHM) { return new ConcurrentHashMapV8(initialCapacity, loadFactor); } else { return new com.concurrent_ruby.ext.jsr166e.nounsafe.ConcurrentHashMapV8(initialCapacity, loadFactor); } } private static ConcurrentHashMap newCHM() { return newCHM(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR); } private static boolean canUseUnsafeCHM() { try { new com.concurrent_ruby.ext.jsr166e.ConcurrentHashMapV8(); // force class load and initialization return true; } catch (Throwable t) { // ensuring we really do catch everything // Doug's Unsafe setup errors always have this "Could not ini.." message if (isCausedBySecurityException(t)) { return false; } throw (t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(t)); } } private static boolean isCausedBySecurityException(Throwable t) { while (t != null) { if ((t.getMessage() != null && t.getMessage().contains("Could not initialize intrinsics")) || t instanceof SecurityException) { return true; } t = t.getCause(); } return false; } public JRubyMapBackend(Ruby runtime, RubyClass klass) { super(runtime, klass); } @JRubyMethod public IRubyObject initialize(ThreadContext context) { map = newCHM(); return context.getRuntime().getNil(); } @JRubyMethod public IRubyObject initialize(ThreadContext context, IRubyObject options) { map = toCHM(context, options); return context.getRuntime().getNil(); } private ConcurrentHashMap toCHM(ThreadContext context, IRubyObject options) { Ruby runtime = context.getRuntime(); if (!options.isNil() && options.respondsTo("[]")) { IRubyObject rInitialCapacity = options.callMethod(context, "[]", runtime.newSymbol("initial_capacity")); IRubyObject rLoadFactor = options.callMethod(context, "[]", runtime.newSymbol("load_factor")); int initialCapacity = !rInitialCapacity.isNil() ? RubyNumeric.num2int(rInitialCapacity.convertToInteger()) : DEFAULT_INITIAL_CAPACITY; float loadFactor = !rLoadFactor.isNil() ? (float)RubyNumeric.num2dbl(rLoadFactor.convertToFloat()) : DEFAULT_LOAD_FACTOR; return newCHM(initialCapacity, loadFactor); } else { return newCHM(); } } @JRubyMethod(name = "[]", required = 1) public IRubyObject op_aref(ThreadContext context, IRubyObject key) { IRubyObject value; return ((value = map.get(key)) == null) ? context.getRuntime().getNil() : value; } @JRubyMethod(name = {"[]="}, required = 2) public IRubyObject op_aset(IRubyObject key, IRubyObject value) { map.put(key, value); return value; } @JRubyMethod public IRubyObject put_if_absent(IRubyObject key, IRubyObject value) { IRubyObject result = map.putIfAbsent(key, value); return result == null ? getRuntime().getNil() : result; } @JRubyMethod public IRubyObject compute_if_absent(final ThreadContext context, final IRubyObject key, final Block block) { return map.computeIfAbsent(key, new ConcurrentHashMap.Fun() { @Override public IRubyObject apply(IRubyObject key) { return block.yieldSpecific(context); } }); } @JRubyMethod public IRubyObject compute_if_present(final ThreadContext context, final IRubyObject key, final Block block) { IRubyObject result = map.computeIfPresent(key, new ConcurrentHashMap.BiFun() { @Override public IRubyObject apply(IRubyObject key, IRubyObject oldValue) { IRubyObject result = block.yieldSpecific(context, oldValue == null ? context.getRuntime().getNil() : oldValue); return result.isNil() ? null : result; } }); return result == null ? context.getRuntime().getNil() : result; } @JRubyMethod public IRubyObject compute(final ThreadContext context, final IRubyObject key, final Block block) { IRubyObject result = map.compute(key, new ConcurrentHashMap.BiFun() { @Override public IRubyObject apply(IRubyObject key, IRubyObject oldValue) { IRubyObject result = block.yieldSpecific(context, oldValue == null ? context.getRuntime().getNil() : oldValue); return result.isNil() ? null : result; } }); return result == null ? context.getRuntime().getNil() : result; } @JRubyMethod public IRubyObject merge_pair(final ThreadContext context, final IRubyObject key, final IRubyObject value, final Block block) { IRubyObject result = map.merge(key, value, new ConcurrentHashMap.BiFun() { @Override public IRubyObject apply(IRubyObject oldValue, IRubyObject newValue) { IRubyObject result = block.yieldSpecific(context, oldValue == null ? context.getRuntime().getNil() : oldValue); return result.isNil() ? null : result; } }); return result == null ? context.getRuntime().getNil() : result; } @JRubyMethod public RubyBoolean replace_pair(IRubyObject key, IRubyObject oldValue, IRubyObject newValue) { return getRuntime().newBoolean(map.replace(key, oldValue, newValue)); } @JRubyMethod(name = "key?", required = 1) public RubyBoolean has_key_p(IRubyObject key) { return map.containsKey(key) ? getRuntime().getTrue() : getRuntime().getFalse(); } @JRubyMethod public IRubyObject key(IRubyObject value) { final IRubyObject key = map.findKey(value); return key == null ? getRuntime().getNil() : key; } @JRubyMethod public IRubyObject replace_if_exists(IRubyObject key, IRubyObject value) { IRubyObject result = map.replace(key, value); return result == null ? getRuntime().getNil() : result; } @JRubyMethod public IRubyObject get_and_set(IRubyObject key, IRubyObject value) { IRubyObject result = map.put(key, value); return result == null ? getRuntime().getNil() : result; } @JRubyMethod public IRubyObject delete(IRubyObject key) { IRubyObject result = map.remove(key); return result == null ? getRuntime().getNil() : result; } @JRubyMethod public RubyBoolean delete_pair(IRubyObject key, IRubyObject value) { return getRuntime().newBoolean(map.remove(key, value)); } @JRubyMethod public IRubyObject clear() { map.clear(); return this; } @JRubyMethod public IRubyObject each_pair(ThreadContext context, Block block) { for (Map.Entry entry : map.entrySet()) { block.yieldSpecific(context, entry.getKey(), entry.getValue()); } return this; } @JRubyMethod public RubyFixnum size(ThreadContext context) { return context.getRuntime().newFixnum(map.size()); } @JRubyMethod public IRubyObject get_or_default(IRubyObject key, IRubyObject defaultValue) { return map.getValueOrDefault(key, defaultValue); } @JRubyMethod(visibility = PRIVATE) public JRubyMapBackend initialize_copy(ThreadContext context, IRubyObject other) { map = newCHM(); return this; } } } concurrent-ruby-1.0.5/ext/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java000066400000000000000000000062141305460430400277670ustar00rootroot00000000000000package com.concurrent_ruby.ext; import java.io.IOException; import org.jruby.Ruby; import org.jruby.RubyClass; import org.jruby.RubyModule; import org.jruby.RubyObject; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; import org.jruby.runtime.ObjectAllocator; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.runtime.load.Library; import java.util.concurrent.atomic.AtomicBoolean; import org.jruby.RubyBoolean; import org.jruby.RubyNil; import org.jruby.runtime.ThreadContext; public class JavaAtomicBooleanLibrary implements Library { public void load(Ruby runtime, boolean wrap) throws IOException { RubyModule concurrentMod = runtime.defineModule("Concurrent"); RubyClass atomicCls = concurrentMod.defineClassUnder("JavaAtomicBoolean", runtime.getObject(), JRUBYREFERENCE_ALLOCATOR); atomicCls.defineAnnotatedMethods(JavaAtomicBoolean.class); } private static final ObjectAllocator JRUBYREFERENCE_ALLOCATOR = new ObjectAllocator() { public IRubyObject allocate(Ruby runtime, RubyClass klazz) { return new JavaAtomicBoolean(runtime, klazz); } }; @JRubyClass(name = "JavaAtomicBoolean", parent = "Object") public static class JavaAtomicBoolean extends RubyObject { private AtomicBoolean atomicBoolean; public JavaAtomicBoolean(Ruby runtime, RubyClass metaClass) { super(runtime, metaClass); } @JRubyMethod public IRubyObject initialize(ThreadContext context, IRubyObject value) { atomicBoolean = new AtomicBoolean(convertRubyBooleanToJavaBoolean(value)); return context.nil; } @JRubyMethod public IRubyObject initialize(ThreadContext context) { atomicBoolean = new AtomicBoolean(); return context.nil; } @JRubyMethod(name = "value") public IRubyObject value() { return getRuntime().newBoolean(atomicBoolean.get()); } @JRubyMethod(name = "true?") public IRubyObject isAtomicTrue() { return getRuntime().newBoolean(atomicBoolean.get()); } @JRubyMethod(name = "false?") public IRubyObject isAtomicFalse() { return getRuntime().newBoolean((atomicBoolean.get() == false)); } @JRubyMethod(name = "value=") public IRubyObject setAtomic(ThreadContext context, IRubyObject newValue) { atomicBoolean.set(convertRubyBooleanToJavaBoolean(newValue)); return context.nil; } @JRubyMethod(name = "make_true") public IRubyObject makeTrue() { return getRuntime().newBoolean(atomicBoolean.compareAndSet(false, true)); } @JRubyMethod(name = "make_false") public IRubyObject makeFalse() { return getRuntime().newBoolean(atomicBoolean.compareAndSet(true, false)); } private boolean convertRubyBooleanToJavaBoolean(IRubyObject newValue) { if (newValue instanceof RubyBoolean.False || newValue instanceof RubyNil) { return false; } else { return true; } } } } concurrent-ruby-1.0.5/ext/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java000077500000000000000000000100611305460430400276540ustar00rootroot00000000000000package com.concurrent_ruby.ext; import java.io.IOException; import java.util.concurrent.atomic.AtomicLong; import org.jruby.Ruby; import org.jruby.RubyClass; import org.jruby.RubyFixnum; import org.jruby.RubyModule; import org.jruby.RubyObject; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; import org.jruby.runtime.ObjectAllocator; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.runtime.load.Library; import org.jruby.runtime.Block; public class JavaAtomicFixnumLibrary implements Library { public void load(Ruby runtime, boolean wrap) throws IOException { RubyModule concurrentMod = runtime.defineModule("Concurrent"); RubyClass atomicCls = concurrentMod.defineClassUnder("JavaAtomicFixnum", runtime.getObject(), JRUBYREFERENCE_ALLOCATOR); atomicCls.defineAnnotatedMethods(JavaAtomicFixnum.class); } private static final ObjectAllocator JRUBYREFERENCE_ALLOCATOR = new ObjectAllocator() { public IRubyObject allocate(Ruby runtime, RubyClass klazz) { return new JavaAtomicFixnum(runtime, klazz); } }; @JRubyClass(name = "JavaAtomicFixnum", parent = "Object") public static class JavaAtomicFixnum extends RubyObject { private AtomicLong atomicLong; public JavaAtomicFixnum(Ruby runtime, RubyClass metaClass) { super(runtime, metaClass); } @JRubyMethod public IRubyObject initialize(ThreadContext context) { this.atomicLong = new AtomicLong(0); return context.nil; } @JRubyMethod public IRubyObject initialize(ThreadContext context, IRubyObject value) { this.atomicLong = new AtomicLong(rubyFixnumToLong(value)); return context.nil; } @JRubyMethod(name = "value") public IRubyObject getValue() { return getRuntime().newFixnum(atomicLong.get()); } @JRubyMethod(name = "value=") public IRubyObject setValue(ThreadContext context, IRubyObject newValue) { atomicLong.set(rubyFixnumToLong(newValue)); return context.nil; } @JRubyMethod(name = {"increment", "up"}) public IRubyObject increment() { return getRuntime().newFixnum(atomicLong.incrementAndGet()); } @JRubyMethod(name = {"increment", "up"}) public IRubyObject increment(IRubyObject value) { long delta = rubyFixnumToLong(value); return getRuntime().newFixnum(atomicLong.addAndGet(delta)); } @JRubyMethod(name = {"decrement", "down"}) public IRubyObject decrement() { return getRuntime().newFixnum(atomicLong.decrementAndGet()); } @JRubyMethod(name = {"decrement", "down"}) public IRubyObject decrement(IRubyObject value) { long delta = rubyFixnumToLong(value); return getRuntime().newFixnum(atomicLong.addAndGet(-delta)); } @JRubyMethod(name = "compare_and_set") public IRubyObject compareAndSet(ThreadContext context, IRubyObject expect, IRubyObject update) { return getRuntime().newBoolean(atomicLong.compareAndSet(rubyFixnumToLong(expect), rubyFixnumToLong(update))); } @JRubyMethod public IRubyObject update(ThreadContext context, Block block) { for (;;) { long _oldValue = atomicLong.get(); IRubyObject oldValue = getRuntime().newFixnum(_oldValue); IRubyObject newValue = block.yield(context, oldValue); if (atomicLong.compareAndSet(_oldValue, rubyFixnumToLong(newValue))) { return newValue; } } } private long rubyFixnumToLong(IRubyObject value) { if (value instanceof RubyFixnum) { RubyFixnum fixNum = (RubyFixnum) value; return fixNum.getLongValue(); } else { throw getRuntime().newArgumentError("value must be a Fixnum"); } } } } concurrent-ruby-1.0.5/ext/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java000077500000000000000000000140521305460430400272000ustar00rootroot00000000000000package com.concurrent_ruby.ext; import java.io.IOException; import java.util.concurrent.Semaphore; import org.jruby.Ruby; import org.jruby.RubyClass; import org.jruby.RubyFixnum; import org.jruby.RubyModule; import org.jruby.RubyNumeric; import org.jruby.RubyObject; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; import org.jruby.runtime.ObjectAllocator; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; public class JavaSemaphoreLibrary { public void load(Ruby runtime, boolean wrap) throws IOException { RubyModule concurrentMod = runtime.defineModule("Concurrent"); RubyClass atomicCls = concurrentMod.defineClassUnder("JavaSemaphore", runtime.getObject(), JRUBYREFERENCE_ALLOCATOR); atomicCls.defineAnnotatedMethods(JavaSemaphore.class); } private static final ObjectAllocator JRUBYREFERENCE_ALLOCATOR = new ObjectAllocator() { public IRubyObject allocate(Ruby runtime, RubyClass klazz) { return new JavaSemaphore(runtime, klazz); } }; @JRubyClass(name = "JavaSemaphore", parent = "Object") public static class JavaSemaphore extends RubyObject { private JRubySemaphore semaphore; public JavaSemaphore(Ruby runtime, RubyClass metaClass) { super(runtime, metaClass); } @JRubyMethod public IRubyObject initialize(ThreadContext context, IRubyObject value) { this.semaphore = new JRubySemaphore(rubyFixnumInt(value, "count")); return context.nil; } @JRubyMethod public IRubyObject acquire(ThreadContext context, IRubyObject value) throws InterruptedException { this.semaphore.acquire(rubyFixnumToPositiveInt(value, "permits")); return context.nil; } @JRubyMethod(name = "available_permits") public IRubyObject availablePermits(ThreadContext context) { return getRuntime().newFixnum(this.semaphore.availablePermits()); } @JRubyMethod(name = "drain_permits") public IRubyObject drainPermits(ThreadContext context) { return getRuntime().newFixnum(this.semaphore.drainPermits()); } @JRubyMethod public IRubyObject acquire(ThreadContext context) throws InterruptedException { this.semaphore.acquire(1); return context.nil; } @JRubyMethod(name = "try_acquire") public IRubyObject tryAcquire(ThreadContext context) throws InterruptedException { return getRuntime().newBoolean(semaphore.tryAcquire(1)); } @JRubyMethod(name = "try_acquire") public IRubyObject tryAcquire(ThreadContext context, IRubyObject permits) throws InterruptedException { return getRuntime().newBoolean(semaphore.tryAcquire(rubyFixnumToPositiveInt(permits, "permits"))); } @JRubyMethod(name = "try_acquire") public IRubyObject tryAcquire(ThreadContext context, IRubyObject permits, IRubyObject timeout) throws InterruptedException { return getRuntime().newBoolean( semaphore.tryAcquire( rubyFixnumToPositiveInt(permits, "permits"), rubyNumericToLong(timeout, "timeout"), java.util.concurrent.TimeUnit.SECONDS) ); } @JRubyMethod public IRubyObject release(ThreadContext context) { this.semaphore.release(1); return getRuntime().newBoolean(true); } @JRubyMethod public IRubyObject release(ThreadContext context, IRubyObject value) { this.semaphore.release(rubyFixnumToPositiveInt(value, "permits")); return getRuntime().newBoolean(true); } @JRubyMethod(name = "reduce_permits") public IRubyObject reducePermits(ThreadContext context, IRubyObject reduction) throws InterruptedException { this.semaphore.publicReducePermits(rubyFixnumToNonNegativeInt(reduction, "reduction")); return context.nil; } private int rubyFixnumInt(IRubyObject value, String paramName) { if (value instanceof RubyFixnum) { RubyFixnum fixNum = (RubyFixnum) value; return (int) fixNum.getLongValue(); } else { throw getRuntime().newArgumentError(paramName + " must be integer"); } } private int rubyFixnumToNonNegativeInt(IRubyObject value, String paramName) { if (value instanceof RubyFixnum && ((RubyFixnum) value).getLongValue() >= 0) { RubyFixnum fixNum = (RubyFixnum) value; return (int) fixNum.getLongValue(); } else { throw getRuntime().newArgumentError(paramName + " must be a non-negative integer"); } } private int rubyFixnumToPositiveInt(IRubyObject value, String paramName) { if (value instanceof RubyFixnum && ((RubyFixnum) value).getLongValue() > 0) { RubyFixnum fixNum = (RubyFixnum) value; return (int) fixNum.getLongValue(); } else { throw getRuntime().newArgumentError(paramName + " must be an integer greater than zero"); } } private long rubyNumericToLong(IRubyObject value, String paramName) { if (value instanceof RubyNumeric && ((RubyNumeric) value).getDoubleValue() > 0) { RubyNumeric fixNum = (RubyNumeric) value; return fixNum.getLongValue(); } else { throw getRuntime().newArgumentError(paramName + " must be a float greater than zero"); } } class JRubySemaphore extends Semaphore { public JRubySemaphore(int permits) { super(permits); } public JRubySemaphore(int permits, boolean value) { super(permits, value); } public void publicReducePermits(int i) { reducePermits(i); } } } } concurrent-ruby-1.0.5/ext/com/concurrent_ruby/ext/SynchronizationLibrary.java000066400000000000000000000251321305460430400276520ustar00rootroot00000000000000package com.concurrent_ruby.ext; import org.jruby.Ruby; import org.jruby.RubyBasicObject; import org.jruby.RubyClass; import org.jruby.RubyModule; import org.jruby.RubyObject; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; import org.jruby.runtime.Block; import org.jruby.runtime.ObjectAllocator; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.Visibility; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.runtime.load.Library; import sun.misc.Unsafe; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; public class SynchronizationLibrary implements Library { private static final Unsafe UNSAFE = loadUnsafe(); private static Unsafe loadUnsafe() { try { Class ncdfe = Class.forName("sun.misc.Unsafe"); Field f = ncdfe.getDeclaredField("theUnsafe"); f.setAccessible(true); return (Unsafe) f.get((java.lang.Object) null); } catch (Exception var2) { return null; } catch (NoClassDefFoundError var3) { return null; } } private static boolean supportsFences() { if (UNSAFE == null) { return false; } else { try { Method m = UNSAFE.getClass().getDeclaredMethod("fullFence", new Class[0]); if (m != null) { return true; } } catch (Exception var1) { // nothing } return false; } } private static final ObjectAllocator JRUBY_OBJECT_ALLOCATOR = new ObjectAllocator() { public IRubyObject allocate(Ruby runtime, RubyClass klazz) { return new JRubyObject(runtime, klazz); } }; private static final ObjectAllocator OBJECT_ALLOCATOR = new ObjectAllocator() { public IRubyObject allocate(Ruby runtime, RubyClass klazz) { return new Object(runtime, klazz); } }; private static final ObjectAllocator ABSTRACT_LOCKABLE_OBJECT_ALLOCATOR = new ObjectAllocator() { public IRubyObject allocate(Ruby runtime, RubyClass klazz) { return new AbstractLockableObject(runtime, klazz); } }; private static final ObjectAllocator JRUBY_LOCKABLE_OBJECT_ALLOCATOR = new ObjectAllocator() { public IRubyObject allocate(Ruby runtime, RubyClass klazz) { return new JRubyLockableObject(runtime, klazz); } }; public void load(Ruby runtime, boolean wrap) throws IOException { RubyModule synchronizationModule = runtime. defineModule("Concurrent"). defineModuleUnder("Synchronization"); RubyModule jrubyAttrVolatileModule = synchronizationModule.defineModuleUnder("JRubyAttrVolatile"); jrubyAttrVolatileModule.defineAnnotatedMethods(JRubyAttrVolatile.class); defineClass(runtime, synchronizationModule, "AbstractObject", "JRubyObject", JRubyObject.class, JRUBY_OBJECT_ALLOCATOR); defineClass(runtime, synchronizationModule, "JRubyObject", "Object", Object.class, OBJECT_ALLOCATOR); defineClass(runtime, synchronizationModule, "Object", "AbstractLockableObject", AbstractLockableObject.class, ABSTRACT_LOCKABLE_OBJECT_ALLOCATOR); defineClass(runtime, synchronizationModule, "AbstractLockableObject", "JRubyLockableObject", JRubyLockableObject.class, JRUBY_LOCKABLE_OBJECT_ALLOCATOR); } private RubyClass defineClass( Ruby runtime, RubyModule namespace, String parentName, String name, Class javaImplementation, ObjectAllocator allocator) { final RubyClass parentClass = namespace.getClass(parentName); if (parentClass == null) { System.out.println("not found " + parentName); throw runtime.newRuntimeError(namespace.toString() + "::" + parentName + " is missing"); } final RubyClass newClass = namespace.defineClassUnder(name, parentClass, allocator); newClass.defineAnnotatedMethods(javaImplementation); return newClass; } // Facts: // - all ivar reads are without any synchronisation of fences see // https://github.com/jruby/jruby/blob/master/core/src/main/java/org/jruby/runtime/ivars/VariableAccessor.java#L110-110 // - writes depend on UnsafeHolder.U, null -> SynchronizedVariableAccessor, !null -> StampedVariableAccessor // SynchronizedVariableAccessor wraps with synchronized block, StampedVariableAccessor uses fullFence or // volatilePut // TODO (pitr 16-Sep-2015): what do we do in Java 9 ? // module JRubyAttrVolatile public static class JRubyAttrVolatile { // volatile threadContext is used as a memory barrier per the JVM memory model happens-before semantic // on volatile fields. any volatile field could have been used but using the thread context is an // attempt to avoid code elimination. private static volatile ThreadContext threadContext = null; @JRubyMethod(name = "full_memory_barrier", visibility = Visibility.PUBLIC) public static IRubyObject fullMemoryBarrier(ThreadContext context, IRubyObject self) { // Prevent reordering of ivar writes with publication of this instance if (!supportsFences()) { // Assuming that following volatile read and write is not eliminated it simulates fullFence. // If it's eliminated it'll cause problems only on non-x86 platforms. // http://shipilev.net/blog/2014/jmm-pragmatics/#_happens_before_test_your_understanding final ThreadContext oldContext = threadContext; threadContext = context; } else { UNSAFE.fullFence(); } return context.nil; } @JRubyMethod(name = "instance_variable_get_volatile", visibility = Visibility.PUBLIC) public static IRubyObject instanceVariableGetVolatile( ThreadContext context, IRubyObject self, IRubyObject name) { // Ensure we ses latest value with loadFence if (!supportsFences()) { // piggybacking on volatile read, simulating loadFence final ThreadContext oldContext = threadContext; return ((RubyBasicObject) self).instance_variable_get(context, name); } else { UNSAFE.loadFence(); return ((RubyBasicObject) self).instance_variable_get(context, name); } } @JRubyMethod(name = "instance_variable_set_volatile", visibility = Visibility.PUBLIC) public static IRubyObject InstanceVariableSetVolatile( ThreadContext context, IRubyObject self, IRubyObject name, IRubyObject value) { // Ensure we make last update visible if (!supportsFences()) { // piggybacking on volatile write, simulating storeFence final IRubyObject result = ((RubyBasicObject) self).instance_variable_set(name, value); threadContext = context; return result; } else { // JRuby uses StampedVariableAccessor which calls fullFence // so no additional steps needed. // See https://github.com/jruby/jruby/blob/master/core/src/main/java/org/jruby/runtime/ivars/StampedVariableAccessor.java#L151-L159 return ((RubyBasicObject) self).instance_variable_set(name, value); } } } @JRubyClass(name = "JRubyObject", parent = "AbstractObject") public static class JRubyObject extends RubyObject { public JRubyObject(Ruby runtime, RubyClass metaClass) { super(runtime, metaClass); } } @JRubyClass(name = "Object", parent = "JRubyObject") public static class Object extends JRubyObject { public Object(Ruby runtime, RubyClass metaClass) { super(runtime, metaClass); } } @JRubyClass(name = "AbstractLockableObject", parent = "Object") public static class AbstractLockableObject extends Object { public AbstractLockableObject(Ruby runtime, RubyClass metaClass) { super(runtime, metaClass); } } @JRubyClass(name = "JRubyLockableObject", parent = "AbstractLockableObject") public static class JRubyLockableObject extends JRubyObject { public JRubyLockableObject(Ruby runtime, RubyClass metaClass) { super(runtime, metaClass); } @JRubyMethod(name = "synchronize", visibility = Visibility.PROTECTED) public IRubyObject rubySynchronize(ThreadContext context, Block block) { synchronized (this) { return block.yield(context, null); } } @JRubyMethod(name = "ns_wait", optional = 1, visibility = Visibility.PROTECTED) public IRubyObject nsWait(ThreadContext context, IRubyObject[] args) { Ruby runtime = context.runtime; if (args.length > 1) { throw runtime.newArgumentError(args.length, 1); } Double timeout = null; if (args.length > 0 && !args[0].isNil()) { timeout = args[0].convertToFloat().getDoubleValue(); if (timeout < 0) { throw runtime.newArgumentError("time interval must be positive"); } } if (Thread.interrupted()) { throw runtime.newConcurrencyError("thread interrupted"); } boolean success = false; try { success = context.getThread().wait_timeout(this, timeout); } catch (InterruptedException ie) { throw runtime.newConcurrencyError(ie.getLocalizedMessage()); } finally { // An interrupt or timeout may have caused us to miss // a notify that we consumed, so do another notify in // case someone else is available to pick it up. if (!success) { this.notify(); } } return this; } @JRubyMethod(name = "ns_signal", visibility = Visibility.PROTECTED) public IRubyObject nsSignal(ThreadContext context) { notify(); return this; } @JRubyMethod(name = "ns_broadcast", visibility = Visibility.PROTECTED) public IRubyObject nsBroadcast(ThreadContext context) { notifyAll(); return this; } } } concurrent-ruby-1.0.5/ext/com/concurrent_ruby/ext/jsr166e/000077500000000000000000000000001305460430400234565ustar00rootroot00000000000000concurrent-ruby-1.0.5/ext/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMap.java000066400000000000000000000022641305460430400277110ustar00rootroot00000000000000package com.concurrent_ruby.ext.jsr166e; import java.util.Map; import java.util.Set; public interface ConcurrentHashMap { /** Interface describing a function of one argument */ public interface Fun { T apply(A a); } /** Interface describing a function of two arguments */ public interface BiFun { T apply(A a, B b); } public V get(K key); public V put(K key, V value); public V putIfAbsent(K key, V value); public V computeIfAbsent(K key, Fun mf); public V computeIfPresent(K key, BiFun mf); public V compute(K key, BiFun mf); public V merge(K key, V value, BiFun mf); public boolean replace(K key, V oldVal, V newVal); public V replace(K key, V value); public boolean containsKey(K key); public boolean remove(Object key, Object value); public V remove(K key); public void clear(); public Set> entrySet(); public int size(); public V getValueOrDefault(Object key, V defaultValue); public boolean containsValue(V value); public K findKey(V value); } concurrent-ruby-1.0.5/ext/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java000066400000000000000000004671041305460430400301370ustar00rootroot00000000000000/* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/publicdomain/zero/1.0/ */ // This is based on the 1.79 version. package com.concurrent_ruby.ext.jsr166e; import org.jruby.RubyClass; import org.jruby.RubyNumeric; import org.jruby.RubyObject; import org.jruby.exceptions.RaiseException; import com.concurrent_ruby.ext.jsr166y.ThreadLocalRandom; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import java.util.Arrays; import java.util.Map; import java.util.Set; import java.util.Collection; import java.util.Hashtable; import java.util.HashMap; import java.util.Iterator; import java.util.Enumeration; import java.util.ConcurrentModificationException; import java.util.NoSuchElementException; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.locks.AbstractQueuedSynchronizer; import java.io.Serializable; /** * A hash table supporting full concurrency of retrievals and * high expected concurrency for updates. This class obeys the * same functional specification as {@link java.util.Hashtable}, and * includes versions of methods corresponding to each method of * {@code Hashtable}. However, even though all operations are * thread-safe, retrieval operations do not entail locking, * and there is not any support for locking the entire table * in a way that prevents all access. This class is fully * interoperable with {@code Hashtable} in programs that rely on its * thread safety but not on its synchronization details. * *

Retrieval operations (including {@code get}) generally do not * block, so may overlap with update operations (including {@code put} * and {@code remove}). Retrievals reflect the results of the most * recently completed update operations holding upon their * onset. (More formally, an update operation for a given key bears a * happens-before relation with any (non-null) retrieval for * that key reporting the updated value.) For aggregate operations * such as {@code putAll} and {@code clear}, concurrent retrievals may * reflect insertion or removal of only some entries. Similarly, * Iterators and Enumerations return elements reflecting the state of * the hash table at some point at or since the creation of the * iterator/enumeration. They do not throw {@link * ConcurrentModificationException}. However, iterators are designed * to be used by only one thread at a time. Bear in mind that the * results of aggregate status methods including {@code size}, {@code * isEmpty}, and {@code containsValue} are typically useful only when * a map is not undergoing concurrent updates in other threads. * Otherwise the results of these methods reflect transient states * that may be adequate for monitoring or estimation purposes, but not * for program control. * *

The table is dynamically expanded when there are too many * collisions (i.e., keys that have distinct hash codes but fall into * the same slot modulo the table size), with the expected average * effect of maintaining roughly two bins per mapping (corresponding * to a 0.75 load factor threshold for resizing). There may be much * variance around this average as mappings are added and removed, but * overall, this maintains a commonly accepted time/space tradeoff for * hash tables. However, resizing this or any other kind of hash * table may be a relatively slow operation. When possible, it is a * good idea to provide a size estimate as an optional {@code * initialCapacity} constructor argument. An additional optional * {@code loadFactor} constructor argument provides a further means of * customizing initial table capacity by specifying the table density * to be used in calculating the amount of space to allocate for the * given number of elements. Also, for compatibility with previous * versions of this class, constructors may optionally specify an * expected {@code concurrencyLevel} as an additional hint for * internal sizing. Note that using many keys with exactly the same * {@code hashCode()} is a sure way to slow down performance of any * hash table. * *

A {@link Set} projection of a ConcurrentHashMapV8 may be created * (using {@link #newKeySet()} or {@link #newKeySet(int)}), or viewed * (using {@link #keySet(Object)} when only keys are of interest, and the * mapped values are (perhaps transiently) not used or all take the * same mapping value. * *

A ConcurrentHashMapV8 can be used as scalable frequency map (a * form of histogram or multiset) by using {@link LongAdder} values * and initializing via {@link #computeIfAbsent}. For example, to add * a count to a {@code ConcurrentHashMapV8 freqs}, you * can use {@code freqs.computeIfAbsent(k -> new * LongAdder()).increment();} * *

This class and its views and iterators implement all of the * optional methods of the {@link Map} and {@link Iterator} * interfaces. * *

Like {@link Hashtable} but unlike {@link HashMap}, this class * does not allow {@code null} to be used as a key or value. * *

ConcurrentHashMapV8s support parallel operations using the {@link * ForkJoinPool#commonPool}. (Tasks that may be used in other contexts * are available in class {@link ForkJoinTasks}). These operations are * designed to be safely, and often sensibly, applied even with maps * that are being concurrently updated by other threads; for example, * when computing a snapshot summary of the values in a shared * registry. There are three kinds of operation, each with four * forms, accepting functions with Keys, Values, Entries, and (Key, * Value) arguments and/or return values. (The first three forms are * also available via the {@link #keySet()}, {@link #values()} and * {@link #entrySet()} views). Because the elements of a * ConcurrentHashMapV8 are not ordered in any particular way, and may be * processed in different orders in different parallel executions, the * correctness of supplied functions should not depend on any * ordering, or on any other objects or values that may transiently * change while computation is in progress; and except for forEach * actions, should ideally be side-effect-free. * *

* *

The concurrency properties of bulk operations follow * from those of ConcurrentHashMapV8: Any non-null result returned * from {@code get(key)} and related access methods bears a * happens-before relation with the associated insertion or * update. The result of any bulk operation reflects the * composition of these per-element relations (but is not * necessarily atomic with respect to the map as a whole unless it * is somehow known to be quiescent). Conversely, because keys * and values in the map are never null, null serves as a reliable * atomic indicator of the current lack of any result. To * maintain this property, null serves as an implicit basis for * all non-scalar reduction operations. For the double, long, and * int versions, the basis should be one that, when combined with * any other value, returns that other value (more formally, it * should be the identity element for the reduction). Most common * reductions have these properties; for example, computing a sum * with basis 0 or a minimum with basis MAX_VALUE. * *

Search and transformation functions provided as arguments * should similarly return null to indicate the lack of any result * (in which case it is not used). In the case of mapped * reductions, this also enables transformations to serve as * filters, returning null (or, in the case of primitive * specializations, the identity basis) if the element should not * be combined. You can create compound transformations and * filterings by composing them yourself under this "null means * there is nothing there now" rule before using them in search or * reduce operations. * *

Methods accepting and/or returning Entry arguments maintain * key-value associations. They may be useful for example when * finding the key for the greatest value. Note that "plain" Entry * arguments can be supplied using {@code new * AbstractMap.SimpleEntry(k,v)}. * *

Bulk operations may complete abruptly, throwing an * exception encountered in the application of a supplied * function. Bear in mind when handling such exceptions that other * concurrently executing functions could also have thrown * exceptions, or would have done so if the first exception had * not occurred. * *

Parallel speedups for bulk operations compared to sequential * processing are common but not guaranteed. Operations involving * brief functions on small maps may execute more slowly than * sequential loops if the underlying work to parallelize the * computation is more expensive than the computation itself. * Similarly, parallelization may not lead to much actual parallelism * if all processors are busy performing unrelated tasks. * *

All arguments to all task methods must be non-null. * *

jsr166e note: During transition, this class * uses nested functional interfaces with different names but the * same forms as those expected for JDK8. * *

This class is a member of the * * Java Collections Framework. * * @since 1.5 * @author Doug Lea * @param the type of keys maintained by this map * @param the type of mapped values */ public class ConcurrentHashMapV8 implements ConcurrentMap, Serializable, ConcurrentHashMap { private static final long serialVersionUID = 7249069246763182397L; /** * A partitionable iterator. A Spliterator can be traversed * directly, but can also be partitioned (before traversal) by * creating another Spliterator that covers a non-overlapping * portion of the elements, and so may be amenable to parallel * execution. * *

This interface exports a subset of expected JDK8 * functionality. * *

Sample usage: Here is one (of the several) ways to compute * the sum of the values held in a map using the ForkJoin * framework. As illustrated here, Spliterators are well suited to * designs in which a task repeatedly splits off half its work * into forked subtasks until small enough to process directly, * and then joins these subtasks. Variants of this style can also * be used in completion-based designs. * *

     * {@code ConcurrentHashMapV8 m = ...
     * // split as if have 8 * parallelism, for load balance
     * int n = m.size();
     * int p = aForkJoinPool.getParallelism() * 8;
     * int split = (n < p)? n : p;
     * long sum = aForkJoinPool.invoke(new SumValues(m.valueSpliterator(), split, null));
     * // ...
     * static class SumValues extends RecursiveTask {
     *   final Spliterator s;
     *   final int split;             // split while > 1
     *   final SumValues nextJoin;    // records forked subtasks to join
     *   SumValues(Spliterator s, int depth, SumValues nextJoin) {
     *     this.s = s; this.depth = depth; this.nextJoin = nextJoin;
     *   }
     *   public Long compute() {
     *     long sum = 0;
     *     SumValues subtasks = null; // fork subtasks
     *     for (int s = split >>> 1; s > 0; s >>>= 1)
     *       (subtasks = new SumValues(s.split(), s, subtasks)).fork();
     *     while (s.hasNext())        // directly process remaining elements
     *       sum += s.next();
     *     for (SumValues t = subtasks; t != null; t = t.nextJoin)
     *       sum += t.join();         // collect subtask results
     *     return sum;
     *   }
     * }
     * }
*/ public static interface Spliterator extends Iterator { /** * Returns a Spliterator covering approximately half of the * elements, guaranteed not to overlap with those subsequently * returned by this Spliterator. After invoking this method, * the current Spliterator will not produce any of * the elements of the returned Spliterator, but the two * Spliterators together will produce all of the elements that * would have been produced by this Spliterator had this * method not been called. The exact number of elements * produced by the returned Spliterator is not guaranteed, and * may be zero (i.e., with {@code hasNext()} reporting {@code * false}) if this Spliterator cannot be further split. * * @return a Spliterator covering approximately half of the * elements * @throws IllegalStateException if this Spliterator has * already commenced traversing elements */ Spliterator split(); } /* * Overview: * * The primary design goal of this hash table is to maintain * concurrent readability (typically method get(), but also * iterators and related methods) while minimizing update * contention. Secondary goals are to keep space consumption about * the same or better than java.util.HashMap, and to support high * initial insertion rates on an empty table by many threads. * * Each key-value mapping is held in a Node. Because Node fields * can contain special values, they are defined using plain Object * types. Similarly in turn, all internal methods that use them * work off Object types. And similarly, so do the internal * methods of auxiliary iterator and view classes. All public * generic typed methods relay in/out of these internal methods, * supplying null-checks and casts as needed. This also allows * many of the public methods to be factored into a smaller number * of internal methods (although sadly not so for the five * variants of put-related operations). The validation-based * approach explained below leads to a lot of code sprawl because * retry-control precludes factoring into smaller methods. * * The table is lazily initialized to a power-of-two size upon the * first insertion. Each bin in the table normally contains a * list of Nodes (most often, the list has only zero or one Node). * Table accesses require volatile/atomic reads, writes, and * CASes. Because there is no other way to arrange this without * adding further indirections, we use intrinsics * (sun.misc.Unsafe) operations. The lists of nodes within bins * are always accurately traversable under volatile reads, so long * as lookups check hash code and non-nullness of value before * checking key equality. * * We use the top two bits of Node hash fields for control * purposes -- they are available anyway because of addressing * constraints. As explained further below, these top bits are * used as follows: * 00 - Normal * 01 - Locked * 11 - Locked and may have a thread waiting for lock * 10 - Node is a forwarding node * * The lower 30 bits of each Node's hash field contain a * transformation of the key's hash code, except for forwarding * nodes, for which the lower bits are zero (and so always have * hash field == MOVED). * * Insertion (via put or its variants) of the first node in an * empty bin is performed by just CASing it to the bin. This is * by far the most common case for put operations under most * key/hash distributions. Other update operations (insert, * delete, and replace) require locks. We do not want to waste * the space required to associate a distinct lock object with * each bin, so instead use the first node of a bin list itself as * a lock. Blocking support for these locks relies on the builtin * "synchronized" monitors. However, we also need a tryLock * construction, so we overlay these by using bits of the Node * hash field for lock control (see above), and so normally use * builtin monitors only for blocking and signalling using * wait/notifyAll constructions. See Node.tryAwaitLock. * * Using the first node of a list as a lock does not by itself * suffice though: When a node is locked, any update must first * validate that it is still the first node after locking it, and * retry if not. Because new nodes are always appended to lists, * once a node is first in a bin, it remains first until deleted * or the bin becomes invalidated (upon resizing). However, * operations that only conditionally update may inspect nodes * until the point of update. This is a converse of sorts to the * lazy locking technique described by Herlihy & Shavit. * * The main disadvantage of per-bin locks is that other update * operations on other nodes in a bin list protected by the same * lock can stall, for example when user equals() or mapping * functions take a long time. However, statistically, under * random hash codes, this is not a common problem. Ideally, the * frequency of nodes in bins follows a Poisson distribution * (http://en.wikipedia.org/wiki/Poisson_distribution) with a * parameter of about 0.5 on average, given the resizing threshold * of 0.75, although with a large variance because of resizing * granularity. Ignoring variance, the expected occurrences of * list size k are (exp(-0.5) * pow(0.5, k) / factorial(k)). The * first values are: * * 0: 0.60653066 * 1: 0.30326533 * 2: 0.07581633 * 3: 0.01263606 * 4: 0.00157952 * 5: 0.00015795 * 6: 0.00001316 * 7: 0.00000094 * 8: 0.00000006 * more: less than 1 in ten million * * Lock contention probability for two threads accessing distinct * elements is roughly 1 / (8 * #elements) under random hashes. * * Actual hash code distributions encountered in practice * sometimes deviate significantly from uniform randomness. This * includes the case when N > (1<<30), so some keys MUST collide. * Similarly for dumb or hostile usages in which multiple keys are * designed to have identical hash codes. Also, although we guard * against the worst effects of this (see method spread), sets of * hashes may differ only in bits that do not impact their bin * index for a given power-of-two mask. So we use a secondary * strategy that applies when the number of nodes in a bin exceeds * a threshold, and at least one of the keys implements * Comparable. These TreeBins use a balanced tree to hold nodes * (a specialized form of red-black trees), bounding search time * to O(log N). Each search step in a TreeBin is around twice as * slow as in a regular list, but given that N cannot exceed * (1<<64) (before running out of addresses) this bounds search * steps, lock hold times, etc, to reasonable constants (roughly * 100 nodes inspected per operation worst case) so long as keys * are Comparable (which is very common -- String, Long, etc). * TreeBin nodes (TreeNodes) also maintain the same "next" * traversal pointers as regular nodes, so can be traversed in * iterators in the same way. * * The table is resized when occupancy exceeds a percentage * threshold (nominally, 0.75, but see below). Only a single * thread performs the resize (using field "sizeCtl", to arrange * exclusion), but the table otherwise remains usable for reads * and updates. Resizing proceeds by transferring bins, one by * one, from the table to the next table. Because we are using * power-of-two expansion, the elements from each bin must either * stay at same index, or move with a power of two offset. We * eliminate unnecessary node creation by catching cases where old * nodes can be reused because their next fields won't change. On * average, only about one-sixth of them need cloning when a table * doubles. The nodes they replace will be garbage collectable as * soon as they are no longer referenced by any reader thread that * may be in the midst of concurrently traversing table. Upon * transfer, the old table bin contains only a special forwarding * node (with hash field "MOVED") that contains the next table as * its key. On encountering a forwarding node, access and update * operations restart, using the new table. * * Each bin transfer requires its bin lock. However, unlike other * cases, a transfer can skip a bin if it fails to acquire its * lock, and revisit it later (unless it is a TreeBin). Method * rebuild maintains a buffer of TRANSFER_BUFFER_SIZE bins that * have been skipped because of failure to acquire a lock, and * blocks only if none are available (i.e., only very rarely). * The transfer operation must also ensure that all accessible * bins in both the old and new table are usable by any traversal. * When there are no lock acquisition failures, this is arranged * simply by proceeding from the last bin (table.length - 1) up * towards the first. Upon seeing a forwarding node, traversals * (see class Iter) arrange to move to the new table * without revisiting nodes. However, when any node is skipped * during a transfer, all earlier table bins may have become * visible, so are initialized with a reverse-forwarding node back * to the old table until the new ones are established. (This * sometimes requires transiently locking a forwarding node, which * is possible under the above encoding.) These more expensive * mechanics trigger only when necessary. * * The traversal scheme also applies to partial traversals of * ranges of bins (via an alternate Traverser constructor) * to support partitioned aggregate operations. Also, read-only * operations give up if ever forwarded to a null table, which * provides support for shutdown-style clearing, which is also not * currently implemented. * * Lazy table initialization minimizes footprint until first use, * and also avoids resizings when the first operation is from a * putAll, constructor with map argument, or deserialization. * These cases attempt to override the initial capacity settings, * but harmlessly fail to take effect in cases of races. * * The element count is maintained using a LongAdder, which avoids * contention on updates but can encounter cache thrashing if read * too frequently during concurrent access. To avoid reading so * often, resizing is attempted either when a bin lock is * contended, or upon adding to a bin already holding two or more * nodes (checked before adding in the xIfAbsent methods, after * adding in others). Under uniform hash distributions, the * probability of this occurring at threshold is around 13%, * meaning that only about 1 in 8 puts check threshold (and after * resizing, many fewer do so). But this approximation has high * variance for small table sizes, so we check on any collision * for sizes <= 64. The bulk putAll operation further reduces * contention by only committing count updates upon these size * checks. * * Maintaining API and serialization compatibility with previous * versions of this class introduces several oddities. Mainly: We * leave untouched but unused constructor arguments refering to * concurrencyLevel. We accept a loadFactor constructor argument, * but apply it only to initial table capacity (which is the only * time that we can guarantee to honor it.) We also declare an * unused "Segment" class that is instantiated in minimal form * only when serializing. */ /* ---------------- Constants -------------- */ /** * The largest possible table capacity. This value must be * exactly 1<<30 to stay within Java array allocation and indexing * bounds for power of two table sizes, and is further required * because the top two bits of 32bit hash fields are used for * control purposes. */ private static final int MAXIMUM_CAPACITY = 1 << 30; /** * The default initial table capacity. Must be a power of 2 * (i.e., at least 1) and at most MAXIMUM_CAPACITY. */ private static final int DEFAULT_CAPACITY = 16; /** * The largest possible (non-power of two) array size. * Needed by toArray and related methods. */ static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; /** * The default concurrency level for this table. Unused but * defined for compatibility with previous versions of this class. */ private static final int DEFAULT_CONCURRENCY_LEVEL = 16; /** * The load factor for this table. Overrides of this value in * constructors affect only the initial table capacity. The * actual floating point value isn't normally used -- it is * simpler to use expressions such as {@code n - (n >>> 2)} for * the associated resizing threshold. */ private static final float LOAD_FACTOR = 0.75f; /** * The buffer size for skipped bins during transfers. The * value is arbitrary but should be large enough to avoid * most locking stalls during resizes. */ private static final int TRANSFER_BUFFER_SIZE = 32; /** * The bin count threshold for using a tree rather than list for a * bin. The value reflects the approximate break-even point for * using tree-based operations. * Note that Doug's version defaults to 8, but when dealing with * Ruby objects it is actually beneficial to avoid TreeNodes * as long as possible as it usually means going into Ruby land. */ private static final int TREE_THRESHOLD = 16; /* * Encodings for special uses of Node hash fields. See above for * explanation. */ static final int MOVED = 0x80000000; // hash field for forwarding nodes static final int LOCKED = 0x40000000; // set/tested only as a bit static final int WAITING = 0xc0000000; // both bits set/tested together static final int HASH_BITS = 0x3fffffff; // usable bits of normal node hash /* ---------------- Fields -------------- */ /** * The array of bins. Lazily initialized upon first insertion. * Size is always a power of two. Accessed directly by iterators. */ transient volatile Node[] table; /** * The counter maintaining number of elements. */ private transient final LongAdder counter; /** * Table initialization and resizing control. When negative, the * table is being initialized or resized. Otherwise, when table is * null, holds the initial table size to use upon creation, or 0 * for default. After initialization, holds the next element count * value upon which to resize the table. */ private transient volatile int sizeCtl; // views private transient KeySetView keySet; private transient ValuesView values; private transient EntrySetView entrySet; /** For serialization compatibility. Null unless serialized; see below */ private Segment[] segments; /* ---------------- Table element access -------------- */ /* * Volatile access methods are used for table elements as well as * elements of in-progress next table while resizing. Uses are * null checked by callers, and implicitly bounds-checked, relying * on the invariants that tab arrays have non-zero size, and all * indices are masked with (tab.length - 1) which is never * negative and always less than length. Note that, to be correct * wrt arbitrary concurrency errors by users, bounds checks must * operate on local variables, which accounts for some odd-looking * inline assignments below. */ static final Node tabAt(Node[] tab, int i) { // used by Iter return (Node)UNSAFE.getObjectVolatile(tab, ((long)i< 1 ? 64 : 1; /** * Spins a while if LOCKED bit set and this node is the first * of its bin, and then sets WAITING bits on hash field and * blocks (once) if they are still set. It is OK for this * method to return even if lock is not available upon exit, * which enables these simple single-wait mechanics. * * The corresponding signalling operation is performed within * callers: Upon detecting that WAITING has been set when * unlocking lock (via a failed CAS from non-waiting LOCKED * state), unlockers acquire the sync lock and perform a * notifyAll. * * The initial sanity check on tab and bounds is not currently * necessary in the only usages of this method, but enables * use in other future contexts. */ final void tryAwaitLock(Node[] tab, int i) { if (tab != null && i >= 0 && i < tab.length) { // sanity check int r = ThreadLocalRandom.current().nextInt(); // randomize spins int spins = MAX_SPINS, h; while (tabAt(tab, i) == this && ((h = hash) & LOCKED) != 0) { if (spins >= 0) { r ^= r << 1; r ^= r >>> 3; r ^= r << 10; // xorshift if (r >= 0 && --spins == 0) Thread.yield(); // yield before block } else if (casHash(h, h | WAITING)) { synchronized (this) { if (tabAt(tab, i) == this && (hash & WAITING) == WAITING) { try { wait(); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); } } else notifyAll(); // possibly won race vs signaller } break; } } } } // Unsafe mechanics for casHash private static final sun.misc.Unsafe UNSAFE; private static final long hashOffset; static { try { UNSAFE = getUnsafe(); Class k = Node.class; hashOffset = UNSAFE.objectFieldOffset (k.getDeclaredField("hash")); } catch (Exception e) { throw new Error(e); } } } /* ---------------- TreeBins -------------- */ /** * Nodes for use in TreeBins */ static final class TreeNode extends Node { TreeNode parent; // red-black tree links TreeNode left; TreeNode right; TreeNode prev; // needed to unlink next upon deletion boolean red; TreeNode(int hash, Object key, Object val, Node next, TreeNode parent) { super(hash, key, val, next); this.parent = parent; } } /** * A specialized form of red-black tree for use in bins * whose size exceeds a threshold. * * TreeBins use a special form of comparison for search and * related operations (which is the main reason we cannot use * existing collections such as TreeMaps). TreeBins contain * Comparable elements, but may contain others, as well as * elements that are Comparable but not necessarily Comparable * for the same T, so we cannot invoke compareTo among them. To * handle this, the tree is ordered primarily by hash value, then * by getClass().getName() order, and then by Comparator order * among elements of the same class. On lookup at a node, if * elements are not comparable or compare as 0, both left and * right children may need to be searched in the case of tied hash * values. (This corresponds to the full list search that would be * necessary if all elements were non-Comparable and had tied * hashes.) The red-black balancing code is updated from * pre-jdk-collections * (http://gee.cs.oswego.edu/dl/classes/collections/RBCell.java) * based in turn on Cormen, Leiserson, and Rivest "Introduction to * Algorithms" (CLR). * * TreeBins also maintain a separate locking discipline than * regular bins. Because they are forwarded via special MOVED * nodes at bin heads (which can never change once established), * we cannot use those nodes as locks. Instead, TreeBin * extends AbstractQueuedSynchronizer to support a simple form of * read-write lock. For update operations and table validation, * the exclusive form of lock behaves in the same way as bin-head * locks. However, lookups use shared read-lock mechanics to allow * multiple readers in the absence of writers. Additionally, * these lookups do not ever block: While the lock is not * available, they proceed along the slow traversal path (via * next-pointers) until the lock becomes available or the list is * exhausted, whichever comes first. (These cases are not fast, * but maximize aggregate expected throughput.) The AQS mechanics * for doing this are straightforward. The lock state is held as * AQS getState(). Read counts are negative; the write count (1) * is positive. There are no signalling preferences among readers * and writers. Since we don't need to export full Lock API, we * just override the minimal AQS methods and use them directly. */ static final class TreeBin extends AbstractQueuedSynchronizer { private static final long serialVersionUID = 2249069246763182397L; transient TreeNode root; // root of tree transient TreeNode first; // head of next-pointer list /* AQS overrides */ public final boolean isHeldExclusively() { return getState() > 0; } public final boolean tryAcquire(int ignore) { if (compareAndSetState(0, 1)) { setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } public final boolean tryRelease(int ignore) { setExclusiveOwnerThread(null); setState(0); return true; } public final int tryAcquireShared(int ignore) { for (int c;;) { if ((c = getState()) > 0) return -1; if (compareAndSetState(c, c -1)) return 1; } } public final boolean tryReleaseShared(int ignore) { int c; do {} while (!compareAndSetState(c = getState(), c + 1)); return c == -1; } /** From CLR */ private void rotateLeft(TreeNode p) { if (p != null) { TreeNode r = p.right, pp, rl; if ((rl = p.right = r.left) != null) rl.parent = p; if ((pp = r.parent = p.parent) == null) root = r; else if (pp.left == p) pp.left = r; else pp.right = r; r.left = p; p.parent = r; } } /** From CLR */ private void rotateRight(TreeNode p) { if (p != null) { TreeNode l = p.left, pp, lr; if ((lr = p.left = l.right) != null) lr.parent = p; if ((pp = l.parent = p.parent) == null) root = l; else if (pp.right == p) pp.right = l; else pp.left = l; l.right = p; p.parent = l; } } @SuppressWarnings("unchecked") final TreeNode getTreeNode (int h, Object k, TreeNode p) { return getTreeNode(h, (RubyObject)k, p); } /** * Returns the TreeNode (or null if not found) for the given key * starting at given root. */ @SuppressWarnings("unchecked") final TreeNode getTreeNode (int h, RubyObject k, TreeNode p) { RubyClass c = k.getMetaClass(); boolean kNotComparable = !k.respondsTo("<=>"); while (p != null) { int dir, ph; RubyObject pk; RubyClass pc; if ((ph = p.hash) == h) { if ((pk = (RubyObject)p.key) == k || k.equals(pk)) return p; if (c != (pc = (RubyClass)pk.getMetaClass()) || kNotComparable || (dir = rubyCompare(k, pk)) == 0) { dir = (c == pc) ? 0 : c.getName().compareTo(pc.getName()); if (dir == 0) { // if still stuck, need to check both sides TreeNode r = null, pl, pr; // try to recurse on the right if ((pr = p.right) != null && h >= pr.hash && (r = getTreeNode(h, k, pr)) != null) return r; // try to continue iterating on the left side else if ((pl = p.left) != null && h <= pl.hash) dir = -1; else // no matching node found return null; } } } else dir = (h < ph) ? -1 : 1; p = (dir > 0) ? p.right : p.left; } return null; } int rubyCompare(RubyObject l, RubyObject r) { ThreadContext context = l.getMetaClass().getRuntime().getCurrentContext(); IRubyObject result; try { result = l.callMethod(context, "<=>", r); } catch (RaiseException e) { // handle objects "lying" about responding to <=>, ie: an Array containing non-comparable keys if (context.runtime.getNoMethodError().isInstance(e.getException())) { return 0; } throw e; } return result.isNil() ? 0 : RubyNumeric.num2int(result.convertToInteger()); } /** * Wrapper for getTreeNode used by CHM.get. Tries to obtain * read-lock to call getTreeNode, but during failure to get * lock, searches along next links. */ final Object getValue(int h, Object k) { Node r = null; int c = getState(); // Must read lock state first for (Node e = first; e != null; e = e.next) { if (c <= 0 && compareAndSetState(c, c - 1)) { try { r = getTreeNode(h, k, root); } finally { releaseShared(0); } break; } else if ((e.hash & HASH_BITS) == h && k.equals(e.key)) { r = e; break; } else c = getState(); } return r == null ? null : r.val; } @SuppressWarnings("unchecked") final TreeNode putTreeNode (int h, Object k, Object v) { return putTreeNode(h, (RubyObject)k, v); } /** * Finds or adds a node. * @return null if added */ @SuppressWarnings("unchecked") final TreeNode putTreeNode (int h, RubyObject k, Object v) { RubyClass c = k.getMetaClass(); boolean kNotComparable = !k.respondsTo("<=>"); TreeNode pp = root, p = null; int dir = 0; while (pp != null) { // find existing node or leaf to insert at int ph; RubyObject pk; RubyClass pc; p = pp; if ((ph = p.hash) == h) { if ((pk = (RubyObject)p.key) == k || k.equals(pk)) return p; if (c != (pc = pk.getMetaClass()) || kNotComparable || (dir = rubyCompare(k, pk)) == 0) { dir = (c == pc) ? 0 : c.getName().compareTo(pc.getName()); if (dir == 0) { // if still stuck, need to check both sides TreeNode r = null, pr; // try to recurse on the right if ((pr = p.right) != null && h >= pr.hash && (r = getTreeNode(h, k, pr)) != null) return r; else // continue descending down the left subtree dir = -1; } } } else dir = (h < ph) ? -1 : 1; pp = (dir > 0) ? p.right : p.left; } TreeNode f = first; TreeNode x = first = new TreeNode(h, (Object)k, v, f, p); if (p == null) root = x; else { // attach and rebalance; adapted from CLR TreeNode xp, xpp; if (f != null) f.prev = x; if (dir <= 0) p.left = x; else p.right = x; x.red = true; while (x != null && (xp = x.parent) != null && xp.red && (xpp = xp.parent) != null) { TreeNode xppl = xpp.left; if (xp == xppl) { TreeNode y = xpp.right; if (y != null && y.red) { y.red = false; xp.red = false; xpp.red = true; x = xpp; } else { if (x == xp.right) { rotateLeft(x = xp); xpp = (xp = x.parent) == null ? null : xp.parent; } if (xp != null) { xp.red = false; if (xpp != null) { xpp.red = true; rotateRight(xpp); } } } } else { TreeNode y = xppl; if (y != null && y.red) { y.red = false; xp.red = false; xpp.red = true; x = xpp; } else { if (x == xp.left) { rotateRight(x = xp); xpp = (xp = x.parent) == null ? null : xp.parent; } if (xp != null) { xp.red = false; if (xpp != null) { xpp.red = true; rotateLeft(xpp); } } } } } TreeNode r = root; if (r != null && r.red) r.red = false; } return null; } /** * Removes the given node, that must be present before this * call. This is messier than typical red-black deletion code * because we cannot swap the contents of an interior node * with a leaf successor that is pinned by "next" pointers * that are accessible independently of lock. So instead we * swap the tree linkages. */ final void deleteTreeNode(TreeNode p) { TreeNode next = (TreeNode)p.next; // unlink traversal pointers TreeNode pred = p.prev; if (pred == null) first = next; else pred.next = next; if (next != null) next.prev = pred; TreeNode replacement; TreeNode pl = p.left; TreeNode pr = p.right; if (pl != null && pr != null) { TreeNode s = pr, sl; while ((sl = s.left) != null) // find successor s = sl; boolean c = s.red; s.red = p.red; p.red = c; // swap colors TreeNode sr = s.right; TreeNode pp = p.parent; if (s == pr) { // p was s's direct parent p.parent = s; s.right = p; } else { TreeNode sp = s.parent; if ((p.parent = sp) != null) { if (s == sp.left) sp.left = p; else sp.right = p; } if ((s.right = pr) != null) pr.parent = s; } p.left = null; if ((p.right = sr) != null) sr.parent = p; if ((s.left = pl) != null) pl.parent = s; if ((s.parent = pp) == null) root = s; else if (p == pp.left) pp.left = s; else pp.right = s; replacement = sr; } else replacement = (pl != null) ? pl : pr; TreeNode pp = p.parent; if (replacement == null) { if (pp == null) { root = null; return; } replacement = p; } else { replacement.parent = pp; if (pp == null) root = replacement; else if (p == pp.left) pp.left = replacement; else pp.right = replacement; p.left = p.right = p.parent = null; } if (!p.red) { // rebalance, from CLR TreeNode x = replacement; while (x != null) { TreeNode xp, xpl; if (x.red || (xp = x.parent) == null) { x.red = false; break; } if (x == (xpl = xp.left)) { TreeNode sib = xp.right; if (sib != null && sib.red) { sib.red = false; xp.red = true; rotateLeft(xp); sib = (xp = x.parent) == null ? null : xp.right; } if (sib == null) x = xp; else { TreeNode sl = sib.left, sr = sib.right; if ((sr == null || !sr.red) && (sl == null || !sl.red)) { sib.red = true; x = xp; } else { if (sr == null || !sr.red) { if (sl != null) sl.red = false; sib.red = true; rotateRight(sib); sib = (xp = x.parent) == null ? null : xp.right; } if (sib != null) { sib.red = (xp == null) ? false : xp.red; if ((sr = sib.right) != null) sr.red = false; } if (xp != null) { xp.red = false; rotateLeft(xp); } x = root; } } } else { // symmetric TreeNode sib = xpl; if (sib != null && sib.red) { sib.red = false; xp.red = true; rotateRight(xp); sib = (xp = x.parent) == null ? null : xp.left; } if (sib == null) x = xp; else { TreeNode sl = sib.left, sr = sib.right; if ((sl == null || !sl.red) && (sr == null || !sr.red)) { sib.red = true; x = xp; } else { if (sl == null || !sl.red) { if (sr != null) sr.red = false; sib.red = true; rotateLeft(sib); sib = (xp = x.parent) == null ? null : xp.left; } if (sib != null) { sib.red = (xp == null) ? false : xp.red; if ((sl = sib.left) != null) sl.red = false; } if (xp != null) { xp.red = false; rotateRight(xp); } x = root; } } } } } if (p == replacement && (pp = p.parent) != null) { if (p == pp.left) // detach pointers pp.left = null; else if (p == pp.right) pp.right = null; p.parent = null; } } } /* ---------------- Collision reduction methods -------------- */ /** * Spreads higher bits to lower, and also forces top 2 bits to 0. * Because the table uses power-of-two masking, sets of hashes * that vary only in bits above the current mask will always * collide. (Among known examples are sets of Float keys holding * consecutive whole numbers in small tables.) To counter this, * we apply a transform that spreads the impact of higher bits * downward. There is a tradeoff between speed, utility, and * quality of bit-spreading. Because many common sets of hashes * are already reasonably distributed across bits (so don't benefit * from spreading), and because we use trees to handle large sets * of collisions in bins, we don't need excessively high quality. */ private static final int spread(int h) { h ^= (h >>> 18) ^ (h >>> 12); return (h ^ (h >>> 10)) & HASH_BITS; } /** * Replaces a list bin with a tree bin. Call only when locked. * Fails to replace if the given key is non-comparable or table * is, or needs, resizing. */ private final void replaceWithTreeBin(Node[] tab, int index, Object key) { if ((key instanceof Comparable) && (tab.length >= MAXIMUM_CAPACITY || counter.sum() < (long)sizeCtl)) { TreeBin t = new TreeBin(); for (Node e = tabAt(tab, index); e != null; e = e.next) t.putTreeNode(e.hash & HASH_BITS, e.key, e.val); setTabAt(tab, index, new Node(MOVED, t, null, null)); } } /* ---------------- Internal access and update methods -------------- */ /** Implementation for get and containsKey */ private final Object internalGet(Object k) { int h = spread(k.hashCode()); retry: for (Node[] tab = table; tab != null;) { Node e, p; Object ek, ev; int eh; // locals to read fields once for (e = tabAt(tab, (tab.length - 1) & h); e != null; e = e.next) { if ((eh = e.hash) == MOVED) { if ((ek = e.key) instanceof TreeBin) // search TreeBin return ((TreeBin)ek).getValue(h, k); else { // restart with new table tab = (Node[])ek; continue retry; } } else if ((eh & HASH_BITS) == h && (ev = e.val) != null && ((ek = e.key) == k || k.equals(ek))) return ev; } break; } return null; } /** * Implementation for the four public remove/replace methods: * Replaces node value with v, conditional upon match of cv if * non-null. If resulting value is null, delete. */ private final Object internalReplace(Object k, Object v, Object cv) { int h = spread(k.hashCode()); Object oldVal = null; for (Node[] tab = table;;) { Node f; int i, fh; Object fk; if (tab == null || (f = tabAt(tab, i = (tab.length - 1) & h)) == null) break; else if ((fh = f.hash) == MOVED) { if ((fk = f.key) instanceof TreeBin) { TreeBin t = (TreeBin)fk; boolean validated = false; boolean deleted = false; t.acquire(0); try { if (tabAt(tab, i) == f) { validated = true; TreeNode p = t.getTreeNode(h, k, t.root); if (p != null) { Object pv = p.val; if (cv == null || cv == pv || cv.equals(pv)) { oldVal = pv; if ((p.val = v) == null) { deleted = true; t.deleteTreeNode(p); } } } } } finally { t.release(0); } if (validated) { if (deleted) counter.add(-1L); break; } } else tab = (Node[])fk; } else if ((fh & HASH_BITS) != h && f.next == null) // precheck break; // rules out possible existence else if ((fh & LOCKED) != 0) { checkForResize(); // try resizing if can't get lock f.tryAwaitLock(tab, i); } else if (f.casHash(fh, fh | LOCKED)) { boolean validated = false; boolean deleted = false; try { if (tabAt(tab, i) == f) { validated = true; for (Node e = f, pred = null;;) { Object ek, ev; if ((e.hash & HASH_BITS) == h && ((ev = e.val) != null) && ((ek = e.key) == k || k.equals(ek))) { if (cv == null || cv == ev || cv.equals(ev)) { oldVal = ev; if ((e.val = v) == null) { deleted = true; Node en = e.next; if (pred != null) pred.next = en; else setTabAt(tab, i, en); } } break; } pred = e; if ((e = e.next) == null) break; } } } finally { if (!f.casHash(fh | LOCKED, fh)) { f.hash = fh; synchronized (f) { f.notifyAll(); }; } } if (validated) { if (deleted) counter.add(-1L); break; } } } return oldVal; } /* * Internal versions of the six insertion methods, each a * little more complicated than the last. All have * the same basic structure as the first (internalPut): * 1. If table uninitialized, create * 2. If bin empty, try to CAS new node * 3. If bin stale, use new table * 4. if bin converted to TreeBin, validate and relay to TreeBin methods * 5. Lock and validate; if valid, scan and add or update * * The others interweave other checks and/or alternative actions: * * Plain put checks for and performs resize after insertion. * * putIfAbsent prescans for mapping without lock (and fails to add * if present), which also makes pre-emptive resize checks worthwhile. * * computeIfAbsent extends form used in putIfAbsent with additional * mechanics to deal with, calls, potential exceptions and null * returns from function call. * * compute uses the same function-call mechanics, but without * the prescans * * merge acts as putIfAbsent in the absent case, but invokes the * update function if present * * putAll attempts to pre-allocate enough table space * and more lazily performs count updates and checks. * * Someday when details settle down a bit more, it might be worth * some factoring to reduce sprawl. */ /** Implementation for put */ private final Object internalPut(Object k, Object v) { int h = spread(k.hashCode()); int count = 0; for (Node[] tab = table;;) { int i; Node f; int fh; Object fk; if (tab == null) tab = initTable(); else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) { if (casTabAt(tab, i, null, new Node(h, k, v, null))) break; // no lock when adding to empty bin } else if ((fh = f.hash) == MOVED) { if ((fk = f.key) instanceof TreeBin) { TreeBin t = (TreeBin)fk; Object oldVal = null; t.acquire(0); try { if (tabAt(tab, i) == f) { count = 2; TreeNode p = t.putTreeNode(h, k, v); if (p != null) { oldVal = p.val; p.val = v; } } } finally { t.release(0); } if (count != 0) { if (oldVal != null) return oldVal; break; } } else tab = (Node[])fk; } else if ((fh & LOCKED) != 0) { checkForResize(); f.tryAwaitLock(tab, i); } else if (f.casHash(fh, fh | LOCKED)) { Object oldVal = null; try { // needed in case equals() throws if (tabAt(tab, i) == f) { count = 1; for (Node e = f;; ++count) { Object ek, ev; if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && ((ek = e.key) == k || k.equals(ek))) { oldVal = ev; e.val = v; break; } Node last = e; if ((e = e.next) == null) { last.next = new Node(h, k, v, null); if (count >= TREE_THRESHOLD) replaceWithTreeBin(tab, i, k); break; } } } } finally { // unlock and signal if needed if (!f.casHash(fh | LOCKED, fh)) { f.hash = fh; synchronized (f) { f.notifyAll(); }; } } if (count != 0) { if (oldVal != null) return oldVal; if (tab.length <= 64) count = 2; break; } } } counter.add(1L); if (count > 1) checkForResize(); return null; } /** Implementation for putIfAbsent */ private final Object internalPutIfAbsent(Object k, Object v) { int h = spread(k.hashCode()); int count = 0; for (Node[] tab = table;;) { int i; Node f; int fh; Object fk, fv; if (tab == null) tab = initTable(); else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) { if (casTabAt(tab, i, null, new Node(h, k, v, null))) break; } else if ((fh = f.hash) == MOVED) { if ((fk = f.key) instanceof TreeBin) { TreeBin t = (TreeBin)fk; Object oldVal = null; t.acquire(0); try { if (tabAt(tab, i) == f) { count = 2; TreeNode p = t.putTreeNode(h, k, v); if (p != null) oldVal = p.val; } } finally { t.release(0); } if (count != 0) { if (oldVal != null) return oldVal; break; } } else tab = (Node[])fk; } else if ((fh & HASH_BITS) == h && (fv = f.val) != null && ((fk = f.key) == k || k.equals(fk))) return fv; else { Node g = f.next; if (g != null) { // at least 2 nodes -- search and maybe resize for (Node e = g;;) { Object ek, ev; if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && ((ek = e.key) == k || k.equals(ek))) return ev; if ((e = e.next) == null) { checkForResize(); break; } } } if (((fh = f.hash) & LOCKED) != 0) { checkForResize(); f.tryAwaitLock(tab, i); } else if (tabAt(tab, i) == f && f.casHash(fh, fh | LOCKED)) { Object oldVal = null; try { if (tabAt(tab, i) == f) { count = 1; for (Node e = f;; ++count) { Object ek, ev; if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && ((ek = e.key) == k || k.equals(ek))) { oldVal = ev; break; } Node last = e; if ((e = e.next) == null) { last.next = new Node(h, k, v, null); if (count >= TREE_THRESHOLD) replaceWithTreeBin(tab, i, k); break; } } } } finally { if (!f.casHash(fh | LOCKED, fh)) { f.hash = fh; synchronized (f) { f.notifyAll(); }; } } if (count != 0) { if (oldVal != null) return oldVal; if (tab.length <= 64) count = 2; break; } } } } counter.add(1L); if (count > 1) checkForResize(); return null; } /** Implementation for computeIfAbsent */ private final Object internalComputeIfAbsent(K k, Fun mf) { int h = spread(k.hashCode()); Object val = null; int count = 0; for (Node[] tab = table;;) { Node f; int i, fh; Object fk, fv; if (tab == null) tab = initTable(); else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) { Node node = new Node(fh = h | LOCKED, k, null, null); if (casTabAt(tab, i, null, node)) { count = 1; try { if ((val = mf.apply(k)) != null) node.val = val; } finally { if (val == null) setTabAt(tab, i, null); if (!node.casHash(fh, h)) { node.hash = h; synchronized (node) { node.notifyAll(); }; } } } if (count != 0) break; } else if ((fh = f.hash) == MOVED) { if ((fk = f.key) instanceof TreeBin) { TreeBin t = (TreeBin)fk; boolean added = false; t.acquire(0); try { if (tabAt(tab, i) == f) { count = 1; TreeNode p = t.getTreeNode(h, k, t.root); if (p != null) val = p.val; else if ((val = mf.apply(k)) != null) { added = true; count = 2; t.putTreeNode(h, k, val); } } } finally { t.release(0); } if (count != 0) { if (!added) return val; break; } } else tab = (Node[])fk; } else if ((fh & HASH_BITS) == h && (fv = f.val) != null && ((fk = f.key) == k || k.equals(fk))) return fv; else { Node g = f.next; if (g != null) { for (Node e = g;;) { Object ek, ev; if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && ((ek = e.key) == k || k.equals(ek))) return ev; if ((e = e.next) == null) { checkForResize(); break; } } } if (((fh = f.hash) & LOCKED) != 0) { checkForResize(); f.tryAwaitLock(tab, i); } else if (tabAt(tab, i) == f && f.casHash(fh, fh | LOCKED)) { boolean added = false; try { if (tabAt(tab, i) == f) { count = 1; for (Node e = f;; ++count) { Object ek, ev; if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && ((ek = e.key) == k || k.equals(ek))) { val = ev; break; } Node last = e; if ((e = e.next) == null) { if ((val = mf.apply(k)) != null) { added = true; last.next = new Node(h, k, val, null); if (count >= TREE_THRESHOLD) replaceWithTreeBin(tab, i, k); } break; } } } } finally { if (!f.casHash(fh | LOCKED, fh)) { f.hash = fh; synchronized (f) { f.notifyAll(); }; } } if (count != 0) { if (!added) return val; if (tab.length <= 64) count = 2; break; } } } } if (val != null) { counter.add(1L); if (count > 1) checkForResize(); } return val; } /** Implementation for compute */ @SuppressWarnings("unchecked") private final Object internalCompute (K k, boolean onlyIfPresent, BiFun mf) { int h = spread(k.hashCode()); Object val = null; int delta = 0; int count = 0; for (Node[] tab = table;;) { Node f; int i, fh; Object fk; if (tab == null) tab = initTable(); else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) { if (onlyIfPresent) break; Node node = new Node(fh = h | LOCKED, k, null, null); if (casTabAt(tab, i, null, node)) { try { count = 1; if ((val = mf.apply(k, null)) != null) { node.val = val; delta = 1; } } finally { if (delta == 0) setTabAt(tab, i, null); if (!node.casHash(fh, h)) { node.hash = h; synchronized (node) { node.notifyAll(); }; } } } if (count != 0) break; } else if ((fh = f.hash) == MOVED) { if ((fk = f.key) instanceof TreeBin) { TreeBin t = (TreeBin)fk; t.acquire(0); try { if (tabAt(tab, i) == f) { count = 1; TreeNode p = t.getTreeNode(h, k, t.root); Object pv; if (p == null) { if (onlyIfPresent) break; pv = null; } else pv = p.val; if ((val = mf.apply(k, (V)pv)) != null) { if (p != null) p.val = val; else { count = 2; delta = 1; t.putTreeNode(h, k, val); } } else if (p != null) { delta = -1; t.deleteTreeNode(p); } } } finally { t.release(0); } if (count != 0) break; } else tab = (Node[])fk; } else if ((fh & LOCKED) != 0) { checkForResize(); f.tryAwaitLock(tab, i); } else if (f.casHash(fh, fh | LOCKED)) { try { if (tabAt(tab, i) == f) { count = 1; for (Node e = f, pred = null;; ++count) { Object ek, ev; if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && ((ek = e.key) == k || k.equals(ek))) { val = mf.apply(k, (V)ev); if (val != null) e.val = val; else { delta = -1; Node en = e.next; if (pred != null) pred.next = en; else setTabAt(tab, i, en); } break; } pred = e; if ((e = e.next) == null) { if (!onlyIfPresent && (val = mf.apply(k, null)) != null) { pred.next = new Node(h, k, val, null); delta = 1; if (count >= TREE_THRESHOLD) replaceWithTreeBin(tab, i, k); } break; } } } } finally { if (!f.casHash(fh | LOCKED, fh)) { f.hash = fh; synchronized (f) { f.notifyAll(); }; } } if (count != 0) { if (tab.length <= 64) count = 2; break; } } } if (delta != 0) { counter.add((long)delta); if (count > 1) checkForResize(); } return val; } /** Implementation for merge */ @SuppressWarnings("unchecked") private final Object internalMerge (K k, V v, BiFun mf) { int h = spread(k.hashCode()); Object val = null; int delta = 0; int count = 0; for (Node[] tab = table;;) { int i; Node f; int fh; Object fk, fv; if (tab == null) tab = initTable(); else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) { if (casTabAt(tab, i, null, new Node(h, k, v, null))) { delta = 1; val = v; break; } } else if ((fh = f.hash) == MOVED) { if ((fk = f.key) instanceof TreeBin) { TreeBin t = (TreeBin)fk; t.acquire(0); try { if (tabAt(tab, i) == f) { count = 1; TreeNode p = t.getTreeNode(h, k, t.root); val = (p == null) ? v : mf.apply((V)p.val, v); if (val != null) { if (p != null) p.val = val; else { count = 2; delta = 1; t.putTreeNode(h, k, val); } } else if (p != null) { delta = -1; t.deleteTreeNode(p); } } } finally { t.release(0); } if (count != 0) break; } else tab = (Node[])fk; } else if ((fh & LOCKED) != 0) { checkForResize(); f.tryAwaitLock(tab, i); } else if (f.casHash(fh, fh | LOCKED)) { try { if (tabAt(tab, i) == f) { count = 1; for (Node e = f, pred = null;; ++count) { Object ek, ev; if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && ((ek = e.key) == k || k.equals(ek))) { val = mf.apply((V)ev, v); if (val != null) e.val = val; else { delta = -1; Node en = e.next; if (pred != null) pred.next = en; else setTabAt(tab, i, en); } break; } pred = e; if ((e = e.next) == null) { val = v; pred.next = new Node(h, k, val, null); delta = 1; if (count >= TREE_THRESHOLD) replaceWithTreeBin(tab, i, k); break; } } } } finally { if (!f.casHash(fh | LOCKED, fh)) { f.hash = fh; synchronized (f) { f.notifyAll(); }; } } if (count != 0) { if (tab.length <= 64) count = 2; break; } } } if (delta != 0) { counter.add((long)delta); if (count > 1) checkForResize(); } return val; } /** Implementation for putAll */ private final void internalPutAll(Map m) { tryPresize(m.size()); long delta = 0L; // number of uncommitted additions boolean npe = false; // to throw exception on exit for nulls try { // to clean up counts on other exceptions for (Map.Entry entry : m.entrySet()) { Object k, v; if (entry == null || (k = entry.getKey()) == null || (v = entry.getValue()) == null) { npe = true; break; } int h = spread(k.hashCode()); for (Node[] tab = table;;) { int i; Node f; int fh; Object fk; if (tab == null) tab = initTable(); else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null){ if (casTabAt(tab, i, null, new Node(h, k, v, null))) { ++delta; break; } } else if ((fh = f.hash) == MOVED) { if ((fk = f.key) instanceof TreeBin) { TreeBin t = (TreeBin)fk; boolean validated = false; t.acquire(0); try { if (tabAt(tab, i) == f) { validated = true; TreeNode p = t.getTreeNode(h, k, t.root); if (p != null) p.val = v; else { t.putTreeNode(h, k, v); ++delta; } } } finally { t.release(0); } if (validated) break; } else tab = (Node[])fk; } else if ((fh & LOCKED) != 0) { counter.add(delta); delta = 0L; checkForResize(); f.tryAwaitLock(tab, i); } else if (f.casHash(fh, fh | LOCKED)) { int count = 0; try { if (tabAt(tab, i) == f) { count = 1; for (Node e = f;; ++count) { Object ek, ev; if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && ((ek = e.key) == k || k.equals(ek))) { e.val = v; break; } Node last = e; if ((e = e.next) == null) { ++delta; last.next = new Node(h, k, v, null); if (count >= TREE_THRESHOLD) replaceWithTreeBin(tab, i, k); break; } } } } finally { if (!f.casHash(fh | LOCKED, fh)) { f.hash = fh; synchronized (f) { f.notifyAll(); }; } } if (count != 0) { if (count > 1) { counter.add(delta); delta = 0L; checkForResize(); } break; } } } } } finally { if (delta != 0) counter.add(delta); } if (npe) throw new NullPointerException(); } /* ---------------- Table Initialization and Resizing -------------- */ /** * Returns a power of two table size for the given desired capacity. * See Hackers Delight, sec 3.2 */ private static final int tableSizeFor(int c) { int n = c - 1; n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16; return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; } /** * Initializes table, using the size recorded in sizeCtl. */ private final Node[] initTable() { Node[] tab; int sc; while ((tab = table) == null) { if ((sc = sizeCtl) < 0) Thread.yield(); // lost initialization race; just spin else if (UNSAFE.compareAndSwapInt(this, sizeCtlOffset, sc, -1)) { try { if ((tab = table) == null) { int n = (sc > 0) ? sc : DEFAULT_CAPACITY; tab = table = new Node[n]; sc = n - (n >>> 2); } } finally { sizeCtl = sc; } break; } } return tab; } /** * If table is too small and not already resizing, creates next * table and transfers bins. Rechecks occupancy after a transfer * to see if another resize is already needed because resizings * are lagging additions. */ private final void checkForResize() { Node[] tab; int n, sc; while ((tab = table) != null && (n = tab.length) < MAXIMUM_CAPACITY && (sc = sizeCtl) >= 0 && counter.sum() >= (long)sc && UNSAFE.compareAndSwapInt(this, sizeCtlOffset, sc, -1)) { try { if (tab == table) { table = rebuild(tab); sc = (n << 1) - (n >>> 1); } } finally { sizeCtl = sc; } } } /** * Tries to presize table to accommodate the given number of elements. * * @param size number of elements (doesn't need to be perfectly accurate) */ private final void tryPresize(int size) { int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY : tableSizeFor(size + (size >>> 1) + 1); int sc; while ((sc = sizeCtl) >= 0) { Node[] tab = table; int n; if (tab == null || (n = tab.length) == 0) { n = (sc > c) ? sc : c; if (UNSAFE.compareAndSwapInt(this, sizeCtlOffset, sc, -1)) { try { if (table == tab) { table = new Node[n]; sc = n - (n >>> 2); } } finally { sizeCtl = sc; } } } else if (c <= sc || n >= MAXIMUM_CAPACITY) break; else if (UNSAFE.compareAndSwapInt(this, sizeCtlOffset, sc, -1)) { try { if (table == tab) { table = rebuild(tab); sc = (n << 1) - (n >>> 1); } } finally { sizeCtl = sc; } } } } /* * Moves and/or copies the nodes in each bin to new table. See * above for explanation. * * @return the new table */ private static final Node[] rebuild(Node[] tab) { int n = tab.length; Node[] nextTab = new Node[n << 1]; Node fwd = new Node(MOVED, nextTab, null, null); int[] buffer = null; // holds bins to revisit; null until needed Node rev = null; // reverse forwarder; null until needed int nbuffered = 0; // the number of bins in buffer list int bufferIndex = 0; // buffer index of current buffered bin int bin = n - 1; // current non-buffered bin or -1 if none for (int i = bin;;) { // start upwards sweep int fh; Node f; if ((f = tabAt(tab, i)) == null) { if (bin >= 0) { // Unbuffered; no lock needed (or available) if (!casTabAt(tab, i, f, fwd)) continue; } else { // transiently use a locked forwarding node Node g = new Node(MOVED|LOCKED, nextTab, null, null); if (!casTabAt(tab, i, f, g)) continue; setTabAt(nextTab, i, null); setTabAt(nextTab, i + n, null); setTabAt(tab, i, fwd); if (!g.casHash(MOVED|LOCKED, MOVED)) { g.hash = MOVED; synchronized (g) { g.notifyAll(); } } } } else if ((fh = f.hash) == MOVED) { Object fk = f.key; if (fk instanceof TreeBin) { TreeBin t = (TreeBin)fk; boolean validated = false; t.acquire(0); try { if (tabAt(tab, i) == f) { validated = true; splitTreeBin(nextTab, i, t); setTabAt(tab, i, fwd); } } finally { t.release(0); } if (!validated) continue; } } else if ((fh & LOCKED) == 0 && f.casHash(fh, fh|LOCKED)) { boolean validated = false; try { // split to lo and hi lists; copying as needed if (tabAt(tab, i) == f) { validated = true; splitBin(nextTab, i, f); setTabAt(tab, i, fwd); } } finally { if (!f.casHash(fh | LOCKED, fh)) { f.hash = fh; synchronized (f) { f.notifyAll(); }; } } if (!validated) continue; } else { if (buffer == null) // initialize buffer for revisits buffer = new int[TRANSFER_BUFFER_SIZE]; if (bin < 0 && bufferIndex > 0) { int j = buffer[--bufferIndex]; buffer[bufferIndex] = i; i = j; // swap with another bin continue; } if (bin < 0 || nbuffered >= TRANSFER_BUFFER_SIZE) { f.tryAwaitLock(tab, i); continue; // no other options -- block } if (rev == null) // initialize reverse-forwarder rev = new Node(MOVED, tab, null, null); if (tabAt(tab, i) != f || (f.hash & LOCKED) == 0) continue; // recheck before adding to list buffer[nbuffered++] = i; setTabAt(nextTab, i, rev); // install place-holders setTabAt(nextTab, i + n, rev); } if (bin > 0) i = --bin; else if (buffer != null && nbuffered > 0) { bin = -1; i = buffer[bufferIndex = --nbuffered]; } else return nextTab; } } /** * Splits a normal bin with list headed by e into lo and hi parts; * installs in given table. */ private static void splitBin(Node[] nextTab, int i, Node e) { int bit = nextTab.length >>> 1; // bit to split on int runBit = e.hash & bit; Node lastRun = e, lo = null, hi = null; for (Node p = e.next; p != null; p = p.next) { int b = p.hash & bit; if (b != runBit) { runBit = b; lastRun = p; } } if (runBit == 0) lo = lastRun; else hi = lastRun; for (Node p = e; p != lastRun; p = p.next) { int ph = p.hash & HASH_BITS; Object pk = p.key, pv = p.val; if ((ph & bit) == 0) lo = new Node(ph, pk, pv, lo); else hi = new Node(ph, pk, pv, hi); } setTabAt(nextTab, i, lo); setTabAt(nextTab, i + bit, hi); } /** * Splits a tree bin into lo and hi parts; installs in given table. */ private static void splitTreeBin(Node[] nextTab, int i, TreeBin t) { int bit = nextTab.length >>> 1; TreeBin lt = new TreeBin(); TreeBin ht = new TreeBin(); int lc = 0, hc = 0; for (Node e = t.first; e != null; e = e.next) { int h = e.hash & HASH_BITS; Object k = e.key, v = e.val; if ((h & bit) == 0) { ++lc; lt.putTreeNode(h, k, v); } else { ++hc; ht.putTreeNode(h, k, v); } } Node ln, hn; // throw away trees if too small if (lc <= (TREE_THRESHOLD >>> 1)) { ln = null; for (Node p = lt.first; p != null; p = p.next) ln = new Node(p.hash, p.key, p.val, ln); } else ln = new Node(MOVED, lt, null, null); setTabAt(nextTab, i, ln); if (hc <= (TREE_THRESHOLD >>> 1)) { hn = null; for (Node p = ht.first; p != null; p = p.next) hn = new Node(p.hash, p.key, p.val, hn); } else hn = new Node(MOVED, ht, null, null); setTabAt(nextTab, i + bit, hn); } /** * Implementation for clear. Steps through each bin, removing all * nodes. */ private final void internalClear() { long delta = 0L; // negative number of deletions int i = 0; Node[] tab = table; while (tab != null && i < tab.length) { int fh; Object fk; Node f = tabAt(tab, i); if (f == null) ++i; else if ((fh = f.hash) == MOVED) { if ((fk = f.key) instanceof TreeBin) { TreeBin t = (TreeBin)fk; t.acquire(0); try { if (tabAt(tab, i) == f) { for (Node p = t.first; p != null; p = p.next) { if (p.val != null) { // (currently always true) p.val = null; --delta; } } t.first = null; t.root = null; ++i; } } finally { t.release(0); } } else tab = (Node[])fk; } else if ((fh & LOCKED) != 0) { counter.add(delta); // opportunistically update count delta = 0L; f.tryAwaitLock(tab, i); } else if (f.casHash(fh, fh | LOCKED)) { try { if (tabAt(tab, i) == f) { for (Node e = f; e != null; e = e.next) { if (e.val != null) { // (currently always true) e.val = null; --delta; } } setTabAt(tab, i, null); ++i; } } finally { if (!f.casHash(fh | LOCKED, fh)) { f.hash = fh; synchronized (f) { f.notifyAll(); }; } } } } if (delta != 0) counter.add(delta); } /* ----------------Table Traversal -------------- */ /** * Encapsulates traversal for methods such as containsValue; also * serves as a base class for other iterators and bulk tasks. * * At each step, the iterator snapshots the key ("nextKey") and * value ("nextVal") of a valid node (i.e., one that, at point of * snapshot, has a non-null user value). Because val fields can * change (including to null, indicating deletion), field nextVal * might not be accurate at point of use, but still maintains the * weak consistency property of holding a value that was once * valid. To support iterator.remove, the nextKey field is not * updated (nulled out) when the iterator cannot advance. * * Internal traversals directly access these fields, as in: * {@code while (it.advance() != null) { process(it.nextKey); }} * * Exported iterators must track whether the iterator has advanced * (in hasNext vs next) (by setting/checking/nulling field * nextVal), and then extract key, value, or key-value pairs as * return values of next(). * * The iterator visits once each still-valid node that was * reachable upon iterator construction. It might miss some that * were added to a bin after the bin was visited, which is OK wrt * consistency guarantees. Maintaining this property in the face * of possible ongoing resizes requires a fair amount of * bookkeeping state that is difficult to optimize away amidst * volatile accesses. Even so, traversal maintains reasonable * throughput. * * Normally, iteration proceeds bin-by-bin traversing lists. * However, if the table has been resized, then all future steps * must traverse both the bin at the current index as well as at * (index + baseSize); and so on for further resizings. To * paranoically cope with potential sharing by users of iterators * across threads, iteration terminates if a bounds checks fails * for a table read. * * This class extends ForkJoinTask to streamline parallel * iteration in bulk operations (see BulkTask). This adds only an * int of space overhead, which is close enough to negligible in * cases where it is not needed to not worry about it. Because * ForkJoinTask is Serializable, but iterators need not be, we * need to add warning suppressions. */ @SuppressWarnings("serial") static class Traverser { final ConcurrentHashMapV8 map; Node next; // the next entry to use K nextKey; // cached key field of next V nextVal; // cached val field of next Node[] tab; // current table; updated if resized int index; // index of bin to use next int baseIndex; // current index of initial table int baseLimit; // index bound for initial table int baseSize; // initial table size /** Creates iterator for all entries in the table. */ Traverser(ConcurrentHashMapV8 map) { this.map = map; } /** Creates iterator for split() methods */ Traverser(Traverser it) { ConcurrentHashMapV8 m; Node[] t; if ((m = this.map = it.map) == null) t = null; else if ((t = it.tab) == null && // force parent tab initialization (t = it.tab = m.table) != null) it.baseLimit = it.baseSize = t.length; this.tab = t; this.baseSize = it.baseSize; it.baseLimit = this.index = this.baseIndex = ((this.baseLimit = it.baseLimit) + it.baseIndex + 1) >>> 1; } /** * Advances next; returns nextVal or null if terminated. * See above for explanation. */ final V advance() { Node e = next; V ev = null; outer: do { if (e != null) // advance past used/skipped node e = e.next; while (e == null) { // get to next non-null bin ConcurrentHashMapV8 m; Node[] t; int b, i, n; Object ek; // checks must use locals if ((t = tab) != null) n = t.length; else if ((m = map) != null && (t = tab = m.table) != null) n = baseLimit = baseSize = t.length; else break outer; if ((b = baseIndex) >= baseLimit || (i = index) < 0 || i >= n) break outer; if ((e = tabAt(t, i)) != null && e.hash == MOVED) { if ((ek = e.key) instanceof TreeBin) e = ((TreeBin)ek).first; else { tab = (Node[])ek; continue; // restarts due to null val } } // visit upper slots if present index = (i += baseSize) < n ? i : (baseIndex = b + 1); } nextKey = (K) e.key; } while ((ev = (V) e.val) == null); // skip deleted or special nodes next = e; return nextVal = ev; } public final void remove() { Object k = nextKey; if (k == null && (advance() == null || (k = nextKey) == null)) throw new IllegalStateException(); map.internalReplace(k, null, null); } public final boolean hasNext() { return nextVal != null || advance() != null; } public final boolean hasMoreElements() { return hasNext(); } public final void setRawResult(Object x) { } public R getRawResult() { return null; } public boolean exec() { return true; } } /* ---------------- Public operations -------------- */ /** * Creates a new, empty map with the default initial table size (16). */ public ConcurrentHashMapV8() { this.counter = new LongAdder(); } /** * Creates a new, empty map with an initial table size * accommodating the specified number of elements without the need * to dynamically resize. * * @param initialCapacity The implementation performs internal * sizing to accommodate this many elements. * @throws IllegalArgumentException if the initial capacity of * elements is negative */ public ConcurrentHashMapV8(int initialCapacity) { if (initialCapacity < 0) throw new IllegalArgumentException(); int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY : tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1)); this.counter = new LongAdder(); this.sizeCtl = cap; } /** * Creates a new map with the same mappings as the given map. * * @param m the map */ public ConcurrentHashMapV8(Map m) { this.counter = new LongAdder(); this.sizeCtl = DEFAULT_CAPACITY; internalPutAll(m); } /** * Creates a new, empty map with an initial table size based on * the given number of elements ({@code initialCapacity}) and * initial table density ({@code loadFactor}). * * @param initialCapacity the initial capacity. The implementation * performs internal sizing to accommodate this many elements, * given the specified load factor. * @param loadFactor the load factor (table density) for * establishing the initial table size * @throws IllegalArgumentException if the initial capacity of * elements is negative or the load factor is nonpositive * * @since 1.6 */ public ConcurrentHashMapV8(int initialCapacity, float loadFactor) { this(initialCapacity, loadFactor, 1); } /** * Creates a new, empty map with an initial table size based on * the given number of elements ({@code initialCapacity}), table * density ({@code loadFactor}), and number of concurrently * updating threads ({@code concurrencyLevel}). * * @param initialCapacity the initial capacity. The implementation * performs internal sizing to accommodate this many elements, * given the specified load factor. * @param loadFactor the load factor (table density) for * establishing the initial table size * @param concurrencyLevel the estimated number of concurrently * updating threads. The implementation may use this value as * a sizing hint. * @throws IllegalArgumentException if the initial capacity is * negative or the load factor or concurrencyLevel are * nonpositive */ public ConcurrentHashMapV8(int initialCapacity, float loadFactor, int concurrencyLevel) { if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0) throw new IllegalArgumentException(); if (initialCapacity < concurrencyLevel) // Use at least as many bins initialCapacity = concurrencyLevel; // as estimated threads long size = (long)(1.0 + (long)initialCapacity / loadFactor); int cap = (size >= (long)MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : tableSizeFor((int)size); this.counter = new LongAdder(); this.sizeCtl = cap; } /** * Creates a new {@link Set} backed by a ConcurrentHashMapV8 * from the given type to {@code Boolean.TRUE}. * * @return the new set */ public static KeySetView newKeySet() { return new KeySetView(new ConcurrentHashMapV8(), Boolean.TRUE); } /** * Creates a new {@link Set} backed by a ConcurrentHashMapV8 * from the given type to {@code Boolean.TRUE}. * * @param initialCapacity The implementation performs internal * sizing to accommodate this many elements. * @throws IllegalArgumentException if the initial capacity of * elements is negative * @return the new set */ public static KeySetView newKeySet(int initialCapacity) { return new KeySetView(new ConcurrentHashMapV8(initialCapacity), Boolean.TRUE); } /** * {@inheritDoc} */ public boolean isEmpty() { return counter.sum() <= 0L; // ignore transient negative values } /** * {@inheritDoc} */ public int size() { long n = counter.sum(); return ((n < 0L) ? 0 : (n > (long)Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int)n); } /** * Returns the number of mappings. This method should be used * instead of {@link #size} because a ConcurrentHashMapV8 may * contain more mappings than can be represented as an int. The * value returned is a snapshot; the actual count may differ if * there are ongoing concurrent insertions or removals. * * @return the number of mappings */ public long mappingCount() { long n = counter.sum(); return (n < 0L) ? 0L : n; // ignore transient negative values } /** * Returns the value to which the specified key is mapped, * or {@code null} if this map contains no mapping for the key. * *

More formally, if this map contains a mapping from a key * {@code k} to a value {@code v} such that {@code key.equals(k)}, * then this method returns {@code v}; otherwise it returns * {@code null}. (There can be at most one such mapping.) * * @throws NullPointerException if the specified key is null */ @SuppressWarnings("unchecked") public V get(Object key) { if (key == null) throw new NullPointerException(); return (V)internalGet(key); } /** * Returns the value to which the specified key is mapped, * or the given defaultValue if this map contains no mapping for the key. * * @param key the key * @param defaultValue the value to return if this map contains * no mapping for the given key * @return the mapping for the key, if present; else the defaultValue * @throws NullPointerException if the specified key is null */ @SuppressWarnings("unchecked") public V getValueOrDefault(Object key, V defaultValue) { if (key == null) throw new NullPointerException(); V v = (V) internalGet(key); return v == null ? defaultValue : v; } /** * Tests if the specified object is a key in this table. * * @param key possible key * @return {@code true} if and only if the specified object * is a key in this table, as determined by the * {@code equals} method; {@code false} otherwise * @throws NullPointerException if the specified key is null */ public boolean containsKey(Object key) { if (key == null) throw new NullPointerException(); return internalGet(key) != null; } /** * Returns {@code true} if this map maps one or more keys to the * specified value. Note: This method may require a full traversal * of the map, and is much slower than method {@code containsKey}. * * @param value value whose presence in this map is to be tested * @return {@code true} if this map maps one or more keys to the * specified value * @throws NullPointerException if the specified value is null */ public boolean containsValue(Object value) { if (value == null) throw new NullPointerException(); Object v; Traverser it = new Traverser(this); while ((v = it.advance()) != null) { if (v == value || value.equals(v)) return true; } return false; } public K findKey(Object value) { if (value == null) throw new NullPointerException(); Object v; Traverser it = new Traverser(this); while ((v = it.advance()) != null) { if (v == value || value.equals(v)) return it.nextKey; } return null; } /** * Legacy method testing if some key maps into the specified value * in this table. This method is identical in functionality to * {@link #containsValue}, and exists solely to ensure * full compatibility with class {@link java.util.Hashtable}, * which supported this method prior to introduction of the * Java Collections framework. * * @param value a value to search for * @return {@code true} if and only if some key maps to the * {@code value} argument in this table as * determined by the {@code equals} method; * {@code false} otherwise * @throws NullPointerException if the specified value is null */ public boolean contains(Object value) { return containsValue(value); } /** * Maps the specified key to the specified value in this table. * Neither the key nor the value can be null. * *

The value can be retrieved by calling the {@code get} method * with a key that is equal to the original key. * * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * @return the previous value associated with {@code key}, or * {@code null} if there was no mapping for {@code key} * @throws NullPointerException if the specified key or value is null */ @SuppressWarnings("unchecked") public V put(K key, V value) { if (key == null || value == null) throw new NullPointerException(); return (V)internalPut(key, value); } /** * {@inheritDoc} * * @return the previous value associated with the specified key, * or {@code null} if there was no mapping for the key * @throws NullPointerException if the specified key or value is null */ @SuppressWarnings("unchecked") public V putIfAbsent(K key, V value) { if (key == null || value == null) throw new NullPointerException(); return (V)internalPutIfAbsent(key, value); } /** * Copies all of the mappings from the specified map to this one. * These mappings replace any mappings that this map had for any of the * keys currently in the specified map. * * @param m mappings to be stored in this map */ public void putAll(Map m) { internalPutAll(m); } /** * If the specified key is not already associated with a value, * computes its value using the given mappingFunction and enters * it into the map unless null. This is equivalent to *

 {@code
     * if (map.containsKey(key))
     *   return map.get(key);
     * value = mappingFunction.apply(key);
     * if (value != null)
     *   map.put(key, value);
     * return value;}
* * except that the action is performed atomically. If the * function returns {@code null} no mapping is recorded. If the * function itself throws an (unchecked) exception, the exception * is rethrown to its caller, and no mapping is recorded. Some * attempted update operations on this map by other threads may be * blocked while computation is in progress, so the computation * should be short and simple, and must not attempt to update any * other mappings of this Map. The most appropriate usage is to * construct a new object serving as an initial mapped value, or * memoized result, as in: * *
 {@code
     * map.computeIfAbsent(key, new Fun() {
     *   public V map(K k) { return new Value(f(k)); }});}
* * @param key key with which the specified value is to be associated * @param mappingFunction the function to compute a value * @return the current (existing or computed) value associated with * the specified key, or null if the computed value is null * @throws NullPointerException if the specified key or mappingFunction * is null * @throws IllegalStateException if the computation detectably * attempts a recursive update to this map that would * otherwise never complete * @throws RuntimeException or Error if the mappingFunction does so, * in which case the mapping is left unestablished */ @SuppressWarnings("unchecked") public V computeIfAbsent (K key, Fun mappingFunction) { if (key == null || mappingFunction == null) throw new NullPointerException(); return (V)internalComputeIfAbsent(key, mappingFunction); } /** * If the given key is present, computes a new mapping value given a key and * its current mapped value. This is equivalent to *
 {@code
     *   if (map.containsKey(key)) {
     *     value = remappingFunction.apply(key, map.get(key));
     *     if (value != null)
     *       map.put(key, value);
     *     else
     *       map.remove(key);
     *   }
     * }
* * except that the action is performed atomically. If the * function returns {@code null}, the mapping is removed. If the * function itself throws an (unchecked) exception, the exception * is rethrown to its caller, and the current mapping is left * unchanged. Some attempted update operations on this map by * other threads may be blocked while computation is in progress, * so the computation should be short and simple, and must not * attempt to update any other mappings of this Map. For example, * to either create or append new messages to a value mapping: * * @param key key with which the specified value is to be associated * @param remappingFunction the function to compute a value * @return the new value associated with the specified key, or null if none * @throws NullPointerException if the specified key or remappingFunction * is null * @throws IllegalStateException if the computation detectably * attempts a recursive update to this map that would * otherwise never complete * @throws RuntimeException or Error if the remappingFunction does so, * in which case the mapping is unchanged */ @SuppressWarnings("unchecked") public V computeIfPresent (K key, BiFun remappingFunction) { if (key == null || remappingFunction == null) throw new NullPointerException(); return (V)internalCompute(key, true, remappingFunction); } /** * Computes a new mapping value given a key and * its current mapped value (or {@code null} if there is no current * mapping). This is equivalent to *
 {@code
     *   value = remappingFunction.apply(key, map.get(key));
     *   if (value != null)
     *     map.put(key, value);
     *   else
     *     map.remove(key);
     * }
* * except that the action is performed atomically. If the * function returns {@code null}, the mapping is removed. If the * function itself throws an (unchecked) exception, the exception * is rethrown to its caller, and the current mapping is left * unchanged. Some attempted update operations on this map by * other threads may be blocked while computation is in progress, * so the computation should be short and simple, and must not * attempt to update any other mappings of this Map. For example, * to either create or append new messages to a value mapping: * *
 {@code
     * Map map = ...;
     * final String msg = ...;
     * map.compute(key, new BiFun() {
     *   public String apply(Key k, String v) {
     *    return (v == null) ? msg : v + msg;});}}
* * @param key key with which the specified value is to be associated * @param remappingFunction the function to compute a value * @return the new value associated with the specified key, or null if none * @throws NullPointerException if the specified key or remappingFunction * is null * @throws IllegalStateException if the computation detectably * attempts a recursive update to this map that would * otherwise never complete * @throws RuntimeException or Error if the remappingFunction does so, * in which case the mapping is unchanged */ @SuppressWarnings("unchecked") public V compute (K key, BiFun remappingFunction) { if (key == null || remappingFunction == null) throw new NullPointerException(); return (V)internalCompute(key, false, remappingFunction); } /** * If the specified key is not already associated * with a value, associate it with the given value. * Otherwise, replace the value with the results of * the given remapping function. This is equivalent to: *
 {@code
     *   if (!map.containsKey(key))
     *     map.put(value);
     *   else {
     *     newValue = remappingFunction.apply(map.get(key), value);
     *     if (value != null)
     *       map.put(key, value);
     *     else
     *       map.remove(key);
     *   }
     * }
* except that the action is performed atomically. If the * function returns {@code null}, the mapping is removed. If the * function itself throws an (unchecked) exception, the exception * is rethrown to its caller, and the current mapping is left * unchanged. Some attempted update operations on this map by * other threads may be blocked while computation is in progress, * so the computation should be short and simple, and must not * attempt to update any other mappings of this Map. */ @SuppressWarnings("unchecked") public V merge (K key, V value, BiFun remappingFunction) { if (key == null || value == null || remappingFunction == null) throw new NullPointerException(); return (V)internalMerge(key, value, remappingFunction); } /** * Removes the key (and its corresponding value) from this map. * This method does nothing if the key is not in the map. * * @param key the key that needs to be removed * @return the previous value associated with {@code key}, or * {@code null} if there was no mapping for {@code key} * @throws NullPointerException if the specified key is null */ @SuppressWarnings("unchecked") public V remove(Object key) { if (key == null) throw new NullPointerException(); return (V)internalReplace(key, null, null); } /** * {@inheritDoc} * * @throws NullPointerException if the specified key is null */ public boolean remove(Object key, Object value) { if (key == null) throw new NullPointerException(); if (value == null) return false; return internalReplace(key, null, value) != null; } /** * {@inheritDoc} * * @throws NullPointerException if any of the arguments are null */ public boolean replace(K key, V oldValue, V newValue) { if (key == null || oldValue == null || newValue == null) throw new NullPointerException(); return internalReplace(key, newValue, oldValue) != null; } /** * {@inheritDoc} * * @return the previous value associated with the specified key, * or {@code null} if there was no mapping for the key * @throws NullPointerException if the specified key or value is null */ @SuppressWarnings("unchecked") public V replace(K key, V value) { if (key == null || value == null) throw new NullPointerException(); return (V)internalReplace(key, value, null); } /** * Removes all of the mappings from this map. */ public void clear() { internalClear(); } /** * Returns a {@link Set} view of the keys contained in this map. * The set is backed by the map, so changes to the map are * reflected in the set, and vice-versa. * * @return the set view */ public KeySetView keySet() { KeySetView ks = keySet; return (ks != null) ? ks : (keySet = new KeySetView(this, null)); } /** * Returns a {@link Set} view of the keys in this map, using the * given common mapped value for any additions (i.e., {@link * Collection#add} and {@link Collection#addAll}). This is of * course only appropriate if it is acceptable to use the same * value for all additions from this view. * * @param mappedValue the mapped value to use for any * additions. * @return the set view * @throws NullPointerException if the mappedValue is null */ public KeySetView keySet(V mappedValue) { if (mappedValue == null) throw new NullPointerException(); return new KeySetView(this, mappedValue); } /** * Returns a {@link Collection} view of the values contained in this map. * The collection is backed by the map, so changes to the map are * reflected in the collection, and vice-versa. */ public ValuesView values() { ValuesView vs = values; return (vs != null) ? vs : (values = new ValuesView(this)); } /** * Returns a {@link Set} view of the mappings contained in this map. * The set is backed by the map, so changes to the map are * reflected in the set, and vice-versa. The set supports element * removal, which removes the corresponding mapping from the map, * via the {@code Iterator.remove}, {@code Set.remove}, * {@code removeAll}, {@code retainAll}, and {@code clear} * operations. It does not support the {@code add} or * {@code addAll} operations. * *

The view's {@code iterator} is a "weakly consistent" iterator * that will never throw {@link ConcurrentModificationException}, * and guarantees to traverse elements as they existed upon * construction of the iterator, and may (but is not guaranteed to) * reflect any modifications subsequent to construction. */ public Set> entrySet() { EntrySetView es = entrySet; return (es != null) ? es : (entrySet = new EntrySetView(this)); } /** * Returns an enumeration of the keys in this table. * * @return an enumeration of the keys in this table * @see #keySet() */ public Enumeration keys() { return new KeyIterator(this); } /** * Returns an enumeration of the values in this table. * * @return an enumeration of the values in this table * @see #values() */ public Enumeration elements() { return new ValueIterator(this); } /** * Returns a partitionable iterator of the keys in this map. * * @return a partitionable iterator of the keys in this map */ public Spliterator keySpliterator() { return new KeyIterator(this); } /** * Returns a partitionable iterator of the values in this map. * * @return a partitionable iterator of the values in this map */ public Spliterator valueSpliterator() { return new ValueIterator(this); } /** * Returns a partitionable iterator of the entries in this map. * * @return a partitionable iterator of the entries in this map */ public Spliterator> entrySpliterator() { return new EntryIterator(this); } /** * Returns the hash code value for this {@link Map}, i.e., * the sum of, for each key-value pair in the map, * {@code key.hashCode() ^ value.hashCode()}. * * @return the hash code value for this map */ public int hashCode() { int h = 0; Traverser it = new Traverser(this); Object v; while ((v = it.advance()) != null) { h += it.nextKey.hashCode() ^ v.hashCode(); } return h; } /** * Returns a string representation of this map. The string * representation consists of a list of key-value mappings (in no * particular order) enclosed in braces ("{@code {}}"). Adjacent * mappings are separated by the characters {@code ", "} (comma * and space). Each key-value mapping is rendered as the key * followed by an equals sign ("{@code =}") followed by the * associated value. * * @return a string representation of this map */ public String toString() { Traverser it = new Traverser(this); StringBuilder sb = new StringBuilder(); sb.append('{'); Object v; if ((v = it.advance()) != null) { for (;;) { Object k = it.nextKey; sb.append(k == this ? "(this Map)" : k); sb.append('='); sb.append(v == this ? "(this Map)" : v); if ((v = it.advance()) == null) break; sb.append(',').append(' '); } } return sb.append('}').toString(); } /** * Compares the specified object with this map for equality. * Returns {@code true} if the given object is a map with the same * mappings as this map. This operation may return misleading * results if either map is concurrently modified during execution * of this method. * * @param o object to be compared for equality with this map * @return {@code true} if the specified object is equal to this map */ public boolean equals(Object o) { if (o != this) { if (!(o instanceof Map)) return false; Map m = (Map) o; Traverser it = new Traverser(this); Object val; while ((val = it.advance()) != null) { Object v = m.get(it.nextKey); if (v == null || (v != val && !v.equals(val))) return false; } for (Map.Entry e : m.entrySet()) { Object mk, mv, v; if ((mk = e.getKey()) == null || (mv = e.getValue()) == null || (v = internalGet(mk)) == null || (mv != v && !mv.equals(v))) return false; } } return true; } /* ----------------Iterators -------------- */ @SuppressWarnings("serial") static final class KeyIterator extends Traverser implements Spliterator, Enumeration { KeyIterator(ConcurrentHashMapV8 map) { super(map); } KeyIterator(Traverser it) { super(it); } public KeyIterator split() { if (nextKey != null) throw new IllegalStateException(); return new KeyIterator(this); } @SuppressWarnings("unchecked") public final K next() { if (nextVal == null && advance() == null) throw new NoSuchElementException(); Object k = nextKey; nextVal = null; return (K) k; } public final K nextElement() { return next(); } } @SuppressWarnings("serial") static final class ValueIterator extends Traverser implements Spliterator, Enumeration { ValueIterator(ConcurrentHashMapV8 map) { super(map); } ValueIterator(Traverser it) { super(it); } public ValueIterator split() { if (nextKey != null) throw new IllegalStateException(); return new ValueIterator(this); } @SuppressWarnings("unchecked") public final V next() { Object v; if ((v = nextVal) == null && (v = advance()) == null) throw new NoSuchElementException(); nextVal = null; return (V) v; } public final V nextElement() { return next(); } } @SuppressWarnings("serial") static final class EntryIterator extends Traverser implements Spliterator> { EntryIterator(ConcurrentHashMapV8 map) { super(map); } EntryIterator(Traverser it) { super(it); } public EntryIterator split() { if (nextKey != null) throw new IllegalStateException(); return new EntryIterator(this); } @SuppressWarnings("unchecked") public final Map.Entry next() { Object v; if ((v = nextVal) == null && (v = advance()) == null) throw new NoSuchElementException(); Object k = nextKey; nextVal = null; return new MapEntry((K)k, (V)v, map); } } /** * Exported Entry for iterators */ static final class MapEntry implements Map.Entry { final K key; // non-null V val; // non-null final ConcurrentHashMapV8 map; MapEntry(K key, V val, ConcurrentHashMapV8 map) { this.key = key; this.val = val; this.map = map; } public final K getKey() { return key; } public final V getValue() { return val; } public final int hashCode() { return key.hashCode() ^ val.hashCode(); } public final String toString(){ return key + "=" + val; } public final boolean equals(Object o) { Object k, v; Map.Entry e; return ((o instanceof Map.Entry) && (k = (e = (Map.Entry)o).getKey()) != null && (v = e.getValue()) != null && (k == key || k.equals(key)) && (v == val || v.equals(val))); } /** * Sets our entry's value and writes through to the map. The * value to return is somewhat arbitrary here. Since we do not * necessarily track asynchronous changes, the most recent * "previous" value could be different from what we return (or * could even have been removed in which case the put will * re-establish). We do not and cannot guarantee more. */ public final V setValue(V value) { if (value == null) throw new NullPointerException(); V v = val; val = value; map.put(key, value); return v; } } /* ---------------- Serialization Support -------------- */ /** * Stripped-down version of helper class used in previous version, * declared for the sake of serialization compatibility */ static class Segment implements Serializable { private static final long serialVersionUID = 2249069246763182397L; final float loadFactor; Segment(float lf) { this.loadFactor = lf; } } /** * Saves the state of the {@code ConcurrentHashMapV8} instance to a * stream (i.e., serializes it). * @param s the stream * @serialData * the key (Object) and value (Object) * for each key-value mapping, followed by a null pair. * The key-value mappings are emitted in no particular order. */ @SuppressWarnings("unchecked") private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { if (segments == null) { // for serialization compatibility segments = (Segment[]) new Segment[DEFAULT_CONCURRENCY_LEVEL]; for (int i = 0; i < segments.length; ++i) segments[i] = new Segment(LOAD_FACTOR); } s.defaultWriteObject(); Traverser it = new Traverser(this); Object v; while ((v = it.advance()) != null) { s.writeObject(it.nextKey); s.writeObject(v); } s.writeObject(null); s.writeObject(null); segments = null; // throw away } /** * Reconstitutes the instance from a stream (that is, deserializes it). * @param s the stream */ @SuppressWarnings("unchecked") private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); this.segments = null; // unneeded // initialize transient final field UNSAFE.putObjectVolatile(this, counterOffset, new LongAdder()); // Create all nodes, then place in table once size is known long size = 0L; Node p = null; for (;;) { K k = (K) s.readObject(); V v = (V) s.readObject(); if (k != null && v != null) { int h = spread(k.hashCode()); p = new Node(h, k, v, p); ++size; } else break; } if (p != null) { boolean init = false; int n; if (size >= (long)(MAXIMUM_CAPACITY >>> 1)) n = MAXIMUM_CAPACITY; else { int sz = (int)size; n = tableSizeFor(sz + (sz >>> 1) + 1); } int sc = sizeCtl; boolean collide = false; if (n > sc && UNSAFE.compareAndSwapInt(this, sizeCtlOffset, sc, -1)) { try { if (table == null) { init = true; Node[] tab = new Node[n]; int mask = n - 1; while (p != null) { int j = p.hash & mask; Node next = p.next; Node q = p.next = tabAt(tab, j); setTabAt(tab, j, p); if (!collide && q != null && q.hash == p.hash) collide = true; p = next; } table = tab; counter.add(size); sc = n - (n >>> 2); } } finally { sizeCtl = sc; } if (collide) { // rescan and convert to TreeBins Node[] tab = table; for (int i = 0; i < tab.length; ++i) { int c = 0; for (Node e = tabAt(tab, i); e != null; e = e.next) { if (++c > TREE_THRESHOLD && (e.key instanceof Comparable)) { replaceWithTreeBin(tab, i, e.key); break; } } } } } if (!init) { // Can only happen if unsafely published. while (p != null) { internalPut(p.key, p.val); p = p.next; } } } } // ------------------------------------------------------- // Sams /** Interface describing a void action of one argument */ public interface Action { void apply(A a); } /** Interface describing a void action of two arguments */ public interface BiAction { void apply(A a, B b); } /** Interface describing a function of one argument */ public interface Generator { T apply(); } /** Interface describing a function mapping its argument to a double */ public interface ObjectToDouble { double apply(A a); } /** Interface describing a function mapping its argument to a long */ public interface ObjectToLong { long apply(A a); } /** Interface describing a function mapping its argument to an int */ public interface ObjectToInt {int apply(A a); } /** Interface describing a function mapping two arguments to a double */ public interface ObjectByObjectToDouble { double apply(A a, B b); } /** Interface describing a function mapping two arguments to a long */ public interface ObjectByObjectToLong { long apply(A a, B b); } /** Interface describing a function mapping two arguments to an int */ public interface ObjectByObjectToInt {int apply(A a, B b); } /** Interface describing a function mapping a double to a double */ public interface DoubleToDouble { double apply(double a); } /** Interface describing a function mapping a long to a long */ public interface LongToLong { long apply(long a); } /** Interface describing a function mapping an int to an int */ public interface IntToInt { int apply(int a); } /** Interface describing a function mapping two doubles to a double */ public interface DoubleByDoubleToDouble { double apply(double a, double b); } /** Interface describing a function mapping two longs to a long */ public interface LongByLongToLong { long apply(long a, long b); } /** Interface describing a function mapping two ints to an int */ public interface IntByIntToInt { int apply(int a, int b); } /* ----------------Views -------------- */ /** * Base class for views. */ static abstract class CHMView { final ConcurrentHashMapV8 map; CHMView(ConcurrentHashMapV8 map) { this.map = map; } /** * Returns the map backing this view. * * @return the map backing this view */ public ConcurrentHashMapV8 getMap() { return map; } public final int size() { return map.size(); } public final boolean isEmpty() { return map.isEmpty(); } public final void clear() { map.clear(); } // implementations below rely on concrete classes supplying these abstract public Iterator iterator(); abstract public boolean contains(Object o); abstract public boolean remove(Object o); private static final String oomeMsg = "Required array size too large"; public final Object[] toArray() { long sz = map.mappingCount(); if (sz > (long)(MAX_ARRAY_SIZE)) throw new OutOfMemoryError(oomeMsg); int n = (int)sz; Object[] r = new Object[n]; int i = 0; Iterator it = iterator(); while (it.hasNext()) { if (i == n) { if (n >= MAX_ARRAY_SIZE) throw new OutOfMemoryError(oomeMsg); if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1) n = MAX_ARRAY_SIZE; else n += (n >>> 1) + 1; r = Arrays.copyOf(r, n); } r[i++] = it.next(); } return (i == n) ? r : Arrays.copyOf(r, i); } @SuppressWarnings("unchecked") public final T[] toArray(T[] a) { long sz = map.mappingCount(); if (sz > (long)(MAX_ARRAY_SIZE)) throw new OutOfMemoryError(oomeMsg); int m = (int)sz; T[] r = (a.length >= m) ? a : (T[])java.lang.reflect.Array .newInstance(a.getClass().getComponentType(), m); int n = r.length; int i = 0; Iterator it = iterator(); while (it.hasNext()) { if (i == n) { if (n >= MAX_ARRAY_SIZE) throw new OutOfMemoryError(oomeMsg); if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1) n = MAX_ARRAY_SIZE; else n += (n >>> 1) + 1; r = Arrays.copyOf(r, n); } r[i++] = (T)it.next(); } if (a == r && i < n) { r[i] = null; // null-terminate return r; } return (i == n) ? r : Arrays.copyOf(r, i); } public final int hashCode() { int h = 0; for (Iterator it = iterator(); it.hasNext();) h += it.next().hashCode(); return h; } public final String toString() { StringBuilder sb = new StringBuilder(); sb.append('['); Iterator it = iterator(); if (it.hasNext()) { for (;;) { Object e = it.next(); sb.append(e == this ? "(this Collection)" : e); if (!it.hasNext()) break; sb.append(',').append(' '); } } return sb.append(']').toString(); } public final boolean containsAll(Collection c) { if (c != this) { for (Iterator it = c.iterator(); it.hasNext();) { Object e = it.next(); if (e == null || !contains(e)) return false; } } return true; } public final boolean removeAll(Collection c) { boolean modified = false; for (Iterator it = iterator(); it.hasNext();) { if (c.contains(it.next())) { it.remove(); modified = true; } } return modified; } public final boolean retainAll(Collection c) { boolean modified = false; for (Iterator it = iterator(); it.hasNext();) { if (!c.contains(it.next())) { it.remove(); modified = true; } } return modified; } } /** * A view of a ConcurrentHashMapV8 as a {@link Set} of keys, in * which additions may optionally be enabled by mapping to a * common value. This class cannot be directly instantiated. See * {@link #keySet}, {@link #keySet(Object)}, {@link #newKeySet()}, * {@link #newKeySet(int)}. */ public static class KeySetView extends CHMView implements Set, java.io.Serializable { private static final long serialVersionUID = 7249069246763182397L; private final V value; KeySetView(ConcurrentHashMapV8 map, V value) { // non-public super(map); this.value = value; } /** * Returns the default mapped value for additions, * or {@code null} if additions are not supported. * * @return the default mapped value for additions, or {@code null} * if not supported. */ public V getMappedValue() { return value; } // implement Set API public boolean contains(Object o) { return map.containsKey(o); } public boolean remove(Object o) { return map.remove(o) != null; } /** * Returns a "weakly consistent" iterator that will never * throw {@link ConcurrentModificationException}, and * guarantees to traverse elements as they existed upon * construction of the iterator, and may (but is not * guaranteed to) reflect any modifications subsequent to * construction. * * @return an iterator over the keys of this map */ public Iterator iterator() { return new KeyIterator(map); } public boolean add(K e) { V v; if ((v = value) == null) throw new UnsupportedOperationException(); if (e == null) throw new NullPointerException(); return map.internalPutIfAbsent(e, v) == null; } public boolean addAll(Collection c) { boolean added = false; V v; if ((v = value) == null) throw new UnsupportedOperationException(); for (K e : c) { if (e == null) throw new NullPointerException(); if (map.internalPutIfAbsent(e, v) == null) added = true; } return added; } public boolean equals(Object o) { Set c; return ((o instanceof Set) && ((c = (Set)o) == this || (containsAll(c) && c.containsAll(this)))); } } /** * A view of a ConcurrentHashMapV8 as a {@link Collection} of * values, in which additions are disabled. This class cannot be * directly instantiated. See {@link #values}, * *

The view's {@code iterator} is a "weakly consistent" iterator * that will never throw {@link ConcurrentModificationException}, * and guarantees to traverse elements as they existed upon * construction of the iterator, and may (but is not guaranteed to) * reflect any modifications subsequent to construction. */ public static final class ValuesView extends CHMView implements Collection { ValuesView(ConcurrentHashMapV8 map) { super(map); } public final boolean contains(Object o) { return map.containsValue(o); } public final boolean remove(Object o) { if (o != null) { Iterator it = new ValueIterator(map); while (it.hasNext()) { if (o.equals(it.next())) { it.remove(); return true; } } } return false; } /** * Returns a "weakly consistent" iterator that will never * throw {@link ConcurrentModificationException}, and * guarantees to traverse elements as they existed upon * construction of the iterator, and may (but is not * guaranteed to) reflect any modifications subsequent to * construction. * * @return an iterator over the values of this map */ public final Iterator iterator() { return new ValueIterator(map); } public final boolean add(V e) { throw new UnsupportedOperationException(); } public final boolean addAll(Collection c) { throw new UnsupportedOperationException(); } } /** * A view of a ConcurrentHashMapV8 as a {@link Set} of (key, value) * entries. This class cannot be directly instantiated. See * {@link #entrySet}. */ public static final class EntrySetView extends CHMView implements Set> { EntrySetView(ConcurrentHashMapV8 map) { super(map); } public final boolean contains(Object o) { Object k, v, r; Map.Entry e; return ((o instanceof Map.Entry) && (k = (e = (Map.Entry)o).getKey()) != null && (r = map.get(k)) != null && (v = e.getValue()) != null && (v == r || v.equals(r))); } public final boolean remove(Object o) { Object k, v; Map.Entry e; return ((o instanceof Map.Entry) && (k = (e = (Map.Entry)o).getKey()) != null && (v = e.getValue()) != null && map.remove(k, v)); } /** * Returns a "weakly consistent" iterator that will never * throw {@link ConcurrentModificationException}, and * guarantees to traverse elements as they existed upon * construction of the iterator, and may (but is not * guaranteed to) reflect any modifications subsequent to * construction. * * @return an iterator over the entries of this map */ public final Iterator> iterator() { return new EntryIterator(map); } public final boolean add(Entry e) { K key = e.getKey(); V value = e.getValue(); if (key == null || value == null) throw new NullPointerException(); return map.internalPut(key, value) == null; } public final boolean addAll(Collection> c) { boolean added = false; for (Entry e : c) { if (add(e)) added = true; } return added; } public boolean equals(Object o) { Set c; return ((o instanceof Set) && ((c = (Set)o) == this || (containsAll(c) && c.containsAll(this)))); } } // Unsafe mechanics private static final sun.misc.Unsafe UNSAFE; private static final long counterOffset; private static final long sizeCtlOffset; private static final long ABASE; private static final int ASHIFT; static { int ss; try { UNSAFE = getUnsafe(); Class k = ConcurrentHashMapV8.class; counterOffset = UNSAFE.objectFieldOffset (k.getDeclaredField("counter")); sizeCtlOffset = UNSAFE.objectFieldOffset (k.getDeclaredField("sizeCtl")); Class sc = Node[].class; ABASE = UNSAFE.arrayBaseOffset(sc); ss = UNSAFE.arrayIndexScale(sc); } catch (Exception e) { throw new Error(e); } if ((ss & (ss-1)) != 0) throw new Error("data type scale not a power of two"); ASHIFT = 31 - Integer.numberOfLeadingZeros(ss); } /** * Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package. * Replace with a simple call to Unsafe.getUnsafe when integrating * into a jdk. * * @return a sun.misc.Unsafe */ private static sun.misc.Unsafe getUnsafe() { try { return sun.misc.Unsafe.getUnsafe(); } catch (SecurityException se) { try { return java.security.AccessController.doPrivileged (new java.security .PrivilegedExceptionAction() { public sun.misc.Unsafe run() throws Exception { java.lang.reflect.Field f = sun.misc .Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); return (sun.misc.Unsafe) f.get(null); }}); } catch (java.security.PrivilegedActionException e) { throw new RuntimeException("Could not initialize intrinsics", e.getCause()); } } } } concurrent-ruby-1.0.5/ext/com/concurrent_ruby/ext/jsr166e/LongAdder.java000066400000000000000000000133471305460430400261700ustar00rootroot00000000000000/* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/publicdomain/zero/1.0/ */ // This is based on 1.9 version. package com.concurrent_ruby.ext.jsr166e; import java.util.concurrent.atomic.AtomicLong; import java.io.IOException; import java.io.Serializable; import java.io.ObjectInputStream; /** * One or more variables that together maintain an initially zero * {@code long} sum. When updates (method {@link #add}) are contended * across threads, the set of variables may grow dynamically to reduce * contention. Method {@link #sum} (or, equivalently, {@link * #longValue}) returns the current total combined across the * variables maintaining the sum. * *

This class is usually preferable to {@link AtomicLong} when * multiple threads update a common sum that is used for purposes such * as collecting statistics, not for fine-grained synchronization * control. Under low update contention, the two classes have similar * characteristics. But under high contention, expected throughput of * this class is significantly higher, at the expense of higher space * consumption. * *

This class extends {@link Number}, but does not define * methods such as {@code hashCode} and {@code compareTo} because * instances are expected to be mutated, and so are not useful as * collection keys. * *

jsr166e note: This class is targeted to be placed in * java.util.concurrent.atomic. * * @since 1.8 * @author Doug Lea */ public class LongAdder extends Striped64 implements Serializable { private static final long serialVersionUID = 7249069246863182397L; /** * Version of plus for use in retryUpdate */ final long fn(long v, long x) { return v + x; } /** * Creates a new adder with initial sum of zero. */ public LongAdder() { } /** * Adds the given value. * * @param x the value to add */ public void add(long x) { Cell[] as; long b, v; HashCode hc; Cell a; int n; if ((as = cells) != null || !casBase(b = base, b + x)) { boolean uncontended = true; int h = (hc = threadHashCode.get()).code; if (as == null || (n = as.length) < 1 || (a = as[(n - 1) & h]) == null || !(uncontended = a.cas(v = a.value, v + x))) retryUpdate(x, hc, uncontended); } } /** * Equivalent to {@code add(1)}. */ public void increment() { add(1L); } /** * Equivalent to {@code add(-1)}. */ public void decrement() { add(-1L); } /** * Returns the current sum. The returned value is NOT an * atomic snapshot: Invocation in the absence of concurrent * updates returns an accurate result, but concurrent updates that * occur while the sum is being calculated might not be * incorporated. * * @return the sum */ public long sum() { long sum = base; Cell[] as = cells; if (as != null) { int n = as.length; for (int i = 0; i < n; ++i) { Cell a = as[i]; if (a != null) sum += a.value; } } return sum; } /** * Resets variables maintaining the sum to zero. This method may * be a useful alternative to creating a new adder, but is only * effective if there are no concurrent updates. Because this * method is intrinsically racy, it should only be used when it is * known that no threads are concurrently updating. */ public void reset() { internalReset(0L); } /** * Equivalent in effect to {@link #sum} followed by {@link * #reset}. This method may apply for example during quiescent * points between multithreaded computations. If there are * updates concurrent with this method, the returned value is * not guaranteed to be the final value occurring before * the reset. * * @return the sum */ public long sumThenReset() { long sum = base; Cell[] as = cells; base = 0L; if (as != null) { int n = as.length; for (int i = 0; i < n; ++i) { Cell a = as[i]; if (a != null) { sum += a.value; a.value = 0L; } } } return sum; } /** * Returns the String representation of the {@link #sum}. * @return the String representation of the {@link #sum} */ public String toString() { return Long.toString(sum()); } /** * Equivalent to {@link #sum}. * * @return the sum */ public long longValue() { return sum(); } /** * Returns the {@link #sum} as an {@code int} after a narrowing * primitive conversion. */ public int intValue() { return (int)sum(); } /** * Returns the {@link #sum} as a {@code float} * after a widening primitive conversion. */ public float floatValue() { return (float)sum(); } /** * Returns the {@link #sum} as a {@code double} after a widening * primitive conversion. */ public double doubleValue() { return (double)sum(); } private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { s.defaultWriteObject(); s.writeLong(sum()); } private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); busy = 0; cells = null; base = s.readLong(); } } concurrent-ruby-1.0.5/ext/com/concurrent_ruby/ext/jsr166e/Striped64.java000066400000000000000000000321561305460430400261140ustar00rootroot00000000000000/* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/publicdomain/zero/1.0/ */ // This is based on 1.5 version. package com.concurrent_ruby.ext.jsr166e; import java.util.Random; /** * A package-local class holding common representation and mechanics * for classes supporting dynamic striping on 64bit values. The class * extends Number so that concrete subclasses must publicly do so. */ abstract class Striped64 extends Number { /* * This class maintains a lazily-initialized table of atomically * updated variables, plus an extra "base" field. The table size * is a power of two. Indexing uses masked per-thread hash codes. * Nearly all declarations in this class are package-private, * accessed directly by subclasses. * * Table entries are of class Cell; a variant of AtomicLong padded * to reduce cache contention on most processors. Padding is * overkill for most Atomics because they are usually irregularly * scattered in memory and thus don't interfere much with each * other. But Atomic objects residing in arrays will tend to be * placed adjacent to each other, and so will most often share * cache lines (with a huge negative performance impact) without * this precaution. * * In part because Cells are relatively large, we avoid creating * them until they are needed. When there is no contention, all * updates are made to the base field. Upon first contention (a * failed CAS on base update), the table is initialized to size 2. * The table size is doubled upon further contention until * reaching the nearest power of two greater than or equal to the * number of CPUS. Table slots remain empty (null) until they are * needed. * * A single spinlock ("busy") is used for initializing and * resizing the table, as well as populating slots with new Cells. * There is no need for a blocking lock: When the lock is not * available, threads try other slots (or the base). During these * retries, there is increased contention and reduced locality, * which is still better than alternatives. * * Per-thread hash codes are initialized to random values. * Contention and/or table collisions are indicated by failed * CASes when performing an update operation (see method * retryUpdate). Upon a collision, if the table size is less than * the capacity, it is doubled in size unless some other thread * holds the lock. If a hashed slot is empty, and lock is * available, a new Cell is created. Otherwise, if the slot * exists, a CAS is tried. Retries proceed by "double hashing", * using a secondary hash (Marsaglia XorShift) to try to find a * free slot. * * The table size is capped because, when there are more threads * than CPUs, supposing that each thread were bound to a CPU, * there would exist a perfect hash function mapping threads to * slots that eliminates collisions. When we reach capacity, we * search for this mapping by randomly varying the hash codes of * colliding threads. Because search is random, and collisions * only become known via CAS failures, convergence can be slow, * and because threads are typically not bound to CPUS forever, * may not occur at all. However, despite these limitations, * observed contention rates are typically low in these cases. * * It is possible for a Cell to become unused when threads that * once hashed to it terminate, as well as in the case where * doubling the table causes no thread to hash to it under * expanded mask. We do not try to detect or remove such cells, * under the assumption that for long-running instances, observed * contention levels will recur, so the cells will eventually be * needed again; and for short-lived ones, it does not matter. */ /** * Padded variant of AtomicLong supporting only raw accesses plus CAS. * The value field is placed between pads, hoping that the JVM doesn't * reorder them. * * JVM intrinsics note: It would be possible to use a release-only * form of CAS here, if it were provided. */ static final class Cell { volatile long p0, p1, p2, p3, p4, p5, p6; volatile long value; volatile long q0, q1, q2, q3, q4, q5, q6; Cell(long x) { value = x; } final boolean cas(long cmp, long val) { return UNSAFE.compareAndSwapLong(this, valueOffset, cmp, val); } // Unsafe mechanics private static final sun.misc.Unsafe UNSAFE; private static final long valueOffset; static { try { UNSAFE = getUnsafe(); Class ak = Cell.class; valueOffset = UNSAFE.objectFieldOffset (ak.getDeclaredField("value")); } catch (Exception e) { throw new Error(e); } } } /** * Holder for the thread-local hash code. The code is initially * random, but may be set to a different value upon collisions. */ static final class HashCode { static final Random rng = new Random(); int code; HashCode() { int h = rng.nextInt(); // Avoid zero to allow xorShift rehash code = (h == 0) ? 1 : h; } } /** * The corresponding ThreadLocal class */ static final class ThreadHashCode extends ThreadLocal { public HashCode initialValue() { return new HashCode(); } } /** * Static per-thread hash codes. Shared across all instances to * reduce ThreadLocal pollution and because adjustments due to * collisions in one table are likely to be appropriate for * others. */ static final ThreadHashCode threadHashCode = new ThreadHashCode(); /** Number of CPUS, to place bound on table size */ static final int NCPU = Runtime.getRuntime().availableProcessors(); /** * Table of cells. When non-null, size is a power of 2. */ transient volatile Cell[] cells; /** * Base value, used mainly when there is no contention, but also as * a fallback during table initialization races. Updated via CAS. */ transient volatile long base; /** * Spinlock (locked via CAS) used when resizing and/or creating Cells. */ transient volatile int busy; /** * Package-private default constructor */ Striped64() { } /** * CASes the base field. */ final boolean casBase(long cmp, long val) { return UNSAFE.compareAndSwapLong(this, baseOffset, cmp, val); } /** * CASes the busy field from 0 to 1 to acquire lock. */ final boolean casBusy() { return UNSAFE.compareAndSwapInt(this, busyOffset, 0, 1); } /** * Computes the function of current and new value. Subclasses * should open-code this update function for most uses, but the * virtualized form is needed within retryUpdate. * * @param currentValue the current value (of either base or a cell) * @param newValue the argument from a user update call * @return result of the update function */ abstract long fn(long currentValue, long newValue); /** * Handles cases of updates involving initialization, resizing, * creating new Cells, and/or contention. See above for * explanation. This method suffers the usual non-modularity * problems of optimistic retry code, relying on rechecked sets of * reads. * * @param x the value * @param hc the hash code holder * @param wasUncontended false if CAS failed before call */ final void retryUpdate(long x, HashCode hc, boolean wasUncontended) { int h = hc.code; boolean collide = false; // True if last slot nonempty for (;;) { Cell[] as; Cell a; int n; long v; if ((as = cells) != null && (n = as.length) > 0) { if ((a = as[(n - 1) & h]) == null) { if (busy == 0) { // Try to attach new Cell Cell r = new Cell(x); // Optimistically create if (busy == 0 && casBusy()) { boolean created = false; try { // Recheck under lock Cell[] rs; int m, j; if ((rs = cells) != null && (m = rs.length) > 0 && rs[j = (m - 1) & h] == null) { rs[j] = r; created = true; } } finally { busy = 0; } if (created) break; continue; // Slot is now non-empty } } collide = false; } else if (!wasUncontended) // CAS already known to fail wasUncontended = true; // Continue after rehash else if (a.cas(v = a.value, fn(v, x))) break; else if (n >= NCPU || cells != as) collide = false; // At max size or stale else if (!collide) collide = true; else if (busy == 0 && casBusy()) { try { if (cells == as) { // Expand table unless stale Cell[] rs = new Cell[n << 1]; for (int i = 0; i < n; ++i) rs[i] = as[i]; cells = rs; } } finally { busy = 0; } collide = false; continue; // Retry with expanded table } h ^= h << 13; // Rehash h ^= h >>> 17; h ^= h << 5; } else if (busy == 0 && cells == as && casBusy()) { boolean init = false; try { // Initialize table if (cells == as) { Cell[] rs = new Cell[2]; rs[h & 1] = new Cell(x); cells = rs; init = true; } } finally { busy = 0; } if (init) break; } else if (casBase(v = base, fn(v, x))) break; // Fall back on using base } hc.code = h; // Record index for next time } /** * Sets base and all cells to the given value. */ final void internalReset(long initialValue) { Cell[] as = cells; base = initialValue; if (as != null) { int n = as.length; for (int i = 0; i < n; ++i) { Cell a = as[i]; if (a != null) a.value = initialValue; } } } // Unsafe mechanics private static final sun.misc.Unsafe UNSAFE; private static final long baseOffset; private static final long busyOffset; static { try { UNSAFE = getUnsafe(); Class sk = Striped64.class; baseOffset = UNSAFE.objectFieldOffset (sk.getDeclaredField("base")); busyOffset = UNSAFE.objectFieldOffset (sk.getDeclaredField("busy")); } catch (Exception e) { throw new Error(e); } } /** * Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package. * Replace with a simple call to Unsafe.getUnsafe when integrating * into a jdk. * * @return a sun.misc.Unsafe */ private static sun.misc.Unsafe getUnsafe() { try { return sun.misc.Unsafe.getUnsafe(); } catch (SecurityException se) { try { return java.security.AccessController.doPrivileged (new java.security .PrivilegedExceptionAction() { public sun.misc.Unsafe run() throws Exception { java.lang.reflect.Field f = sun.misc .Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); return (sun.misc.Unsafe) f.get(null); }}); } catch (java.security.PrivilegedActionException e) { throw new RuntimeException("Could not initialize intrinsics", e.getCause()); } } } } concurrent-ruby-1.0.5/ext/com/concurrent_ruby/ext/jsr166e/nounsafe/000077500000000000000000000000001305460430400252745ustar00rootroot00000000000000concurrent-ruby-1.0.5/ext/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java000066400000000000000000004642111305460430400317510ustar00rootroot00000000000000/* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/publicdomain/zero/1.0/ */ // This is based on the 1.79 version. package com.concurrent_ruby.ext.jsr166e.nounsafe; import org.jruby.RubyClass; import org.jruby.RubyNumeric; import org.jruby.RubyObject; import org.jruby.exceptions.RaiseException; import com.concurrent_ruby.ext.jsr166e.ConcurrentHashMap; import com.concurrent_ruby.ext.jsr166y.ThreadLocalRandom; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import java.util.Arrays; import java.util.Map; import java.util.Set; import java.util.Collection; import java.util.Hashtable; import java.util.HashMap; import java.util.Iterator; import java.util.Enumeration; import java.util.ConcurrentModificationException; import java.util.NoSuchElementException; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicReferenceArray; import java.util.concurrent.locks.AbstractQueuedSynchronizer; import java.io.Serializable; /** * A hash table supporting full concurrency of retrievals and * high expected concurrency for updates. This class obeys the * same functional specification as {@link java.util.Hashtable}, and * includes versions of methods corresponding to each method of * {@code Hashtable}. However, even though all operations are * thread-safe, retrieval operations do not entail locking, * and there is not any support for locking the entire table * in a way that prevents all access. This class is fully * interoperable with {@code Hashtable} in programs that rely on its * thread safety but not on its synchronization details. * *

Retrieval operations (including {@code get}) generally do not * block, so may overlap with update operations (including {@code put} * and {@code remove}). Retrievals reflect the results of the most * recently completed update operations holding upon their * onset. (More formally, an update operation for a given key bears a * happens-before relation with any (non-null) retrieval for * that key reporting the updated value.) For aggregate operations * such as {@code putAll} and {@code clear}, concurrent retrievals may * reflect insertion or removal of only some entries. Similarly, * Iterators and Enumerations return elements reflecting the state of * the hash table at some point at or since the creation of the * iterator/enumeration. They do not throw {@link * ConcurrentModificationException}. However, iterators are designed * to be used by only one thread at a time. Bear in mind that the * results of aggregate status methods including {@code size}, {@code * isEmpty}, and {@code containsValue} are typically useful only when * a map is not undergoing concurrent updates in other threads. * Otherwise the results of these methods reflect transient states * that may be adequate for monitoring or estimation purposes, but not * for program control. * *

The table is dynamically expanded when there are too many * collisions (i.e., keys that have distinct hash codes but fall into * the same slot modulo the table size), with the expected average * effect of maintaining roughly two bins per mapping (corresponding * to a 0.75 load factor threshold for resizing). There may be much * variance around this average as mappings are added and removed, but * overall, this maintains a commonly accepted time/space tradeoff for * hash tables. However, resizing this or any other kind of hash * table may be a relatively slow operation. When possible, it is a * good idea to provide a size estimate as an optional {@code * initialCapacity} constructor argument. An additional optional * {@code loadFactor} constructor argument provides a further means of * customizing initial table capacity by specifying the table density * to be used in calculating the amount of space to allocate for the * given number of elements. Also, for compatibility with previous * versions of this class, constructors may optionally specify an * expected {@code concurrencyLevel} as an additional hint for * internal sizing. Note that using many keys with exactly the same * {@code hashCode()} is a sure way to slow down performance of any * hash table. * *

A {@link Set} projection of a ConcurrentHashMapV8 may be created * (using {@link #newKeySet()} or {@link #newKeySet(int)}), or viewed * (using {@link #keySet(Object)} when only keys are of interest, and the * mapped values are (perhaps transiently) not used or all take the * same mapping value. * *

A ConcurrentHashMapV8 can be used as scalable frequency map (a * form of histogram or multiset) by using {@link LongAdder} values * and initializing via {@link #computeIfAbsent}. For example, to add * a count to a {@code ConcurrentHashMapV8 freqs}, you * can use {@code freqs.computeIfAbsent(k -> new * LongAdder()).increment();} * *

This class and its views and iterators implement all of the * optional methods of the {@link Map} and {@link Iterator} * interfaces. * *

Like {@link Hashtable} but unlike {@link HashMap}, this class * does not allow {@code null} to be used as a key or value. * *

ConcurrentHashMapV8s support parallel operations using the {@link * ForkJoinPool#commonPool}. (Tasks that may be used in other contexts * are available in class {@link ForkJoinTasks}). These operations are * designed to be safely, and often sensibly, applied even with maps * that are being concurrently updated by other threads; for example, * when computing a snapshot summary of the values in a shared * registry. There are three kinds of operation, each with four * forms, accepting functions with Keys, Values, Entries, and (Key, * Value) arguments and/or return values. (The first three forms are * also available via the {@link #keySet()}, {@link #values()} and * {@link #entrySet()} views). Because the elements of a * ConcurrentHashMapV8 are not ordered in any particular way, and may be * processed in different orders in different parallel executions, the * correctness of supplied functions should not depend on any * ordering, or on any other objects or values that may transiently * change while computation is in progress; and except for forEach * actions, should ideally be side-effect-free. * *

* *

The concurrency properties of bulk operations follow * from those of ConcurrentHashMapV8: Any non-null result returned * from {@code get(key)} and related access methods bears a * happens-before relation with the associated insertion or * update. The result of any bulk operation reflects the * composition of these per-element relations (but is not * necessarily atomic with respect to the map as a whole unless it * is somehow known to be quiescent). Conversely, because keys * and values in the map are never null, null serves as a reliable * atomic indicator of the current lack of any result. To * maintain this property, null serves as an implicit basis for * all non-scalar reduction operations. For the double, long, and * int versions, the basis should be one that, when combined with * any other value, returns that other value (more formally, it * should be the identity element for the reduction). Most common * reductions have these properties; for example, computing a sum * with basis 0 or a minimum with basis MAX_VALUE. * *

Search and transformation functions provided as arguments * should similarly return null to indicate the lack of any result * (in which case it is not used). In the case of mapped * reductions, this also enables transformations to serve as * filters, returning null (or, in the case of primitive * specializations, the identity basis) if the element should not * be combined. You can create compound transformations and * filterings by composing them yourself under this "null means * there is nothing there now" rule before using them in search or * reduce operations. * *

Methods accepting and/or returning Entry arguments maintain * key-value associations. They may be useful for example when * finding the key for the greatest value. Note that "plain" Entry * arguments can be supplied using {@code new * AbstractMap.SimpleEntry(k,v)}. * *

Bulk operations may complete abruptly, throwing an * exception encountered in the application of a supplied * function. Bear in mind when handling such exceptions that other * concurrently executing functions could also have thrown * exceptions, or would have done so if the first exception had * not occurred. * *

Parallel speedups for bulk operations compared to sequential * processing are common but not guaranteed. Operations involving * brief functions on small maps may execute more slowly than * sequential loops if the underlying work to parallelize the * computation is more expensive than the computation itself. * Similarly, parallelization may not lead to much actual parallelism * if all processors are busy performing unrelated tasks. * *

All arguments to all task methods must be non-null. * *

jsr166e note: During transition, this class * uses nested functional interfaces with different names but the * same forms as those expected for JDK8. * *

This class is a member of the * * Java Collections Framework. * * @since 1.5 * @author Doug Lea * @param the type of keys maintained by this map * @param the type of mapped values */ public class ConcurrentHashMapV8 implements ConcurrentMap, Serializable, ConcurrentHashMap { private static final long serialVersionUID = 7249069246763182397L; /** * A partitionable iterator. A Spliterator can be traversed * directly, but can also be partitioned (before traversal) by * creating another Spliterator that covers a non-overlapping * portion of the elements, and so may be amenable to parallel * execution. * *

This interface exports a subset of expected JDK8 * functionality. * *

Sample usage: Here is one (of the several) ways to compute * the sum of the values held in a map using the ForkJoin * framework. As illustrated here, Spliterators are well suited to * designs in which a task repeatedly splits off half its work * into forked subtasks until small enough to process directly, * and then joins these subtasks. Variants of this style can also * be used in completion-based designs. * *

     * {@code ConcurrentHashMapV8 m = ...
     * // split as if have 8 * parallelism, for load balance
     * int n = m.size();
     * int p = aForkJoinPool.getParallelism() * 8;
     * int split = (n < p)? n : p;
     * long sum = aForkJoinPool.invoke(new SumValues(m.valueSpliterator(), split, null));
     * // ...
     * static class SumValues extends RecursiveTask {
     *   final Spliterator s;
     *   final int split;             // split while > 1
     *   final SumValues nextJoin;    // records forked subtasks to join
     *   SumValues(Spliterator s, int depth, SumValues nextJoin) {
     *     this.s = s; this.depth = depth; this.nextJoin = nextJoin;
     *   }
     *   public Long compute() {
     *     long sum = 0;
     *     SumValues subtasks = null; // fork subtasks
     *     for (int s = split >>> 1; s > 0; s >>>= 1)
     *       (subtasks = new SumValues(s.split(), s, subtasks)).fork();
     *     while (s.hasNext())        // directly process remaining elements
     *       sum += s.next();
     *     for (SumValues t = subtasks; t != null; t = t.nextJoin)
     *       sum += t.join();         // collect subtask results
     *     return sum;
     *   }
     * }
     * }
*/ public static interface Spliterator extends Iterator { /** * Returns a Spliterator covering approximately half of the * elements, guaranteed not to overlap with those subsequently * returned by this Spliterator. After invoking this method, * the current Spliterator will not produce any of * the elements of the returned Spliterator, but the two * Spliterators together will produce all of the elements that * would have been produced by this Spliterator had this * method not been called. The exact number of elements * produced by the returned Spliterator is not guaranteed, and * may be zero (i.e., with {@code hasNext()} reporting {@code * false}) if this Spliterator cannot be further split. * * @return a Spliterator covering approximately half of the * elements * @throws IllegalStateException if this Spliterator has * already commenced traversing elements */ Spliterator split(); } /* * Overview: * * The primary design goal of this hash table is to maintain * concurrent readability (typically method get(), but also * iterators and related methods) while minimizing update * contention. Secondary goals are to keep space consumption about * the same or better than java.util.HashMap, and to support high * initial insertion rates on an empty table by many threads. * * Each key-value mapping is held in a Node. Because Node fields * can contain special values, they are defined using plain Object * types. Similarly in turn, all internal methods that use them * work off Object types. And similarly, so do the internal * methods of auxiliary iterator and view classes. All public * generic typed methods relay in/out of these internal methods, * supplying null-checks and casts as needed. This also allows * many of the public methods to be factored into a smaller number * of internal methods (although sadly not so for the five * variants of put-related operations). The validation-based * approach explained below leads to a lot of code sprawl because * retry-control precludes factoring into smaller methods. * * The table is lazily initialized to a power-of-two size upon the * first insertion. Each bin in the table normally contains a * list of Nodes (most often, the list has only zero or one Node). * Table accesses require volatile/atomic reads, writes, and * CASes. Because there is no other way to arrange this without * adding further indirections, we use intrinsics * (sun.misc.Unsafe) operations. The lists of nodes within bins * are always accurately traversable under volatile reads, so long * as lookups check hash code and non-nullness of value before * checking key equality. * * We use the top two bits of Node hash fields for control * purposes -- they are available anyway because of addressing * constraints. As explained further below, these top bits are * used as follows: * 00 - Normal * 01 - Locked * 11 - Locked and may have a thread waiting for lock * 10 - Node is a forwarding node * * The lower 30 bits of each Node's hash field contain a * transformation of the key's hash code, except for forwarding * nodes, for which the lower bits are zero (and so always have * hash field == MOVED). * * Insertion (via put or its variants) of the first node in an * empty bin is performed by just CASing it to the bin. This is * by far the most common case for put operations under most * key/hash distributions. Other update operations (insert, * delete, and replace) require locks. We do not want to waste * the space required to associate a distinct lock object with * each bin, so instead use the first node of a bin list itself as * a lock. Blocking support for these locks relies on the builtin * "synchronized" monitors. However, we also need a tryLock * construction, so we overlay these by using bits of the Node * hash field for lock control (see above), and so normally use * builtin monitors only for blocking and signalling using * wait/notifyAll constructions. See Node.tryAwaitLock. * * Using the first node of a list as a lock does not by itself * suffice though: When a node is locked, any update must first * validate that it is still the first node after locking it, and * retry if not. Because new nodes are always appended to lists, * once a node is first in a bin, it remains first until deleted * or the bin becomes invalidated (upon resizing). However, * operations that only conditionally update may inspect nodes * until the point of update. This is a converse of sorts to the * lazy locking technique described by Herlihy & Shavit. * * The main disadvantage of per-bin locks is that other update * operations on other nodes in a bin list protected by the same * lock can stall, for example when user equals() or mapping * functions take a long time. However, statistically, under * random hash codes, this is not a common problem. Ideally, the * frequency of nodes in bins follows a Poisson distribution * (http://en.wikipedia.org/wiki/Poisson_distribution) with a * parameter of about 0.5 on average, given the resizing threshold * of 0.75, although with a large variance because of resizing * granularity. Ignoring variance, the expected occurrences of * list size k are (exp(-0.5) * pow(0.5, k) / factorial(k)). The * first values are: * * 0: 0.60653066 * 1: 0.30326533 * 2: 0.07581633 * 3: 0.01263606 * 4: 0.00157952 * 5: 0.00015795 * 6: 0.00001316 * 7: 0.00000094 * 8: 0.00000006 * more: less than 1 in ten million * * Lock contention probability for two threads accessing distinct * elements is roughly 1 / (8 * #elements) under random hashes. * * Actual hash code distributions encountered in practice * sometimes deviate significantly from uniform randomness. This * includes the case when N > (1<<30), so some keys MUST collide. * Similarly for dumb or hostile usages in which multiple keys are * designed to have identical hash codes. Also, although we guard * against the worst effects of this (see method spread), sets of * hashes may differ only in bits that do not impact their bin * index for a given power-of-two mask. So we use a secondary * strategy that applies when the number of nodes in a bin exceeds * a threshold, and at least one of the keys implements * Comparable. These TreeBins use a balanced tree to hold nodes * (a specialized form of red-black trees), bounding search time * to O(log N). Each search step in a TreeBin is around twice as * slow as in a regular list, but given that N cannot exceed * (1<<64) (before running out of addresses) this bounds search * steps, lock hold times, etc, to reasonable constants (roughly * 100 nodes inspected per operation worst case) so long as keys * are Comparable (which is very common -- String, Long, etc). * TreeBin nodes (TreeNodes) also maintain the same "next" * traversal pointers as regular nodes, so can be traversed in * iterators in the same way. * * The table is resized when occupancy exceeds a percentage * threshold (nominally, 0.75, but see below). Only a single * thread performs the resize (using field "sizeCtl", to arrange * exclusion), but the table otherwise remains usable for reads * and updates. Resizing proceeds by transferring bins, one by * one, from the table to the next table. Because we are using * power-of-two expansion, the elements from each bin must either * stay at same index, or move with a power of two offset. We * eliminate unnecessary node creation by catching cases where old * nodes can be reused because their next fields won't change. On * average, only about one-sixth of them need cloning when a table * doubles. The nodes they replace will be garbage collectable as * soon as they are no longer referenced by any reader thread that * may be in the midst of concurrently traversing table. Upon * transfer, the old table bin contains only a special forwarding * node (with hash field "MOVED") that contains the next table as * its key. On encountering a forwarding node, access and update * operations restart, using the new table. * * Each bin transfer requires its bin lock. However, unlike other * cases, a transfer can skip a bin if it fails to acquire its * lock, and revisit it later (unless it is a TreeBin). Method * rebuild maintains a buffer of TRANSFER_BUFFER_SIZE bins that * have been skipped because of failure to acquire a lock, and * blocks only if none are available (i.e., only very rarely). * The transfer operation must also ensure that all accessible * bins in both the old and new table are usable by any traversal. * When there are no lock acquisition failures, this is arranged * simply by proceeding from the last bin (table.length - 1) up * towards the first. Upon seeing a forwarding node, traversals * (see class Iter) arrange to move to the new table * without revisiting nodes. However, when any node is skipped * during a transfer, all earlier table bins may have become * visible, so are initialized with a reverse-forwarding node back * to the old table until the new ones are established. (This * sometimes requires transiently locking a forwarding node, which * is possible under the above encoding.) These more expensive * mechanics trigger only when necessary. * * The traversal scheme also applies to partial traversals of * ranges of bins (via an alternate Traverser constructor) * to support partitioned aggregate operations. Also, read-only * operations give up if ever forwarded to a null table, which * provides support for shutdown-style clearing, which is also not * currently implemented. * * Lazy table initialization minimizes footprint until first use, * and also avoids resizings when the first operation is from a * putAll, constructor with map argument, or deserialization. * These cases attempt to override the initial capacity settings, * but harmlessly fail to take effect in cases of races. * * The element count is maintained using a LongAdder, which avoids * contention on updates but can encounter cache thrashing if read * too frequently during concurrent access. To avoid reading so * often, resizing is attempted either when a bin lock is * contended, or upon adding to a bin already holding two or more * nodes (checked before adding in the xIfAbsent methods, after * adding in others). Under uniform hash distributions, the * probability of this occurring at threshold is around 13%, * meaning that only about 1 in 8 puts check threshold (and after * resizing, many fewer do so). But this approximation has high * variance for small table sizes, so we check on any collision * for sizes <= 64. The bulk putAll operation further reduces * contention by only committing count updates upon these size * checks. * * Maintaining API and serialization compatibility with previous * versions of this class introduces several oddities. Mainly: We * leave untouched but unused constructor arguments refering to * concurrencyLevel. We accept a loadFactor constructor argument, * but apply it only to initial table capacity (which is the only * time that we can guarantee to honor it.) We also declare an * unused "Segment" class that is instantiated in minimal form * only when serializing. */ /* ---------------- Constants -------------- */ /** * The largest possible table capacity. This value must be * exactly 1<<30 to stay within Java array allocation and indexing * bounds for power of two table sizes, and is further required * because the top two bits of 32bit hash fields are used for * control purposes. */ private static final int MAXIMUM_CAPACITY = 1 << 30; /** * The default initial table capacity. Must be a power of 2 * (i.e., at least 1) and at most MAXIMUM_CAPACITY. */ private static final int DEFAULT_CAPACITY = 16; /** * The largest possible (non-power of two) array size. * Needed by toArray and related methods. */ static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; /** * The default concurrency level for this table. Unused but * defined for compatibility with previous versions of this class. */ private static final int DEFAULT_CONCURRENCY_LEVEL = 16; /** * The load factor for this table. Overrides of this value in * constructors affect only the initial table capacity. The * actual floating point value isn't normally used -- it is * simpler to use expressions such as {@code n - (n >>> 2)} for * the associated resizing threshold. */ private static final float LOAD_FACTOR = 0.75f; /** * The buffer size for skipped bins during transfers. The * value is arbitrary but should be large enough to avoid * most locking stalls during resizes. */ private static final int TRANSFER_BUFFER_SIZE = 32; /** * The bin count threshold for using a tree rather than list for a * bin. The value reflects the approximate break-even point for * using tree-based operations. * Note that Doug's version defaults to 8, but when dealing with * Ruby objects it is actually beneficial to avoid TreeNodes * as long as possible as it usually means going into Ruby land. */ private static final int TREE_THRESHOLD = 16; /* * Encodings for special uses of Node hash fields. See above for * explanation. */ static final int MOVED = 0x80000000; // hash field for forwarding nodes static final int LOCKED = 0x40000000; // set/tested only as a bit static final int WAITING = 0xc0000000; // both bits set/tested together static final int HASH_BITS = 0x3fffffff; // usable bits of normal node hash /* ---------------- Fields -------------- */ /** * The array of bins. Lazily initialized upon first insertion. * Size is always a power of two. Accessed directly by iterators. */ transient volatile AtomicReferenceArray table; /** * The counter maintaining number of elements. */ private transient LongAdder counter; /** * Table initialization and resizing control. When negative, the * table is being initialized or resized. Otherwise, when table is * null, holds the initial table size to use upon creation, or 0 * for default. After initialization, holds the next element count * value upon which to resize the table. */ private transient volatile int sizeCtl; // views private transient KeySetView keySet; private transient ValuesView values; private transient EntrySetView entrySet; /** For serialization compatibility. Null unless serialized; see below */ private Segment[] segments; static AtomicIntegerFieldUpdater SIZE_CTRL_UPDATER = AtomicIntegerFieldUpdater.newUpdater(ConcurrentHashMapV8.class, "sizeCtl"); /* ---------------- Table element access -------------- */ /* * Volatile access methods are used for table elements as well as * elements of in-progress next table while resizing. Uses are * null checked by callers, and implicitly bounds-checked, relying * on the invariants that tab arrays have non-zero size, and all * indices are masked with (tab.length - 1) which is never * negative and always less than length. Note that, to be correct * wrt arbitrary concurrency errors by users, bounds checks must * operate on local variables, which accounts for some odd-looking * inline assignments below. */ static final Node tabAt(AtomicReferenceArray tab, int i) { // used by Iter return tab.get(i); } private static final boolean casTabAt(AtomicReferenceArray tab, int i, Node c, Node v) { return tab.compareAndSet(i, c, v); } private static final void setTabAt(AtomicReferenceArray tab, int i, Node v) { tab.set(i, v); } /* ---------------- Nodes -------------- */ /** * Key-value entry. Note that this is never exported out as a * user-visible Map.Entry (see MapEntry below). Nodes with a hash * field of MOVED are special, and do not contain user keys or * values. Otherwise, keys are never null, and null val fields * indicate that a node is in the process of being deleted or * created. For purposes of read-only access, a key may be read * before a val, but can only be used after checking val to be * non-null. */ static class Node { volatile int hash; final Object key; volatile Object val; volatile Node next; static AtomicIntegerFieldUpdater HASH_UPDATER = AtomicIntegerFieldUpdater.newUpdater(Node.class, "hash"); Node(int hash, Object key, Object val, Node next) { this.hash = hash; this.key = key; this.val = val; this.next = next; } /** CompareAndSet the hash field */ final boolean casHash(int cmp, int val) { return HASH_UPDATER.compareAndSet(this, cmp, val); } /** The number of spins before blocking for a lock */ static final int MAX_SPINS = Runtime.getRuntime().availableProcessors() > 1 ? 64 : 1; /** * Spins a while if LOCKED bit set and this node is the first * of its bin, and then sets WAITING bits on hash field and * blocks (once) if they are still set. It is OK for this * method to return even if lock is not available upon exit, * which enables these simple single-wait mechanics. * * The corresponding signalling operation is performed within * callers: Upon detecting that WAITING has been set when * unlocking lock (via a failed CAS from non-waiting LOCKED * state), unlockers acquire the sync lock and perform a * notifyAll. * * The initial sanity check on tab and bounds is not currently * necessary in the only usages of this method, but enables * use in other future contexts. */ final void tryAwaitLock(AtomicReferenceArray tab, int i) { if (tab != null && i >= 0 && i < tab.length()) { // sanity check int r = ThreadLocalRandom.current().nextInt(); // randomize spins int spins = MAX_SPINS, h; while (tabAt(tab, i) == this && ((h = hash) & LOCKED) != 0) { if (spins >= 0) { r ^= r << 1; r ^= r >>> 3; r ^= r << 10; // xorshift if (r >= 0 && --spins == 0) Thread.yield(); // yield before block } else if (casHash(h, h | WAITING)) { synchronized (this) { if (tabAt(tab, i) == this && (hash & WAITING) == WAITING) { try { wait(); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); } } else notifyAll(); // possibly won race vs signaller } break; } } } } } /* ---------------- TreeBins -------------- */ /** * Nodes for use in TreeBins */ static final class TreeNode extends Node { TreeNode parent; // red-black tree links TreeNode left; TreeNode right; TreeNode prev; // needed to unlink next upon deletion boolean red; TreeNode(int hash, Object key, Object val, Node next, TreeNode parent) { super(hash, key, val, next); this.parent = parent; } } /** * A specialized form of red-black tree for use in bins * whose size exceeds a threshold. * * TreeBins use a special form of comparison for search and * related operations (which is the main reason we cannot use * existing collections such as TreeMaps). TreeBins contain * Comparable elements, but may contain others, as well as * elements that are Comparable but not necessarily Comparable * for the same T, so we cannot invoke compareTo among them. To * handle this, the tree is ordered primarily by hash value, then * by getClass().getName() order, and then by Comparator order * among elements of the same class. On lookup at a node, if * elements are not comparable or compare as 0, both left and * right children may need to be searched in the case of tied hash * values. (This corresponds to the full list search that would be * necessary if all elements were non-Comparable and had tied * hashes.) The red-black balancing code is updated from * pre-jdk-collections * (http://gee.cs.oswego.edu/dl/classes/collections/RBCell.java) * based in turn on Cormen, Leiserson, and Rivest "Introduction to * Algorithms" (CLR). * * TreeBins also maintain a separate locking discipline than * regular bins. Because they are forwarded via special MOVED * nodes at bin heads (which can never change once established), * we cannot use those nodes as locks. Instead, TreeBin * extends AbstractQueuedSynchronizer to support a simple form of * read-write lock. For update operations and table validation, * the exclusive form of lock behaves in the same way as bin-head * locks. However, lookups use shared read-lock mechanics to allow * multiple readers in the absence of writers. Additionally, * these lookups do not ever block: While the lock is not * available, they proceed along the slow traversal path (via * next-pointers) until the lock becomes available or the list is * exhausted, whichever comes first. (These cases are not fast, * but maximize aggregate expected throughput.) The AQS mechanics * for doing this are straightforward. The lock state is held as * AQS getState(). Read counts are negative; the write count (1) * is positive. There are no signalling preferences among readers * and writers. Since we don't need to export full Lock API, we * just override the minimal AQS methods and use them directly. */ static final class TreeBin extends AbstractQueuedSynchronizer { private static final long serialVersionUID = 2249069246763182397L; transient TreeNode root; // root of tree transient TreeNode first; // head of next-pointer list /* AQS overrides */ public final boolean isHeldExclusively() { return getState() > 0; } public final boolean tryAcquire(int ignore) { if (compareAndSetState(0, 1)) { setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } public final boolean tryRelease(int ignore) { setExclusiveOwnerThread(null); setState(0); return true; } public final int tryAcquireShared(int ignore) { for (int c;;) { if ((c = getState()) > 0) return -1; if (compareAndSetState(c, c -1)) return 1; } } public final boolean tryReleaseShared(int ignore) { int c; do {} while (!compareAndSetState(c = getState(), c + 1)); return c == -1; } /** From CLR */ private void rotateLeft(TreeNode p) { if (p != null) { TreeNode r = p.right, pp, rl; if ((rl = p.right = r.left) != null) rl.parent = p; if ((pp = r.parent = p.parent) == null) root = r; else if (pp.left == p) pp.left = r; else pp.right = r; r.left = p; p.parent = r; } } /** From CLR */ private void rotateRight(TreeNode p) { if (p != null) { TreeNode l = p.left, pp, lr; if ((lr = p.left = l.right) != null) lr.parent = p; if ((pp = l.parent = p.parent) == null) root = l; else if (pp.right == p) pp.right = l; else pp.left = l; l.right = p; p.parent = l; } } @SuppressWarnings("unchecked") final TreeNode getTreeNode (int h, Object k, TreeNode p) { return getTreeNode(h, (RubyObject)k, p); } /** * Returns the TreeNode (or null if not found) for the given key * starting at given root. */ @SuppressWarnings("unchecked") final TreeNode getTreeNode (int h, RubyObject k, TreeNode p) { RubyClass c = k.getMetaClass(); boolean kNotComparable = !k.respondsTo("<=>"); while (p != null) { int dir, ph; RubyObject pk; RubyClass pc; if ((ph = p.hash) == h) { if ((pk = (RubyObject)p.key) == k || k.equals(pk)) return p; if (c != (pc = (RubyClass)pk.getMetaClass()) || kNotComparable || (dir = rubyCompare(k, pk)) == 0) { dir = (c == pc) ? 0 : c.getName().compareTo(pc.getName()); if (dir == 0) { // if still stuck, need to check both sides TreeNode r = null, pl, pr; // try to recurse on the right if ((pr = p.right) != null && h >= pr.hash && (r = getTreeNode(h, k, pr)) != null) return r; // try to continue iterating on the left side else if ((pl = p.left) != null && h <= pl.hash) dir = -1; else // no matching node found return null; } } } else dir = (h < ph) ? -1 : 1; p = (dir > 0) ? p.right : p.left; } return null; } int rubyCompare(RubyObject l, RubyObject r) { ThreadContext context = l.getMetaClass().getRuntime().getCurrentContext(); IRubyObject result; try { result = l.callMethod(context, "<=>", r); } catch (RaiseException e) { // handle objects "lying" about responding to <=>, ie: an Array containing non-comparable keys if (context.runtime.getNoMethodError().isInstance(e.getException())) { return 0; } throw e; } return result.isNil() ? 0 : RubyNumeric.num2int(result.convertToInteger()); } /** * Wrapper for getTreeNode used by CHM.get. Tries to obtain * read-lock to call getTreeNode, but during failure to get * lock, searches along next links. */ final Object getValue(int h, Object k) { Node r = null; int c = getState(); // Must read lock state first for (Node e = first; e != null; e = e.next) { if (c <= 0 && compareAndSetState(c, c - 1)) { try { r = getTreeNode(h, k, root); } finally { releaseShared(0); } break; } else if ((e.hash & HASH_BITS) == h && k.equals(e.key)) { r = e; break; } else c = getState(); } return r == null ? null : r.val; } @SuppressWarnings("unchecked") final TreeNode putTreeNode (int h, Object k, Object v) { return putTreeNode(h, (RubyObject)k, v); } /** * Finds or adds a node. * @return null if added */ @SuppressWarnings("unchecked") final TreeNode putTreeNode (int h, RubyObject k, Object v) { RubyClass c = k.getMetaClass(); boolean kNotComparable = !k.respondsTo("<=>"); TreeNode pp = root, p = null; int dir = 0; while (pp != null) { // find existing node or leaf to insert at int ph; RubyObject pk; RubyClass pc; p = pp; if ((ph = p.hash) == h) { if ((pk = (RubyObject)p.key) == k || k.equals(pk)) return p; if (c != (pc = pk.getMetaClass()) || kNotComparable || (dir = rubyCompare(k, pk)) == 0) { dir = (c == pc) ? 0 : c.getName().compareTo(pc.getName()); if (dir == 0) { // if still stuck, need to check both sides TreeNode r = null, pr; // try to recurse on the right if ((pr = p.right) != null && h >= pr.hash && (r = getTreeNode(h, k, pr)) != null) return r; else // continue descending down the left subtree dir = -1; } } } else dir = (h < ph) ? -1 : 1; pp = (dir > 0) ? p.right : p.left; } TreeNode f = first; TreeNode x = first = new TreeNode(h, (Object)k, v, f, p); if (p == null) root = x; else { // attach and rebalance; adapted from CLR TreeNode xp, xpp; if (f != null) f.prev = x; if (dir <= 0) p.left = x; else p.right = x; x.red = true; while (x != null && (xp = x.parent) != null && xp.red && (xpp = xp.parent) != null) { TreeNode xppl = xpp.left; if (xp == xppl) { TreeNode y = xpp.right; if (y != null && y.red) { y.red = false; xp.red = false; xpp.red = true; x = xpp; } else { if (x == xp.right) { rotateLeft(x = xp); xpp = (xp = x.parent) == null ? null : xp.parent; } if (xp != null) { xp.red = false; if (xpp != null) { xpp.red = true; rotateRight(xpp); } } } } else { TreeNode y = xppl; if (y != null && y.red) { y.red = false; xp.red = false; xpp.red = true; x = xpp; } else { if (x == xp.left) { rotateRight(x = xp); xpp = (xp = x.parent) == null ? null : xp.parent; } if (xp != null) { xp.red = false; if (xpp != null) { xpp.red = true; rotateLeft(xpp); } } } } } TreeNode r = root; if (r != null && r.red) r.red = false; } return null; } /** * Removes the given node, that must be present before this * call. This is messier than typical red-black deletion code * because we cannot swap the contents of an interior node * with a leaf successor that is pinned by "next" pointers * that are accessible independently of lock. So instead we * swap the tree linkages. */ final void deleteTreeNode(TreeNode p) { TreeNode next = (TreeNode)p.next; // unlink traversal pointers TreeNode pred = p.prev; if (pred == null) first = next; else pred.next = next; if (next != null) next.prev = pred; TreeNode replacement; TreeNode pl = p.left; TreeNode pr = p.right; if (pl != null && pr != null) { TreeNode s = pr, sl; while ((sl = s.left) != null) // find successor s = sl; boolean c = s.red; s.red = p.red; p.red = c; // swap colors TreeNode sr = s.right; TreeNode pp = p.parent; if (s == pr) { // p was s's direct parent p.parent = s; s.right = p; } else { TreeNode sp = s.parent; if ((p.parent = sp) != null) { if (s == sp.left) sp.left = p; else sp.right = p; } if ((s.right = pr) != null) pr.parent = s; } p.left = null; if ((p.right = sr) != null) sr.parent = p; if ((s.left = pl) != null) pl.parent = s; if ((s.parent = pp) == null) root = s; else if (p == pp.left) pp.left = s; else pp.right = s; replacement = sr; } else replacement = (pl != null) ? pl : pr; TreeNode pp = p.parent; if (replacement == null) { if (pp == null) { root = null; return; } replacement = p; } else { replacement.parent = pp; if (pp == null) root = replacement; else if (p == pp.left) pp.left = replacement; else pp.right = replacement; p.left = p.right = p.parent = null; } if (!p.red) { // rebalance, from CLR TreeNode x = replacement; while (x != null) { TreeNode xp, xpl; if (x.red || (xp = x.parent) == null) { x.red = false; break; } if (x == (xpl = xp.left)) { TreeNode sib = xp.right; if (sib != null && sib.red) { sib.red = false; xp.red = true; rotateLeft(xp); sib = (xp = x.parent) == null ? null : xp.right; } if (sib == null) x = xp; else { TreeNode sl = sib.left, sr = sib.right; if ((sr == null || !sr.red) && (sl == null || !sl.red)) { sib.red = true; x = xp; } else { if (sr == null || !sr.red) { if (sl != null) sl.red = false; sib.red = true; rotateRight(sib); sib = (xp = x.parent) == null ? null : xp.right; } if (sib != null) { sib.red = (xp == null) ? false : xp.red; if ((sr = sib.right) != null) sr.red = false; } if (xp != null) { xp.red = false; rotateLeft(xp); } x = root; } } } else { // symmetric TreeNode sib = xpl; if (sib != null && sib.red) { sib.red = false; xp.red = true; rotateRight(xp); sib = (xp = x.parent) == null ? null : xp.left; } if (sib == null) x = xp; else { TreeNode sl = sib.left, sr = sib.right; if ((sl == null || !sl.red) && (sr == null || !sr.red)) { sib.red = true; x = xp; } else { if (sl == null || !sl.red) { if (sr != null) sr.red = false; sib.red = true; rotateLeft(sib); sib = (xp = x.parent) == null ? null : xp.left; } if (sib != null) { sib.red = (xp == null) ? false : xp.red; if ((sl = sib.left) != null) sl.red = false; } if (xp != null) { xp.red = false; rotateRight(xp); } x = root; } } } } } if (p == replacement && (pp = p.parent) != null) { if (p == pp.left) // detach pointers pp.left = null; else if (p == pp.right) pp.right = null; p.parent = null; } } } /* ---------------- Collision reduction methods -------------- */ /** * Spreads higher bits to lower, and also forces top 2 bits to 0. * Because the table uses power-of-two masking, sets of hashes * that vary only in bits above the current mask will always * collide. (Among known examples are sets of Float keys holding * consecutive whole numbers in small tables.) To counter this, * we apply a transform that spreads the impact of higher bits * downward. There is a tradeoff between speed, utility, and * quality of bit-spreading. Because many common sets of hashes * are already reasonably distributed across bits (so don't benefit * from spreading), and because we use trees to handle large sets * of collisions in bins, we don't need excessively high quality. */ private static final int spread(int h) { h ^= (h >>> 18) ^ (h >>> 12); return (h ^ (h >>> 10)) & HASH_BITS; } /** * Replaces a list bin with a tree bin. Call only when locked. * Fails to replace if the given key is non-comparable or table * is, or needs, resizing. */ private final void replaceWithTreeBin(AtomicReferenceArray tab, int index, Object key) { if ((key instanceof Comparable) && (tab.length() >= MAXIMUM_CAPACITY || counter.sum() < (long)sizeCtl)) { TreeBin t = new TreeBin(); for (Node e = tabAt(tab, index); e != null; e = e.next) t.putTreeNode(e.hash & HASH_BITS, e.key, e.val); setTabAt(tab, index, new Node(MOVED, t, null, null)); } } /* ---------------- Internal access and update methods -------------- */ /** Implementation for get and containsKey */ private final Object internalGet(Object k) { int h = spread(k.hashCode()); retry: for (AtomicReferenceArray tab = table; tab != null;) { Node e, p; Object ek, ev; int eh; // locals to read fields once for (e = tabAt(tab, (tab.length() - 1) & h); e != null; e = e.next) { if ((eh = e.hash) == MOVED) { if ((ek = e.key) instanceof TreeBin) // search TreeBin return ((TreeBin)ek).getValue(h, k); else { // restart with new table tab = (AtomicReferenceArray)ek; continue retry; } } else if ((eh & HASH_BITS) == h && (ev = e.val) != null && ((ek = e.key) == k || k.equals(ek))) return ev; } break; } return null; } /** * Implementation for the four public remove/replace methods: * Replaces node value with v, conditional upon match of cv if * non-null. If resulting value is null, delete. */ private final Object internalReplace(Object k, Object v, Object cv) { int h = spread(k.hashCode()); Object oldVal = null; for (AtomicReferenceArray tab = table;;) { Node f; int i, fh; Object fk; if (tab == null || (f = tabAt(tab, i = (tab.length() - 1) & h)) == null) break; else if ((fh = f.hash) == MOVED) { if ((fk = f.key) instanceof TreeBin) { TreeBin t = (TreeBin)fk; boolean validated = false; boolean deleted = false; t.acquire(0); try { if (tabAt(tab, i) == f) { validated = true; TreeNode p = t.getTreeNode(h, k, t.root); if (p != null) { Object pv = p.val; if (cv == null || cv == pv || cv.equals(pv)) { oldVal = pv; if ((p.val = v) == null) { deleted = true; t.deleteTreeNode(p); } } } } } finally { t.release(0); } if (validated) { if (deleted) counter.add(-1L); break; } } else tab = (AtomicReferenceArray)fk; } else if ((fh & HASH_BITS) != h && f.next == null) // precheck break; // rules out possible existence else if ((fh & LOCKED) != 0) { checkForResize(); // try resizing if can't get lock f.tryAwaitLock(tab, i); } else if (f.casHash(fh, fh | LOCKED)) { boolean validated = false; boolean deleted = false; try { if (tabAt(tab, i) == f) { validated = true; for (Node e = f, pred = null;;) { Object ek, ev; if ((e.hash & HASH_BITS) == h && ((ev = e.val) != null) && ((ek = e.key) == k || k.equals(ek))) { if (cv == null || cv == ev || cv.equals(ev)) { oldVal = ev; if ((e.val = v) == null) { deleted = true; Node en = e.next; if (pred != null) pred.next = en; else setTabAt(tab, i, en); } } break; } pred = e; if ((e = e.next) == null) break; } } } finally { if (!f.casHash(fh | LOCKED, fh)) { f.hash = fh; synchronized (f) { f.notifyAll(); }; } } if (validated) { if (deleted) counter.add(-1L); break; } } } return oldVal; } /* * Internal versions of the six insertion methods, each a * little more complicated than the last. All have * the same basic structure as the first (internalPut): * 1. If table uninitialized, create * 2. If bin empty, try to CAS new node * 3. If bin stale, use new table * 4. if bin converted to TreeBin, validate and relay to TreeBin methods * 5. Lock and validate; if valid, scan and add or update * * The others interweave other checks and/or alternative actions: * * Plain put checks for and performs resize after insertion. * * putIfAbsent prescans for mapping without lock (and fails to add * if present), which also makes pre-emptive resize checks worthwhile. * * computeIfAbsent extends form used in putIfAbsent with additional * mechanics to deal with, calls, potential exceptions and null * returns from function call. * * compute uses the same function-call mechanics, but without * the prescans * * merge acts as putIfAbsent in the absent case, but invokes the * update function if present * * putAll attempts to pre-allocate enough table space * and more lazily performs count updates and checks. * * Someday when details settle down a bit more, it might be worth * some factoring to reduce sprawl. */ /** Implementation for put */ private final Object internalPut(Object k, Object v) { int h = spread(k.hashCode()); int count = 0; for (AtomicReferenceArray tab = table;;) { int i; Node f; int fh; Object fk; if (tab == null) tab = initTable(); else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null) { if (casTabAt(tab, i, null, new Node(h, k, v, null))) break; // no lock when adding to empty bin } else if ((fh = f.hash) == MOVED) { if ((fk = f.key) instanceof TreeBin) { TreeBin t = (TreeBin)fk; Object oldVal = null; t.acquire(0); try { if (tabAt(tab, i) == f) { count = 2; TreeNode p = t.putTreeNode(h, k, v); if (p != null) { oldVal = p.val; p.val = v; } } } finally { t.release(0); } if (count != 0) { if (oldVal != null) return oldVal; break; } } else tab = (AtomicReferenceArray)fk; } else if ((fh & LOCKED) != 0) { checkForResize(); f.tryAwaitLock(tab, i); } else if (f.casHash(fh, fh | LOCKED)) { Object oldVal = null; try { // needed in case equals() throws if (tabAt(tab, i) == f) { count = 1; for (Node e = f;; ++count) { Object ek, ev; if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && ((ek = e.key) == k || k.equals(ek))) { oldVal = ev; e.val = v; break; } Node last = e; if ((e = e.next) == null) { last.next = new Node(h, k, v, null); if (count >= TREE_THRESHOLD) replaceWithTreeBin(tab, i, k); break; } } } } finally { // unlock and signal if needed if (!f.casHash(fh | LOCKED, fh)) { f.hash = fh; synchronized (f) { f.notifyAll(); }; } } if (count != 0) { if (oldVal != null) return oldVal; if (tab.length() <= 64) count = 2; break; } } } counter.add(1L); if (count > 1) checkForResize(); return null; } /** Implementation for putIfAbsent */ private final Object internalPutIfAbsent(Object k, Object v) { int h = spread(k.hashCode()); int count = 0; for (AtomicReferenceArray tab = table;;) { int i; Node f; int fh; Object fk, fv; if (tab == null) tab = initTable(); else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null) { if (casTabAt(tab, i, null, new Node(h, k, v, null))) break; } else if ((fh = f.hash) == MOVED) { if ((fk = f.key) instanceof TreeBin) { TreeBin t = (TreeBin)fk; Object oldVal = null; t.acquire(0); try { if (tabAt(tab, i) == f) { count = 2; TreeNode p = t.putTreeNode(h, k, v); if (p != null) oldVal = p.val; } } finally { t.release(0); } if (count != 0) { if (oldVal != null) return oldVal; break; } } else tab = (AtomicReferenceArray)fk; } else if ((fh & HASH_BITS) == h && (fv = f.val) != null && ((fk = f.key) == k || k.equals(fk))) return fv; else { Node g = f.next; if (g != null) { // at least 2 nodes -- search and maybe resize for (Node e = g;;) { Object ek, ev; if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && ((ek = e.key) == k || k.equals(ek))) return ev; if ((e = e.next) == null) { checkForResize(); break; } } } if (((fh = f.hash) & LOCKED) != 0) { checkForResize(); f.tryAwaitLock(tab, i); } else if (tabAt(tab, i) == f && f.casHash(fh, fh | LOCKED)) { Object oldVal = null; try { if (tabAt(tab, i) == f) { count = 1; for (Node e = f;; ++count) { Object ek, ev; if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && ((ek = e.key) == k || k.equals(ek))) { oldVal = ev; break; } Node last = e; if ((e = e.next) == null) { last.next = new Node(h, k, v, null); if (count >= TREE_THRESHOLD) replaceWithTreeBin(tab, i, k); break; } } } } finally { if (!f.casHash(fh | LOCKED, fh)) { f.hash = fh; synchronized (f) { f.notifyAll(); }; } } if (count != 0) { if (oldVal != null) return oldVal; if (tab.length() <= 64) count = 2; break; } } } } counter.add(1L); if (count > 1) checkForResize(); return null; } /** Implementation for computeIfAbsent */ private final Object internalComputeIfAbsent(K k, Fun mf) { int h = spread(k.hashCode()); Object val = null; int count = 0; for (AtomicReferenceArray tab = table;;) { Node f; int i, fh; Object fk, fv; if (tab == null) tab = initTable(); else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null) { Node node = new Node(fh = h | LOCKED, k, null, null); if (casTabAt(tab, i, null, node)) { count = 1; try { if ((val = mf.apply(k)) != null) node.val = val; } finally { if (val == null) setTabAt(tab, i, null); if (!node.casHash(fh, h)) { node.hash = h; synchronized (node) { node.notifyAll(); }; } } } if (count != 0) break; } else if ((fh = f.hash) == MOVED) { if ((fk = f.key) instanceof TreeBin) { TreeBin t = (TreeBin)fk; boolean added = false; t.acquire(0); try { if (tabAt(tab, i) == f) { count = 1; TreeNode p = t.getTreeNode(h, k, t.root); if (p != null) val = p.val; else if ((val = mf.apply(k)) != null) { added = true; count = 2; t.putTreeNode(h, k, val); } } } finally { t.release(0); } if (count != 0) { if (!added) return val; break; } } else tab = (AtomicReferenceArray)fk; } else if ((fh & HASH_BITS) == h && (fv = f.val) != null && ((fk = f.key) == k || k.equals(fk))) return fv; else { Node g = f.next; if (g != null) { for (Node e = g;;) { Object ek, ev; if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && ((ek = e.key) == k || k.equals(ek))) return ev; if ((e = e.next) == null) { checkForResize(); break; } } } if (((fh = f.hash) & LOCKED) != 0) { checkForResize(); f.tryAwaitLock(tab, i); } else if (tabAt(tab, i) == f && f.casHash(fh, fh | LOCKED)) { boolean added = false; try { if (tabAt(tab, i) == f) { count = 1; for (Node e = f;; ++count) { Object ek, ev; if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && ((ek = e.key) == k || k.equals(ek))) { val = ev; break; } Node last = e; if ((e = e.next) == null) { if ((val = mf.apply(k)) != null) { added = true; last.next = new Node(h, k, val, null); if (count >= TREE_THRESHOLD) replaceWithTreeBin(tab, i, k); } break; } } } } finally { if (!f.casHash(fh | LOCKED, fh)) { f.hash = fh; synchronized (f) { f.notifyAll(); }; } } if (count != 0) { if (!added) return val; if (tab.length() <= 64) count = 2; break; } } } } if (val != null) { counter.add(1L); if (count > 1) checkForResize(); } return val; } /** Implementation for compute */ @SuppressWarnings("unchecked") private final Object internalCompute (K k, boolean onlyIfPresent, BiFun mf) { int h = spread(k.hashCode()); Object val = null; int delta = 0; int count = 0; for (AtomicReferenceArray tab = table;;) { Node f; int i, fh; Object fk; if (tab == null) tab = initTable(); else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null) { if (onlyIfPresent) break; Node node = new Node(fh = h | LOCKED, k, null, null); if (casTabAt(tab, i, null, node)) { try { count = 1; if ((val = mf.apply(k, null)) != null) { node.val = val; delta = 1; } } finally { if (delta == 0) setTabAt(tab, i, null); if (!node.casHash(fh, h)) { node.hash = h; synchronized (node) { node.notifyAll(); }; } } } if (count != 0) break; } else if ((fh = f.hash) == MOVED) { if ((fk = f.key) instanceof TreeBin) { TreeBin t = (TreeBin)fk; t.acquire(0); try { if (tabAt(tab, i) == f) { count = 1; TreeNode p = t.getTreeNode(h, k, t.root); Object pv; if (p == null) { if (onlyIfPresent) break; pv = null; } else pv = p.val; if ((val = mf.apply(k, (V)pv)) != null) { if (p != null) p.val = val; else { count = 2; delta = 1; t.putTreeNode(h, k, val); } } else if (p != null) { delta = -1; t.deleteTreeNode(p); } } } finally { t.release(0); } if (count != 0) break; } else tab = (AtomicReferenceArray)fk; } else if ((fh & LOCKED) != 0) { checkForResize(); f.tryAwaitLock(tab, i); } else if (f.casHash(fh, fh | LOCKED)) { try { if (tabAt(tab, i) == f) { count = 1; for (Node e = f, pred = null;; ++count) { Object ek, ev; if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && ((ek = e.key) == k || k.equals(ek))) { val = mf.apply(k, (V)ev); if (val != null) e.val = val; else { delta = -1; Node en = e.next; if (pred != null) pred.next = en; else setTabAt(tab, i, en); } break; } pred = e; if ((e = e.next) == null) { if (!onlyIfPresent && (val = mf.apply(k, null)) != null) { pred.next = new Node(h, k, val, null); delta = 1; if (count >= TREE_THRESHOLD) replaceWithTreeBin(tab, i, k); } break; } } } } finally { if (!f.casHash(fh | LOCKED, fh)) { f.hash = fh; synchronized (f) { f.notifyAll(); }; } } if (count != 0) { if (tab.length() <= 64) count = 2; break; } } } if (delta != 0) { counter.add((long)delta); if (count > 1) checkForResize(); } return val; } /** Implementation for merge */ @SuppressWarnings("unchecked") private final Object internalMerge (K k, V v, BiFun mf) { int h = spread(k.hashCode()); Object val = null; int delta = 0; int count = 0; for (AtomicReferenceArray tab = table;;) { int i; Node f; int fh; Object fk, fv; if (tab == null) tab = initTable(); else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null) { if (casTabAt(tab, i, null, new Node(h, k, v, null))) { delta = 1; val = v; break; } } else if ((fh = f.hash) == MOVED) { if ((fk = f.key) instanceof TreeBin) { TreeBin t = (TreeBin)fk; t.acquire(0); try { if (tabAt(tab, i) == f) { count = 1; TreeNode p = t.getTreeNode(h, k, t.root); val = (p == null) ? v : mf.apply((V)p.val, v); if (val != null) { if (p != null) p.val = val; else { count = 2; delta = 1; t.putTreeNode(h, k, val); } } else if (p != null) { delta = -1; t.deleteTreeNode(p); } } } finally { t.release(0); } if (count != 0) break; } else tab = (AtomicReferenceArray)fk; } else if ((fh & LOCKED) != 0) { checkForResize(); f.tryAwaitLock(tab, i); } else if (f.casHash(fh, fh | LOCKED)) { try { if (tabAt(tab, i) == f) { count = 1; for (Node e = f, pred = null;; ++count) { Object ek, ev; if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && ((ek = e.key) == k || k.equals(ek))) { val = mf.apply((V)ev, v); if (val != null) e.val = val; else { delta = -1; Node en = e.next; if (pred != null) pred.next = en; else setTabAt(tab, i, en); } break; } pred = e; if ((e = e.next) == null) { val = v; pred.next = new Node(h, k, val, null); delta = 1; if (count >= TREE_THRESHOLD) replaceWithTreeBin(tab, i, k); break; } } } } finally { if (!f.casHash(fh | LOCKED, fh)) { f.hash = fh; synchronized (f) { f.notifyAll(); }; } } if (count != 0) { if (tab.length() <= 64) count = 2; break; } } } if (delta != 0) { counter.add((long)delta); if (count > 1) checkForResize(); } return val; } /** Implementation for putAll */ private final void internalPutAll(Map m) { tryPresize(m.size()); long delta = 0L; // number of uncommitted additions boolean npe = false; // to throw exception on exit for nulls try { // to clean up counts on other exceptions for (Map.Entry entry : m.entrySet()) { Object k, v; if (entry == null || (k = entry.getKey()) == null || (v = entry.getValue()) == null) { npe = true; break; } int h = spread(k.hashCode()); for (AtomicReferenceArray tab = table;;) { int i; Node f; int fh; Object fk; if (tab == null) tab = initTable(); else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null){ if (casTabAt(tab, i, null, new Node(h, k, v, null))) { ++delta; break; } } else if ((fh = f.hash) == MOVED) { if ((fk = f.key) instanceof TreeBin) { TreeBin t = (TreeBin)fk; boolean validated = false; t.acquire(0); try { if (tabAt(tab, i) == f) { validated = true; TreeNode p = t.getTreeNode(h, k, t.root); if (p != null) p.val = v; else { t.putTreeNode(h, k, v); ++delta; } } } finally { t.release(0); } if (validated) break; } else tab = (AtomicReferenceArray)fk; } else if ((fh & LOCKED) != 0) { counter.add(delta); delta = 0L; checkForResize(); f.tryAwaitLock(tab, i); } else if (f.casHash(fh, fh | LOCKED)) { int count = 0; try { if (tabAt(tab, i) == f) { count = 1; for (Node e = f;; ++count) { Object ek, ev; if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && ((ek = e.key) == k || k.equals(ek))) { e.val = v; break; } Node last = e; if ((e = e.next) == null) { ++delta; last.next = new Node(h, k, v, null); if (count >= TREE_THRESHOLD) replaceWithTreeBin(tab, i, k); break; } } } } finally { if (!f.casHash(fh | LOCKED, fh)) { f.hash = fh; synchronized (f) { f.notifyAll(); }; } } if (count != 0) { if (count > 1) { counter.add(delta); delta = 0L; checkForResize(); } break; } } } } } finally { if (delta != 0) counter.add(delta); } if (npe) throw new NullPointerException(); } /* ---------------- Table Initialization and Resizing -------------- */ /** * Returns a power of two table size for the given desired capacity. * See Hackers Delight, sec 3.2 */ private static final int tableSizeFor(int c) { int n = c - 1; n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16; return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; } /** * Initializes table, using the size recorded in sizeCtl. */ private final AtomicReferenceArray initTable() { AtomicReferenceArray tab; int sc; while ((tab = table) == null) { if ((sc = sizeCtl) < 0) Thread.yield(); // lost initialization race; just spin else if (SIZE_CTRL_UPDATER.compareAndSet(this, sc, -1)) { try { if ((tab = table) == null) { int n = (sc > 0) ? sc : DEFAULT_CAPACITY; tab = table = new AtomicReferenceArray(n); sc = n - (n >>> 2); } } finally { sizeCtl = sc; } break; } } return tab; } /** * If table is too small and not already resizing, creates next * table and transfers bins. Rechecks occupancy after a transfer * to see if another resize is already needed because resizings * are lagging additions. */ private final void checkForResize() { AtomicReferenceArray tab; int n, sc; while ((tab = table) != null && (n = tab.length()) < MAXIMUM_CAPACITY && (sc = sizeCtl) >= 0 && counter.sum() >= (long)sc && SIZE_CTRL_UPDATER.compareAndSet(this, sc, -1)) { try { if (tab == table) { table = rebuild(tab); sc = (n << 1) - (n >>> 1); } } finally { sizeCtl = sc; } } } /** * Tries to presize table to accommodate the given number of elements. * * @param size number of elements (doesn't need to be perfectly accurate) */ private final void tryPresize(int size) { int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY : tableSizeFor(size + (size >>> 1) + 1); int sc; while ((sc = sizeCtl) >= 0) { AtomicReferenceArray tab = table; int n; if (tab == null || (n = tab.length()) == 0) { n = (sc > c) ? sc : c; if (SIZE_CTRL_UPDATER.compareAndSet(this, sc, -1)) { try { if (table == tab) { table = new AtomicReferenceArray(n); sc = n - (n >>> 2); } } finally { sizeCtl = sc; } } } else if (c <= sc || n >= MAXIMUM_CAPACITY) break; else if (SIZE_CTRL_UPDATER.compareAndSet(this, sc, -1)) { try { if (table == tab) { table = rebuild(tab); sc = (n << 1) - (n >>> 1); } } finally { sizeCtl = sc; } } } } /* * Moves and/or copies the nodes in each bin to new table. See * above for explanation. * * @return the new table */ private static final AtomicReferenceArray rebuild(AtomicReferenceArray tab) { int n = tab.length(); AtomicReferenceArray nextTab = new AtomicReferenceArray(n << 1); Node fwd = new Node(MOVED, nextTab, null, null); int[] buffer = null; // holds bins to revisit; null until needed Node rev = null; // reverse forwarder; null until needed int nbuffered = 0; // the number of bins in buffer list int bufferIndex = 0; // buffer index of current buffered bin int bin = n - 1; // current non-buffered bin or -1 if none for (int i = bin;;) { // start upwards sweep int fh; Node f; if ((f = tabAt(tab, i)) == null) { if (bin >= 0) { // Unbuffered; no lock needed (or available) if (!casTabAt(tab, i, f, fwd)) continue; } else { // transiently use a locked forwarding node Node g = new Node(MOVED|LOCKED, nextTab, null, null); if (!casTabAt(tab, i, f, g)) continue; setTabAt(nextTab, i, null); setTabAt(nextTab, i + n, null); setTabAt(tab, i, fwd); if (!g.casHash(MOVED|LOCKED, MOVED)) { g.hash = MOVED; synchronized (g) { g.notifyAll(); } } } } else if ((fh = f.hash) == MOVED) { Object fk = f.key; if (fk instanceof TreeBin) { TreeBin t = (TreeBin)fk; boolean validated = false; t.acquire(0); try { if (tabAt(tab, i) == f) { validated = true; splitTreeBin(nextTab, i, t); setTabAt(tab, i, fwd); } } finally { t.release(0); } if (!validated) continue; } } else if ((fh & LOCKED) == 0 && f.casHash(fh, fh|LOCKED)) { boolean validated = false; try { // split to lo and hi lists; copying as needed if (tabAt(tab, i) == f) { validated = true; splitBin(nextTab, i, f); setTabAt(tab, i, fwd); } } finally { if (!f.casHash(fh | LOCKED, fh)) { f.hash = fh; synchronized (f) { f.notifyAll(); }; } } if (!validated) continue; } else { if (buffer == null) // initialize buffer for revisits buffer = new int[TRANSFER_BUFFER_SIZE]; if (bin < 0 && bufferIndex > 0) { int j = buffer[--bufferIndex]; buffer[bufferIndex] = i; i = j; // swap with another bin continue; } if (bin < 0 || nbuffered >= TRANSFER_BUFFER_SIZE) { f.tryAwaitLock(tab, i); continue; // no other options -- block } if (rev == null) // initialize reverse-forwarder rev = new Node(MOVED, tab, null, null); if (tabAt(tab, i) != f || (f.hash & LOCKED) == 0) continue; // recheck before adding to list buffer[nbuffered++] = i; setTabAt(nextTab, i, rev); // install place-holders setTabAt(nextTab, i + n, rev); } if (bin > 0) i = --bin; else if (buffer != null && nbuffered > 0) { bin = -1; i = buffer[bufferIndex = --nbuffered]; } else return nextTab; } } /** * Splits a normal bin with list headed by e into lo and hi parts; * installs in given table. */ private static void splitBin(AtomicReferenceArray nextTab, int i, Node e) { int bit = nextTab.length() >>> 1; // bit to split on int runBit = e.hash & bit; Node lastRun = e, lo = null, hi = null; for (Node p = e.next; p != null; p = p.next) { int b = p.hash & bit; if (b != runBit) { runBit = b; lastRun = p; } } if (runBit == 0) lo = lastRun; else hi = lastRun; for (Node p = e; p != lastRun; p = p.next) { int ph = p.hash & HASH_BITS; Object pk = p.key, pv = p.val; if ((ph & bit) == 0) lo = new Node(ph, pk, pv, lo); else hi = new Node(ph, pk, pv, hi); } setTabAt(nextTab, i, lo); setTabAt(nextTab, i + bit, hi); } /** * Splits a tree bin into lo and hi parts; installs in given table. */ private static void splitTreeBin(AtomicReferenceArray nextTab, int i, TreeBin t) { int bit = nextTab.length() >>> 1; TreeBin lt = new TreeBin(); TreeBin ht = new TreeBin(); int lc = 0, hc = 0; for (Node e = t.first; e != null; e = e.next) { int h = e.hash & HASH_BITS; Object k = e.key, v = e.val; if ((h & bit) == 0) { ++lc; lt.putTreeNode(h, k, v); } else { ++hc; ht.putTreeNode(h, k, v); } } Node ln, hn; // throw away trees if too small if (lc <= (TREE_THRESHOLD >>> 1)) { ln = null; for (Node p = lt.first; p != null; p = p.next) ln = new Node(p.hash, p.key, p.val, ln); } else ln = new Node(MOVED, lt, null, null); setTabAt(nextTab, i, ln); if (hc <= (TREE_THRESHOLD >>> 1)) { hn = null; for (Node p = ht.first; p != null; p = p.next) hn = new Node(p.hash, p.key, p.val, hn); } else hn = new Node(MOVED, ht, null, null); setTabAt(nextTab, i + bit, hn); } /** * Implementation for clear. Steps through each bin, removing all * nodes. */ private final void internalClear() { long delta = 0L; // negative number of deletions int i = 0; AtomicReferenceArray tab = table; while (tab != null && i < tab.length()) { int fh; Object fk; Node f = tabAt(tab, i); if (f == null) ++i; else if ((fh = f.hash) == MOVED) { if ((fk = f.key) instanceof TreeBin) { TreeBin t = (TreeBin)fk; t.acquire(0); try { if (tabAt(tab, i) == f) { for (Node p = t.first; p != null; p = p.next) { if (p.val != null) { // (currently always true) p.val = null; --delta; } } t.first = null; t.root = null; ++i; } } finally { t.release(0); } } else tab = (AtomicReferenceArray)fk; } else if ((fh & LOCKED) != 0) { counter.add(delta); // opportunistically update count delta = 0L; f.tryAwaitLock(tab, i); } else if (f.casHash(fh, fh | LOCKED)) { try { if (tabAt(tab, i) == f) { for (Node e = f; e != null; e = e.next) { if (e.val != null) { // (currently always true) e.val = null; --delta; } } setTabAt(tab, i, null); ++i; } } finally { if (!f.casHash(fh | LOCKED, fh)) { f.hash = fh; synchronized (f) { f.notifyAll(); }; } } } } if (delta != 0) counter.add(delta); } /* ----------------Table Traversal -------------- */ /** * Encapsulates traversal for methods such as containsValue; also * serves as a base class for other iterators and bulk tasks. * * At each step, the iterator snapshots the key ("nextKey") and * value ("nextVal") of a valid node (i.e., one that, at point of * snapshot, has a non-null user value). Because val fields can * change (including to null, indicating deletion), field nextVal * might not be accurate at point of use, but still maintains the * weak consistency property of holding a value that was once * valid. To support iterator.remove, the nextKey field is not * updated (nulled out) when the iterator cannot advance. * * Internal traversals directly access these fields, as in: * {@code while (it.advance() != null) { process(it.nextKey); }} * * Exported iterators must track whether the iterator has advanced * (in hasNext vs next) (by setting/checking/nulling field * nextVal), and then extract key, value, or key-value pairs as * return values of next(). * * The iterator visits once each still-valid node that was * reachable upon iterator construction. It might miss some that * were added to a bin after the bin was visited, which is OK wrt * consistency guarantees. Maintaining this property in the face * of possible ongoing resizes requires a fair amount of * bookkeeping state that is difficult to optimize away amidst * volatile accesses. Even so, traversal maintains reasonable * throughput. * * Normally, iteration proceeds bin-by-bin traversing lists. * However, if the table has been resized, then all future steps * must traverse both the bin at the current index as well as at * (index + baseSize); and so on for further resizings. To * paranoically cope with potential sharing by users of iterators * across threads, iteration terminates if a bounds checks fails * for a table read. * * This class extends ForkJoinTask to streamline parallel * iteration in bulk operations (see BulkTask). This adds only an * int of space overhead, which is close enough to negligible in * cases where it is not needed to not worry about it. Because * ForkJoinTask is Serializable, but iterators need not be, we * need to add warning suppressions. */ @SuppressWarnings("serial") static class Traverser { final ConcurrentHashMapV8 map; Node next; // the next entry to use K nextKey; // cached key field of next V nextVal; // cached val field of next AtomicReferenceArray tab; // current table; updated if resized int index; // index of bin to use next int baseIndex; // current index of initial table int baseLimit; // index bound for initial table int baseSize; // initial table size /** Creates iterator for all entries in the table. */ Traverser(ConcurrentHashMapV8 map) { this.map = map; } /** Creates iterator for split() methods */ Traverser(Traverser it) { ConcurrentHashMapV8 m; AtomicReferenceArray t; if ((m = this.map = it.map) == null) t = null; else if ((t = it.tab) == null && // force parent tab initialization (t = it.tab = m.table) != null) it.baseLimit = it.baseSize = t.length(); this.tab = t; this.baseSize = it.baseSize; it.baseLimit = this.index = this.baseIndex = ((this.baseLimit = it.baseLimit) + it.baseIndex + 1) >>> 1; } /** * Advances next; returns nextVal or null if terminated. * See above for explanation. */ final V advance() { Node e = next; V ev = null; outer: do { if (e != null) // advance past used/skipped node e = e.next; while (e == null) { // get to next non-null bin ConcurrentHashMapV8 m; AtomicReferenceArray t; int b, i, n; Object ek; // checks must use locals if ((t = tab) != null) n = t.length(); else if ((m = map) != null && (t = tab = m.table) != null) n = baseLimit = baseSize = t.length(); else break outer; if ((b = baseIndex) >= baseLimit || (i = index) < 0 || i >= n) break outer; if ((e = tabAt(t, i)) != null && e.hash == MOVED) { if ((ek = e.key) instanceof TreeBin) e = ((TreeBin)ek).first; else { tab = (AtomicReferenceArray)ek; continue; // restarts due to null val } } // visit upper slots if present index = (i += baseSize) < n ? i : (baseIndex = b + 1); } nextKey = (K) e.key; } while ((ev = (V) e.val) == null); // skip deleted or special nodes next = e; return nextVal = ev; } public final void remove() { Object k = nextKey; if (k == null && (advance() == null || (k = nextKey) == null)) throw new IllegalStateException(); map.internalReplace(k, null, null); } public final boolean hasNext() { return nextVal != null || advance() != null; } public final boolean hasMoreElements() { return hasNext(); } public final void setRawResult(Object x) { } public R getRawResult() { return null; } public boolean exec() { return true; } } /* ---------------- Public operations -------------- */ /** * Creates a new, empty map with the default initial table size (16). */ public ConcurrentHashMapV8() { this.counter = new LongAdder(); } /** * Creates a new, empty map with an initial table size * accommodating the specified number of elements without the need * to dynamically resize. * * @param initialCapacity The implementation performs internal * sizing to accommodate this many elements. * @throws IllegalArgumentException if the initial capacity of * elements is negative */ public ConcurrentHashMapV8(int initialCapacity) { if (initialCapacity < 0) throw new IllegalArgumentException(); int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY : tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1)); this.counter = new LongAdder(); this.sizeCtl = cap; } /** * Creates a new map with the same mappings as the given map. * * @param m the map */ public ConcurrentHashMapV8(Map m) { this.counter = new LongAdder(); this.sizeCtl = DEFAULT_CAPACITY; internalPutAll(m); } /** * Creates a new, empty map with an initial table size based on * the given number of elements ({@code initialCapacity}) and * initial table density ({@code loadFactor}). * * @param initialCapacity the initial capacity. The implementation * performs internal sizing to accommodate this many elements, * given the specified load factor. * @param loadFactor the load factor (table density) for * establishing the initial table size * @throws IllegalArgumentException if the initial capacity of * elements is negative or the load factor is nonpositive * * @since 1.6 */ public ConcurrentHashMapV8(int initialCapacity, float loadFactor) { this(initialCapacity, loadFactor, 1); } /** * Creates a new, empty map with an initial table size based on * the given number of elements ({@code initialCapacity}), table * density ({@code loadFactor}), and number of concurrently * updating threads ({@code concurrencyLevel}). * * @param initialCapacity the initial capacity. The implementation * performs internal sizing to accommodate this many elements, * given the specified load factor. * @param loadFactor the load factor (table density) for * establishing the initial table size * @param concurrencyLevel the estimated number of concurrently * updating threads. The implementation may use this value as * a sizing hint. * @throws IllegalArgumentException if the initial capacity is * negative or the load factor or concurrencyLevel are * nonpositive */ public ConcurrentHashMapV8(int initialCapacity, float loadFactor, int concurrencyLevel) { if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0) throw new IllegalArgumentException(); if (initialCapacity < concurrencyLevel) // Use at least as many bins initialCapacity = concurrencyLevel; // as estimated threads long size = (long)(1.0 + (long)initialCapacity / loadFactor); int cap = (size >= (long)MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : tableSizeFor((int)size); this.counter = new LongAdder(); this.sizeCtl = cap; } /** * Creates a new {@link Set} backed by a ConcurrentHashMapV8 * from the given type to {@code Boolean.TRUE}. * * @return the new set */ public static KeySetView newKeySet() { return new KeySetView(new ConcurrentHashMapV8(), Boolean.TRUE); } /** * Creates a new {@link Set} backed by a ConcurrentHashMapV8 * from the given type to {@code Boolean.TRUE}. * * @param initialCapacity The implementation performs internal * sizing to accommodate this many elements. * @throws IllegalArgumentException if the initial capacity of * elements is negative * @return the new set */ public static KeySetView newKeySet(int initialCapacity) { return new KeySetView(new ConcurrentHashMapV8(initialCapacity), Boolean.TRUE); } /** * {@inheritDoc} */ public boolean isEmpty() { return counter.sum() <= 0L; // ignore transient negative values } /** * {@inheritDoc} */ public int size() { long n = counter.sum(); return ((n < 0L) ? 0 : (n > (long)Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int)n); } /** * Returns the number of mappings. This method should be used * instead of {@link #size} because a ConcurrentHashMapV8 may * contain more mappings than can be represented as an int. The * value returned is a snapshot; the actual count may differ if * there are ongoing concurrent insertions or removals. * * @return the number of mappings */ public long mappingCount() { long n = counter.sum(); return (n < 0L) ? 0L : n; // ignore transient negative values } /** * Returns the value to which the specified key is mapped, * or {@code null} if this map contains no mapping for the key. * *

More formally, if this map contains a mapping from a key * {@code k} to a value {@code v} such that {@code key.equals(k)}, * then this method returns {@code v}; otherwise it returns * {@code null}. (There can be at most one such mapping.) * * @throws NullPointerException if the specified key is null */ @SuppressWarnings("unchecked") public V get(Object key) { if (key == null) throw new NullPointerException(); return (V)internalGet(key); } /** * Returns the value to which the specified key is mapped, * or the given defaultValue if this map contains no mapping for the key. * * @param key the key * @param defaultValue the value to return if this map contains * no mapping for the given key * @return the mapping for the key, if present; else the defaultValue * @throws NullPointerException if the specified key is null */ @SuppressWarnings("unchecked") public V getValueOrDefault(Object key, V defaultValue) { if (key == null) throw new NullPointerException(); V v = (V) internalGet(key); return v == null ? defaultValue : v; } /** * Tests if the specified object is a key in this table. * * @param key possible key * @return {@code true} if and only if the specified object * is a key in this table, as determined by the * {@code equals} method; {@code false} otherwise * @throws NullPointerException if the specified key is null */ public boolean containsKey(Object key) { if (key == null) throw new NullPointerException(); return internalGet(key) != null; } /** * Returns {@code true} if this map maps one or more keys to the * specified value. Note: This method may require a full traversal * of the map, and is much slower than method {@code containsKey}. * * @param value value whose presence in this map is to be tested * @return {@code true} if this map maps one or more keys to the * specified value * @throws NullPointerException if the specified value is null */ public boolean containsValue(Object value) { if (value == null) throw new NullPointerException(); Object v; Traverser it = new Traverser(this); while ((v = it.advance()) != null) { if (v == value || value.equals(v)) return true; } return false; } public K findKey(Object value) { if (value == null) throw new NullPointerException(); Object v; Traverser it = new Traverser(this); while ((v = it.advance()) != null) { if (v == value || value.equals(v)) return it.nextKey; } return null; } /** * Legacy method testing if some key maps into the specified value * in this table. This method is identical in functionality to * {@link #containsValue}, and exists solely to ensure * full compatibility with class {@link java.util.Hashtable}, * which supported this method prior to introduction of the * Java Collections framework. * * @param value a value to search for * @return {@code true} if and only if some key maps to the * {@code value} argument in this table as * determined by the {@code equals} method; * {@code false} otherwise * @throws NullPointerException if the specified value is null */ public boolean contains(Object value) { return containsValue(value); } /** * Maps the specified key to the specified value in this table. * Neither the key nor the value can be null. * *

The value can be retrieved by calling the {@code get} method * with a key that is equal to the original key. * * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * @return the previous value associated with {@code key}, or * {@code null} if there was no mapping for {@code key} * @throws NullPointerException if the specified key or value is null */ @SuppressWarnings("unchecked") public V put(K key, V value) { if (key == null || value == null) throw new NullPointerException(); return (V)internalPut(key, value); } /** * {@inheritDoc} * * @return the previous value associated with the specified key, * or {@code null} if there was no mapping for the key * @throws NullPointerException if the specified key or value is null */ @SuppressWarnings("unchecked") public V putIfAbsent(K key, V value) { if (key == null || value == null) throw new NullPointerException(); return (V)internalPutIfAbsent(key, value); } /** * Copies all of the mappings from the specified map to this one. * These mappings replace any mappings that this map had for any of the * keys currently in the specified map. * * @param m mappings to be stored in this map */ public void putAll(Map m) { internalPutAll(m); } /** * If the specified key is not already associated with a value, * computes its value using the given mappingFunction and enters * it into the map unless null. This is equivalent to *

 {@code
     * if (map.containsKey(key))
     *   return map.get(key);
     * value = mappingFunction.apply(key);
     * if (value != null)
     *   map.put(key, value);
     * return value;}
* * except that the action is performed atomically. If the * function returns {@code null} no mapping is recorded. If the * function itself throws an (unchecked) exception, the exception * is rethrown to its caller, and no mapping is recorded. Some * attempted update operations on this map by other threads may be * blocked while computation is in progress, so the computation * should be short and simple, and must not attempt to update any * other mappings of this Map. The most appropriate usage is to * construct a new object serving as an initial mapped value, or * memoized result, as in: * *
 {@code
     * map.computeIfAbsent(key, new Fun() {
     *   public V map(K k) { return new Value(f(k)); }});}
* * @param key key with which the specified value is to be associated * @param mappingFunction the function to compute a value * @return the current (existing or computed) value associated with * the specified key, or null if the computed value is null * @throws NullPointerException if the specified key or mappingFunction * is null * @throws IllegalStateException if the computation detectably * attempts a recursive update to this map that would * otherwise never complete * @throws RuntimeException or Error if the mappingFunction does so, * in which case the mapping is left unestablished */ @SuppressWarnings("unchecked") public V computeIfAbsent (K key, Fun mappingFunction) { if (key == null || mappingFunction == null) throw new NullPointerException(); return (V)internalComputeIfAbsent(key, mappingFunction); } /** * If the given key is present, computes a new mapping value given a key and * its current mapped value. This is equivalent to *
 {@code
     *   if (map.containsKey(key)) {
     *     value = remappingFunction.apply(key, map.get(key));
     *     if (value != null)
     *       map.put(key, value);
     *     else
     *       map.remove(key);
     *   }
     * }
* * except that the action is performed atomically. If the * function returns {@code null}, the mapping is removed. If the * function itself throws an (unchecked) exception, the exception * is rethrown to its caller, and the current mapping is left * unchanged. Some attempted update operations on this map by * other threads may be blocked while computation is in progress, * so the computation should be short and simple, and must not * attempt to update any other mappings of this Map. For example, * to either create or append new messages to a value mapping: * * @param key key with which the specified value is to be associated * @param remappingFunction the function to compute a value * @return the new value associated with the specified key, or null if none * @throws NullPointerException if the specified key or remappingFunction * is null * @throws IllegalStateException if the computation detectably * attempts a recursive update to this map that would * otherwise never complete * @throws RuntimeException or Error if the remappingFunction does so, * in which case the mapping is unchanged */ @SuppressWarnings("unchecked") public V computeIfPresent (K key, BiFun remappingFunction) { if (key == null || remappingFunction == null) throw new NullPointerException(); return (V)internalCompute(key, true, remappingFunction); } /** * Computes a new mapping value given a key and * its current mapped value (or {@code null} if there is no current * mapping). This is equivalent to *
 {@code
     *   value = remappingFunction.apply(key, map.get(key));
     *   if (value != null)
     *     map.put(key, value);
     *   else
     *     map.remove(key);
     * }
* * except that the action is performed atomically. If the * function returns {@code null}, the mapping is removed. If the * function itself throws an (unchecked) exception, the exception * is rethrown to its caller, and the current mapping is left * unchanged. Some attempted update operations on this map by * other threads may be blocked while computation is in progress, * so the computation should be short and simple, and must not * attempt to update any other mappings of this Map. For example, * to either create or append new messages to a value mapping: * *
 {@code
     * Map map = ...;
     * final String msg = ...;
     * map.compute(key, new BiFun() {
     *   public String apply(Key k, String v) {
     *    return (v == null) ? msg : v + msg;});}}
* * @param key key with which the specified value is to be associated * @param remappingFunction the function to compute a value * @return the new value associated with the specified key, or null if none * @throws NullPointerException if the specified key or remappingFunction * is null * @throws IllegalStateException if the computation detectably * attempts a recursive update to this map that would * otherwise never complete * @throws RuntimeException or Error if the remappingFunction does so, * in which case the mapping is unchanged */ @SuppressWarnings("unchecked") public V compute (K key, BiFun remappingFunction) { if (key == null || remappingFunction == null) throw new NullPointerException(); return (V)internalCompute(key, false, remappingFunction); } /** * If the specified key is not already associated * with a value, associate it with the given value. * Otherwise, replace the value with the results of * the given remapping function. This is equivalent to: *
 {@code
     *   if (!map.containsKey(key))
     *     map.put(value);
     *   else {
     *     newValue = remappingFunction.apply(map.get(key), value);
     *     if (value != null)
     *       map.put(key, value);
     *     else
     *       map.remove(key);
     *   }
     * }
* except that the action is performed atomically. If the * function returns {@code null}, the mapping is removed. If the * function itself throws an (unchecked) exception, the exception * is rethrown to its caller, and the current mapping is left * unchanged. Some attempted update operations on this map by * other threads may be blocked while computation is in progress, * so the computation should be short and simple, and must not * attempt to update any other mappings of this Map. */ @SuppressWarnings("unchecked") public V merge (K key, V value, BiFun remappingFunction) { if (key == null || value == null || remappingFunction == null) throw new NullPointerException(); return (V)internalMerge(key, value, remappingFunction); } /** * Removes the key (and its corresponding value) from this map. * This method does nothing if the key is not in the map. * * @param key the key that needs to be removed * @return the previous value associated with {@code key}, or * {@code null} if there was no mapping for {@code key} * @throws NullPointerException if the specified key is null */ @SuppressWarnings("unchecked") public V remove(Object key) { if (key == null) throw new NullPointerException(); return (V)internalReplace(key, null, null); } /** * {@inheritDoc} * * @throws NullPointerException if the specified key is null */ public boolean remove(Object key, Object value) { if (key == null) throw new NullPointerException(); if (value == null) return false; return internalReplace(key, null, value) != null; } /** * {@inheritDoc} * * @throws NullPointerException if any of the arguments are null */ public boolean replace(K key, V oldValue, V newValue) { if (key == null || oldValue == null || newValue == null) throw new NullPointerException(); return internalReplace(key, newValue, oldValue) != null; } /** * {@inheritDoc} * * @return the previous value associated with the specified key, * or {@code null} if there was no mapping for the key * @throws NullPointerException if the specified key or value is null */ @SuppressWarnings("unchecked") public V replace(K key, V value) { if (key == null || value == null) throw new NullPointerException(); return (V)internalReplace(key, value, null); } /** * Removes all of the mappings from this map. */ public void clear() { internalClear(); } /** * Returns a {@link Set} view of the keys contained in this map. * The set is backed by the map, so changes to the map are * reflected in the set, and vice-versa. * * @return the set view */ public KeySetView keySet() { KeySetView ks = keySet; return (ks != null) ? ks : (keySet = new KeySetView(this, null)); } /** * Returns a {@link Set} view of the keys in this map, using the * given common mapped value for any additions (i.e., {@link * Collection#add} and {@link Collection#addAll}). This is of * course only appropriate if it is acceptable to use the same * value for all additions from this view. * * @param mappedValue the mapped value to use for any * additions. * @return the set view * @throws NullPointerException if the mappedValue is null */ public KeySetView keySet(V mappedValue) { if (mappedValue == null) throw new NullPointerException(); return new KeySetView(this, mappedValue); } /** * Returns a {@link Collection} view of the values contained in this map. * The collection is backed by the map, so changes to the map are * reflected in the collection, and vice-versa. */ public ValuesView values() { ValuesView vs = values; return (vs != null) ? vs : (values = new ValuesView(this)); } /** * Returns a {@link Set} view of the mappings contained in this map. * The set is backed by the map, so changes to the map are * reflected in the set, and vice-versa. The set supports element * removal, which removes the corresponding mapping from the map, * via the {@code Iterator.remove}, {@code Set.remove}, * {@code removeAll}, {@code retainAll}, and {@code clear} * operations. It does not support the {@code add} or * {@code addAll} operations. * *

The view's {@code iterator} is a "weakly consistent" iterator * that will never throw {@link ConcurrentModificationException}, * and guarantees to traverse elements as they existed upon * construction of the iterator, and may (but is not guaranteed to) * reflect any modifications subsequent to construction. */ public Set> entrySet() { EntrySetView es = entrySet; return (es != null) ? es : (entrySet = new EntrySetView(this)); } /** * Returns an enumeration of the keys in this table. * * @return an enumeration of the keys in this table * @see #keySet() */ public Enumeration keys() { return new KeyIterator(this); } /** * Returns an enumeration of the values in this table. * * @return an enumeration of the values in this table * @see #values() */ public Enumeration elements() { return new ValueIterator(this); } /** * Returns a partitionable iterator of the keys in this map. * * @return a partitionable iterator of the keys in this map */ public Spliterator keySpliterator() { return new KeyIterator(this); } /** * Returns a partitionable iterator of the values in this map. * * @return a partitionable iterator of the values in this map */ public Spliterator valueSpliterator() { return new ValueIterator(this); } /** * Returns a partitionable iterator of the entries in this map. * * @return a partitionable iterator of the entries in this map */ public Spliterator> entrySpliterator() { return new EntryIterator(this); } /** * Returns the hash code value for this {@link Map}, i.e., * the sum of, for each key-value pair in the map, * {@code key.hashCode() ^ value.hashCode()}. * * @return the hash code value for this map */ public int hashCode() { int h = 0; Traverser it = new Traverser(this); Object v; while ((v = it.advance()) != null) { h += it.nextKey.hashCode() ^ v.hashCode(); } return h; } /** * Returns a string representation of this map. The string * representation consists of a list of key-value mappings (in no * particular order) enclosed in braces ("{@code {}}"). Adjacent * mappings are separated by the characters {@code ", "} (comma * and space). Each key-value mapping is rendered as the key * followed by an equals sign ("{@code =}") followed by the * associated value. * * @return a string representation of this map */ public String toString() { Traverser it = new Traverser(this); StringBuilder sb = new StringBuilder(); sb.append('{'); Object v; if ((v = it.advance()) != null) { for (;;) { Object k = it.nextKey; sb.append(k == this ? "(this Map)" : k); sb.append('='); sb.append(v == this ? "(this Map)" : v); if ((v = it.advance()) == null) break; sb.append(',').append(' '); } } return sb.append('}').toString(); } /** * Compares the specified object with this map for equality. * Returns {@code true} if the given object is a map with the same * mappings as this map. This operation may return misleading * results if either map is concurrently modified during execution * of this method. * * @param o object to be compared for equality with this map * @return {@code true} if the specified object is equal to this map */ public boolean equals(Object o) { if (o != this) { if (!(o instanceof Map)) return false; Map m = (Map) o; Traverser it = new Traverser(this); Object val; while ((val = it.advance()) != null) { Object v = m.get(it.nextKey); if (v == null || (v != val && !v.equals(val))) return false; } for (Map.Entry e : m.entrySet()) { Object mk, mv, v; if ((mk = e.getKey()) == null || (mv = e.getValue()) == null || (v = internalGet(mk)) == null || (mv != v && !mv.equals(v))) return false; } } return true; } /* ----------------Iterators -------------- */ @SuppressWarnings("serial") static final class KeyIterator extends Traverser implements Spliterator, Enumeration { KeyIterator(ConcurrentHashMapV8 map) { super(map); } KeyIterator(Traverser it) { super(it); } public KeyIterator split() { if (nextKey != null) throw new IllegalStateException(); return new KeyIterator(this); } @SuppressWarnings("unchecked") public final K next() { if (nextVal == null && advance() == null) throw new NoSuchElementException(); Object k = nextKey; nextVal = null; return (K) k; } public final K nextElement() { return next(); } } @SuppressWarnings("serial") static final class ValueIterator extends Traverser implements Spliterator, Enumeration { ValueIterator(ConcurrentHashMapV8 map) { super(map); } ValueIterator(Traverser it) { super(it); } public ValueIterator split() { if (nextKey != null) throw new IllegalStateException(); return new ValueIterator(this); } @SuppressWarnings("unchecked") public final V next() { Object v; if ((v = nextVal) == null && (v = advance()) == null) throw new NoSuchElementException(); nextVal = null; return (V) v; } public final V nextElement() { return next(); } } @SuppressWarnings("serial") static final class EntryIterator extends Traverser implements Spliterator> { EntryIterator(ConcurrentHashMapV8 map) { super(map); } EntryIterator(Traverser it) { super(it); } public EntryIterator split() { if (nextKey != null) throw new IllegalStateException(); return new EntryIterator(this); } @SuppressWarnings("unchecked") public final Map.Entry next() { Object v; if ((v = nextVal) == null && (v = advance()) == null) throw new NoSuchElementException(); Object k = nextKey; nextVal = null; return new MapEntry((K)k, (V)v, map); } } /** * Exported Entry for iterators */ static final class MapEntry implements Map.Entry { final K key; // non-null V val; // non-null final ConcurrentHashMapV8 map; MapEntry(K key, V val, ConcurrentHashMapV8 map) { this.key = key; this.val = val; this.map = map; } public final K getKey() { return key; } public final V getValue() { return val; } public final int hashCode() { return key.hashCode() ^ val.hashCode(); } public final String toString(){ return key + "=" + val; } public final boolean equals(Object o) { Object k, v; Map.Entry e; return ((o instanceof Map.Entry) && (k = (e = (Map.Entry)o).getKey()) != null && (v = e.getValue()) != null && (k == key || k.equals(key)) && (v == val || v.equals(val))); } /** * Sets our entry's value and writes through to the map. The * value to return is somewhat arbitrary here. Since we do not * necessarily track asynchronous changes, the most recent * "previous" value could be different from what we return (or * could even have been removed in which case the put will * re-establish). We do not and cannot guarantee more. */ public final V setValue(V value) { if (value == null) throw new NullPointerException(); V v = val; val = value; map.put(key, value); return v; } } /* ---------------- Serialization Support -------------- */ /** * Stripped-down version of helper class used in previous version, * declared for the sake of serialization compatibility */ static class Segment implements Serializable { private static final long serialVersionUID = 2249069246763182397L; final float loadFactor; Segment(float lf) { this.loadFactor = lf; } } /** * Saves the state of the {@code ConcurrentHashMapV8} instance to a * stream (i.e., serializes it). * @param s the stream * @serialData * the key (Object) and value (Object) * for each key-value mapping, followed by a null pair. * The key-value mappings are emitted in no particular order. */ @SuppressWarnings("unchecked") private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { if (segments == null) { // for serialization compatibility segments = (Segment[]) new Segment[DEFAULT_CONCURRENCY_LEVEL]; for (int i = 0; i < segments.length; ++i) segments[i] = new Segment(LOAD_FACTOR); } s.defaultWriteObject(); Traverser it = new Traverser(this); Object v; while ((v = it.advance()) != null) { s.writeObject(it.nextKey); s.writeObject(v); } s.writeObject(null); s.writeObject(null); segments = null; // throw away } /** * Reconstitutes the instance from a stream (that is, deserializes it). * @param s the stream */ @SuppressWarnings("unchecked") private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); this.segments = null; // unneeded // initialize transient final field this.counter = new LongAdder(); // Create all nodes, then place in table once size is known long size = 0L; Node p = null; for (;;) { K k = (K) s.readObject(); V v = (V) s.readObject(); if (k != null && v != null) { int h = spread(k.hashCode()); p = new Node(h, k, v, p); ++size; } else break; } if (p != null) { boolean init = false; int n; if (size >= (long)(MAXIMUM_CAPACITY >>> 1)) n = MAXIMUM_CAPACITY; else { int sz = (int)size; n = tableSizeFor(sz + (sz >>> 1) + 1); } int sc = sizeCtl; boolean collide = false; if (n > sc && SIZE_CTRL_UPDATER.compareAndSet(this, sc, -1)) { try { if (table == null) { init = true; AtomicReferenceArray tab = new AtomicReferenceArray(n); int mask = n - 1; while (p != null) { int j = p.hash & mask; Node next = p.next; Node q = p.next = tabAt(tab, j); setTabAt(tab, j, p); if (!collide && q != null && q.hash == p.hash) collide = true; p = next; } table = tab; counter.add(size); sc = n - (n >>> 2); } } finally { sizeCtl = sc; } if (collide) { // rescan and convert to TreeBins AtomicReferenceArray tab = table; for (int i = 0; i < tab.length(); ++i) { int c = 0; for (Node e = tabAt(tab, i); e != null; e = e.next) { if (++c > TREE_THRESHOLD && (e.key instanceof Comparable)) { replaceWithTreeBin(tab, i, e.key); break; } } } } } if (!init) { // Can only happen if unsafely published. while (p != null) { internalPut(p.key, p.val); p = p.next; } } } } // ------------------------------------------------------- // Sams /** Interface describing a void action of one argument */ public interface Action { void apply(A a); } /** Interface describing a void action of two arguments */ public interface BiAction { void apply(A a, B b); } /** Interface describing a function of one argument */ public interface Generator { T apply(); } /** Interface describing a function mapping its argument to a double */ public interface ObjectToDouble { double apply(A a); } /** Interface describing a function mapping its argument to a long */ public interface ObjectToLong { long apply(A a); } /** Interface describing a function mapping its argument to an int */ public interface ObjectToInt {int apply(A a); } /** Interface describing a function mapping two arguments to a double */ public interface ObjectByObjectToDouble { double apply(A a, B b); } /** Interface describing a function mapping two arguments to a long */ public interface ObjectByObjectToLong { long apply(A a, B b); } /** Interface describing a function mapping two arguments to an int */ public interface ObjectByObjectToInt {int apply(A a, B b); } /** Interface describing a function mapping a double to a double */ public interface DoubleToDouble { double apply(double a); } /** Interface describing a function mapping a long to a long */ public interface LongToLong { long apply(long a); } /** Interface describing a function mapping an int to an int */ public interface IntToInt { int apply(int a); } /** Interface describing a function mapping two doubles to a double */ public interface DoubleByDoubleToDouble { double apply(double a, double b); } /** Interface describing a function mapping two longs to a long */ public interface LongByLongToLong { long apply(long a, long b); } /** Interface describing a function mapping two ints to an int */ public interface IntByIntToInt { int apply(int a, int b); } /* ----------------Views -------------- */ /** * Base class for views. */ static abstract class CHMView { final ConcurrentHashMapV8 map; CHMView(ConcurrentHashMapV8 map) { this.map = map; } /** * Returns the map backing this view. * * @return the map backing this view */ public ConcurrentHashMapV8 getMap() { return map; } public final int size() { return map.size(); } public final boolean isEmpty() { return map.isEmpty(); } public final void clear() { map.clear(); } // implementations below rely on concrete classes supplying these abstract public Iterator iterator(); abstract public boolean contains(Object o); abstract public boolean remove(Object o); private static final String oomeMsg = "Required array size too large"; public final Object[] toArray() { long sz = map.mappingCount(); if (sz > (long)(MAX_ARRAY_SIZE)) throw new OutOfMemoryError(oomeMsg); int n = (int)sz; Object[] r = new Object[n]; int i = 0; Iterator it = iterator(); while (it.hasNext()) { if (i == n) { if (n >= MAX_ARRAY_SIZE) throw new OutOfMemoryError(oomeMsg); if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1) n = MAX_ARRAY_SIZE; else n += (n >>> 1) + 1; r = Arrays.copyOf(r, n); } r[i++] = it.next(); } return (i == n) ? r : Arrays.copyOf(r, i); } @SuppressWarnings("unchecked") public final T[] toArray(T[] a) { long sz = map.mappingCount(); if (sz > (long)(MAX_ARRAY_SIZE)) throw new OutOfMemoryError(oomeMsg); int m = (int)sz; T[] r = (a.length >= m) ? a : (T[])java.lang.reflect.Array .newInstance(a.getClass().getComponentType(), m); int n = r.length; int i = 0; Iterator it = iterator(); while (it.hasNext()) { if (i == n) { if (n >= MAX_ARRAY_SIZE) throw new OutOfMemoryError(oomeMsg); if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1) n = MAX_ARRAY_SIZE; else n += (n >>> 1) + 1; r = Arrays.copyOf(r, n); } r[i++] = (T)it.next(); } if (a == r && i < n) { r[i] = null; // null-terminate return r; } return (i == n) ? r : Arrays.copyOf(r, i); } public final int hashCode() { int h = 0; for (Iterator it = iterator(); it.hasNext();) h += it.next().hashCode(); return h; } public final String toString() { StringBuilder sb = new StringBuilder(); sb.append('['); Iterator it = iterator(); if (it.hasNext()) { for (;;) { Object e = it.next(); sb.append(e == this ? "(this Collection)" : e); if (!it.hasNext()) break; sb.append(',').append(' '); } } return sb.append(']').toString(); } public final boolean containsAll(Collection c) { if (c != this) { for (Iterator it = c.iterator(); it.hasNext();) { Object e = it.next(); if (e == null || !contains(e)) return false; } } return true; } public final boolean removeAll(Collection c) { boolean modified = false; for (Iterator it = iterator(); it.hasNext();) { if (c.contains(it.next())) { it.remove(); modified = true; } } return modified; } public final boolean retainAll(Collection c) { boolean modified = false; for (Iterator it = iterator(); it.hasNext();) { if (!c.contains(it.next())) { it.remove(); modified = true; } } return modified; } } /** * A view of a ConcurrentHashMapV8 as a {@link Set} of keys, in * which additions may optionally be enabled by mapping to a * common value. This class cannot be directly instantiated. See * {@link #keySet}, {@link #keySet(Object)}, {@link #newKeySet()}, * {@link #newKeySet(int)}. */ public static class KeySetView extends CHMView implements Set, java.io.Serializable { private static final long serialVersionUID = 7249069246763182397L; private final V value; KeySetView(ConcurrentHashMapV8 map, V value) { // non-public super(map); this.value = value; } /** * Returns the default mapped value for additions, * or {@code null} if additions are not supported. * * @return the default mapped value for additions, or {@code null} * if not supported. */ public V getMappedValue() { return value; } // implement Set API public boolean contains(Object o) { return map.containsKey(o); } public boolean remove(Object o) { return map.remove(o) != null; } /** * Returns a "weakly consistent" iterator that will never * throw {@link ConcurrentModificationException}, and * guarantees to traverse elements as they existed upon * construction of the iterator, and may (but is not * guaranteed to) reflect any modifications subsequent to * construction. * * @return an iterator over the keys of this map */ public Iterator iterator() { return new KeyIterator(map); } public boolean add(K e) { V v; if ((v = value) == null) throw new UnsupportedOperationException(); if (e == null) throw new NullPointerException(); return map.internalPutIfAbsent(e, v) == null; } public boolean addAll(Collection c) { boolean added = false; V v; if ((v = value) == null) throw new UnsupportedOperationException(); for (K e : c) { if (e == null) throw new NullPointerException(); if (map.internalPutIfAbsent(e, v) == null) added = true; } return added; } public boolean equals(Object o) { Set c; return ((o instanceof Set) && ((c = (Set)o) == this || (containsAll(c) && c.containsAll(this)))); } } /** * A view of a ConcurrentHashMapV8 as a {@link Collection} of * values, in which additions are disabled. This class cannot be * directly instantiated. See {@link #values}, * *

The view's {@code iterator} is a "weakly consistent" iterator * that will never throw {@link ConcurrentModificationException}, * and guarantees to traverse elements as they existed upon * construction of the iterator, and may (but is not guaranteed to) * reflect any modifications subsequent to construction. */ public static final class ValuesView extends CHMView implements Collection { ValuesView(ConcurrentHashMapV8 map) { super(map); } public final boolean contains(Object o) { return map.containsValue(o); } public final boolean remove(Object o) { if (o != null) { Iterator it = new ValueIterator(map); while (it.hasNext()) { if (o.equals(it.next())) { it.remove(); return true; } } } return false; } /** * Returns a "weakly consistent" iterator that will never * throw {@link ConcurrentModificationException}, and * guarantees to traverse elements as they existed upon * construction of the iterator, and may (but is not * guaranteed to) reflect any modifications subsequent to * construction. * * @return an iterator over the values of this map */ public final Iterator iterator() { return new ValueIterator(map); } public final boolean add(V e) { throw new UnsupportedOperationException(); } public final boolean addAll(Collection c) { throw new UnsupportedOperationException(); } } /** * A view of a ConcurrentHashMapV8 as a {@link Set} of (key, value) * entries. This class cannot be directly instantiated. See * {@link #entrySet}. */ public static final class EntrySetView extends CHMView implements Set> { EntrySetView(ConcurrentHashMapV8 map) { super(map); } public final boolean contains(Object o) { Object k, v, r; Map.Entry e; return ((o instanceof Map.Entry) && (k = (e = (Map.Entry)o).getKey()) != null && (r = map.get(k)) != null && (v = e.getValue()) != null && (v == r || v.equals(r))); } public final boolean remove(Object o) { Object k, v; Map.Entry e; return ((o instanceof Map.Entry) && (k = (e = (Map.Entry)o).getKey()) != null && (v = e.getValue()) != null && map.remove(k, v)); } /** * Returns a "weakly consistent" iterator that will never * throw {@link ConcurrentModificationException}, and * guarantees to traverse elements as they existed upon * construction of the iterator, and may (but is not * guaranteed to) reflect any modifications subsequent to * construction. * * @return an iterator over the entries of this map */ public final Iterator> iterator() { return new EntryIterator(map); } public final boolean add(Entry e) { K key = e.getKey(); V value = e.getValue(); if (key == null || value == null) throw new NullPointerException(); return map.internalPut(key, value) == null; } public final boolean addAll(Collection> c) { boolean added = false; for (Entry e : c) { if (add(e)) added = true; } return added; } public boolean equals(Object o) { Set c; return ((o instanceof Set) && ((c = (Set)o) == this || (containsAll(c) && c.containsAll(this)))); } } } concurrent-ruby-1.0.5/ext/com/concurrent_ruby/ext/jsr166e/nounsafe/LongAdder.java000066400000000000000000000133611305460430400300020ustar00rootroot00000000000000/* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/publicdomain/zero/1.0/ */ // This is based on 1.9 version. package com.concurrent_ruby.ext.jsr166e.nounsafe; import java.util.concurrent.atomic.AtomicLong; import java.io.IOException; import java.io.Serializable; import java.io.ObjectInputStream; /** * One or more variables that together maintain an initially zero * {@code long} sum. When updates (method {@link #add}) are contended * across threads, the set of variables may grow dynamically to reduce * contention. Method {@link #sum} (or, equivalently, {@link * #longValue}) returns the current total combined across the * variables maintaining the sum. * *

This class is usually preferable to {@link AtomicLong} when * multiple threads update a common sum that is used for purposes such * as collecting statistics, not for fine-grained synchronization * control. Under low update contention, the two classes have similar * characteristics. But under high contention, expected throughput of * this class is significantly higher, at the expense of higher space * consumption. * *

This class extends {@link Number}, but does not define * methods such as {@code hashCode} and {@code compareTo} because * instances are expected to be mutated, and so are not useful as * collection keys. * *

jsr166e note: This class is targeted to be placed in * java.util.concurrent.atomic. * * @since 1.8 * @author Doug Lea */ public class LongAdder extends Striped64 implements Serializable { private static final long serialVersionUID = 7249069246863182397L; /** * Version of plus for use in retryUpdate */ final long fn(long v, long x) { return v + x; } /** * Creates a new adder with initial sum of zero. */ public LongAdder() { } /** * Adds the given value. * * @param x the value to add */ public void add(long x) { Cell[] as; long b, v; HashCode hc; Cell a; int n; if ((as = cells) != null || !casBase(b = base, b + x)) { boolean uncontended = true; int h = (hc = threadHashCode.get()).code; if (as == null || (n = as.length) < 1 || (a = as[(n - 1) & h]) == null || !(uncontended = a.cas(v = a.value, v + x))) retryUpdate(x, hc, uncontended); } } /** * Equivalent to {@code add(1)}. */ public void increment() { add(1L); } /** * Equivalent to {@code add(-1)}. */ public void decrement() { add(-1L); } /** * Returns the current sum. The returned value is NOT an * atomic snapshot: Invocation in the absence of concurrent * updates returns an accurate result, but concurrent updates that * occur while the sum is being calculated might not be * incorporated. * * @return the sum */ public long sum() { long sum = base; Cell[] as = cells; if (as != null) { int n = as.length; for (int i = 0; i < n; ++i) { Cell a = as[i]; if (a != null) sum += a.value; } } return sum; } /** * Resets variables maintaining the sum to zero. This method may * be a useful alternative to creating a new adder, but is only * effective if there are no concurrent updates. Because this * method is intrinsically racy, it should only be used when it is * known that no threads are concurrently updating. */ public void reset() { internalReset(0L); } /** * Equivalent in effect to {@link #sum} followed by {@link * #reset}. This method may apply for example during quiescent * points between multithreaded computations. If there are * updates concurrent with this method, the returned value is * not guaranteed to be the final value occurring before * the reset. * * @return the sum */ public long sumThenReset() { long sum = base; Cell[] as = cells; base = 0L; if (as != null) { int n = as.length; for (int i = 0; i < n; ++i) { Cell a = as[i]; if (a != null) { sum += a.value; a.value = 0L; } } } return sum; } /** * Returns the String representation of the {@link #sum}. * @return the String representation of the {@link #sum} */ public String toString() { return Long.toString(sum()); } /** * Equivalent to {@link #sum}. * * @return the sum */ public long longValue() { return sum(); } /** * Returns the {@link #sum} as an {@code int} after a narrowing * primitive conversion. */ public int intValue() { return (int)sum(); } /** * Returns the {@link #sum} as a {@code float} * after a widening primitive conversion. */ public float floatValue() { return (float)sum(); } /** * Returns the {@link #sum} as a {@code double} after a widening * primitive conversion. */ public double doubleValue() { return (double)sum(); } private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { s.defaultWriteObject(); s.writeLong(sum()); } private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); busy = 0; cells = null; base = s.readLong(); } } concurrent-ruby-1.0.5/ext/com/concurrent_ruby/ext/jsr166e/nounsafe/Striped64.java000066400000000000000000000266571305460430400277430ustar00rootroot00000000000000/* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/publicdomain/zero/1.0/ */ // This is based on 1.5 version. package com.concurrent_ruby.ext.jsr166e.nounsafe; import java.util.Random; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicLongFieldUpdater; /** * A package-local class holding common representation and mechanics * for classes supporting dynamic striping on 64bit values. The class * extends Number so that concrete subclasses must publicly do so. */ abstract class Striped64 extends Number { /* * This class maintains a lazily-initialized table of atomically * updated variables, plus an extra "base" field. The table size * is a power of two. Indexing uses masked per-thread hash codes. * Nearly all declarations in this class are package-private, * accessed directly by subclasses. * * Table entries are of class Cell; a variant of AtomicLong padded * to reduce cache contention on most processors. Padding is * overkill for most Atomics because they are usually irregularly * scattered in memory and thus don't interfere much with each * other. But Atomic objects residing in arrays will tend to be * placed adjacent to each other, and so will most often share * cache lines (with a huge negative performance impact) without * this precaution. * * In part because Cells are relatively large, we avoid creating * them until they are needed. When there is no contention, all * updates are made to the base field. Upon first contention (a * failed CAS on base update), the table is initialized to size 2. * The table size is doubled upon further contention until * reaching the nearest power of two greater than or equal to the * number of CPUS. Table slots remain empty (null) until they are * needed. * * A single spinlock ("busy") is used for initializing and * resizing the table, as well as populating slots with new Cells. * There is no need for a blocking lock: When the lock is not * available, threads try other slots (or the base). During these * retries, there is increased contention and reduced locality, * which is still better than alternatives. * * Per-thread hash codes are initialized to random values. * Contention and/or table collisions are indicated by failed * CASes when performing an update operation (see method * retryUpdate). Upon a collision, if the table size is less than * the capacity, it is doubled in size unless some other thread * holds the lock. If a hashed slot is empty, and lock is * available, a new Cell is created. Otherwise, if the slot * exists, a CAS is tried. Retries proceed by "double hashing", * using a secondary hash (Marsaglia XorShift) to try to find a * free slot. * * The table size is capped because, when there are more threads * than CPUs, supposing that each thread were bound to a CPU, * there would exist a perfect hash function mapping threads to * slots that eliminates collisions. When we reach capacity, we * search for this mapping by randomly varying the hash codes of * colliding threads. Because search is random, and collisions * only become known via CAS failures, convergence can be slow, * and because threads are typically not bound to CPUS forever, * may not occur at all. However, despite these limitations, * observed contention rates are typically low in these cases. * * It is possible for a Cell to become unused when threads that * once hashed to it terminate, as well as in the case where * doubling the table causes no thread to hash to it under * expanded mask. We do not try to detect or remove such cells, * under the assumption that for long-running instances, observed * contention levels will recur, so the cells will eventually be * needed again; and for short-lived ones, it does not matter. */ /** * Padded variant of AtomicLong supporting only raw accesses plus CAS. * The value field is placed between pads, hoping that the JVM doesn't * reorder them. * * JVM intrinsics note: It would be possible to use a release-only * form of CAS here, if it were provided. */ static final class Cell { volatile long p0, p1, p2, p3, p4, p5, p6; volatile long value; volatile long q0, q1, q2, q3, q4, q5, q6; static AtomicLongFieldUpdater VALUE_UPDATER = AtomicLongFieldUpdater.newUpdater(Cell.class, "value"); Cell(long x) { value = x; } final boolean cas(long cmp, long val) { return VALUE_UPDATER.compareAndSet(this, cmp, val); } } /** * Holder for the thread-local hash code. The code is initially * random, but may be set to a different value upon collisions. */ static final class HashCode { static final Random rng = new Random(); int code; HashCode() { int h = rng.nextInt(); // Avoid zero to allow xorShift rehash code = (h == 0) ? 1 : h; } } /** * The corresponding ThreadLocal class */ static final class ThreadHashCode extends ThreadLocal { public HashCode initialValue() { return new HashCode(); } } /** * Static per-thread hash codes. Shared across all instances to * reduce ThreadLocal pollution and because adjustments due to * collisions in one table are likely to be appropriate for * others. */ static final ThreadHashCode threadHashCode = new ThreadHashCode(); /** Number of CPUS, to place bound on table size */ static final int NCPU = Runtime.getRuntime().availableProcessors(); /** * Table of cells. When non-null, size is a power of 2. */ transient volatile Cell[] cells; /** * Base value, used mainly when there is no contention, but also as * a fallback during table initialization races. Updated via CAS. */ transient volatile long base; /** * Spinlock (locked via CAS) used when resizing and/or creating Cells. */ transient volatile int busy; AtomicLongFieldUpdater BASE_UPDATER = AtomicLongFieldUpdater.newUpdater(Striped64.class, "base"); AtomicIntegerFieldUpdater BUSY_UPDATER = AtomicIntegerFieldUpdater.newUpdater(Striped64.class, "busy"); /** * Package-private default constructor */ Striped64() { } /** * CASes the base field. */ final boolean casBase(long cmp, long val) { return BASE_UPDATER.compareAndSet(this, cmp, val); } /** * CASes the busy field from 0 to 1 to acquire lock. */ final boolean casBusy() { return BUSY_UPDATER.compareAndSet(this, 0, 1); } /** * Computes the function of current and new value. Subclasses * should open-code this update function for most uses, but the * virtualized form is needed within retryUpdate. * * @param currentValue the current value (of either base or a cell) * @param newValue the argument from a user update call * @return result of the update function */ abstract long fn(long currentValue, long newValue); /** * Handles cases of updates involving initialization, resizing, * creating new Cells, and/or contention. See above for * explanation. This method suffers the usual non-modularity * problems of optimistic retry code, relying on rechecked sets of * reads. * * @param x the value * @param hc the hash code holder * @param wasUncontended false if CAS failed before call */ final void retryUpdate(long x, HashCode hc, boolean wasUncontended) { int h = hc.code; boolean collide = false; // True if last slot nonempty for (;;) { Cell[] as; Cell a; int n; long v; if ((as = cells) != null && (n = as.length) > 0) { if ((a = as[(n - 1) & h]) == null) { if (busy == 0) { // Try to attach new Cell Cell r = new Cell(x); // Optimistically create if (busy == 0 && casBusy()) { boolean created = false; try { // Recheck under lock Cell[] rs; int m, j; if ((rs = cells) != null && (m = rs.length) > 0 && rs[j = (m - 1) & h] == null) { rs[j] = r; created = true; } } finally { busy = 0; } if (created) break; continue; // Slot is now non-empty } } collide = false; } else if (!wasUncontended) // CAS already known to fail wasUncontended = true; // Continue after rehash else if (a.cas(v = a.value, fn(v, x))) break; else if (n >= NCPU || cells != as) collide = false; // At max size or stale else if (!collide) collide = true; else if (busy == 0 && casBusy()) { try { if (cells == as) { // Expand table unless stale Cell[] rs = new Cell[n << 1]; for (int i = 0; i < n; ++i) rs[i] = as[i]; cells = rs; } } finally { busy = 0; } collide = false; continue; // Retry with expanded table } h ^= h << 13; // Rehash h ^= h >>> 17; h ^= h << 5; } else if (busy == 0 && cells == as && casBusy()) { boolean init = false; try { // Initialize table if (cells == as) { Cell[] rs = new Cell[2]; rs[h & 1] = new Cell(x); cells = rs; init = true; } } finally { busy = 0; } if (init) break; } else if (casBase(v = base, fn(v, x))) break; // Fall back on using base } hc.code = h; // Record index for next time } /** * Sets base and all cells to the given value. */ final void internalReset(long initialValue) { Cell[] as = cells; base = initialValue; if (as != null) { int n = as.length; for (int i = 0; i < n; ++i) { Cell a = as[i]; if (a != null) a.value = initialValue; } } } } concurrent-ruby-1.0.5/ext/com/concurrent_ruby/ext/jsr166y/000077500000000000000000000000001305460430400235025ustar00rootroot00000000000000concurrent-ruby-1.0.5/ext/com/concurrent_ruby/ext/jsr166y/ThreadLocalRandom.java000066400000000000000000000152541305460430400276770ustar00rootroot00000000000000/* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/publicdomain/zero/1.0/ */ // This is based on 1.16 version package com.concurrent_ruby.ext.jsr166y; import java.util.Random; /** * A random number generator isolated to the current thread. Like the * global {@link java.util.Random} generator used by the {@link * java.lang.Math} class, a {@code ThreadLocalRandom} is initialized * with an internally generated seed that may not otherwise be * modified. When applicable, use of {@code ThreadLocalRandom} rather * than shared {@code Random} objects in concurrent programs will * typically encounter much less overhead and contention. Use of * {@code ThreadLocalRandom} is particularly appropriate when multiple * tasks (for example, each a {@link ForkJoinTask}) use random numbers * in parallel in thread pools. * *

Usages of this class should typically be of the form: * {@code ThreadLocalRandom.current().nextX(...)} (where * {@code X} is {@code Int}, {@code Long}, etc). * When all usages are of this form, it is never possible to * accidently share a {@code ThreadLocalRandom} across multiple threads. * *

This class also provides additional commonly used bounded random * generation methods. * * @since 1.7 * @author Doug Lea */ public class ThreadLocalRandom extends Random { // same constants as Random, but must be redeclared because private private static final long multiplier = 0x5DEECE66DL; private static final long addend = 0xBL; private static final long mask = (1L << 48) - 1; /** * The random seed. We can't use super.seed. */ private long rnd; /** * Initialization flag to permit calls to setSeed to succeed only * while executing the Random constructor. We can't allow others * since it would cause setting seed in one part of a program to * unintentionally impact other usages by the thread. */ boolean initialized; // Padding to help avoid memory contention among seed updates in // different TLRs in the common case that they are located near // each other. private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7; /** * The actual ThreadLocal */ private static final ThreadLocal localRandom = new ThreadLocal() { protected ThreadLocalRandom initialValue() { return new ThreadLocalRandom(); } }; /** * Constructor called only by localRandom.initialValue. */ ThreadLocalRandom() { super(); initialized = true; } /** * Returns the current thread's {@code ThreadLocalRandom}. * * @return the current thread's {@code ThreadLocalRandom} */ public static ThreadLocalRandom current() { return localRandom.get(); } /** * Throws {@code UnsupportedOperationException}. Setting seeds in * this generator is not supported. * * @throws UnsupportedOperationException always */ public void setSeed(long seed) { if (initialized) throw new UnsupportedOperationException(); rnd = (seed ^ multiplier) & mask; } protected int next(int bits) { rnd = (rnd * multiplier + addend) & mask; return (int) (rnd >>> (48-bits)); } /** * Returns a pseudorandom, uniformly distributed value between the * given least value (inclusive) and bound (exclusive). * * @param least the least value returned * @param bound the upper bound (exclusive) * @throws IllegalArgumentException if least greater than or equal * to bound * @return the next value */ public int nextInt(int least, int bound) { if (least >= bound) throw new IllegalArgumentException(); return nextInt(bound - least) + least; } /** * Returns a pseudorandom, uniformly distributed value * between 0 (inclusive) and the specified value (exclusive). * * @param n the bound on the random number to be returned. Must be * positive. * @return the next value * @throws IllegalArgumentException if n is not positive */ public long nextLong(long n) { if (n <= 0) throw new IllegalArgumentException("n must be positive"); // Divide n by two until small enough for nextInt. On each // iteration (at most 31 of them but usually much less), // randomly choose both whether to include high bit in result // (offset) and whether to continue with the lower vs upper // half (which makes a difference only if odd). long offset = 0; while (n >= Integer.MAX_VALUE) { int bits = next(2); long half = n >>> 1; long nextn = ((bits & 2) == 0) ? half : n - half; if ((bits & 1) == 0) offset += n - nextn; n = nextn; } return offset + nextInt((int) n); } /** * Returns a pseudorandom, uniformly distributed value between the * given least value (inclusive) and bound (exclusive). * * @param least the least value returned * @param bound the upper bound (exclusive) * @return the next value * @throws IllegalArgumentException if least greater than or equal * to bound */ public long nextLong(long least, long bound) { if (least >= bound) throw new IllegalArgumentException(); return nextLong(bound - least) + least; } /** * Returns a pseudorandom, uniformly distributed {@code double} value * between 0 (inclusive) and the specified value (exclusive). * * @param n the bound on the random number to be returned. Must be * positive. * @return the next value * @throws IllegalArgumentException if n is not positive */ public double nextDouble(double n) { if (n <= 0) throw new IllegalArgumentException("n must be positive"); return nextDouble() * n; } /** * Returns a pseudorandom, uniformly distributed value between the * given least value (inclusive) and bound (exclusive). * * @param least the least value returned * @param bound the upper bound (exclusive) * @return the next value * @throws IllegalArgumentException if least greater than or equal * to bound */ public double nextDouble(double least, double bound) { if (least >= bound) throw new IllegalArgumentException(); return nextDouble() * (bound - least) + least; } private static final long serialVersionUID = -5851777807851030925L; } concurrent-ruby-1.0.5/ext/concurrent/000077500000000000000000000000001305460430400176375ustar00rootroot00000000000000concurrent-ruby-1.0.5/ext/concurrent/atomic_boolean.c000066400000000000000000000023631305460430400227620ustar00rootroot00000000000000#include #include "atomic_boolean.h" #include "atomic_reference.h" #include "ruby_193_compatible.h" void atomic_boolean_mark(void *value) { rb_gc_mark_maybe((VALUE) value); } VALUE atomic_boolean_allocate(VALUE klass) { return rb_data_object_alloc(klass, (void *) Qfalse, atomic_boolean_mark, NULL); } VALUE method_atomic_boolean_initialize(int argc, VALUE* argv, VALUE self) { VALUE value = Qfalse; rb_check_arity(argc, 0, 1); if (argc == 1) value = TRUTHY(argv[0]); DATA_PTR(self) = (void *) value; return(self); } VALUE method_atomic_boolean_value(VALUE self) { return (VALUE) DATA_PTR(self); } VALUE method_atomic_boolean_value_set(VALUE self, VALUE value) { VALUE new_value = TRUTHY(value); DATA_PTR(self) = (void *) new_value; return(new_value); } VALUE method_atomic_boolean_true_question(VALUE self) { return(method_atomic_boolean_value(self)); } VALUE method_atomic_boolean_false_question(VALUE self) { VALUE current = method_atomic_boolean_value(self); return(current == Qfalse ? Qtrue : Qfalse); } VALUE method_atomic_boolean_make_true(VALUE self) { return(ir_compare_and_set(self, Qfalse, Qtrue)); } VALUE method_atomic_boolean_make_false(VALUE self) { return(ir_compare_and_set(self, Qtrue, Qfalse)); } concurrent-ruby-1.0.5/ext/concurrent/atomic_boolean.h000066400000000000000000000010611305460430400227610ustar00rootroot00000000000000#ifndef __ATOMIC_BOOLEAN_H__ #define __ATOMIC_BOOLEAN_H__ #define TRUTHY(value)(value == Qfalse || value == Qnil ? Qfalse : Qtrue) void atomic_boolean_mark(void*); VALUE atomic_boolean_allocate(VALUE); VALUE method_atomic_boolean_initialize(int, VALUE*, VALUE); VALUE method_atomic_boolean_value(VALUE); VALUE method_atomic_boolean_value_set(VALUE, VALUE); VALUE method_atomic_boolean_true_question(VALUE); VALUE method_atomic_boolean_false_question(VALUE); VALUE method_atomic_boolean_make_true(VALUE); VALUE method_atomic_boolean_make_false(VALUE); #endif concurrent-ruby-1.0.5/ext/concurrent/atomic_fixnum.c000066400000000000000000000037071305460430400226540ustar00rootroot00000000000000#include #include "atomic_fixnum.h" #include "atomic_reference.h" #include "ruby_193_compatible.h" void atomic_fixnum_mark(void *value) { rb_gc_mark_maybe((VALUE) value); } VALUE atomic_fixnum_allocate(VALUE klass) { return rb_data_object_alloc(klass, (void *) Qnil, atomic_fixnum_mark, NULL); } VALUE method_atomic_fixnum_initialize(int argc, VALUE* argv, VALUE self) { VALUE value = LL2NUM(0); rb_check_arity(argc, 0, 1); if (argc == 1) { Check_Type(argv[0], T_FIXNUM); value = argv[0]; } DATA_PTR(self) = (void *) value; return(self); } VALUE method_atomic_fixnum_value(VALUE self) { return (VALUE) DATA_PTR(self); } VALUE method_atomic_fixnum_value_set(VALUE self, VALUE value) { Check_Type(value, T_FIXNUM); DATA_PTR(self) = (void *) value; return(value); } VALUE method_atomic_fixnum_increment(int argc, VALUE* argv, VALUE self) { long long value = NUM2LL((VALUE) DATA_PTR(self)); long long delta = 1; rb_check_arity(argc, 0, 1); if (argc == 1) { Check_Type(argv[0], T_FIXNUM); delta = NUM2LL(argv[0]); } return method_atomic_fixnum_value_set(self, LL2NUM(value + delta)); } VALUE method_atomic_fixnum_decrement(int argc, VALUE* argv, VALUE self) { long long value = NUM2LL((VALUE) DATA_PTR(self)); long long delta = 1; rb_check_arity(argc, 0, 1); if (argc == 1) { Check_Type(argv[0], T_FIXNUM); delta = NUM2LL(argv[0]); } return method_atomic_fixnum_value_set(self, LL2NUM(value - delta)); } VALUE method_atomic_fixnum_compare_and_set(VALUE self, VALUE rb_expect, VALUE rb_update) { Check_Type(rb_expect, T_FIXNUM); Check_Type(rb_update, T_FIXNUM); return ir_compare_and_set(self, rb_expect, rb_update); } VALUE method_atomic_fixnum_update(VALUE self) { VALUE old_value, new_value; for (;;) { old_value = method_atomic_fixnum_value(self); new_value = rb_yield(old_value); if (ir_compare_and_set(self, old_value, new_value) == Qtrue) { return new_value; } } } concurrent-ruby-1.0.5/ext/concurrent/atomic_fixnum.h000066400000000000000000000007751305460430400226630ustar00rootroot00000000000000#ifndef __ATOMIC_FIXNUM_H__ #define __ATOMIC_FIXNUM_H__ void atomic_fixnum_mark(void*); VALUE atomic_fixnum_allocate(VALUE); VALUE method_atomic_fixnum_initialize(int, VALUE*, VALUE); VALUE method_atomic_fixnum_value(VALUE); VALUE method_atomic_fixnum_value_set(VALUE, VALUE); VALUE method_atomic_fixnum_increment(int, VALUE*, VALUE); VALUE method_atomic_fixnum_decrement(int, VALUE*, VALUE); VALUE method_atomic_fixnum_compare_and_set(VALUE, VALUE, VALUE); VALUE method_atomic_fixnum_update(VALUE); #endif concurrent-ruby-1.0.5/ext/concurrent/atomic_reference.c000066400000000000000000000046371305460430400233070ustar00rootroot00000000000000#include /*#if defined(__sun)*/ /*#include */ /*#endif*/ /*#ifdef HAVE_LIBKERN_OSATOMIC_H*/ /*#include */ /*#endif*/ #include "atomic_reference.h" void ir_mark(void *value) { rb_gc_mark_maybe((VALUE) value); } VALUE ir_alloc(VALUE klass) { return rb_data_object_alloc(klass, (void *) Qnil, ir_mark, NULL); } VALUE ir_initialize(int argc, VALUE* argv, VALUE self) { VALUE value = Qnil; if (rb_scan_args(argc, argv, "01", &value) == 1) { value = argv[0]; } DATA_PTR(self) = (void *) value; return Qnil; } VALUE ir_get(VALUE self) { #if HAVE_GCC_SYNC __sync_synchronize(); #elif defined _MSC_VER MemoryBarrier(); #elif __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050 OSMemoryBarrier(); #endif return (VALUE) DATA_PTR(self); } VALUE ir_set(VALUE self, VALUE new_value) { DATA_PTR(self) = (void *) new_value; #if HAVE_GCC_SYNC __sync_synchronize(); #elif defined _MSC_VER MemoryBarrier(); #elif __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050 OSMemoryBarrier(); #endif return new_value; } VALUE ir_get_and_set(VALUE self, VALUE new_value) { VALUE old_value; for (;;) { old_value = ir_get(self); if (ir_compare_and_set(self, old_value, new_value) == Qtrue) { return old_value; } } } VALUE ir_compare_and_set(volatile VALUE self, VALUE expect_value, VALUE new_value) { #if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050 if (OSAtomicCompareAndSwap64(expect_value, new_value, &DATA_PTR(self))) { return Qtrue; } #elif defined(__sun) /* Assuming VALUE is uintptr_t */ /* Based on the definition of uintptr_t from /usr/include/sys/int_types.h */ #if defined(_LP64) || defined(_I32LPx) /* 64-bit: uintptr_t === unsigned long */ if (atomic_cas_ulong((uintptr_t *) &DATA_PTR(self), expect_value, new_value)) { return Qtrue; } #else /* 32-bit: uintptr_t === unsigned int */ if (atomic_cas_uint((uintptr_t *) &DATA_PTR(self), expect_value, new_value)) { return Qtrue; } #endif #elif defined _MSC_VER && defined _M_AMD64 if (InterlockedCompareExchange64((LONGLONG*)&DATA_PTR(self), new_value, expect_value)) { return Qtrue; } #elif defined _MSC_VER && defined _M_IX86 if (InterlockedCompareExchange((LONG*)&DATA_PTR(self), new_value, expect_value)) { return Qtrue; } #else if (__sync_bool_compare_and_swap(&DATA_PTR(self), expect_value, new_value)) { return Qtrue; } #endif return Qfalse; } concurrent-ruby-1.0.5/ext/concurrent/atomic_reference.h000066400000000000000000000006351305460430400233060ustar00rootroot00000000000000#ifndef __ATOMIC_REFERENCE_H__ #define __ATOMIC_REFERENCE_H__ #if defined(__sun) #include #endif #ifdef HAVE_LIBKERN_OSATOMIC_H #include #endif void ir_mark(void*); VALUE ir_alloc(VALUE); VALUE ir_initialize(int, VALUE*, VALUE); VALUE ir_get(VALUE); VALUE ir_set(VALUE, VALUE); VALUE ir_get_and_set(VALUE, VALUE); VALUE ir_compare_and_set(volatile VALUE, VALUE, VALUE); #endif concurrent-ruby-1.0.5/ext/concurrent/extconf.rb000066400000000000000000000024341305460430400216350ustar00rootroot00000000000000require 'fileutils' $:.unshift(File.expand_path('../../../lib', __FILE__)) require 'concurrent/utility/native_extension_loader' EXTENSION_NAME = 'extension' def create_dummy_makefile File.open('Makefile', 'w') do |f| f.puts 'all:' f.puts 'install:' end end if Concurrent.on_jruby? || ! Concurrent.allow_c_extensions? create_dummy_makefile warn 'C optimizations are not supported on this version of Ruby.' else begin require 'mkmf' dir_config(EXTENSION_NAME) have_header "libkern/OSAtomic.h" def compiler_is_gcc if CONFIG["GCC"] && CONFIG["GCC"] != "" return true elsif ( # This could stand to be more generic... but I am afraid. CONFIG["CC"] =~ /\bgcc\b/ ) return true end return false end if compiler_is_gcc case CONFIG["arch"] when /mswin32|mingw|solaris/ $CFLAGS += " -march=native" when 'i686-linux' $CFLAGS += " -march=i686" end end try_run(< #include "atomic_reference.h" #include "atomic_boolean.h" #include "atomic_fixnum.h" // module and class definitions static VALUE rb_mConcurrent; static VALUE rb_cAtomicReference; static VALUE rb_cAtomicBoolean; static VALUE rb_cAtomicFixnum; // Init_extension void Init_extension() { // define modules and classes rb_mConcurrent = rb_define_module("Concurrent"); rb_cAtomicReference = rb_define_class_under(rb_mConcurrent, "CAtomicReference", rb_cObject); rb_cAtomicBoolean = rb_define_class_under(rb_mConcurrent, "CAtomicBoolean", rb_cObject); rb_cAtomicFixnum = rb_define_class_under(rb_mConcurrent, "CAtomicFixnum", rb_cObject); // CAtomicReference rb_define_alloc_func(rb_cAtomicReference, ir_alloc); rb_define_method(rb_cAtomicReference, "initialize", ir_initialize, -1); rb_define_method(rb_cAtomicReference, "get", ir_get, 0); rb_define_method(rb_cAtomicReference, "set", ir_set, 1); rb_define_method(rb_cAtomicReference, "get_and_set", ir_get_and_set, 1); rb_define_method(rb_cAtomicReference, "_compare_and_set", ir_compare_and_set, 2); rb_define_alias(rb_cAtomicReference, "value", "get"); rb_define_alias(rb_cAtomicReference, "value=", "set"); rb_define_alias(rb_cAtomicReference, "swap", "get_and_set"); // CAtomicBoolean rb_define_alloc_func(rb_cAtomicBoolean, atomic_boolean_allocate); rb_define_method(rb_cAtomicBoolean, "initialize", method_atomic_boolean_initialize, -1); rb_define_method(rb_cAtomicBoolean, "value", method_atomic_boolean_value, 0); rb_define_method(rb_cAtomicBoolean, "value=", method_atomic_boolean_value_set, 1); rb_define_method(rb_cAtomicBoolean, "true?", method_atomic_boolean_true_question, 0); rb_define_method(rb_cAtomicBoolean, "false?", method_atomic_boolean_false_question, 0); rb_define_method(rb_cAtomicBoolean, "make_true", method_atomic_boolean_make_true, 0); rb_define_method(rb_cAtomicBoolean, "make_false", method_atomic_boolean_make_false, 0); // CAtomicFixnum rb_define_const(rb_cAtomicFixnum, "MIN_VALUE", LL2NUM(LLONG_MIN)); rb_define_const(rb_cAtomicFixnum, "MAX_VALUE", LL2NUM(LLONG_MAX)); rb_define_alloc_func(rb_cAtomicFixnum, atomic_fixnum_allocate); rb_define_method(rb_cAtomicFixnum, "initialize", method_atomic_fixnum_initialize, -1); rb_define_method(rb_cAtomicFixnum, "value", method_atomic_fixnum_value, 0); rb_define_method(rb_cAtomicFixnum, "value=", method_atomic_fixnum_value_set, 1); rb_define_method(rb_cAtomicFixnum, "increment", method_atomic_fixnum_increment, -1); rb_define_method(rb_cAtomicFixnum, "decrement", method_atomic_fixnum_decrement, -1); rb_define_method(rb_cAtomicFixnum, "compare_and_set", method_atomic_fixnum_compare_and_set, 2); rb_define_method(rb_cAtomicFixnum, "update", method_atomic_fixnum_update, 0); rb_define_alias(rb_cAtomicFixnum, "up", "increment"); rb_define_alias(rb_cAtomicFixnum, "down", "decrement"); } concurrent-ruby-1.0.5/ext/concurrent/ruby_193_compatible.h000066400000000000000000000014741305460430400235720ustar00rootroot00000000000000#ifndef rb_check_arity // https://github.com/ruby/ruby/blob/ruby_2_0_0/include/ruby/intern.h // rb_check_arity was added in Ruby 2.0 #define UNLIMITED_ARGUMENTS (-1) static inline VALUE rb_error_arity(int argc, int min, int max) { VALUE err_mess = 0; if (min == max) { err_mess = rb_sprintf("wrong number of arguments (%d for %d)", argc, min); } else if (max == UNLIMITED_ARGUMENTS) { err_mess = rb_sprintf("wrong number of arguments (%d for %d+)", argc, min); } else { err_mess = rb_sprintf("wrong number of arguments (%d for %d..%d)", argc, min, max); } return rb_exc_new3(rb_eTypeError, err_mess); } #define rb_check_arity(argc, min, max) do { \ if (((argc) < (min)) || ((argc) > (max) && (max) != UNLIMITED_ARGUMENTS)) \ rb_exc_raise(rb_error_arity(argc, min, max)); \ } while(0) #endif concurrent-ruby-1.0.5/lib/000077500000000000000000000000001305460430400154235ustar00rootroot00000000000000concurrent-ruby-1.0.5/lib/concurrent-edge.rb000066400000000000000000000007751305460430400210450ustar00rootroot00000000000000require 'concurrent' require 'concurrent/actor' require 'concurrent/agent' require 'concurrent/channel' require 'concurrent/exchanger' require 'concurrent/lazy_register' require 'concurrent/edge/atomic_markable_reference' require 'concurrent/edge/lock_free_linked_set' require 'concurrent/edge/lock_free_queue' require 'concurrent/edge/lock_free_stack' require 'concurrent/edge/promises' require 'concurrent/edge/cancellation' require 'concurrent/edge/throttle' require 'concurrent/edge/processing_actor' concurrent-ruby-1.0.5/lib/concurrent.rb000066400000000000000000000127321305460430400201370ustar00rootroot00000000000000require 'concurrent/version' require 'concurrent/constants' require 'concurrent/errors' require 'concurrent/configuration' require 'concurrent/atomics' require 'concurrent/executors' require 'concurrent/synchronization' require 'concurrent/atomic/atomic_reference' require 'concurrent/agent' require 'concurrent/atom' require 'concurrent/array' require 'concurrent/hash' require 'concurrent/map' require 'concurrent/tuple' require 'concurrent/async' require 'concurrent/dataflow' require 'concurrent/delay' require 'concurrent/exchanger' require 'concurrent/future' require 'concurrent/immutable_struct' require 'concurrent/ivar' require 'concurrent/maybe' require 'concurrent/mutable_struct' require 'concurrent/mvar' require 'concurrent/promise' require 'concurrent/scheduled_task' require 'concurrent/settable_struct' require 'concurrent/timer_task' require 'concurrent/tvar' require 'concurrent/thread_safe/synchronized_delegator' require 'concurrent/thread_safe/util' require 'concurrent/options' # @!macro [new] internal_implementation_note # # @note **Private Implementation:** This abstraction is a private, internal # implementation detail. It should never be used directly. # @!macro [new] monotonic_clock_warning # # @note Time calculations one all platforms and languages are sensitive to # changes to the system clock. To alleviate the potential problems # associated with changing the system clock while an application is running, # most modern operating systems provide a monotonic clock that operates # independently of the system clock. A monotonic clock cannot be used to # determine human-friendly clock times. A monotonic clock is used exclusively # for calculating time intervals. Not all Ruby platforms provide access to an # operating system monotonic clock. On these platforms a pure-Ruby monotonic # clock will be used as a fallback. An operating system monotonic clock is both # faster and more reliable than the pure-Ruby implementation. The pure-Ruby # implementation should be fast and reliable enough for most non-realtime # operations. At this time the common Ruby platforms that provide access to an # operating system monotonic clock are MRI 2.1 and above and JRuby (all versions). # # @see http://linux.die.net/man/3/clock_gettime Linux clock_gettime(3) # @!macro [new] copy_options # # ## Copy Options # # Object references in Ruby are mutable. This can lead to serious # problems when the {#value} of an object is a mutable reference. Which # is always the case unless the value is a `Fixnum`, `Symbol`, or similar # "primitive" data type. Each instance can be configured with a few # options that can help protect the program from potentially dangerous # operations. Each of these options can be optionally set when the object # instance is created: # # * `:dup_on_deref` When true the object will call the `#dup` method on # the `value` object every time the `#value` method is called # (default: false) # * `:freeze_on_deref` When true the object will call the `#freeze` # method on the `value` object every time the `#value` method is called # (default: false) # * `:copy_on_deref` When given a `Proc` object the `Proc` will be run # every time the `#value` method is called. The `Proc` will be given # the current `value` as its only argument and the result returned by # the block will be the return value of the `#value` call. When `nil` # this option will be ignored (default: nil) # # When multiple deref options are set the order of operations is strictly defined. # The order of deref operations is: # * `:copy_on_deref` # * `:dup_on_deref` # * `:freeze_on_deref` # # Because of this ordering there is no need to `#freeze` an object created by a # provided `:copy_on_deref` block. Simply set `:freeze_on_deref` to `true`. # Setting both `:dup_on_deref` to `true` and `:freeze_on_deref` to `true` is # as close to the behavior of a "pure" functional language (like Erlang, Clojure, # or Haskell) as we are likely to get in Ruby. # @!macro [attach] deref_options # # @option opts [Boolean] :dup_on_deref (false) Call `#dup` before # returning the data from {#value} # @option opts [Boolean] :freeze_on_deref (false) Call `#freeze` before # returning the data from {#value} # @option opts [Proc] :copy_on_deref (nil) When calling the {#value} # method, call the given proc passing the internal value as the sole # argument then return the new value returned from the proc. # @!macro [attach] executor_and_deref_options # # @param [Hash] opts the options used to define the behavior at update and deref # and to specify the executor on which to perform actions # @option opts [Executor] :executor when set use the given `Executor` instance. # Three special values are also supported: `:task` returns the global task pool, # `:operation` returns the global operation pool, and `:immediate` returns a new # `ImmediateExecutor` object. # @!macro deref_options # Modern concurrency tools for Ruby. Inspired by Erlang, Clojure, Scala, Haskell, # F#, C#, Java, and classic concurrency patterns. # # The design goals of this gem are: # # * Stay true to the spirit of the languages providing inspiration # * But implement in a way that makes sense for Ruby # * Keep the semantics as idiomatic Ruby as possible # * Support features that make sense in Ruby # * Exclude features that don't make sense in Ruby # * Be small, lean, and loosely coupled module Concurrent end concurrent-ruby-1.0.5/lib/concurrent/000077500000000000000000000000001305460430400176055ustar00rootroot00000000000000concurrent-ruby-1.0.5/lib/concurrent/.gitignore000066400000000000000000000000001305460430400215630ustar00rootroot00000000000000concurrent-ruby-1.0.5/lib/concurrent/actor.rb000066400000000000000000000070371305460430400212510ustar00rootroot00000000000000require 'concurrent/configuration' require 'concurrent/executor/serialized_execution' require 'concurrent/synchronization' require 'concurrent/edge/promises' module Concurrent # TODO https://github.com/celluloid/celluloid/wiki/Supervision-Groups ? # TODO Remote actors using DRb # TODO un/become # TODO supervision tree, pause children on error in parent, pause may need higher priority # TODO more effective executor # {include:file:doc/actor/main.md} # @api Actor # @!macro edge_warning module Actor require 'concurrent/actor/type_check' require 'concurrent/actor/errors' require 'concurrent/actor/public_delegations' require 'concurrent/actor/internal_delegations' require 'concurrent/actor/envelope' require 'concurrent/actor/reference' require 'concurrent/actor/core' require 'concurrent/actor/behaviour' require 'concurrent/actor/context' require 'concurrent/actor/default_dead_letter_handler' require 'concurrent/actor/root' require 'concurrent/actor/utils' # @return [Reference, nil] current executing actor if any def self.current Thread.current[:__current_actor__] end @root = Concurrent::Promises.delay do Core.new(parent: nil, name: '/', class: Root, initialized: future = Concurrent::Promises.resolvable_future).reference.tap do future.wait! end end # A root actor, a default parent of all actors spawned outside an actor def self.root @root.value! end # Spawns a new actor. {Concurrent::Actor::AbstractContext.spawn} allows to omit class parameter. # To see the list of available options see {Core#initialize} # @see Concurrent::Actor::AbstractContext.spawn # @see Core#initialize # @example by class and name # Actor.spawn(AdHoc, :ping1) { -> message { message } } # # @example by option hash # inc2 = Actor.spawn(class: AdHoc, # name: 'increment by 2', # args: [2], # executor: Concurrent.global_io_executor) do |increment_by| # lambda { |number| number + increment_by } # end # inc2.ask!(2) # => 4 # # @param block for context_class instantiation # @param args see {.to_spawn_options} # @return [Reference] never the actual actor def self.spawn(*args, &block) options = to_spawn_options(*args) if options[:executor] && options[:executor].is_a?(ImmediateExecutor) raise ArgumentError, 'ImmediateExecutor is not supported' end if Actor.current Core.new(options.merge(parent: Actor.current), &block).reference else root.ask([:spawn, options, block]).value! end end # as {.spawn} but it'll block until actor is initialized or it'll raise exception on error def self.spawn!(*args, &block) spawn(to_spawn_options(*args).merge(initialized: future = Concurrent::Promises.resolvable_future), &block).tap { future.wait! } end # @overload to_spawn_options(context_class, name, *args) # @param [AbstractContext] context_class to be spawned # @param [String, Symbol] name of the instance, it's used to generate the # {Core#path} of the actor # @param args for context_class instantiation # @overload to_spawn_options(opts) # see {Core#initialize} opts def self.to_spawn_options(*args) if args.size == 1 && args.first.is_a?(::Hash) args.first else { class: args[0], name: args[1], args: args[2..-1] } end end end end concurrent-ruby-1.0.5/lib/concurrent/actor/000077500000000000000000000000001305460430400207155ustar00rootroot00000000000000concurrent-ruby-1.0.5/lib/concurrent/actor/behaviour.rb000066400000000000000000000100721305460430400232260ustar00rootroot00000000000000module Concurrent module Actor # Actors have modular architecture, which is achieved by combining a light core with chain of # behaviours. Each message or internal event propagates through the chain allowing the # behaviours react based on their responsibility. # # - {Behaviour::Linking}: # # > {include:Actor::Behaviour::Linking} # # - {Behaviour::Awaits}: # # > {include:Actor::Behaviour::Awaits} # # - {Behaviour::Pausing}: # # > {include:Actor::Behaviour::Pausing} # # - {Behaviour::Supervising}: # # > {include:Actor::Behaviour::Supervising} # # - {Behaviour::Supervising}: # # > {include:Actor::Behaviour::Supervising} # # - {Behaviour::ExecutesContext}: # # > {include:Actor::Behaviour::ExecutesContext} # # - {Behaviour::ErrorsOnUnknownMessage}: # # > {include:Actor::Behaviour::ErrorsOnUnknownMessage} # # - {Behaviour::Termination}: # # > {include:Actor::Behaviour::Termination} # # - {Behaviour::RemovesChild}: # # > {include:Actor::Behaviour::RemovesChild} # # If needed new behaviours can be added, or old one removed to get required behaviour. # # - {Context} uses # {include:Actor::Behaviour.basic_behaviour_definition} # # - {RestartingContext} uses # {include:Actor::Behaviour.restarting_behaviour_definition} module Behaviour MESSAGE_PROCESSED = Object.new require 'concurrent/actor/behaviour/abstract' require 'concurrent/actor/behaviour/awaits' require 'concurrent/actor/behaviour/buffer' require 'concurrent/actor/behaviour/errors_on_unknown_message' require 'concurrent/actor/behaviour/executes_context' require 'concurrent/actor/behaviour/linking' require 'concurrent/actor/behaviour/pausing' require 'concurrent/actor/behaviour/removes_child' require 'concurrent/actor/behaviour/sets_results' require 'concurrent/actor/behaviour/supervising' require 'concurrent/actor/behaviour/termination' # Array of behaviours and their construction parameters. # # [[Behaviour::SetResults, :terminate!], # [Behaviour::RemovesChild], # [Behaviour::Termination], # [Behaviour::Linking], # [Behaviour::Awaits], # [Behaviour::ExecutesContext], # [Behaviour::ErrorsOnUnknownMessage]] # # @see '' its source code def self.basic_behaviour_definition [*base(:terminate!), *linking, *user_messages] end # Array of behaviours and their construction parameters. # # [[Behaviour::SetResults, :pause!], # [Behaviour::RemovesChild], # [Behaviour::Termination], # [Behaviour::Linking], # [Behaviour::Pausing], # [Behaviour::Supervising, :reset!, :one_for_one], # [Behaviour::Awaits], # [Behaviour::ExecutesContext], # [Behaviour::ErrorsOnUnknownMessage]] # # @see '' its source code def self.restarting_behaviour_definition(handle = :reset!, strategy = :one_for_one) [*base(:pause!), *linking, *supervised, *supervising(handle, strategy), *user_messages] end # @see '' its source code def self.base(on_error) [[SetResults, on_error], # has to be before Termination to be able to remove children from terminated actor RemovesChild, Termination] end # @see '' its source code def self.linking [Linking] end # @see '' its source code def self.supervised [Pausing] end # @see '' its source code def self.supervising(handle = :reset!, strategy = :one_for_one) [[Behaviour::Supervising, handle, strategy]] end # @see '' its source code def self.user_messages [Awaits, ExecutesContext, ErrorsOnUnknownMessage] end end end end concurrent-ruby-1.0.5/lib/concurrent/actor/behaviour/000077500000000000000000000000001305460430400227015ustar00rootroot00000000000000concurrent-ruby-1.0.5/lib/concurrent/actor/behaviour/abstract.rb000066400000000000000000000026241305460430400250350ustar00rootroot00000000000000require 'concurrent/concern/logging' module Concurrent module Actor module Behaviour class Abstract include TypeCheck include InternalDelegations attr_reader :core, :subsequent def initialize(core, subsequent, core_options) @core = Type! core, Core @subsequent = Type! subsequent, Abstract, NilClass end # override to add extra behaviour # @note super needs to be called not to break the chain def on_envelope(envelope) pass envelope end # @param [Envelope] envelope to pass to {#subsequent} behaviour def pass(envelope) subsequent.on_envelope envelope end # override to add extra behaviour # @note super needs to be called not to break the chain def on_event(public, event) subsequent.on_event public, event if subsequent end # broadcasts event to all behaviours and context # @see #on_event # @see AbstractContext#on_event def broadcast(public, event) core.broadcast(public, event) end def reject_envelope(envelope) envelope.reject! ActorTerminated.new(reference) dead_letter_routing << envelope unless envelope.future log(DEBUG) { "rejected #{envelope.message} from #{envelope.sender_path}"} end end end end end concurrent-ruby-1.0.5/lib/concurrent/actor/behaviour/awaits.rb000066400000000000000000000007611305460430400245220ustar00rootroot00000000000000module Concurrent module Actor module Behaviour # Accepts `:await` messages. Which allows to wait on Actor to process all previously send # messages. # # actor << :a << :b # actor.ask(:await).wait # blocks until :a and :b are processed class Awaits < Abstract def on_envelope(envelope) if envelope.message == :await true else pass envelope end end end end end end concurrent-ruby-1.0.5/lib/concurrent/actor/behaviour/buffer.rb000066400000000000000000000037131305460430400245030ustar00rootroot00000000000000module Concurrent module Actor module Behaviour # Any message reaching this behaviour is buffered. Only one message is is # scheduled at any given time. Others are kept in buffer until another one # can be scheduled. This effectively means that messages handled by # behaviours before buffer have higher priority and they can be processed # before messages arriving into buffer. This allows for the processing of # internal actor messages like (`:link`, `:supervise`) first. class Buffer < Abstract def initialize(core, subsequent, core_options) super core, subsequent, core_options @buffer = [] @receive_envelope_scheduled = false end def on_envelope(envelope) @buffer.push envelope process_envelopes? MESSAGE_PROCESSED end # Ensures that only one envelope processing is scheduled with #schedule_execution, # this allows other scheduled blocks to be executed before next envelope processing. # Simply put this ensures that Core is still responsive to internal calls (like add_child) # even though the Actor is flooded with messages. def process_envelopes? unless @buffer.empty? || @receive_envelope_scheduled @receive_envelope_scheduled = true process_envelope end end def process_envelope envelope = @buffer.shift return nil unless envelope pass envelope ensure @receive_envelope_scheduled = false core.schedule_execution { process_envelopes? } end def on_event(public, event) event_name, _ = event case event_name when :terminated, :restarted @buffer.each { |envelope| reject_envelope envelope } @buffer.clear end super public, event_name end end end end end concurrent-ruby-1.0.5/lib/concurrent/actor/behaviour/errors_on_unknown_message.rb000066400000000000000000000004501305460430400305200ustar00rootroot00000000000000module Concurrent module Actor module Behaviour # Simply fails when message arrives here. It's usually the last behaviour. class ErrorsOnUnknownMessage < Abstract def on_envelope(envelope) raise UnknownMessage, envelope end end end end end concurrent-ruby-1.0.5/lib/concurrent/actor/behaviour/executes_context.rb000066400000000000000000000006041305460430400266170ustar00rootroot00000000000000module Concurrent module Actor module Behaviour # Delegates messages and events to {AbstractContext} instance. class ExecutesContext < Abstract def on_envelope(envelope) context.on_envelope envelope end def on_event(public, event) context.on_event(event) super public, event end end end end end concurrent-ruby-1.0.5/lib/concurrent/actor/behaviour/linking.rb000066400000000000000000000051451305460430400246660ustar00rootroot00000000000000module Concurrent module Actor module Behaviour # TODO track what is linked, clean when :terminated # send :linked/:unlinked messages back to build the array of linked actors # Links the actor to other actors and sends actor's events to them, # like: `:terminated`, `:paused`, `:resumed`, errors, etc. # Linked actor needs to handle those messages. # # listener = AdHoc.spawn name: :listener do # lambda do |message| # case message # when Reference # if message.ask!(:linked?) # message << :unlink # else # message << :link # end # else # puts "got event #{message.inspect} from #{envelope.sender}" # end # end # end # # an_actor = AdHoc.spawn name: :an_actor, supervise: true, behaviour_definition: Behaviour.restarting_behaviour_definition do # lambda { |message| raise 'failed'} # end # # # link the actor # listener.ask(an_actor).wait # an_actor.ask(:fail).wait # # unlink the actor # listener.ask(an_actor).wait # an_actor.ask(:fail).wait # an_actor << :terminate! # # produces only two events, other events happened after unlinking # # got event # from # # got event :reset from # class Linking < Abstract def initialize(core, subsequent, core_options) super core, subsequent, core_options @linked = Set.new @linked.add Actor.current if core_options[:link] != false end def on_envelope(envelope) case envelope.message when :link link envelope.sender when :unlink unlink envelope.sender when :linked? @linked.include? envelope.sender when :linked @linked.to_a else pass envelope end end def link(ref) @linked.add(ref) true end def unlink(ref) @linked.delete(ref) true end def on_event(public, event) event_name, _ = event @linked.each { |a| a << event } if public @linked.clear if event_name == :terminated super public, event end end end end end concurrent-ruby-1.0.5/lib/concurrent/actor/behaviour/pausing.rb000066400000000000000000000052671305460430400247060ustar00rootroot00000000000000module Concurrent module Actor module Behaviour # Allows to pause actors on errors. # When paused all arriving messages are collected and processed after the actor # is resumed or reset. Resume will simply continue with next message. # Reset also reinitialized context. # @note TODO missing example class Pausing < Abstract def initialize(core, subsequent, core_options) super core, subsequent, core_options @paused = false @deferred = [] end def paused? @paused end def on_envelope(envelope) case envelope.message when :pause! pause! when :paused? paused? when :resume! resume! when :reset! reset! when :restart! restart! else if paused? @deferred << envelope MESSAGE_PROCESSED else pass envelope end end end def pause!(error = nil) do_pause broadcast true, error || :paused true end def resume! return false unless paused? do_resume broadcast(true, :resumed) true end def reset! return false unless paused? broadcast(false, :resetting) do_reset broadcast(true, :reset) true end def restart! return false unless paused? broadcast(false, :restarting) do_restart broadcast(true, :restarted) true end def on_event(public, event) event_name, _ = event reject_deferred if event_name == :terminated super public, event end private def do_pause @paused = true nil end def do_resume @paused = false reschedule_deferred nil end def do_reset rebuild_context do_resume reschedule_deferred nil end def do_restart rebuild_context reject_deferred do_resume nil end def rebuild_context core.allocate_context core.build_context nil end def reschedule_deferred @deferred.each { |envelope| core.schedule_execution { core.process_envelope envelope } } @deferred.clear end def reject_deferred @deferred.each { |envelope| reject_envelope envelope } @deferred.clear end end end end end concurrent-ruby-1.0.5/lib/concurrent/actor/behaviour/removes_child.rb000066400000000000000000000005351305460430400260540ustar00rootroot00000000000000module Concurrent module Actor module Behaviour # Removes terminated children. class RemovesChild < Abstract def on_envelope(envelope) if envelope.message == :remove_child core.remove_child envelope.sender else pass envelope end end end end end end concurrent-ruby-1.0.5/lib/concurrent/actor/behaviour/sets_results.rb000066400000000000000000000021451305460430400257670ustar00rootroot00000000000000module Concurrent module Actor module Behaviour # Collects returning value and sets the ResolvableFuture in the {Envelope} or error on failure. class SetResults < Abstract attr_reader :error_strategy def initialize(core, subsequent, core_options, error_strategy) super core, subsequent, core_options @error_strategy = Match! error_strategy, :just_log, :terminate!, :pause! end def on_envelope(envelope) result = pass envelope if result != MESSAGE_PROCESSED && !envelope.future.nil? envelope.future.fulfill result log(DEBUG) { "finished processing of #{envelope.message.inspect}"} end nil rescue => error log ERROR, error case error_strategy when :terminate! terminate! when :pause! behaviour!(Pausing).pause!(error) when :just_log # nothing else raise end envelope.future.reject error unless envelope.future.nil? end end end end end concurrent-ruby-1.0.5/lib/concurrent/actor/behaviour/supervising.rb000066400000000000000000000026411305460430400256070ustar00rootroot00000000000000module Concurrent module Actor module Behaviour # Handles supervised actors. Handle configures what to do with failed child: :terminate!, :resume!, :reset!, # or :restart!. Strategy sets :one_for_one (restarts just failed actor) or :one_for_all (restarts all child actors). # @note TODO missing example # @note this will change in next version to support supervision trees better class Supervising < Abstract def initialize(core, subsequent, core_options, handle, strategy) super core, subsequent, core_options @handle = Match! handle, :terminate!, :resume!, :reset!, :restart! @strategy = case @handle when :terminate! Match! strategy, nil when :resume! Match! strategy, :one_for_one when :reset!, :restart! Match! strategy, :one_for_one, :one_for_all end end def on_envelope(envelope) case envelope.message when Exception, :paused receivers = if @strategy == :one_for_all children else [envelope.sender] end receivers.each { |ch| ch << @handle } else pass envelope end end end end end end concurrent-ruby-1.0.5/lib/concurrent/actor/behaviour/termination.rb000066400000000000000000000054271305460430400255670ustar00rootroot00000000000000module Concurrent module Actor module Behaviour # Handles actor termination. Waits until all its children are terminated, # can be configured on behaviour initialization. # @note Actor rejects envelopes when terminated. # @note TODO missing example class Termination < Abstract # @!attribute [r] terminated # @return [Edge::Event] event which will become set when actor is terminated. attr_reader :terminated def initialize(core, subsequent, core_options, trapping = false, terminate_children = true) super core, subsequent, core_options @terminated = Concurrent::Promises.resolvable_future @public_terminated = @terminated.with_hidden_resolvable @trapping = trapping @terminate_children = terminate_children end # @note Actor rejects envelopes when terminated. # @return [true, false] if actor is terminated def terminated? @terminated.resolved? end def trapping? @trapping end def trapping=(val) @trapping = !!val end def on_envelope(envelope) command, reason = envelope.message case command when :terminated? terminated? when :terminate! if trapping? && reason != :kill pass envelope else terminate! reason, envelope end when :termination_event @public_terminated else if terminated? reject_envelope envelope MESSAGE_PROCESSED else pass envelope end end end # Terminates the actor. Any Envelope received after termination is rejected. # Terminates all its children, does not wait until they are terminated. def terminate!(reason = nil, envelope = nil) return true if terminated? self_termination = Concurrent::Promises.resolved_future(reason.nil?, reason.nil? || nil, reason) all_terminations = if @terminate_children Concurrent::Promises.zip(*children.map { |ch| ch.ask(:terminate!) }, self_termination) else self_termination end all_terminations.chain_resolvable(@terminated) if envelope && envelope.future all_terminations.chain { |fulfilled, _, reason| envelope.future.resolve fulfilled, true, reason } end broadcast(true, [:terminated, reason]) # TODO do not end up in Dead Letter Router parent << :remove_child if parent MESSAGE_PROCESSED end end end end end concurrent-ruby-1.0.5/lib/concurrent/actor/context.rb000066400000000000000000000126331305460430400227330ustar00rootroot00000000000000require 'concurrent/concern/logging' module Concurrent module Actor # New actor is defined by subclassing {RestartingContext}, {Context} and defining its abstract methods. # {AbstractContext} can be subclassed directly to implement more specific behaviour see {Root} implementation. # # - {Context} # # > {include:Actor::Context} # # - {RestartingContext}. # # > {include:Actor::RestartingContext} # # Example of ac actor definition: # # {include:file:doc/actor/define.out.rb} # # See methods of {AbstractContext} what else can be tweaked, e.g {AbstractContext#default_reference_class} # # @abstract implement {AbstractContext#on_message} and {AbstractContext#behaviour_definition} class AbstractContext include TypeCheck include InternalDelegations attr_reader :core # @abstract override to define Actor's behaviour # @param [Object] message # @return [Object] a result which will be used to set the Future supplied to Reference#ask # @note self should not be returned (or sent to other actors), {#reference} should be used # instead def on_message(message) raise NotImplementedError end # override to add custom code invocation on internal events like `:terminated`, `:resumed`, `anError`. def on_event(event) end # @api private def on_envelope(envelope) @envelope = envelope on_message envelope.message ensure @envelope = nil end # if you want to pass the message to next behaviour, usually # {Behaviour::ErrorsOnUnknownMessage} def pass core.behaviour!(Behaviour::ExecutesContext).pass envelope end # Defines an actor responsible for dead letters. Any rejected message send # with {Reference#tell} is sent there, a message with future is considered # already monitored for failures. Default behaviour is to use # {AbstractContext#dead_letter_routing} of the parent, so if no # {AbstractContext#dead_letter_routing} method is overridden in # parent-chain the message ends up in `Actor.root.dead_letter_routing` # agent which will log warning. # @return [Reference] def dead_letter_routing parent.dead_letter_routing end # @return [Array)>] def behaviour_definition raise NotImplementedError end # @return [Envelope] current envelope, accessible inside #on_message processing def envelope @envelope or raise 'envelope not set' end # override if different class for reference is needed # @return [CLass] descendant of {Reference} def default_reference_class Reference end # override to se different default executor, e.g. to change it to global_operation_pool # @return [Executor] def default_executor Concurrent.global_io_executor end # tell self a message def tell(message) reference.tell message end def ask(message) raise 'actor cannot ask itself' end alias_method :<<, :tell alias_method :ask!, :ask # Behaves as {Concurrent::Actor.spawn} but :class is auto-inserted based on receiver so it can be omitted. # @example by class and name # AdHoc.spawn(:ping1) { -> message { message } } # # @example by option hash # inc2 = AdHoc.spawn(name: 'increment by 2', # args: [2], # executor: Concurrent.configuration.global_task_pool) do |increment_by| # lambda { |number| number + increment_by } # end # inc2.ask!(2) # => 4 # @see Concurrent::Actor.spawn def self.spawn(name_or_opts, *args, &block) Actor.spawn to_spawn_options(name_or_opts, *args), &block end # behaves as {Concurrent::Actor.spawn!} but :class is auto-inserted based on receiver so it can be omitted. def self.spawn!(name_or_opts, *args, &block) Actor.spawn! to_spawn_options(name_or_opts, *args), &block end private def initialize_core(core) @core = Type! core, Core end def self.to_spawn_options(name_or_opts, *args) if name_or_opts.is_a? ::Hash if name_or_opts.key?(:class) && name_or_opts[:class] != self raise ArgumentError, ':class option is ignored when calling on context class, use Actor.spawn instead' end name_or_opts.merge class: self else { class: self, name: name_or_opts, args: args } end end # to avoid confusion with Kernel.spawn undef_method :spawn end # Basic Context of an Actor. It supports only linking and it simply terminates on error. # Uses {Behaviour.basic_behaviour_definition}: # # @abstract implement {AbstractContext#on_message} class Context < AbstractContext def behaviour_definition Behaviour.basic_behaviour_definition end end # Context of an Actor for robust systems. It supports supervision, linking, pauses on error. # Uses {Behaviour.restarting_behaviour_definition} # # @abstract implement {AbstractContext#on_message} class RestartingContext < AbstractContext def behaviour_definition Behaviour.restarting_behaviour_definition end end end end concurrent-ruby-1.0.5/lib/concurrent/actor/core.rb000066400000000000000000000171631305460430400222020ustar00rootroot00000000000000require 'concurrent/concern/logging' require 'concurrent/executors' module Concurrent module Actor require 'set' # Core of the actor. # @note Whole class should be considered private. An user should use {Context}s and {Reference}s only. # @note devel: core should not block on anything, e.g. it cannot wait on children to terminate # that would eat up all threads in task pool and deadlock class Core < Synchronization::LockableObject include TypeCheck include Concern::Logging # @!attribute [r] reference # Reference to this actor which can be safely passed around. # @return [Reference] # @!attribute [r] name # The name of actor instance, it should be uniq (not enforced). Allows easier orientation # between actor instances. # @return [String] # @!attribute [r] path # Path of this actor. It is used for easier orientation and logging. # Path is constructed recursively with: `parent.path + self.name` up to a {Actor.root}, # e.g. `/an_actor/its_child`. # @return [String] # @!attribute [r] executor # Executor which is used to process messages. # @return [Executor] # @!attribute [r] actor_class # A subclass of {AbstractContext} representing Actor's behaviour. # @return [Context] attr_reader :reference, :name, :path, :executor, :context_class, :context, :behaviour_definition # @option opts [String] name # @option opts [Context] actor_class a class to be instantiated defining Actor's behaviour # @option opts [Array] args arguments for actor_class instantiation # @option opts [Executor] executor, default is `global_io_executor` # @option opts [true, false] link, atomically link the actor to its parent (default: true) # @option opts [Class] reference a custom descendant of {Reference} to use # @option opts [Array)>] behaviour_definition, array of pairs # where each pair is behaviour class and its args, see {Behaviour.basic_behaviour_definition} # @option opts [ResolvableFuture, nil] initialized, if present it'll be set or failed after {Context} initialization # @option opts [Reference, nil] parent **private api** parent of the actor (the one spawning ) # @option opts [Proc, nil] logger a proc accepting (level, progname, message = nil, &block) params, # can be used to hook actor instance to any logging system, see {Concurrent::Concern::Logging} # @param [Proc] block for class instantiation def initialize(opts = {}, &block) super(&nil) synchronize { ns_initialize(opts, &block) } end # A parent Actor. When actor is spawned the {Actor.current} becomes its parent. # When actor is spawned from a thread outside of an actor ({Actor.current} is nil) {Actor.root} is assigned. # @return [Reference, nil] def parent @parent_core && @parent_core.reference end # @see AbstractContext#dead_letter_routing def dead_letter_routing @context.dead_letter_routing end # @return [Array] of children actors def children guard! @children.to_a end # @api private def add_child(child) guard! Type! child, Reference @children.add child nil end # @api private def remove_child(child) guard! Type! child, Reference @children.delete child nil end # is executed by Reference scheduling processing of new messages # can be called from other alternative Reference implementations # @param [Envelope] envelope def on_envelope(envelope) schedule_execution do log(DEBUG) { "was #{envelope.future ? 'asked' : 'told'} #{envelope.message.inspect} by #{envelope.sender}" } process_envelope envelope end nil end # ensures that we are inside of the executor def guard! unless Actor.current == reference raise "can be called only inside actor #{reference} but was #{Actor.current}" end end def log(level, message = nil, &block) super level, @path, message, &block end # Schedules blocks to be executed on executor sequentially, # sets Actress.current def schedule_execution @serialized_execution.post(@executor) do synchronize do begin Thread.current[:__current_actor__] = reference yield rescue => e log FATAL, e ensure Thread.current[:__current_actor__] = nil end end end nil end def broadcast(public, event) log(DEBUG) { "event: #{event.inspect} (#{public ? 'public' : 'private'})" } @first_behaviour.on_event(public, event) end # @param [Class] behaviour_class # @return [Behaviour::Abstract, nil] based on behaviour_class def behaviour(behaviour_class) @behaviours[behaviour_class] end # @param [Class] behaviour_class # @return [Behaviour::Abstract] based on behaviour_class # @raise [KeyError] when no behaviour def behaviour!(behaviour_class) @behaviours.fetch behaviour_class end # @api private def allocate_context @context = @context_class.allocate end # @api private def build_context @context.send :initialize_core, self @context.send :initialize, *@args, &@block end # @api private def process_envelope(envelope) @first_behaviour.on_envelope envelope end private def ns_initialize(opts, &block) @mailbox = ::Array.new @serialized_execution = SerializedExecution.new @children = Set.new @context_class = Child! opts.fetch(:class), AbstractContext allocate_context @executor = Type! opts.fetch(:executor, @context.default_executor), Concurrent::AbstractExecutorService @reference = (Child! opts[:reference_class] || @context.default_reference_class, Reference).new self @name = (Type! opts.fetch(:name), String, Symbol).to_s parent = opts[:parent] @parent_core = (Type! parent, Reference, NilClass) && parent.send(:core) if @parent_core.nil? && @name != '/' raise 'only root has no parent' end @path = @parent_core ? File.join(@parent_core.path, @name) : @name @logger = opts[:logger] @parent_core.add_child reference if @parent_core initialize_behaviours opts @args = opts.fetch(:args, []) @block = block initialized = Type! opts[:initialized], Promises::ResolvableFuture, NilClass schedule_execution do begin build_context initialized.fulfill reference if initialized log DEBUG, 'spawned' rescue => ex log ERROR, ex @first_behaviour.terminate! initialized.reject ex if initialized end end end def initialize_behaviours(opts) @behaviour_definition = (Type! opts[:behaviour_definition] || @context.behaviour_definition, ::Array).each do |(behaviour, _)| Child! behaviour, Behaviour::Abstract end @behaviours = {} @first_behaviour = @behaviour_definition.reverse. reduce(nil) { |last, (behaviour, *args)| @behaviours[behaviour] = behaviour.new(self, last, opts, *args) } end end end end concurrent-ruby-1.0.5/lib/concurrent/actor/default_dead_letter_handler.rb000066400000000000000000000003241305460430400267160ustar00rootroot00000000000000module Concurrent module Actor class DefaultDeadLetterHandler < RestartingContext def on_message(dead_letter) log(INFO) { "got dead letter #{dead_letter.inspect}"} end end end end concurrent-ruby-1.0.5/lib/concurrent/actor/envelope.rb000066400000000000000000000020721305460430400230600ustar00rootroot00000000000000module Concurrent module Actor class Envelope include TypeCheck # @!attribute [r] message # @return [Object] a message # @!attribute [r] future # @return [Edge::Future] a future which becomes resolved after message is processed # @!attribute [r] sender # @return [Reference, Thread] an actor or thread sending the message # @!attribute [r] address # @return [Reference] where this message will be delivered attr_reader :message, :future, :sender, :address def initialize(message, future, sender, address) @message = message @future = Type! future, Promises::ResolvableFuture, NilClass @sender = Type! sender, Reference, Thread @address = Type! address, Reference end def sender_path if sender.is_a? Reference sender.path else sender.to_s end end def address_path address.path end def reject!(error) future.reject error unless future.nil? end end end end concurrent-ruby-1.0.5/lib/concurrent/actor/errors.rb000066400000000000000000000010501305460430400225520ustar00rootroot00000000000000module Concurrent module Actor Error = Class.new(StandardError) class ActorTerminated < Error include TypeCheck attr_reader :reference def initialize(reference) @reference = Type! reference, Reference super reference.path end end class UnknownMessage < Error include TypeCheck attr_reader :envelope def initialize(envelope) @envelope = Type! envelope, Envelope super "#{envelope.message.inspect} from #{envelope.sender_path}" end end end end concurrent-ruby-1.0.5/lib/concurrent/actor/internal_delegations.rb000066400000000000000000000025331305460430400254370ustar00rootroot00000000000000module Concurrent module Actor module InternalDelegations include PublicDelegations include Logger::Severity # @see Core#children def children core.children end # @see Termination#terminate! def terminate!(reason = nil) behaviour!(Behaviour::Termination).terminate!(reason) end # @see Termination#terminated? def terminated? behaviour!(Behaviour::Termination).terminated? end # # @see Termination#reason # def reason # behaviour!(Behaviour::Termination).reason # end # delegates to core.log # @see Logging#log def log(level, message = nil, &block) core.log(level, message, &block) end # @see AbstractContext#dead_letter_routing def dead_letter_routing context.dead_letter_routing end def redirect(reference, envelope = self.envelope) reference.message(envelope.message, envelope.future) Behaviour::MESSAGE_PROCESSED end # @return [AbstractContext] def context core.context end # see Core#behaviour def behaviour(behaviour_class) core.behaviour(behaviour_class) end # see Core#behaviour! def behaviour!(behaviour_class) core.behaviour!(behaviour_class) end end end end concurrent-ruby-1.0.5/lib/concurrent/actor/public_delegations.rb000066400000000000000000000012541305460430400251000ustar00rootroot00000000000000module Concurrent module Actor # Provides publicly expose-able methods from {Core}. module PublicDelegations # @see Core#name def name core.name end # @see Core#path def path core.path end # @see Core#parent def parent core.parent end # @see Core#reference def reference core.reference end # @see Core#executor def executor core.executor end # @see Core#context_class def context_class core.context_class end alias_method :ref, :reference alias_method :actor_class, :context_class end end end concurrent-ruby-1.0.5/lib/concurrent/actor/reference.rb000066400000000000000000000102221305460430400231750ustar00rootroot00000000000000module Concurrent module Actor # {Reference} is public interface of Actor instances. It is used for sending messages and can # be freely passed around the application. It also provides some basic information about the actor, # see {PublicDelegations}. # # AdHoc.spawn('printer') { -> message { puts message } } # # => # # # ^object_id ^path ^context class class Reference include TypeCheck include PublicDelegations attr_reader :core private :core # @!visibility private def initialize(core) @core = Type! core, Core end # Sends the message asynchronously to the actor and immediately returns # `self` (the reference) allowing to chain message telling. # @param [Object] message # @return [Reference] self # @example # printer = AdHoc.spawn('printer') { -> message { puts message } } # printer.tell('ping').tell('pong') # printer << 'ping' << 'pong' # # => 'ping'\n'pong'\n'ping'\n'pong'\n def tell(message) message message, nil end alias_method :<<, :tell # @note it's a good practice to use tell whenever possible. Ask should be used only for # testing and when it returns very shortly. It can lead to deadlock if all threads in # global_io_executor will block on while asking. It's fine to use it form outside of actors and # global_io_executor. # # @note it's a good practice to use {#tell} whenever possible. Results can be send back with other messages. # Ask should be used only for testing and when it returns very shortly. It can lead to deadlock if all threads in # global_io_executor will block on while asking. It's fine to use it form outside of actors and # global_io_executor. # @param [Object] message # @param [Promises::Future] future to be fulfilled be message's processing result # @return [Promises::Future] supplied future # @example # adder = AdHoc.spawn('adder') { -> message { message + 1 } } # adder.ask(1).value # => 2 # adder.ask(nil).wait.reason # => # def ask(message, future = Concurrent::Promises.resolvable_future) message message, future end # Sends the message synchronously and blocks until the message # is processed. Raises on error. # # @note it's a good practice to use {#tell} whenever possible. Results can be send back with other messages. # Ask should be used only for testing and when it returns very shortly. It can lead to deadlock if all threads in # global_io_executor will block on while asking. It's fine to use it form outside of actors and # global_io_executor. # @param [Object] message # @param [Promises::Future] future to be fulfilled be message's processing result # @return [Object] message's processing result # @raise [Exception] future.reason if future is #rejected? # @example # adder = AdHoc.spawn('adder') { -> message { message + 1 } } # adder.ask!(1) # => 2 def ask!(message, future = Concurrent::Promises.resolvable_future) ask(message, future).value! end def map(messages) messages.map { |m| self.ask(m) } end # behaves as {#tell} when no future and as {#ask} when future def message(message, future = nil) core.on_envelope Envelope.new(message, future, Actor.current || Thread.current, self) return future ? future.with_hidden_resolvable : self end # @see AbstractContext#dead_letter_routing def dead_letter_routing core.dead_letter_routing end def to_s "#<#{self.class}:0x#{'%x' % (object_id << 1)} #{path} (#{actor_class})>" end alias_method :inspect, :to_s def ==(other) Type? other, self.class and other.send(:core) == core end # to avoid confusion with Kernel.spawn undef_method :spawn end end end concurrent-ruby-1.0.5/lib/concurrent/actor/root.rb000066400000000000000000000020371305460430400222270ustar00rootroot00000000000000module Concurrent module Actor # implements the root actor class Root < AbstractContext def initialize # noinspection RubyArgCount @dead_letter_router = Core.new(parent: reference, class: DefaultDeadLetterHandler, supervise: true, name: :default_dead_letter_handler).reference end # to allow spawning of new actors, spawn needs to be called inside the parent Actor def on_message(message) case when message.is_a?(::Array) && message.first == :spawn Actor.spawn message[1], &message[2] when message == :dead_letter_routing @dead_letter_router else # ignore end end def dead_letter_routing @dead_letter_router end def behaviour_definition [*Behaviour.base(:just_log), *Behaviour.supervising, *Behaviour.user_messages] end end end end concurrent-ruby-1.0.5/lib/concurrent/actor/type_check.rb000066400000000000000000000020451305460430400233610ustar00rootroot00000000000000module Concurrent module Actor # taken from Algebrick # supplies type-checking helpers whenever included module TypeCheck def Type?(value, *types) types.any? { |t| value.is_a? t } end def Type!(value, *types) Type?(value, *types) or TypeCheck.error(value, 'is not', types) value end def Match?(value, *types) types.any? { |t| t === value } end def Match!(value, *types) Match?(value, *types) or TypeCheck.error(value, 'is not matching', types) value end def Child?(value, *types) Type?(value, Class) && types.any? { |t| value <= t } end def Child!(value, *types) Child?(value, *types) or TypeCheck.error(value, 'is not child', types) value end private def self.error(value, message, types) raise TypeError, "Value (#{value.class}) '#{value}' #{message} any of: #{types.join('; ')}." end end end end concurrent-ruby-1.0.5/lib/concurrent/actor/utils.rb000066400000000000000000000003771305460430400224110ustar00rootroot00000000000000module Concurrent module Actor module Utils require 'concurrent/actor/utils/ad_hoc' require 'concurrent/actor/utils/broadcast' require 'concurrent/actor/utils/balancer' require 'concurrent/actor/utils/pool' end end end concurrent-ruby-1.0.5/lib/concurrent/actor/utils/000077500000000000000000000000001305460430400220555ustar00rootroot00000000000000concurrent-ruby-1.0.5/lib/concurrent/actor/utils/ad_hoc.rb000066400000000000000000000012161305460430400236170ustar00rootroot00000000000000module Concurrent module Actor module Utils module AsAdHoc def initialize(*args, &initializer) @on_message = Type! initializer.call(*args), Proc end def on_message(message) instance_exec message, &@on_message end end # Allows quick creation of actors with behaviour defined by blocks. # @example ping # AdHoc.spawn :forward, an_actor do |where| # # this block has to return proc defining #on_message behaviour # -> message { where.tell message } # end class AdHoc < Context include AsAdHoc end end end end concurrent-ruby-1.0.5/lib/concurrent/actor/utils/balancer.rb000066400000000000000000000022261305460430400241530ustar00rootroot00000000000000module Concurrent module Actor module Utils # Distributes messages between subscribed actors. Each actor'll get only one message then # it's unsubscribed. The actor needs to resubscribe when it's ready to receive next message. # It will buffer the messages if there is no worker registered. # @see Pool class Balancer < RestartingContext def initialize @receivers = [] @buffer = [] end def on_message(message) command, who = message case command when :subscribe @receivers << (who || envelope.sender) distribute true when :unsubscribe @receivers.delete(who || envelope.sender) true when :subscribed? @receivers.include?(who || envelope.sender) else @buffer << envelope distribute Behaviour::MESSAGE_PROCESSED end end def distribute while !@receivers.empty? && !@buffer.empty? redirect @receivers.shift, @buffer.shift end end end end end end concurrent-ruby-1.0.5/lib/concurrent/actor/utils/broadcast.rb000066400000000000000000000023641305460430400243510ustar00rootroot00000000000000require 'set' module Concurrent module Actor module Utils # Allows to build pub/sub easily. # @example news # news_channel = Concurrent::Actor::Utils::Broadcast.spawn :news # # 2.times do |i| # Concurrent::Actor::Utils::AdHoc.spawn "listener-#{i}" do # news_channel << :subscribe # -> message { puts message } # end # end # # news_channel << 'Ruby rocks!' # # prints: 'Ruby rocks!' twice class Broadcast < RestartingContext def initialize @receivers = Set.new end def on_message(message) case message when :subscribe if envelope.sender.is_a? Reference @receivers.add envelope.sender true else false end when :unsubscribe !!@receivers.delete(envelope.sender) when :subscribed? @receivers.include? envelope.sender else filtered_receivers.each { |r| r << message } end end # override to define different behaviour, filtering etc def filtered_receivers @receivers end end end end end concurrent-ruby-1.0.5/lib/concurrent/actor/utils/pool.rb000066400000000000000000000041351305460430400233560ustar00rootroot00000000000000require 'concurrent/actor/utils/balancer' module Concurrent module Actor module Utils # Allows to create a pool of workers and distribute work between them # @param [Integer] size number of workers # @yield [balancer, index] a block spawning an worker instance. called +size+ times. # The worker should be descendant of AbstractWorker and supervised, see example. # @yieldparam [Balancer] balancer to pass to the worker # @yieldparam [Integer] index of the worker, usually used in its name # @yieldreturn [Reference] the reference of newly created worker # @example # class Worker < Concurrent::Actor::RestartingContext # def on_message(message) # p message * 5 # end # end # # pool = Concurrent::Actor::Utils::Pool.spawn! 'pool', 5 do |index| # Worker.spawn name: "worker-#{index}", supervise: true, args: [] # end # # pool << 'asd' << 2 # # prints: # # "asdasdasdasdasd" # # 10 class Pool < RestartingContext def initialize(size, &worker_initializer) @balancer = Balancer.spawn name: :balancer, supervise: true @workers = ::Array.new(size, &worker_initializer) @workers.each do |worker| Type! worker, Reference @balancer << [:subscribe, worker] end end def on_message(message) command, _ = message return if [:restarted, :reset, :resumed, :terminated].include? command # ignore events from supervised actors envelope_to_redirect = if envelope.future envelope else Envelope.new(envelope.message, Promises.resolvable_future, envelope.sender, envelope.address) end envelope_to_redirect.future.on_fulfillment! { @balancer << :subscribe } # TODO check safety of @balancer reading redirect @balancer, envelope_to_redirect end end end end end concurrent-ruby-1.0.5/lib/concurrent/agent.rb000066400000000000000000000531171305460430400212370ustar00rootroot00000000000000require 'concurrent/configuration' require 'concurrent/atomic/atomic_reference' require 'concurrent/atomic/thread_local_var' require 'concurrent/collection/copy_on_write_observer_set' require 'concurrent/concern/observable' require 'concurrent/synchronization' module Concurrent # `Agent` is inspired by Clojure's [agent](http://clojure.org/agents) # function. An agent is a shared, mutable variable providing independent, # uncoordinated, *asynchronous* change of individual values. Best used when # the value will undergo frequent, complex updates. Suitable when the result # of an update does not need to be known immediately. `Agent` is (mostly) # functionally equivalent to Clojure's agent, except where the runtime # prevents parity. # # Agents are reactive, not autonomous - there is no imperative message loop # and no blocking receive. The state of an Agent should be itself immutable # and the `#value` of an Agent is always immediately available for reading by # any thread without any messages, i.e. observation does not require # cooperation or coordination. # # Agent action dispatches are made using the various `#send` methods. These # methods always return immediately. At some point later, in another thread, # the following will happen: # # 1. The given `action` will be applied to the state of the Agent and the # `args`, if any were supplied. # 2. The return value of `action` will be passed to the validator lambda, # if one has been set on the Agent. # 3. If the validator succeeds or if no validator was given, the return value # of the given `action` will become the new `#value` of the Agent. See # `#initialize` for details. # 4. If any observers were added to the Agent, they will be notified. See # `#add_observer` for details. # 5. If during the `action` execution any other dispatches are made (directly # or indirectly), they will be held until after the `#value` of the Agent # has been changed. # # If any exceptions are thrown by an action function, no nested dispatches # will occur, and the exception will be cached in the Agent itself. When an # Agent has errors cached, any subsequent interactions will immediately throw # an exception, until the agent's errors are cleared. Agent errors can be # examined with `#error` and the agent restarted with `#restart`. # # The actions of all Agents get interleaved amongst threads in a thread pool. # At any point in time, at most one action for each Agent is being executed. # Actions dispatched to an agent from another single agent or thread will # occur in the order they were sent, potentially interleaved with actions # dispatched to the same agent from other sources. The `#send` method should # be used for actions that are CPU limited, while the `#send_off` method is # appropriate for actions that may block on IO. # # Unlike in Clojure, `Agent` cannot participate in `Concurrent::TVar` transactions. # # ## Example # # ``` # def next_fibonacci(set = nil) # return [0, 1] if set.nil? # set + [set[-2..-1].reduce{|sum,x| sum + x }] # end # # # create an agent with an initial value # agent = Concurrent::Agent.new(next_fibonacci) # # # send a few update requests # 5.times do # agent.send{|set| next_fibonacci(set) } # end # # # wait for them to complete # agent.await # # # get the current value # agent.value #=> [0, 1, 1, 2, 3, 5, 8] # ``` # # ## Observation # # Agents support observers through the {Concurrent::Observable} mixin module. # Notification of observers occurs every time an action dispatch returns and # the new value is successfully validated. Observation will *not* occur if the # action raises an exception, if validation fails, or when a {#restart} occurs. # # When notified the observer will receive three arguments: `time`, `old_value`, # and `new_value`. The `time` argument is the time at which the value change # occurred. The `old_value` is the value of the Agent when the action began # processing. The `new_value` is the value to which the Agent was set when the # action completed. Note that `old_value` and `new_value` may be the same. # This is not an error. It simply means that the action returned the same # value. # # ## Nested Actions # # It is possible for an Agent action to post further actions back to itself. # The nested actions will be enqueued normally then processed *after* the # outer action completes, in the order they were sent, possibly interleaved # with action dispatches from other threads. Nested actions never deadlock # with one another and a failure in a nested action will never affect the # outer action. # # Nested actions can be called using the Agent reference from the enclosing # scope or by passing the reference in as a "send" argument. Nested actions # cannot be post using `self` from within the action block/proc/lambda; `self` # in this context will not reference the Agent. The preferred method for # dispatching nested actions is to pass the Agent as an argument. This allows # Ruby to more effectively manage the closing scope. # # Prefer this: # # ``` # agent = Concurrent::Agent.new(0) # agent.send(agent) do |value, this| # this.send {|v| v + 42 } # 3.14 # end # agent.value #=> 45.14 # ``` # # Over this: # # ``` # agent = Concurrent::Agent.new(0) # agent.send do |value| # agent.send {|v| v + 42 } # 3.14 # end # ``` # # @!macro [new] agent_await_warning # # **NOTE** Never, *under any circumstances*, call any of the "await" methods # ({#await}, {#await_for}, {#await_for!}, and {#wait}) from within an action # block/proc/lambda. The call will block the Agent and will always fail. # Calling either {#await} or {#wait} (with a timeout of `nil`) will # hopelessly deadlock the Agent with no possibility of recovery. # # @!macro thread_safe_variable_comparison # # @see http://clojure.org/Agents Clojure Agents # @see http://clojure.org/state Values and Change - Clojure's approach to Identity and State class Agent < Synchronization::LockableObject include Concern::Observable ERROR_MODES = [:continue, :fail].freeze private_constant :ERROR_MODES AWAIT_FLAG = Object.new private_constant :AWAIT_FLAG AWAIT_ACTION = ->(value, latch) { latch.count_down; AWAIT_FLAG } private_constant :AWAIT_ACTION DEFAULT_ERROR_HANDLER = ->(agent, error) { nil } private_constant :DEFAULT_ERROR_HANDLER DEFAULT_VALIDATOR = ->(value) { true } private_constant :DEFAULT_VALIDATOR Job = Struct.new(:action, :args, :executor, :caller) private_constant :Job # Raised during action processing or any other time in an Agent's lifecycle. class Error < StandardError def initialize(message = nil) message ||= 'agent must be restarted before jobs can post' super(message) end end # Raised when a new value obtained during action processing or at `#restart` # fails validation. class ValidationError < Error def initialize(message = nil) message ||= 'invalid value' super(message) end end # The error mode this Agent is operating in. See {#initialize} for details. attr_reader :error_mode # Create a new `Agent` with the given initial value and options. # # The `:validator` option must be `nil` or a side-effect free proc/lambda # which takes one argument. On any intended value change the validator, if # provided, will be called. If the new value is invalid the validator should # return `false` or raise an error. # # The `:error_handler` option must be `nil` or a proc/lambda which takes two # arguments. When an action raises an error or validation fails, either by # returning false or raising an error, the error handler will be called. The # arguments to the error handler will be a reference to the agent itself and # the error object which was raised. # # The `:error_mode` may be either `:continue` (the default if an error # handler is given) or `:fail` (the default if error handler nil or not # given). # # If an action being run by the agent throws an error or doesn't pass # validation the error handler, if present, will be called. After the # handler executes if the error mode is `:continue` the Agent will continue # as if neither the action that caused the error nor the error itself ever # happened. # # If the mode is `:fail` the Agent will become {#failed?} and will stop # accepting new action dispatches. Any previously queued actions will be # held until {#restart} is called. The {#value} method will still work, # returning the value of the Agent before the error. # # @param [Object] initial the initial value # @param [Hash] opts the configuration options # # @option opts [Symbol] :error_mode either `:continue` or `:fail` # @option opts [nil, Proc] :error_handler the (optional) error handler # @option opts [nil, Proc] :validator the (optional) validation procedure def initialize(initial, opts = {}) super() synchronize { ns_initialize(initial, opts) } end # The current value (state) of the Agent, irrespective of any pending or # in-progress actions. The value is always available and is non-blocking. # # @return [Object] the current value def value @current.value # TODO (pitr 12-Sep-2015): broken unsafe read? end alias_method :deref, :value # When {#failed?} and {#error_mode} is `:fail`, returns the error object # which caused the failure, else `nil`. When {#error_mode} is `:continue` # will *always* return `nil`. # # @return [nil, Error] the error which caused the failure when {#failed?} def error @error.value end alias_method :reason, :error # @!macro [attach] agent_send # # Dispatches an action to the Agent and returns immediately. Subsequently, # in a thread from a thread pool, the {#value} will be set to the return # value of the action. Action dispatches are only allowed when the Agent # is not {#failed?}. # # The action must be a block/proc/lambda which takes 1 or more arguments. # The first argument is the current {#value} of the Agent. Any arguments # passed to the send method via the `args` parameter will be passed to the # action as the remaining arguments. The action must return the new value # of the Agent. # # * {#send} and {#send!} should be used for actions that are CPU limited # * {#send_off}, {#send_off!}, and {#<<} are appropriate for actions that # may block on IO # * {#send_via} and {#send_via!} are used when a specific executor is to # be used for the action # # @param [Array] args zero or more arguments to be passed to # the action # @param [Proc] action the action dispatch to be enqueued # # @yield [agent, value, *args] process the old value and return the new # @yieldparam [Object] value the current {#value} of the Agent # @yieldparam [Array] args zero or more arguments to pass to the # action # @yieldreturn [Object] the new value of the Agent # # @!macro [attach] send_return # @return [Boolean] true if the action is successfully enqueued, false if # the Agent is {#failed?} def send(*args, &action) enqueue_action_job(action, args, Concurrent.global_fast_executor) end # @!macro agent_send # # @!macro [attach] send_bang_return_and_raise # @return [Boolean] true if the action is successfully enqueued # @raise [Concurrent::Agent::Error] if the Agent is {#failed?} def send!(*args, &action) raise Error.new unless send(*args, &action) true end # @!macro agent_send # @!macro send_return def send_off(*args, &action) enqueue_action_job(action, args, Concurrent.global_io_executor) end alias_method :post, :send_off # @!macro agent_send # @!macro send_bang_return_and_raise def send_off!(*args, &action) raise Error.new unless send_off(*args, &action) true end # @!macro agent_send # @!macro send_return # @param [Concurrent::ExecutorService] executor the executor on which the # action is to be dispatched def send_via(executor, *args, &action) enqueue_action_job(action, args, executor) end # @!macro agent_send # @!macro send_bang_return_and_raise # @param [Concurrent::ExecutorService] executor the executor on which the # action is to be dispatched def send_via!(executor, *args, &action) raise Error.new unless send_via(executor, *args, &action) true end # Dispatches an action to the Agent and returns immediately. Subsequently, # in a thread from a thread pool, the {#value} will be set to the return # value of the action. Appropriate for actions that may block on IO. # # @param [Proc] action the action dispatch to be enqueued # @return [Concurrent::Agent] self # @see {#send_off} def <<(action) send_off(&action) self end # Blocks the current thread (indefinitely!) until all actions dispatched # thus far, from this thread or nested by the Agent, have occurred. Will # block when {#failed?}. Will never return if a failed Agent is {#restart} # with `:clear_actions` true. # # Returns a reference to `self` to support method chaining: # # ``` # current_value = agent.await.value # ``` # # @return [Boolean] self # # @!macro agent_await_warning def await wait(nil) self end # Blocks the current thread until all actions dispatched thus far, from this # thread or nested by the Agent, have occurred, or the timeout (in seconds) # has elapsed. # # @param [Float] timeout the maximum number of seconds to wait # @return [Boolean] true if all actions complete before timeout else false # # @!macro agent_await_warning def await_for(timeout) wait(timeout.to_f) end # Blocks the current thread until all actions dispatched thus far, from this # thread or nested by the Agent, have occurred, or the timeout (in seconds) # has elapsed. # # @param [Float] timeout the maximum number of seconds to wait # @return [Boolean] true if all actions complete before timeout # # @raise [Concurrent::TimeoutError] when timout is reached # # @!macro agent_await_warning def await_for!(timeout) raise Concurrent::TimeoutError unless wait(timeout.to_f) true end # Blocks the current thread until all actions dispatched thus far, from this # thread or nested by the Agent, have occurred, or the timeout (in seconds) # has elapsed. Will block indefinitely when timeout is nil or not given. # # Provided mainly for consistency with other classes in this library. Prefer # the various `await` methods instead. # # @param [Float] timeout the maximum number of seconds to wait # @return [Boolean] true if all actions complete before timeout else false # # @!macro agent_await_warning def wait(timeout = nil) latch = Concurrent::CountDownLatch.new(1) enqueue_await_job(latch) latch.wait(timeout) end # Is the Agent in a failed state? # # @see {#restart} def failed? !@error.value.nil? end alias_method :stopped?, :failed? # When an Agent is {#failed?}, changes the Agent {#value} to `new_value` # then un-fails the Agent so that action dispatches are allowed again. If # the `:clear_actions` option is give and true, any actions queued on the # Agent that were being held while it was failed will be discarded, # otherwise those held actions will proceed. The `new_value` must pass the # validator if any, or `restart` will raise an exception and the Agent will # remain failed with its old {#value} and {#error}. Observers, if any, will # not be notified of the new state. # # @param [Object] new_value the new value for the Agent once restarted # @param [Hash] opts the configuration options # @option opts [Symbol] :clear_actions true if all enqueued but unprocessed # actions should be discarded on restart, else false (default: false) # @return [Boolean] true # # @raise [Concurrent:AgentError] when not failed def restart(new_value, opts = {}) clear_actions = opts.fetch(:clear_actions, false) synchronize do raise Error.new('agent is not failed') unless failed? raise ValidationError unless ns_validate(new_value) @current.value = new_value @error.value = nil @queue.clear if clear_actions ns_post_next_job unless @queue.empty? end true end class << self # Blocks the current thread (indefinitely!) until all actions dispatched # thus far to all the given Agents, from this thread or nested by the # given Agents, have occurred. Will block when any of the agents are # failed. Will never return if a failed Agent is restart with # `:clear_actions` true. # # @param [Array] agents the Agents on which to wait # @return [Boolean] true # # @!macro agent_await_warning def await(*agents) agents.each { |agent| agent.await } true end # Blocks the current thread until all actions dispatched thus far to all # the given Agents, from this thread or nested by the given Agents, have # occurred, or the timeout (in seconds) has elapsed. # # @param [Float] timeout the maximum number of seconds to wait # @param [Array] agents the Agents on which to wait # @return [Boolean] true if all actions complete before timeout else false # # @!macro agent_await_warning def await_for(timeout, *agents) end_at = Concurrent.monotonic_time + timeout.to_f ok = agents.length.times do |i| break false if (delay = end_at - Concurrent.monotonic_time) < 0 break false unless agents[i].await_for(delay) end !!ok end # Blocks the current thread until all actions dispatched thus far to all # the given Agents, from this thread or nested by the given Agents, have # occurred, or the timeout (in seconds) has elapsed. # # @param [Float] timeout the maximum number of seconds to wait # @param [Array] agents the Agents on which to wait # @return [Boolean] true if all actions complete before timeout # # @raise [Concurrent::TimeoutError] when timout is reached # @!macro agent_await_warning def await_for!(timeout, *agents) raise Concurrent::TimeoutError unless await_for(timeout, *agents) true end end private def ns_initialize(initial, opts) @error_mode = opts[:error_mode] @error_handler = opts[:error_handler] if @error_mode && !ERROR_MODES.include?(@error_mode) raise ArgumentError.new('unrecognized error mode') elsif @error_mode.nil? @error_mode = @error_handler ? :continue : :fail end @error_handler ||= DEFAULT_ERROR_HANDLER @validator = opts.fetch(:validator, DEFAULT_VALIDATOR) @current = Concurrent::AtomicReference.new(initial) @error = Concurrent::AtomicReference.new(nil) @caller = Concurrent::ThreadLocalVar.new(nil) @queue = [] self.observers = Collection::CopyOnNotifyObserverSet.new end def enqueue_action_job(action, args, executor) raise ArgumentError.new('no action given') unless action job = Job.new(action, args, executor, @caller.value || Thread.current.object_id) synchronize { ns_enqueue_job(job) } end def enqueue_await_job(latch) synchronize do if (index = ns_find_last_job_for_thread) job = Job.new(AWAIT_ACTION, [latch], Concurrent.global_immediate_executor, Thread.current.object_id) ns_enqueue_job(job, index+1) else latch.count_down true end end end def ns_enqueue_job(job, index = nil) # a non-nil index means this is an await job return false if index.nil? && failed? index ||= @queue.length @queue.insert(index, job) # if this is the only job, post to executor ns_post_next_job if @queue.length == 1 true end def ns_post_next_job @queue.first.executor.post { execute_next_job } end def execute_next_job job = synchronize { @queue.first } old_value = @current.value @caller.value = job.caller # for nested actions new_value = job.action.call(old_value, *job.args) @caller.value = nil return if new_value == AWAIT_FLAG if ns_validate(new_value) @current.value = new_value observers.notify_observers(Time.now, old_value, new_value) else handle_error(ValidationError.new) end rescue => error handle_error(error) ensure synchronize do @queue.shift unless failed? || @queue.empty? ns_post_next_job end end end def ns_validate(value) @validator.call(value) rescue false end def handle_error(error) # stop new jobs from posting @error.value = error if @error_mode == :fail @error_handler.call(self, error) rescue # do nothing end def ns_find_last_job_for_thread @queue.rindex { |job| job.caller == Thread.current.object_id } end end end concurrent-ruby-1.0.5/lib/concurrent/array.rb000066400000000000000000000020571305460430400212540ustar00rootroot00000000000000require 'concurrent/utility/engine' require 'concurrent/thread_safe/util' module Concurrent if Concurrent.on_cruby? # Because MRI never runs code in parallel, the existing # non-thread-safe structures should usually work fine. # @!macro [attach] concurrent_array # # A thread-safe subclass of Array. This version locks against the object # itself for every method call, ensuring only one thread can be reading # or writing at a time. This includes iteration methods like `#each`. # # @see http://ruby-doc.org/core-2.2.0/Array.html Ruby standard library `Array` class Array < ::Array; end elsif Concurrent.on_jruby? require 'jruby/synchronized' # @!macro concurrent_array class Array < ::Array include JRuby::Synchronized end elsif Concurrent.on_rbx? || Concurrent.on_truffle? require 'monitor' require 'concurrent/thread_safe/util/array_hash_rbx' # @!macro concurrent_array class Array < ::Array end ThreadSafe::Util.make_synchronized_on_rbx Array end end concurrent-ruby-1.0.5/lib/concurrent/async.rb000066400000000000000000000433131305460430400212530ustar00rootroot00000000000000require 'concurrent/configuration' require 'concurrent/ivar' require 'concurrent/synchronization/lockable_object' module Concurrent # A mixin module that provides simple asynchronous behavior to a class, # turning it into a simple actor. Loosely based on Erlang's # [gen_server](http://www.erlang.org/doc/man/gen_server.html), but without # supervision or linking. # # A more feature-rich {Concurrent::Actor} is also available when the # capabilities of `Async` are too limited. # # ```cucumber # Feature: # As a stateful, plain old Ruby class # I want safe, asynchronous behavior # So my long-running methods don't block the main thread # ``` # # The `Async` module is a way to mix simple yet powerful asynchronous # capabilities into any plain old Ruby object or class, turning each object # into a simple Actor. Method calls are processed on a background thread. The # caller is free to perform other actions while processing occurs in the # background. # # Method calls to the asynchronous object are made via two proxy methods: # `async` (alias `cast`) and `await` (alias `call`). These proxy methods post # the method call to the object's background thread and return a "future" # which will eventually contain the result of the method call. # # This behavior is loosely patterned after Erlang's `gen_server` behavior. # When an Erlang module implements the `gen_server` behavior it becomes # inherently asynchronous. The `start` or `start_link` function spawns a # process (similar to a thread but much more lightweight and efficient) and # returns the ID of the process. Using the process ID, other processes can # send messages to the `gen_server` via the `cast` and `call` methods. Unlike # Erlang's `gen_server`, however, `Async` classes do not support linking or # supervision trees. # # ## Basic Usage # # When this module is mixed into a class, objects of the class become inherently # asynchronous. Each object gets its own background thread on which to post # asynchronous method calls. Asynchronous method calls are executed in the # background one at a time in the order they are received. # # To create an asynchronous class, simply mix in the `Concurrent::Async` module: # # ``` # class Hello # include Concurrent::Async # # def hello(name) # "Hello, #{name}!" # end # end # ``` # # When defining a constructor it is critical that the first line be a call to # `super` with no arguments. The `super` method initializes the background # thread and other asynchronous components. # # ``` # class BackgroundLogger # include Concurrent::Async # # def initialize(level) # super() # @logger = Logger.new(STDOUT) # @logger.level = level # end # # def info(msg) # @logger.info(msg) # end # end # ``` # # Mixing this module into a class provides each object two proxy methods: # `async` and `await`. These methods are thread safe with respect to the # enclosing object. The former proxy allows methods to be called # asynchronously by posting to the object's internal thread. The latter proxy # allows a method to be called synchronously but does so safely with respect # to any pending asynchronous method calls and ensures proper ordering. Both # methods return a {Concurrent::IVar} which can be inspected for the result # of the proxied method call. Calling a method with `async` will return a # `:pending` `IVar` whereas `await` will return a `:complete` `IVar`. # # ``` # class Echo # include Concurrent::Async # # def echo(msg) # print "#{msg}\n" # end # end # # horn = Echo.new # horn.echo('zero') # synchronous, not thread-safe # # returns the actual return value of the method # # horn.async.echo('one') # asynchronous, non-blocking, thread-safe # # returns an IVar in the :pending state # # horn.await.echo('two') # synchronous, blocking, thread-safe # # returns an IVar in the :complete state # ``` # # ## Let It Fail # # The `async` and `await` proxy methods have built-in error protection based # on Erlang's famous "let it fail" philosophy. Instance methods should not be # programmed defensively. When an exception is raised by a delegated method # the proxy will rescue the exception, expose it to the caller as the `reason` # attribute of the returned future, then process the next method call. # # ## Calling Methods Internally # # External method calls should *always* use the `async` and `await` proxy # methods. When one method calls another method, the `async` proxy should # rarely be used and the `await` proxy should *never* be used. # # When an object calls one of its own methods using the `await` proxy the # second call will be enqueued *behind* the currently running method call. # Any attempt to wait on the result will fail as the second call will never # run until after the current call completes. # # Calling a method using the `await` proxy from within a method that was # itself called using `async` or `await` will irreversibly deadlock the # object. Do *not* do this, ever. # # ## Instance Variables and Attribute Accessors # # Instance variables do not need to be thread-safe so long as they are private. # Asynchronous method calls are processed in the order they are received and # are processed one at a time. Therefore private instance variables can only # be accessed by one thread at a time. This is inherently thread-safe. # # When using private instance variables within asynchronous methods, the best # practice is to read the instance variable into a local variable at the start # of the method then update the instance variable at the *end* of the method. # This way, should an exception be raised during method execution the internal # state of the object will not have been changed. # # ### Reader Attributes # # The use of `attr_reader` is discouraged. Internal state exposed externally, # when necessary, should be done through accessor methods. The instance # variables exposed by these methods *must* be thread-safe, or they must be # called using the `async` and `await` proxy methods. These two approaches are # subtly different. # # When internal state is accessed via the `async` and `await` proxy methods, # the returned value represents the object's state *at the time the call is # processed*, which may *not* be the state of the object at the time the call # is made. # # To get the state *at the current* time, irrespective of an enqueued method # calls, a reader method must be called directly. This is inherently unsafe # unless the instance variable is itself thread-safe, preferrably using one # of the thread-safe classes within this library. Because the thread-safe # classes within this library are internally-locking or non-locking, they can # be safely used from within asynchronous methods without causing deadlocks. # # Generally speaking, the best practice is to *not* expose internal state via # reader methods. The best practice is to simply use the method's return value. # # ### Writer Attributes # # Writer attributes should never be used with asynchronous classes. Changing # the state externally, even when done in the thread-safe way, is not logically # consistent. Changes to state need to be timed with respect to all asynchronous # method calls which my be in-process or enqueued. The only safe practice is to # pass all necessary data to each method as arguments and let the method update # the internal state as necessary. # # ## Class Constants, Variables, and Methods # # ### Class Constants # # Class constants do not need to be thread-safe. Since they are read-only and # immutable they may be safely read both externally and from within # asynchronous methods. # # ### Class Variables # # Class variables should be avoided. Class variables represent shared state. # Shared state is anathema to concurrency. Should there be a need to share # state using class variables they *must* be thread-safe, preferrably # using the thread-safe classes within this library. When updating class # variables, never assign a new value/object to the variable itself. Assignment # is not thread-safe in Ruby. Instead, use the thread-safe update functions # of the variable itself to change the value. # # The best practice is to *never* use class variables with `Async` classes. # # ### Class Methods # # Class methods which are pure functions are safe. Class methods which modify # class variables should be avoided, for all the reasons listed above. # # ## An Important Note About Thread Safe Guarantees # # > Thread safe guarantees can only be made when asynchronous method calls # > are not mixed with direct method calls. Use only direct method calls # > when the object is used exclusively on a single thread. Use only # > `async` and `await` when the object is shared between threads. Once you # > call a method using `async` or `await`, you should no longer call methods # > directly on the object. Use `async` and `await` exclusively from then on. # # @example # # class Echo # include Concurrent::Async # # def echo(msg) # print "#{msg}\n" # end # end # # horn = Echo.new # horn.echo('zero') # synchronous, not thread-safe # # returns the actual return value of the method # # horn.async.echo('one') # asynchronous, non-blocking, thread-safe # # returns an IVar in the :pending state # # horn.await.echo('two') # synchronous, blocking, thread-safe # # returns an IVar in the :complete state # # @see Concurrent::Actor # @see https://en.wikipedia.org/wiki/Actor_model "Actor Model" at Wikipedia # @see http://www.erlang.org/doc/man/gen_server.html Erlang gen_server # @see http://c2.com/cgi/wiki?LetItCrash "Let It Crash" at http://c2.com/ module Async # @!method self.new(*args, &block) # # Instanciate a new object and ensure proper initialization of the # synchronization mechanisms. # # @param [Array] args Zero or more arguments to be passed to the # object's initializer. # @param [Proc] block Optional block to pass to the object's initializer. # @return [Object] A properly initialized object of the asynchronous class. # Check for the presence of a method on an object and determine if a given # set of arguments matches the required arity. # # @param [Object] obj the object to check against # @param [Symbol] method the method to check the object for # @param [Array] args zero or more arguments for the arity check # # @raise [NameError] the object does not respond to `method` method # @raise [ArgumentError] the given `args` do not match the arity of `method` # # @note This check is imperfect because of the way Ruby reports the arity of # methods with a variable number of arguments. It is possible to determine # if too few arguments are given but impossible to determine if too many # arguments are given. This check may also fail to recognize dynamic behavior # of the object, such as methods simulated with `method_missing`. # # @see http://www.ruby-doc.org/core-2.1.1/Method.html#method-i-arity Method#arity # @see http://ruby-doc.org/core-2.1.0/Object.html#method-i-respond_to-3F Object#respond_to? # @see http://www.ruby-doc.org/core-2.1.0/BasicObject.html#method-i-method_missing BasicObject#method_missing # # @!visibility private def self.validate_argc(obj, method, *args) argc = args.length arity = obj.method(method).arity if arity >= 0 && argc != arity raise ArgumentError.new("wrong number of arguments (#{argc} for #{arity})") elsif arity < 0 && (arity = (arity + 1).abs) > argc raise ArgumentError.new("wrong number of arguments (#{argc} for #{arity}..*)") end end # @!visibility private def self.included(base) base.singleton_class.send(:alias_method, :original_new, :new) base.extend(ClassMethods) super(base) end # @!visibility private module ClassMethods def new(*args, &block) obj = original_new(*args, &block) obj.send(:init_synchronization) obj end end private_constant :ClassMethods # Delegates asynchronous, thread-safe method calls to the wrapped object. # # @!visibility private class AsyncDelegator < Synchronization::LockableObject safe_initialization! # Create a new delegator object wrapping the given delegate. # # @param [Object] delegate the object to wrap and delegate method calls to def initialize(delegate) super() @delegate = delegate @queue = [] @executor = Concurrent.global_io_executor end # Delegates method calls to the wrapped object. # # @param [Symbol] method the method being called # @param [Array] args zero or more arguments to the method # # @return [IVar] the result of the method call # # @raise [NameError] the object does not respond to `method` method # @raise [ArgumentError] the given `args` do not match the arity of `method` def method_missing(method, *args, &block) super unless @delegate.respond_to?(method) Async::validate_argc(@delegate, method, *args) ivar = Concurrent::IVar.new synchronize do @queue.push [ivar, method, args, block] @executor.post { perform } if @queue.length == 1 end ivar end # Perform all enqueued tasks. # # This method must be called from within the executor. It must not be # called while already running. It will loop until the queue is empty. def perform loop do ivar, method, args, block = synchronize { @queue.first } break unless ivar # queue is empty begin ivar.set(@delegate.send(method, *args, &block)) rescue => error ivar.fail(error) end synchronize do @queue.shift return if @queue.empty? end end end end private_constant :AsyncDelegator # Delegates synchronous, thread-safe method calls to the wrapped object. # # @!visibility private class AwaitDelegator # Create a new delegator object wrapping the given delegate. # # @param [AsyncDelegator] delegate the object to wrap and delegate method calls to def initialize(delegate) @delegate = delegate end # Delegates method calls to the wrapped object. # # @param [Symbol] method the method being called # @param [Array] args zero or more arguments to the method # # @return [IVar] the result of the method call # # @raise [NameError] the object does not respond to `method` method # @raise [ArgumentError] the given `args` do not match the arity of `method` def method_missing(method, *args, &block) ivar = @delegate.send(method, *args, &block) ivar.wait ivar end end private_constant :AwaitDelegator # Causes the chained method call to be performed asynchronously on the # object's thread. The delegated method will return a future in the # `:pending` state and the method call will have been scheduled on the # object's thread. The final disposition of the method call can be obtained # by inspecting the returned future. # # @!macro [attach] async_thread_safety_warning # @note The method call is guaranteed to be thread safe with respect to # all other method calls against the same object that are called with # either `async` or `await`. The mutable nature of Ruby references # (and object orientation in general) prevent any other thread safety # guarantees. Do NOT mix direct method calls with delegated method calls. # Use *only* delegated method calls when sharing the object between threads. # # @return [Concurrent::IVar] the pending result of the asynchronous operation # # @raise [NameError] the object does not respond to the requested method # @raise [ArgumentError] the given `args` do not match the arity of # the requested method def async @__async_delegator__ end alias_method :cast, :async # Causes the chained method call to be performed synchronously on the # current thread. The delegated will return a future in either the # `:fulfilled` or `:rejected` state and the delegated method will have # completed. The final disposition of the delegated method can be obtained # by inspecting the returned future. # # @!macro async_thread_safety_warning # # @return [Concurrent::IVar] the completed result of the synchronous operation # # @raise [NameError] the object does not respond to the requested method # @raise [ArgumentError] the given `args` do not match the arity of the # requested method def await @__await_delegator__ end alias_method :call, :await # Initialize the internal serializer and other stnchronization mechanisms. # # @note This method *must* be called immediately upon object construction. # This is the only way thread-safe initialization can be guaranteed. # # @!visibility private def init_synchronization return self if @__async_initialized__ @__async_initialized__ = true @__async_delegator__ = AsyncDelegator.new(self) @__await_delegator__ = AwaitDelegator.new(@__async_delegator__) self end end end concurrent-ruby-1.0.5/lib/concurrent/atom.rb000066400000000000000000000215441305460430400211000ustar00rootroot00000000000000require 'concurrent/atomic/atomic_reference' require 'concurrent/collection/copy_on_notify_observer_set' require 'concurrent/concern/observable' require 'concurrent/synchronization' # @!macro [new] thread_safe_variable_comparison # # ## Thread-safe Variable Classes # # Each of the thread-safe variable classes is designed to solve a different # problem. In general: # # * *{Concurrent::Agent}:* Shared, mutable variable providing independent, # uncoordinated, *asynchronous* change of individual values. Best used when # the value will undergo frequent, complex updates. Suitable when the result # of an update does not need to be known immediately. # * *{Concurrent::Atom}:* Shared, mutable variable providing independent, # uncoordinated, *synchronous* change of individual values. Best used when # the value will undergo frequent reads but only occasional, though complex, # updates. Suitable when the result of an update must be known immediately. # * *{Concurrent::AtomicReference}:* A simple object reference that can be # atomically. Updates are synchronous but fast. Best used when updates a # simple set operations. Not suitable when updates are complex. # {Concurrent::AtomicBoolean} and {Concurrent::AtomicFixnum} are similar # but optimized for the given data type. # * *{Concurrent::Exchanger}:* Shared, stateless synchronization point. Used # when two or more threads need to exchange data. The threads will pair then # block on each other until the exchange is complete. # * *{Concurrent::MVar}:* Shared synchronization point. Used when one thread # must give a value to another, which must take the value. The threads will # block on each other until the exchange is complete. # * *{Concurrent::ThreadLocalVar}:* Shared, mutable, isolated variable which # holds a different value for each thread which has access. Often used as # an instance variable in objects which must maintain different state # for different threads. # * *{Concurrent::TVar}:* Shared, mutable variables which provide # *coordinated*, *synchronous*, change of *many* stated. Used when multiple # value must change together, in an all-or-nothing transaction. module Concurrent # Atoms provide a way to manage shared, synchronous, independent state. # # An atom is initialized with an initial value and an optional validation # proc. At any time the value of the atom can be synchronously and safely # changed. If a validator is given at construction then any new value # will be checked against the validator and will be rejected if the # validator returns false or raises an exception. # # There are two ways to change the value of an atom: {#compare_and_set} and # {#swap}. The former will set the new value if and only if it validates and # the current value matches the new value. The latter will atomically set the # new value to the result of running the given block if and only if that # value validates. # # ## Example # # ``` # def next_fibonacci(set = nil) # return [0, 1] if set.nil? # set + [set[-2..-1].reduce{|sum,x| sum + x }] # end # # # create an atom with an initial value # atom = Concurrent::Atom.new(next_fibonacci) # # # send a few update requests # 5.times do # atom.swap{|set| next_fibonacci(set) } # end # # # get the current value # atom.value #=> [0, 1, 1, 2, 3, 5, 8] # ``` # # ## Observation # # Atoms support observers through the {Concurrent::Observable} mixin module. # Notification of observers occurs every time the value of the Atom changes. # When notified the observer will receive three arguments: `time`, `old_value`, # and `new_value`. The `time` argument is the time at which the value change # occurred. The `old_value` is the value of the Atom when the change began # The `new_value` is the value to which the Atom was set when the change # completed. Note that `old_value` and `new_value` may be the same. This is # not an error. It simply means that the change operation returned the same # value. # # Unlike in Clojure, `Atom` cannot participate in {Concurrent::TVar} transactions. # # @!macro thread_safe_variable_comparison # # @see http://clojure.org/atoms Clojure Atoms # @see http://clojure.org/state Values and Change - Clojure's approach to Identity and State class Atom < Synchronization::Object include Concern::Observable safe_initialization! private(*attr_atomic(:value)) public :value # Create a new atom with the given initial value. # # @param [Object] value The initial value # @param [Hash] opts The options used to configure the atom # @option opts [Proc] :validator (nil) Optional proc used to validate new # values. It must accept one and only one argument which will be the # intended new value. The validator will return true if the new value # is acceptable else return false (preferrably) or raise an exception. # # @!macro deref_options # # @raise [ArgumentError] if the validator is not a `Proc` (when given) def initialize(value, opts = {}) super() @Validator = opts.fetch(:validator, -> v { true }) self.observers = Collection::CopyOnNotifyObserverSet.new self.value = value end # @!method value # The current value of the atom. # # @return [Object] The current value. alias_method :deref, :value # Atomically swaps the value of atom using the given block. The current # value will be passed to the block, as will any arguments passed as # arguments to the function. The new value will be validated against the # (optional) validator proc given at construction. If validation fails the # value will not be changed. # # Internally, {#swap} reads the current value, applies the block to it, and # attempts to compare-and-set it in. Since another thread may have changed # the value in the intervening time, it may have to retry, and does so in a # spin loop. The net effect is that the value will always be the result of # the application of the supplied block to a current value, atomically. # However, because the block might be called multiple times, it must be free # of side effects. # # @note The given block may be called multiple times, and thus should be free # of side effects. # # @param [Object] args Zero or more arguments passed to the block. # # @yield [value, args] Calculates a new value for the atom based on the # current value and any supplied arguments. # @yieldparam value [Object] The current value of the atom. # @yieldparam args [Object] All arguments passed to the function, in order. # @yieldreturn [Object] The intended new value of the atom. # # @return [Object] The final value of the atom after all operations and # validations are complete. # # @raise [ArgumentError] When no block is given. def swap(*args) raise ArgumentError.new('no block given') unless block_given? loop do old_value = value new_value = yield(old_value, *args) begin break old_value unless valid?(new_value) break new_value if compare_and_set(old_value, new_value) rescue break old_value end end end # Atomically sets the value of atom to the new value if and only if the # current value of the atom is identical to the old value and the new # value successfully validates against the (optional) validator given # at construction. # # @param [Object] old_value The expected current value. # @param [Object] new_value The intended new value. # # @return [Boolean] True if the value is changed else false. def compare_and_set(old_value, new_value) if valid?(new_value) && compare_and_set_value(old_value, new_value) observers.notify_observers(Time.now, old_value, new_value) true else false end end # Atomically sets the value of atom to the new value without regard for the # current value so long as the new value successfully validates against the # (optional) validator given at construction. # # @param [Object] new_value The intended new value. # # @return [Object] The final value of the atom after all operations and # validations are complete. def reset(new_value) old_value = value if valid?(new_value) self.value = new_value observers.notify_observers(Time.now, old_value, new_value) new_value else old_value end end private # Is the new value valid? # # @param [Object] new_value The intended new value. # @return [Boolean] false if the validator function returns false or raises # an exception else true def valid?(new_value) @Validator.call(new_value) rescue false end end end concurrent-ruby-1.0.5/lib/concurrent/atomic/000077500000000000000000000000001305460430400210615ustar00rootroot00000000000000concurrent-ruby-1.0.5/lib/concurrent/atomic/abstract_thread_local_var.rb000066400000000000000000000024631305460430400265670ustar00rootroot00000000000000require 'concurrent/constants' module Concurrent # @!macro thread_local_var # @!macro internal_implementation_note # @!visibility private class AbstractThreadLocalVar # @!macro thread_local_var_method_initialize def initialize(default = nil, &default_block) if default && block_given? raise ArgumentError, "Cannot use both value and block as default value" end if block_given? @default_block = default_block @default = nil else @default_block = nil @default = default end allocate_storage end # @!macro thread_local_var_method_get def value raise NotImplementedError end # @!macro thread_local_var_method_set def value=(value) raise NotImplementedError end # @!macro thread_local_var_method_bind def bind(value, &block) if block_given? old_value = self.value begin self.value = value yield ensure self.value = old_value end end end protected # @!visibility private def allocate_storage raise NotImplementedError end # @!visibility private def default if @default_block self.value = @default_block.call else @default end end end end concurrent-ruby-1.0.5/lib/concurrent/atomic/atomic_boolean.rb000066400000000000000000000074571305460430400243760ustar00rootroot00000000000000require 'concurrent/atomic/mutex_atomic_boolean' require 'concurrent/synchronization' module Concurrent ################################################################### # @!macro [new] atomic_boolean_method_initialize # # Creates a new `AtomicBoolean` with the given initial value. # # @param [Boolean] initial the initial value # @!macro [new] atomic_boolean_method_value_get # # Retrieves the current `Boolean` value. # # @return [Boolean] the current value # @!macro [new] atomic_boolean_method_value_set # # Explicitly sets the value. # # @param [Boolean] value the new value to be set # # @return [Boolean] the current value # @!macro [new] atomic_boolean_method_true_question # # Is the current value `true` # # @return [Boolean] true if the current value is `true`, else false # @!macro [new] atomic_boolean_method_false_question # # Is the current value `false` # # @return [Boolean] true if the current value is `false`, else false # @!macro [new] atomic_boolean_method_make_true # # Explicitly sets the value to true. # # @return [Boolean] true is value has changed, otherwise false # @!macro [new] atomic_boolean_method_make_false # # Explicitly sets the value to false. # # @return [Boolean] true is value has changed, otherwise false ################################################################### # @!macro [new] atomic_boolean_public_api # # @!method initialize(initial = false) # @!macro atomic_boolean_method_initialize # # @!method value # @!macro atomic_boolean_method_value_get # # @!method value=(value) # @!macro atomic_boolean_method_value_set # # @!method true? # @!macro atomic_boolean_method_true_question # # @!method false? # @!macro atomic_boolean_method_false_question # # @!method make_true # @!macro atomic_boolean_method_make_true # # @!method make_false # @!macro atomic_boolean_method_make_false ################################################################### # @!visibility private # @!macro internal_implementation_note AtomicBooleanImplementation = case when defined?(JavaAtomicBoolean) JavaAtomicBoolean when defined?(CAtomicBoolean) CAtomicBoolean else MutexAtomicBoolean end private_constant :AtomicBooleanImplementation # @!macro [attach] atomic_boolean # # A boolean value that can be updated atomically. Reads and writes to an atomic # boolean and thread-safe and guaranteed to succeed. Reads and writes may block # briefly but no explicit locking is required. # # @!macro thread_safe_variable_comparison # # Testing with ruby 2.1.2 # Testing with Concurrent::MutexAtomicBoolean... # 2.790000 0.000000 2.790000 ( 2.791454) # Testing with Concurrent::CAtomicBoolean... # 0.740000 0.000000 0.740000 ( 0.740206) # # Testing with jruby 1.9.3 # Testing with Concurrent::MutexAtomicBoolean... # 5.240000 2.520000 7.760000 ( 3.683000) # Testing with Concurrent::JavaAtomicBoolean... # 3.340000 0.010000 3.350000 ( 0.855000) # # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicBoolean.html java.util.concurrent.atomic.AtomicBoolean # # @!macro atomic_boolean_public_api class AtomicBoolean < AtomicBooleanImplementation # @return [String] Short string representation. def to_s format '<#%s:0x%x value:%s>', self.class, object_id << 1, value end alias_method :inspect, :to_s end end concurrent-ruby-1.0.5/lib/concurrent/atomic/atomic_fixnum.rb000066400000000000000000000110151305460430400242460ustar00rootroot00000000000000require 'concurrent/atomic/mutex_atomic_fixnum' require 'concurrent/synchronization' module Concurrent ################################################################### # @!macro [new] atomic_fixnum_method_initialize # # Creates a new `AtomicFixnum` with the given initial value. # # @param [Fixnum] initial the initial value # @raise [ArgumentError] if the initial value is not a `Fixnum` # @!macro [new] atomic_fixnum_method_value_get # # Retrieves the current `Fixnum` value. # # @return [Fixnum] the current value # @!macro [new] atomic_fixnum_method_value_set # # Explicitly sets the value. # # @param [Fixnum] value the new value to be set # # @return [Fixnum] the current value # # @raise [ArgumentError] if the new value is not a `Fixnum` # @!macro [new] atomic_fixnum_method_increment # # Increases the current value by the given amount (defaults to 1). # # @param [Fixnum] delta the amount by which to increase the current value # # @return [Fixnum] the current value after incrementation # @!macro [new] atomic_fixnum_method_decrement # # Decreases the current value by the given amount (defaults to 1). # # @param [Fixnum] delta the amount by which to decrease the current value # # @return [Fixnum] the current value after decrementation # @!macro [new] atomic_fixnum_method_compare_and_set # # Atomically sets the value to the given updated value if the current # value == the expected value. # # @param [Fixnum] expect the expected value # @param [Fixnum] update the new value # # @return [Fixnum] true if the value was updated else false # @!macro [new] atomic_fixnum_method_update # # Pass the current value to the given block, replacing it # with the block's result. May retry if the value changes # during the block's execution. # # @yield [Object] Calculate a new value for the atomic reference using # given (old) value # @yieldparam [Object] old_value the starting value of the atomic reference # # @return [Object] the new value ################################################################### # @!macro [new] atomic_fixnum_public_api # # @!method initialize(initial = 0) # @!macro atomic_fixnum_method_initialize # # @!method value # @!macro atomic_fixnum_method_value_get # # @!method value=(value) # @!macro atomic_fixnum_method_value_set # # @!method increment # @!macro atomic_fixnum_method_increment # # @!method decrement # @!macro atomic_fixnum_method_decrement # # @!method compare_and_set(expect, update) # @!macro atomic_fixnum_method_compare_and_set # # @!method update # @!macro atomic_fixnum_method_update ################################################################### # @!visibility private # @!macro internal_implementation_note AtomicFixnumImplementation = case when defined?(JavaAtomicFixnum) JavaAtomicFixnum when defined?(CAtomicFixnum) CAtomicFixnum else MutexAtomicFixnum end private_constant :AtomicFixnumImplementation # @!macro [attach] atomic_fixnum # # A numeric value that can be updated atomically. Reads and writes to an atomic # fixnum and thread-safe and guaranteed to succeed. Reads and writes may block # briefly but no explicit locking is required. # # @!macro thread_safe_variable_comparison # # Testing with ruby 2.1.2 # Testing with Concurrent::MutexAtomicFixnum... # 3.130000 0.000000 3.130000 ( 3.136505) # Testing with Concurrent::CAtomicFixnum... # 0.790000 0.000000 0.790000 ( 0.785550) # # Testing with jruby 1.9.3 # Testing with Concurrent::MutexAtomicFixnum... # 5.460000 2.460000 7.920000 ( 3.715000) # Testing with Concurrent::JavaAtomicFixnum... # 4.520000 0.030000 4.550000 ( 1.187000) # # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicLong.html java.util.concurrent.atomic.AtomicLong # # @!macro atomic_fixnum_public_api class AtomicFixnum < AtomicFixnumImplementation # @return [String] Short string representation. def to_s format '<#%s:0x%x value:%s>', self.class, object_id << 1, value end alias_method :inspect, :to_s end end concurrent-ruby-1.0.5/lib/concurrent/atomic/atomic_reference.rb000066400000000000000000000024301305460430400246770ustar00rootroot00000000000000require 'concurrent/synchronization' require 'concurrent/utility/engine' require 'concurrent/atomic_reference/concurrent_update_error' require 'concurrent/atomic_reference/mutex_atomic' begin # force fallback impl with FORCE_ATOMIC_FALLBACK=1 if /[^0fF]/ =~ ENV['FORCE_ATOMIC_FALLBACK'] ruby_engine = 'mutex_atomic' else ruby_engine = Concurrent.ruby_engine end require "concurrent/atomic_reference/#{ruby_engine}" rescue LoadError #warn 'Compiled extensions not installed, pure Ruby Atomic will be used.' end if defined? Concurrent::JavaAtomicReference # @!macro atomic_reference class Concurrent::AtomicReference < Concurrent::JavaAtomicReference end elsif defined? Concurrent::RbxAtomicReference # @!macro atomic_reference class Concurrent::AtomicReference < Concurrent::RbxAtomicReference end elsif defined? Concurrent::CAtomicReference # @!macro atomic_reference class Concurrent::AtomicReference < Concurrent::CAtomicReference end else # @!macro atomic_reference class Concurrent::AtomicReference < Concurrent::MutexAtomicReference end end class Concurrent::AtomicReference # @return [String] Short string representation. def to_s format '<#%s:0x%x value:%s>', self.class, object_id << 1, get end alias_method :inspect, :to_s end concurrent-ruby-1.0.5/lib/concurrent/atomic/count_down_latch.rb000066400000000000000000000063611305460430400247460ustar00rootroot00000000000000require 'concurrent/atomic/mutex_count_down_latch' require 'concurrent/atomic/java_count_down_latch' require 'concurrent/utility/engine' module Concurrent ################################################################### # @!macro [new] count_down_latch_method_initialize # # Create a new `CountDownLatch` with the initial `count`. # # @param [new] count the initial count # # @raise [ArgumentError] if `count` is not an integer or is less than zero # @!macro [new] count_down_latch_method_wait # # Block on the latch until the counter reaches zero or until `timeout` is reached. # # @param [Fixnum] timeout the number of seconds to wait for the counter or `nil` # to block indefinitely # @return [Boolean] `true` if the `count` reaches zero else false on `timeout` # @!macro [new] count_down_latch_method_count_down # # Signal the latch to decrement the counter. Will signal all blocked threads when # the `count` reaches zero. # @!macro [attach] count_down_latch_method_count # # The current value of the counter. # # @return [Fixnum] the current value of the counter ################################################################### # @!macro [new] count_down_latch_public_api # # @!method initialize(count = 1) # @!macro count_down_latch_method_initialize # # @!method wait(timeout = nil) # @!macro count_down_latch_method_wait # # @!method count_down # @!macro count_down_latch_method_count_down # # @!method count # @!macro count_down_latch_method_count ################################################################### # @!visibility private # @!macro internal_implementation_note CountDownLatchImplementation = case when Concurrent.on_jruby? JavaCountDownLatch else MutexCountDownLatch end private_constant :CountDownLatchImplementation # @!macro [attach] count_down_latch # # A synchronization object that allows one thread to wait on multiple other threads. # The thread that will wait creates a `CountDownLatch` and sets the initial value # (normally equal to the number of other threads). The initiating thread passes the # latch to the other threads then waits for the other threads by calling the `#wait` # method. Each of the other threads calls `#count_down` when done with its work. # When the latch counter reaches zero the waiting thread is unblocked and continues # with its work. A `CountDownLatch` can be used only once. Its value cannot be reset. # # @!macro count_down_latch_public_api # @example Waiter and Decrementer # latch = Concurrent::CountDownLatch.new(3) # # waiter = Thread.new do # latch.wait() # puts ("Waiter released") # end # # decrementer = Thread.new do # sleep(1) # latch.count_down # puts latch.count # # sleep(1) # latch.count_down # puts latch.count # # sleep(1) # latch.count_down # puts latch.count # end # # [waiter, decrementer].each(&:join) class CountDownLatch < CountDownLatchImplementation end end concurrent-ruby-1.0.5/lib/concurrent/atomic/cyclic_barrier.rb000066400000000000000000000077671305460430400244030ustar00rootroot00000000000000require 'concurrent/synchronization' require 'concurrent/utility/native_integer' module Concurrent # A synchronization aid that allows a set of threads to all wait for each # other to reach a common barrier point. # @example # barrier = Concurrent::CyclicBarrier.new(3) # jobs = Array.new(3) { |i| -> { sleep i; p done: i } } # process = -> (i) do # # waiting to start at the same time # barrier.wait # # execute job # jobs[i].call # # wait for others to finish # barrier.wait # end # threads = 2.times.map do |i| # Thread.new(i, &process) # end # # # use main as well # process.call 2 # # # here we can be sure that all jobs are processed class CyclicBarrier < Synchronization::LockableObject # @!visibility private Generation = Struct.new(:status) private_constant :Generation # Create a new `CyclicBarrier` that waits for `parties` threads # # @param [Fixnum] parties the number of parties # @yield an optional block that will be executed that will be executed after # the last thread arrives and before the others are released # # @raise [ArgumentError] if `parties` is not an integer or is less than zero def initialize(parties, &block) Utility::NativeInteger.ensure_integer_and_bounds parties Utility::NativeInteger.ensure_positive_and_no_zero parties super(&nil) synchronize { ns_initialize parties, &block } end # @return [Fixnum] the number of threads needed to pass the barrier def parties synchronize { @parties } end # @return [Fixnum] the number of threads currently waiting on the barrier def number_waiting synchronize { @number_waiting } end # Blocks on the barrier until the number of waiting threads is equal to # `parties` or until `timeout` is reached or `reset` is called # If a block has been passed to the constructor, it will be executed once by # the last arrived thread before releasing the others # @param [Fixnum] timeout the number of seconds to wait for the counter or # `nil` to block indefinitely # @return [Boolean] `true` if the `count` reaches zero else false on # `timeout` or on `reset` or if the barrier is broken def wait(timeout = nil) synchronize do return false unless @generation.status == :waiting @number_waiting += 1 if @number_waiting == @parties @action.call if @action ns_generation_done @generation, :fulfilled true else generation = @generation if ns_wait_until(timeout) { generation.status != :waiting } generation.status == :fulfilled else ns_generation_done generation, :broken, false false end end end end # resets the barrier to its initial state # If there is at least one waiting thread, it will be woken up, the `wait` # method will return false and the barrier will be broken # If the barrier is broken, this method restores it to the original state # # @return [nil] def reset synchronize { ns_generation_done @generation, :reset } end # A barrier can be broken when: # - a thread called the `reset` method while at least one other thread was waiting # - at least one thread timed out on `wait` method # # A broken barrier can be restored using `reset` it's safer to create a new one # @return [Boolean] true if the barrier is broken otherwise false def broken? synchronize { @generation.status != :waiting } end protected def ns_generation_done(generation, status, continue = true) generation.status = status ns_next_generation if continue ns_broadcast end def ns_next_generation @generation = Generation.new(:waiting) @number_waiting = 0 end def ns_initialize(parties, &block) @parties = parties @action = block ns_next_generation end end end concurrent-ruby-1.0.5/lib/concurrent/atomic/event.rb000066400000000000000000000054151305460430400225340ustar00rootroot00000000000000require 'thread' require 'concurrent/synchronization' module Concurrent # Old school kernel-style event reminiscent of Win32 programming in C++. # # When an `Event` is created it is in the `unset` state. Threads can choose to # `#wait` on the event, blocking until released by another thread. When one # thread wants to alert all blocking threads it calls the `#set` method which # will then wake up all listeners. Once an `Event` has been set it remains set. # New threads calling `#wait` will return immediately. An `Event` may be # `#reset` at any time once it has been set. # # @see http://msdn.microsoft.com/en-us/library/windows/desktop/ms682655.aspx # @example # event = Concurrent::Event.new # # t1 = Thread.new do # puts "t1 is waiting" # event.wait(1) # puts "event ocurred" # end # # t2 = Thread.new do # puts "t2 calling set" # event.set # end # # [t1, t2].each(&:join) # # # prints: # # t2 calling set # # t1 is waiting # # event ocurred class Event < Synchronization::LockableObject # Creates a new `Event` in the unset state. Threads calling `#wait` on the # `Event` will block. def initialize super synchronize { ns_initialize } end # Is the object in the set state? # # @return [Boolean] indicating whether or not the `Event` has been set def set? synchronize { @set } end # Trigger the event, setting the state to `set` and releasing all threads # waiting on the event. Has no effect if the `Event` has already been set. # # @return [Boolean] should always return `true` def set synchronize { ns_set } end def try? synchronize { @set ? false : ns_set } end # Reset a previously set event back to the `unset` state. # Has no effect if the `Event` has not yet been set. # # @return [Boolean] should always return `true` def reset synchronize do if @set @set = false @iteration +=1 end true end end # Wait a given number of seconds for the `Event` to be set by another # thread. Will wait forever when no `timeout` value is given. Returns # immediately if the `Event` has already been set. # # @return [Boolean] true if the `Event` was set before timeout else false def wait(timeout = nil) synchronize do unless @set iteration = @iteration ns_wait_until(timeout) { iteration < @iteration || @set } else true end end end protected def ns_set unless @set @set = true ns_broadcast end true end def ns_initialize @set = false @iteration = 0 end end end concurrent-ruby-1.0.5/lib/concurrent/atomic/java_count_down_latch.rb000066400000000000000000000017041305460430400257430ustar00rootroot00000000000000if Concurrent.on_jruby? module Concurrent # @!macro count_down_latch # @!visibility private # @!macro internal_implementation_note class JavaCountDownLatch # @!macro count_down_latch_method_initialize def initialize(count = 1) unless count.is_a?(Fixnum) && count >= 0 raise ArgumentError.new('count must be in integer greater than or equal zero') end @latch = java.util.concurrent.CountDownLatch.new(count) end # @!macro count_down_latch_method_wait def wait(timeout = nil) if timeout.nil? @latch.await true else @latch.await(1000 * timeout, java.util.concurrent.TimeUnit::MILLISECONDS) end end # @!macro count_down_latch_method_count_down def count_down @latch.countDown end # @!macro count_down_latch_method_count def count @latch.getCount end end end end concurrent-ruby-1.0.5/lib/concurrent/atomic/java_thread_local_var.rb000066400000000000000000000012631305460430400257020ustar00rootroot00000000000000require 'concurrent/atomic/abstract_thread_local_var' if Concurrent.on_jruby? module Concurrent # @!visibility private # @!macro internal_implementation_note class JavaThreadLocalVar < AbstractThreadLocalVar # @!macro thread_local_var_method_get def value value = @var.get if value.nil? default elsif value == NULL nil else value end end # @!macro thread_local_var_method_set def value=(value) @var.set(value) end protected # @!visibility private def allocate_storage @var = java.lang.ThreadLocal.new end end end end concurrent-ruby-1.0.5/lib/concurrent/atomic/mutex_atomic_boolean.rb000066400000000000000000000023521305460430400256050ustar00rootroot00000000000000require 'concurrent/synchronization' module Concurrent # @!macro atomic_boolean # @!visibility private # @!macro internal_implementation_note class MutexAtomicBoolean < Synchronization::LockableObject # @!macro atomic_boolean_method_initialize def initialize(initial = false) super() synchronize { ns_initialize(initial) } end # @!macro atomic_boolean_method_value_get def value synchronize { @value } end # @!macro atomic_boolean_method_value_set def value=(value) synchronize { @value = !!value } end # @!macro atomic_boolean_method_true_question def true? synchronize { @value } end # @!macro atomic_boolean_method_false_question def false? synchronize { !@value } end # @!macro atomic_boolean_method_make_true def make_true synchronize { ns_make_value(true) } end # @!macro atomic_boolean_method_make_false def make_false synchronize { ns_make_value(false) } end protected # @!visibility private def ns_initialize(initial) @value = !!initial end # @!visibility private def ns_make_value(value) old = @value @value = value old != @value end end end concurrent-ruby-1.0.5/lib/concurrent/atomic/mutex_atomic_fixnum.rb000066400000000000000000000030651305460430400254760ustar00rootroot00000000000000require 'concurrent/synchronization' require 'concurrent/utility/native_integer' module Concurrent # @!macro atomic_fixnum # @!visibility private # @!macro internal_implementation_note class MutexAtomicFixnum < Synchronization::LockableObject # @!macro atomic_fixnum_method_initialize def initialize(initial = 0) super() synchronize { ns_initialize(initial) } end # @!macro atomic_fixnum_method_value_get def value synchronize { @value } end # @!macro atomic_fixnum_method_value_set def value=(value) synchronize { ns_set(value) } end # @!macro atomic_fixnum_method_increment def increment(delta = 1) synchronize { ns_set(@value + delta.to_i) } end alias_method :up, :increment # @!macro atomic_fixnum_method_decrement def decrement(delta = 1) synchronize { ns_set(@value - delta.to_i) } end alias_method :down, :decrement # @!macro atomic_fixnum_method_compare_and_set def compare_and_set(expect, update) synchronize do if @value == expect.to_i @value = update.to_i true else false end end end # @!macro atomic_fixnum_method_update def update synchronize do @value = yield @value end end protected # @!visibility private def ns_initialize(initial) ns_set(initial) end private # @!visibility private def ns_set(value) Utility::NativeInteger.ensure_integer_and_bounds value @value = value end end end concurrent-ruby-1.0.5/lib/concurrent/atomic/mutex_count_down_latch.rb000066400000000000000000000017121305460430400261630ustar00rootroot00000000000000require 'concurrent/synchronization' module Concurrent # @!macro count_down_latch # @!visibility private # @!macro internal_implementation_note class MutexCountDownLatch < Synchronization::LockableObject # @!macro count_down_latch_method_initialize def initialize(count = 1) Utility::NativeInteger.ensure_integer_and_bounds count Utility::NativeInteger.ensure_positive count super() synchronize { ns_initialize count } end # @!macro count_down_latch_method_wait def wait(timeout = nil) synchronize { ns_wait_until(timeout) { @count == 0 } } end # @!macro count_down_latch_method_count_down def count_down synchronize do @count -= 1 if @count > 0 ns_broadcast if @count == 0 end end # @!macro count_down_latch_method_count def count synchronize { @count } end protected def ns_initialize(count) @count = count end end end concurrent-ruby-1.0.5/lib/concurrent/atomic/mutex_semaphore.rb000066400000000000000000000053141305460430400246160ustar00rootroot00000000000000require 'concurrent/synchronization' require 'concurrent/utility/native_integer' module Concurrent # @!macro semaphore # @!visibility private # @!macro internal_implementation_note class MutexSemaphore < Synchronization::LockableObject # @!macro semaphore_method_initialize def initialize(count) Utility::NativeInteger.ensure_integer_and_bounds count super() synchronize { ns_initialize count } end # @!macro semaphore_method_acquire def acquire(permits = 1) Utility::NativeInteger.ensure_integer_and_bounds permits Utility::NativeInteger.ensure_positive permits synchronize do try_acquire_timed(permits, nil) nil end end # @!macro semaphore_method_available_permits def available_permits synchronize { @free } end # @!macro semaphore_method_drain_permits # # Acquires and returns all permits that are immediately available. # # @return [Integer] def drain_permits synchronize do @free.tap { |_| @free = 0 } end end # @!macro semaphore_method_try_acquire def try_acquire(permits = 1, timeout = nil) Utility::NativeInteger.ensure_integer_and_bounds permits Utility::NativeInteger.ensure_positive permits synchronize do if timeout.nil? try_acquire_now(permits) else try_acquire_timed(permits, timeout) end end end # @!macro semaphore_method_release def release(permits = 1) Utility::NativeInteger.ensure_integer_and_bounds permits Utility::NativeInteger.ensure_positive permits synchronize do @free += permits permits.times { ns_signal } end nil end # Shrinks the number of available permits by the indicated reduction. # # @param [Fixnum] reduction Number of permits to remove. # # @raise [ArgumentError] if `reduction` is not an integer or is negative # # @raise [ArgumentError] if `@free` - `@reduction` is less than zero # # @return [nil] # # @!visibility private def reduce_permits(reduction) Utility::NativeInteger.ensure_integer_and_bounds reduction Utility::NativeInteger.ensure_positive reduction synchronize { @free -= reduction } nil end protected # @!visibility private def ns_initialize(count) @free = count end private # @!visibility private def try_acquire_now(permits) if @free >= permits @free -= permits true else false end end # @!visibility private def try_acquire_timed(permits, timeout) ns_wait_until(timeout) { try_acquire_now(permits) } end end end concurrent-ruby-1.0.5/lib/concurrent/atomic/read_write_lock.rb000066400000000000000000000203461305460430400245500ustar00rootroot00000000000000require 'thread' require 'concurrent/atomic/atomic_fixnum' require 'concurrent/errors' require 'concurrent/synchronization' module Concurrent # Ruby read-write lock implementation # # Allows any number of concurrent readers, but only one concurrent writer # (And if the "write" lock is taken, any readers who come along will have to wait) # # If readers are already active when a writer comes along, the writer will wait for # all the readers to finish before going ahead. # Any additional readers that come when the writer is already waiting, will also # wait (so writers are not starved). # # This implementation is based on `java.util.concurrent.ReentrantReadWriteLock`. # # @example # lock = Concurrent::ReadWriteLock.new # lock.with_read_lock { data.retrieve } # lock.with_write_lock { data.modify! } # # @note Do **not** try to acquire the write lock while already holding a read lock # **or** try to acquire the write lock while you already have it. # This will lead to deadlock # # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html java.util.concurrent.ReentrantReadWriteLock class ReadWriteLock < Synchronization::Object # @!visibility private WAITING_WRITER = 1 << 15 # @!visibility private RUNNING_WRITER = 1 << 29 # @!visibility private MAX_READERS = WAITING_WRITER - 1 # @!visibility private MAX_WRITERS = RUNNING_WRITER - MAX_READERS - 1 safe_initialization! # Implementation notes: # A goal is to make the uncontended path for both readers/writers lock-free # Only if there is reader-writer or writer-writer contention, should locks be used # Internal state is represented by a single integer ("counter"), and updated # using atomic compare-and-swap operations # When the counter is 0, the lock is free # Each reader increments the counter by 1 when acquiring a read lock # (and decrements by 1 when releasing the read lock) # The counter is increased by (1 << 15) for each writer waiting to acquire the # write lock, and by (1 << 29) if the write lock is taken # Create a new `ReadWriteLock` in the unlocked state. def initialize super() @Counter = AtomicFixnum.new(0) # single integer which represents lock state @ReadLock = Synchronization::Lock.new @WriteLock = Synchronization::Lock.new end # Execute a block operation within a read lock. # # @yield the task to be performed within the lock. # # @return [Object] the result of the block operation. # # @raise [ArgumentError] when no block is given. # @raise [Concurrent::ResourceLimitError] if the maximum number of readers # is exceeded. def with_read_lock raise ArgumentError.new('no block given') unless block_given? acquire_read_lock begin yield ensure release_read_lock end end # Execute a block operation within a write lock. # # @yield the task to be performed within the lock. # # @return [Object] the result of the block operation. # # @raise [ArgumentError] when no block is given. # @raise [Concurrent::ResourceLimitError] if the maximum number of readers # is exceeded. def with_write_lock raise ArgumentError.new('no block given') unless block_given? acquire_write_lock begin yield ensure release_write_lock end end # Acquire a read lock. If a write lock has been acquired will block until # it is released. Will not block if other read locks have been acquired. # # @return [Boolean] true if the lock is successfully acquired # # @raise [Concurrent::ResourceLimitError] if the maximum number of readers # is exceeded. def acquire_read_lock while true c = @Counter.value raise ResourceLimitError.new('Too many reader threads') if max_readers?(c) # If a writer is waiting when we first queue up, we need to wait if waiting_writer?(c) @ReadLock.wait_until { !waiting_writer? } # after a reader has waited once, they are allowed to "barge" ahead of waiting writers # but if a writer is *running*, the reader still needs to wait (naturally) while true c = @Counter.value if running_writer?(c) @ReadLock.wait_until { !running_writer? } else return if @Counter.compare_and_set(c, c+1) end end else break if @Counter.compare_and_set(c, c+1) end end true end # Release a previously acquired read lock. # # @return [Boolean] true if the lock is successfully released def release_read_lock while true c = @Counter.value if @Counter.compare_and_set(c, c-1) # If one or more writers were waiting, and we were the last reader, wake a writer up if waiting_writer?(c) && running_readers(c) == 1 @WriteLock.signal end break end end true end # Acquire a write lock. Will block and wait for all active readers and writers. # # @return [Boolean] true if the lock is successfully acquired # # @raise [Concurrent::ResourceLimitError] if the maximum number of writers # is exceeded. def acquire_write_lock while true c = @Counter.value raise ResourceLimitError.new('Too many writer threads') if max_writers?(c) if c == 0 # no readers OR writers running # if we successfully swap the RUNNING_WRITER bit on, then we can go ahead break if @Counter.compare_and_set(0, RUNNING_WRITER) elsif @Counter.compare_and_set(c, c+WAITING_WRITER) while true # Now we have successfully incremented, so no more readers will be able to increment # (they will wait instead) # However, readers OR writers could decrement right here, OR another writer could increment @WriteLock.wait_until do # So we have to do another check inside the synchronized section # If a writer OR reader is running, then go to sleep c = @Counter.value !running_writer?(c) && !running_readers?(c) end # We just came out of a wait # If we successfully turn the RUNNING_WRITER bit on with an atomic swap, # Then we are OK to stop waiting and go ahead # Otherwise go back and wait again c = @Counter.value break if !running_writer?(c) && !running_readers?(c) && @Counter.compare_and_set(c, c+RUNNING_WRITER-WAITING_WRITER) end break end end true end # Release a previously acquired write lock. # # @return [Boolean] true if the lock is successfully released def release_write_lock c = @Counter.update { |counter| counter-RUNNING_WRITER } @ReadLock.broadcast @WriteLock.signal if waiting_writers(c) > 0 true end # Queries if the write lock is held by any thread. # # @return [Boolean] true if the write lock is held else false` def write_locked? @Counter.value >= RUNNING_WRITER end # Queries whether any threads are waiting to acquire the read or write lock. # # @return [Boolean] true if any threads are waiting for a lock else false def has_waiters? waiting_writer?(@Counter.value) end private # @!visibility private def running_readers(c = @Counter.value) c & MAX_READERS end # @!visibility private def running_readers?(c = @Counter.value) (c & MAX_READERS) > 0 end # @!visibility private def running_writer?(c = @Counter.value) c >= RUNNING_WRITER end # @!visibility private def waiting_writers(c = @Counter.value) (c & MAX_WRITERS) / WAITING_WRITER end # @!visibility private def waiting_writer?(c = @Counter.value) c >= WAITING_WRITER end # @!visibility private def max_readers?(c = @Counter.value) (c & MAX_READERS) == MAX_READERS end # @!visibility private def max_writers?(c = @Counter.value) (c & MAX_WRITERS) == MAX_WRITERS end end end concurrent-ruby-1.0.5/lib/concurrent/atomic/reentrant_read_write_lock.rb000066400000000000000000000335721305460430400266370ustar00rootroot00000000000000require 'thread' require 'concurrent/atomic/atomic_reference' require 'concurrent/errors' require 'concurrent/synchronization' require 'concurrent/atomic/thread_local_var' module Concurrent # Re-entrant read-write lock implementation # # Allows any number of concurrent readers, but only one concurrent writer # (And while the "write" lock is taken, no read locks can be obtained either. # Hence, the write lock can also be called an "exclusive" lock.) # # If another thread has taken a read lock, any thread which wants a write lock # will block until all the readers release their locks. However, once a thread # starts waiting to obtain a write lock, any additional readers that come along # will also wait (so writers are not starved). # # A thread can acquire both a read and write lock at the same time. A thread can # also acquire a read lock OR a write lock more than once. Only when the read (or # write) lock is released as many times as it was acquired, will the thread # actually let it go, allowing other threads which might have been waiting # to proceed. # # If both read and write locks are acquired by the same thread, it is not strictly # necessary to release them in the same order they were acquired. In other words, # the following code is legal: # # @example # lock = Concurrent::ReentrantReadWriteLock.new # lock.acquire_write_lock # lock.acquire_read_lock # lock.release_write_lock # # At this point, the current thread is holding only a read lock, not a write # # lock. So other threads can take read locks, but not a write lock. # lock.release_read_lock # # Now the current thread is not holding either a read or write lock, so # # another thread could potentially acquire a write lock. # # This implementation was inspired by `java.util.concurrent.ReentrantReadWriteLock`. # # @example # lock = Concurrent::ReentrantReadWriteLock.new # lock.with_read_lock { data.retrieve } # lock.with_write_lock { data.modify! } # # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html java.util.concurrent.ReentrantReadWriteLock class ReentrantReadWriteLock < Synchronization::Object # Implementation notes: # # A goal is to make the uncontended path for both readers/writers mutex-free # Only if there is reader-writer or writer-writer contention, should mutexes be used # Otherwise, a single CAS operation is all we need to acquire/release a lock # # Internal state is represented by a single integer ("counter"), and updated # using atomic compare-and-swap operations # When the counter is 0, the lock is free # Each thread which has one OR MORE read locks increments the counter by 1 # (and decrements by 1 when releasing the read lock) # The counter is increased by (1 << 15) for each writer waiting to acquire the # write lock, and by (1 << 29) if the write lock is taken # # Additionally, each thread uses a thread-local variable to count how many times # it has acquired a read lock, AND how many times it has acquired a write lock. # It uses a similar trick; an increment of 1 means a read lock was taken, and # an increment of (1 << 15) means a write lock was taken # This is what makes re-entrancy possible # # 2 rules are followed to ensure good liveness properties: # 1) Once a writer has queued up and is waiting for a write lock, no other thread # can take a lock without waiting # 2) When a write lock is released, readers are given the "first chance" to wake # up and acquire a read lock # Following these rules means readers and writers tend to "take turns", so neither # can starve the other, even under heavy contention # @!visibility private READER_BITS = 15 # @!visibility private WRITER_BITS = 14 # Used with @Counter: # @!visibility private WAITING_WRITER = 1 << READER_BITS # @!visibility private RUNNING_WRITER = 1 << (READER_BITS + WRITER_BITS) # @!visibility private MAX_READERS = WAITING_WRITER - 1 # @!visibility private MAX_WRITERS = RUNNING_WRITER - MAX_READERS - 1 # Used with @HeldCount: # @!visibility private WRITE_LOCK_HELD = 1 << READER_BITS # @!visibility private READ_LOCK_MASK = WRITE_LOCK_HELD - 1 # @!visibility private WRITE_LOCK_MASK = MAX_WRITERS safe_initialization! # Create a new `ReentrantReadWriteLock` in the unlocked state. def initialize super() @Counter = AtomicFixnum.new(0) # single integer which represents lock state @ReadQueue = Synchronization::Lock.new # used to queue waiting readers @WriteQueue = Synchronization::Lock.new # used to queue waiting writers @HeldCount = ThreadLocalVar.new(0) # indicates # of R & W locks held by this thread end # Execute a block operation within a read lock. # # @yield the task to be performed within the lock. # # @return [Object] the result of the block operation. # # @raise [ArgumentError] when no block is given. # @raise [Concurrent::ResourceLimitError] if the maximum number of readers # is exceeded. def with_read_lock raise ArgumentError.new('no block given') unless block_given? acquire_read_lock begin yield ensure release_read_lock end end # Execute a block operation within a write lock. # # @yield the task to be performed within the lock. # # @return [Object] the result of the block operation. # # @raise [ArgumentError] when no block is given. # @raise [Concurrent::ResourceLimitError] if the maximum number of readers # is exceeded. def with_write_lock raise ArgumentError.new('no block given') unless block_given? acquire_write_lock begin yield ensure release_write_lock end end # Acquire a read lock. If a write lock is held by another thread, will block # until it is released. # # @return [Boolean] true if the lock is successfully acquired # # @raise [Concurrent::ResourceLimitError] if the maximum number of readers # is exceeded. def acquire_read_lock if (held = @HeldCount.value) > 0 # If we already have a lock, there's no need to wait if held & READ_LOCK_MASK == 0 # But we do need to update the counter, if we were holding a write # lock but not a read lock @Counter.update { |c| c + 1 } end @HeldCount.value = held + 1 return true end while true c = @Counter.value raise ResourceLimitError.new('Too many reader threads') if max_readers?(c) # If a writer is waiting OR running when we first queue up, we need to wait if waiting_or_running_writer?(c) # Before going to sleep, check again with the ReadQueue mutex held @ReadQueue.synchronize do @ReadQueue.ns_wait if waiting_or_running_writer? end # Note: the above 'synchronize' block could have used #wait_until, # but that waits repeatedly in a loop, checking the wait condition # each time it wakes up (to protect against spurious wakeups) # But we are already in a loop, which is only broken when we successfully # acquire the lock! So we don't care about spurious wakeups, and would # rather not pay the extra overhead of using #wait_until # After a reader has waited once, they are allowed to "barge" ahead of waiting writers # But if a writer is *running*, the reader still needs to wait (naturally) while true c = @Counter.value if running_writer?(c) @ReadQueue.synchronize do @ReadQueue.ns_wait if running_writer? end elsif @Counter.compare_and_set(c, c+1) @HeldCount.value = held + 1 return true end end elsif @Counter.compare_and_set(c, c+1) @HeldCount.value = held + 1 return true end end end # Try to acquire a read lock and return true if we succeed. If it cannot be # acquired immediately, return false. # # @return [Boolean] true if the lock is successfully acquired def try_read_lock if (held = @HeldCount.value) > 0 if held & READ_LOCK_MASK == 0 # If we hold a write lock, but not a read lock... @Counter.update { |c| c + 1 } end @HeldCount.value = held + 1 return true else c = @Counter.value if !waiting_or_running_writer?(c) && @Counter.compare_and_set(c, c+1) @HeldCount.value = held + 1 return true end end false end # Release a previously acquired read lock. # # @return [Boolean] true if the lock is successfully released def release_read_lock held = @HeldCount.value = @HeldCount.value - 1 rlocks_held = held & READ_LOCK_MASK if rlocks_held == 0 c = @Counter.update { |counter| counter - 1 } # If one or more writers were waiting, and we were the last reader, wake a writer up if waiting_or_running_writer?(c) && running_readers(c) == 0 @WriteQueue.signal end elsif rlocks_held == READ_LOCK_MASK raise IllegalOperationError, "Cannot release a read lock which is not held" end true end # Acquire a write lock. Will block and wait for all active readers and writers. # # @return [Boolean] true if the lock is successfully acquired # # @raise [Concurrent::ResourceLimitError] if the maximum number of writers # is exceeded. def acquire_write_lock if (held = @HeldCount.value) >= WRITE_LOCK_HELD # if we already have a write (exclusive) lock, there's no need to wait @HeldCount.value = held + WRITE_LOCK_HELD return true end while true c = @Counter.value raise ResourceLimitError.new('Too many writer threads') if max_writers?(c) # To go ahead and take the lock without waiting, there must be no writer # running right now, AND no writers who came before us still waiting to # acquire the lock # Additionally, if any read locks have been taken, we must hold all of them if c == held # If we successfully swap the RUNNING_WRITER bit on, then we can go ahead if @Counter.compare_and_set(c, c+RUNNING_WRITER) @HeldCount.value = held + WRITE_LOCK_HELD return true end elsif @Counter.compare_and_set(c, c+WAITING_WRITER) while true # Now we have successfully incremented, so no more readers will be able to increment # (they will wait instead) # However, readers OR writers could decrement right here @WriteQueue.synchronize do # So we have to do another check inside the synchronized section # If a writer OR another reader is running, then go to sleep c = @Counter.value @WriteQueue.ns_wait if running_writer?(c) || running_readers(c) != held end # Note: if you are thinking of replacing the above 'synchronize' block # with #wait_until, read the comment in #acquire_read_lock first! # We just came out of a wait # If we successfully turn the RUNNING_WRITER bit on with an atomic swap, # then we are OK to stop waiting and go ahead # Otherwise go back and wait again c = @Counter.value if !running_writer?(c) && running_readers(c) == held && @Counter.compare_and_set(c, c+RUNNING_WRITER-WAITING_WRITER) @HeldCount.value = held + WRITE_LOCK_HELD return true end end end end end # Try to acquire a write lock and return true if we succeed. If it cannot be # acquired immediately, return false. # # @return [Boolean] true if the lock is successfully acquired def try_write_lock if (held = @HeldCount.value) >= WRITE_LOCK_HELD @HeldCount.value = held + WRITE_LOCK_HELD return true else c = @Counter.value if !waiting_or_running_writer?(c) && running_readers(c) == held && @Counter.compare_and_set(c, c+RUNNING_WRITER) @HeldCount.value = held + WRITE_LOCK_HELD return true end end false end # Release a previously acquired write lock. # # @return [Boolean] true if the lock is successfully released def release_write_lock held = @HeldCount.value = @HeldCount.value - WRITE_LOCK_HELD wlocks_held = held & WRITE_LOCK_MASK if wlocks_held == 0 c = @Counter.update { |counter| counter - RUNNING_WRITER } @ReadQueue.broadcast @WriteQueue.signal if waiting_writers(c) > 0 elsif wlocks_held == WRITE_LOCK_MASK raise IllegalOperationError, "Cannot release a write lock which is not held" end true end private # @!visibility private def running_readers(c = @Counter.value) c & MAX_READERS end # @!visibility private def running_readers?(c = @Counter.value) (c & MAX_READERS) > 0 end # @!visibility private def running_writer?(c = @Counter.value) c >= RUNNING_WRITER end # @!visibility private def waiting_writers(c = @Counter.value) (c & MAX_WRITERS) >> READER_BITS end # @!visibility private def waiting_or_running_writer?(c = @Counter.value) c >= WAITING_WRITER end # @!visibility private def max_readers?(c = @Counter.value) (c & MAX_READERS) == MAX_READERS end # @!visibility private def max_writers?(c = @Counter.value) (c & MAX_WRITERS) == MAX_WRITERS end end end concurrent-ruby-1.0.5/lib/concurrent/atomic/ruby_thread_local_var.rb000066400000000000000000000115521305460430400257440ustar00rootroot00000000000000require 'thread' require 'concurrent/atomic/abstract_thread_local_var' module Concurrent # @!visibility private # @!macro internal_implementation_note class RubyThreadLocalVar < AbstractThreadLocalVar # Each thread has a (lazily initialized) array of thread-local variable values # Each time a new thread-local var is created, we allocate an "index" for it # For example, if the allocated index is 1, that means slot #1 in EVERY # thread's thread-local array will be used for the value of that TLV # # The good thing about using a per-THREAD structure to hold values, rather # than a per-TLV structure, is that no synchronization is needed when # reading and writing those values (since the structure is only ever # accessed by a single thread) # # Of course, when a TLV is GC'd, 1) we need to recover its index for use # by other new TLVs (otherwise the thread-local arrays could get bigger # and bigger with time), and 2) we need to null out all the references # held in the now-unused slots (both to avoid blocking GC of those objects, # and also to prevent "stale" values from being passed on to a new TLV # when the index is reused) # Because we need to null out freed slots, we need to keep references to # ALL the thread-local arrays -- ARRAYS is for that # But when a Thread is GC'd, we need to drop the reference to its thread-local # array, so we don't leak memory # @!visibility private FREE = [] LOCK = Mutex.new ARRAYS = {} # used as a hash set @@next = 0 private_constant :FREE, :LOCK, :ARRAYS # @!macro thread_local_var_method_get def value if array = get_threadlocal_array value = array[@index] if value.nil? default elsif value.equal?(NULL) nil else value end else default end end # @!macro thread_local_var_method_set def value=(value) me = Thread.current # We could keep the thread-local arrays in a hash, keyed by Thread # But why? That would require locking # Using Ruby's built-in thread-local storage is faster unless array = get_threadlocal_array(me) array = set_threadlocal_array([], me) LOCK.synchronize { ARRAYS[array.object_id] = array } ObjectSpace.define_finalizer(me, self.class.thread_finalizer(array)) end array[@index] = (value.nil? ? NULL : value) value end protected # @!visibility private def allocate_storage @index = LOCK.synchronize do FREE.pop || begin result = @@next @@next += 1 result end end ObjectSpace.define_finalizer(self, self.class.threadlocal_finalizer(@index)) end # @!visibility private def self.threadlocal_finalizer(index) proc do Thread.new do # avoid error: can't be called from trap context LOCK.synchronize do FREE.push(index) # The cost of GC'ing a TLV is linear in the number of threads using TLVs # But that is natural! More threads means more storage is used per TLV # So naturally more CPU time is required to free more storage ARRAYS.each_value do |array| array[index] = nil end end end end end # @!visibility private def self.thread_finalizer(array) proc do Thread.new do # avoid error: can't be called from trap context LOCK.synchronize do # The thread which used this thread-local array is now gone # So don't hold onto a reference to the array (thus blocking GC) ARRAYS.delete(array.object_id) end end end end private if Thread.instance_methods.include?(:thread_variable_get) def get_threadlocal_array(thread = Thread.current) thread.thread_variable_get(:__threadlocal_array__) end def set_threadlocal_array(array, thread = Thread.current) thread.thread_variable_set(:__threadlocal_array__, array) end else def get_threadlocal_array(thread = Thread.current) thread[:__threadlocal_array__] end def set_threadlocal_array(array, thread = Thread.current) thread[:__threadlocal_array__] = array end end # This exists only for use in testing # @!visibility private def value_for(thread) if array = get_threadlocal_array(thread) value = array[@index] if value.nil? default_for(thread) elsif value.equal?(NULL) nil else value end else default_for(thread) end end def default_for(thread) if @default_block raise "Cannot use default_for with default block" else @default end end end end concurrent-ruby-1.0.5/lib/concurrent/atomic/semaphore.rb000066400000000000000000000102351305460430400233720ustar00rootroot00000000000000require 'concurrent/atomic/mutex_semaphore' require 'concurrent/synchronization' module Concurrent ################################################################### # @!macro [new] semaphore_method_initialize # # Create a new `Semaphore` with the initial `count`. # # @param [Fixnum] count the initial count # # @raise [ArgumentError] if `count` is not an integer or is less than zero # @!macro [new] semaphore_method_acquire # # Acquires the given number of permits from this semaphore, # blocking until all are available. # # @param [Fixnum] permits Number of permits to acquire # # @raise [ArgumentError] if `permits` is not an integer or is less than # one # # @return [nil] # @!macro [new] semaphore_method_available_permits # # Returns the current number of permits available in this semaphore. # # @return [Integer] # @!macro [new] semaphore_method_drain_permits # # Acquires and returns all permits that are immediately available. # # @return [Integer] # @!macro [new] semaphore_method_try_acquire # # Acquires the given number of permits from this semaphore, # only if all are available at the time of invocation or within # `timeout` interval # # @param [Fixnum] permits the number of permits to acquire # # @param [Fixnum] timeout the number of seconds to wait for the counter # or `nil` to return immediately # # @raise [ArgumentError] if `permits` is not an integer or is less than # one # # @return [Boolean] `false` if no permits are available, `true` when # acquired a permit # @!macro [new] semaphore_method_release # # Releases the given number of permits, returning them to the semaphore. # # @param [Fixnum] permits Number of permits to return to the semaphore. # # @raise [ArgumentError] if `permits` is not a number or is less than one # # @return [nil] ################################################################### # @!macro [new] semaphore_public_api # # @!method initialize(count) # @!macro semaphore_method_initialize # # @!method acquire(permits = 1) # @!macro semaphore_method_acquire # # @!method available_permits # @!macro semaphore_method_available_permits # # @!method drain_permits # @!macro semaphore_method_drain_permits # # @!method try_acquire(permits = 1, timeout = nil) # @!macro semaphore_method_try_acquire # # @!method release(permits = 1) # @!macro semaphore_method_release ################################################################### # @!visibility private # @!macro internal_implementation_note SemaphoreImplementation = case when defined?(JavaSemaphore) JavaSemaphore else MutexSemaphore end private_constant :SemaphoreImplementation # @!macro [attach] semaphore # # A counting semaphore. Conceptually, a semaphore maintains a set of # permits. Each {#acquire} blocks if necessary until a permit is # available, and then takes it. Each {#release} adds a permit, potentially # releasing a blocking acquirer. # However, no actual permit objects are used; the Semaphore just keeps a # count of the number available and acts accordingly. # # @!macro semaphore_public_api # @example # semaphore = Concurrent::Semaphore.new(2) # # t1 = Thread.new do # semaphore.acquire # puts "Thread 1 acquired semaphore" # end # # t2 = Thread.new do # semaphore.acquire # puts "Thread 2 acquired semaphore" # end # # t3 = Thread.new do # semaphore.acquire # puts "Thread 3 acquired semaphore" # end # # t4 = Thread.new do # sleep(2) # puts "Thread 4 releasing semaphore" # semaphore.release # end # # [t1, t2, t3, t4].each(&:join) # # # prints: # # Thread 3 acquired semaphore # # Thread 2 acquired semaphore # # Thread 4 releasing semaphore # # Thread 1 acquired semaphore # class Semaphore < SemaphoreImplementation end end concurrent-ruby-1.0.5/lib/concurrent/atomic/thread_local_var.rb000066400000000000000000000060111305460430400246750ustar00rootroot00000000000000require 'concurrent/atomic/ruby_thread_local_var' require 'concurrent/atomic/java_thread_local_var' require 'concurrent/utility/engine' module Concurrent ################################################################### # @!macro [new] thread_local_var_method_initialize # # Creates a thread local variable. # # @param [Object] default the default value when otherwise unset # @param [Proc] default_block Optional block that gets called to obtain the # default value for each thread # @!macro [new] thread_local_var_method_get # # Returns the value in the current thread's copy of this thread-local variable. # # @return [Object] the current value # @!macro [new] thread_local_var_method_set # # Sets the current thread's copy of this thread-local variable to the specified value. # # @param [Object] value the value to set # @return [Object] the new value # @!macro [new] thread_local_var_method_bind # # Bind the given value to thread local storage during # execution of the given block. # # @param [Object] value the value to bind # @yield the operation to be performed with the bound variable # @return [Object] the value ################################################################### # @!macro [new] thread_local_var_public_api # # @!method initialize(default = nil) # @!macro thread_local_var_method_initialize # # @!method value # @!macro thread_local_var_method_get # # @!method value=(value) # @!macro thread_local_var_method_set # # @!method bind(value, &block) # @!macro thread_local_var_method_bind ################################################################### # @!visibility private # @!macro internal_implementation_note ThreadLocalVarImplementation = case when Concurrent.on_jruby? JavaThreadLocalVar else RubyThreadLocalVar end private_constant :ThreadLocalVarImplementation # @!macro [attach] thread_local_var # # A `ThreadLocalVar` is a variable where the value is different for each thread. # Each variable may have a default value, but when you modify the variable only # the current thread will ever see that change. # # @!macro thread_safe_variable_comparison # # @example # v = ThreadLocalVar.new(14) # v.value #=> 14 # v.value = 2 # v.value #=> 2 # # @example # v = ThreadLocalVar.new(14) # # t1 = Thread.new do # v.value #=> 14 # v.value = 1 # v.value #=> 1 # end # # t2 = Thread.new do # v.value #=> 14 # v.value = 2 # v.value #=> 2 # end # # v.value #=> 14 # # @see https://docs.oracle.com/javase/7/docs/api/java/lang/ThreadLocal.html Java ThreadLocal # # @!macro thread_local_var_public_api class ThreadLocalVar < ThreadLocalVarImplementation end end concurrent-ruby-1.0.5/lib/concurrent/atomic_reference/000077500000000000000000000000001305460430400230775ustar00rootroot00000000000000concurrent-ruby-1.0.5/lib/concurrent/atomic_reference/concurrent_update_error.rb000066400000000000000000000003711305460430400303620ustar00rootroot00000000000000module Concurrent # @!macro atomic_reference class ConcurrentUpdateError < ThreadError # frozen pre-allocated backtrace to speed ConcurrentUpdateError CONC_UP_ERR_BACKTRACE = ['backtrace elided; set verbose to enable'].freeze end end concurrent-ruby-1.0.5/lib/concurrent/atomic_reference/direct_update.rb000066400000000000000000000054061305460430400262450ustar00rootroot00000000000000require 'concurrent/atomic_reference/concurrent_update_error' module Concurrent # Define update methods that use direct paths # # @!visibility private # @!macro internal_implementation_note module AtomicDirectUpdate # @!macro [attach] atomic_reference_method_update # # Pass the current value to the given block, replacing it # with the block's result. May retry if the value changes # during the block's execution. # # @yield [Object] Calculate a new value for the atomic reference using # given (old) value # @yieldparam [Object] old_value the starting value of the atomic reference # # @return [Object] the new value def update true until compare_and_set(old_value = get, new_value = yield(old_value)) new_value end # @!macro [attach] atomic_reference_method_try_update # # Pass the current value to the given block, replacing it # with the block's result. Return nil if the update fails. # # @yield [Object] Calculate a new value for the atomic reference using # given (old) value # @yieldparam [Object] old_value the starting value of the atomic reference # # @note This method was altered to avoid raising an exception by default. # Instead, this method now returns `nil` in case of failure. For more info, # please see: https://github.com/ruby-concurrency/concurrent-ruby/pull/336 # # @return [Object] the new value, or nil if update failed def try_update old_value = get new_value = yield old_value return unless compare_and_set old_value, new_value new_value end # @!macro [attach] atomic_reference_method_try_update! # # Pass the current value to the given block, replacing it # with the block's result. Raise an exception if the update # fails. # # @yield [Object] Calculate a new value for the atomic reference using # given (old) value # @yieldparam [Object] old_value the starting value of the atomic reference # # @note This behavior mimics the behavior of the original # `AtomicReference#try_update` API. The reason this was changed was to # avoid raising exceptions (which are inherently slow) by default. For more # info: https://github.com/ruby-concurrency/concurrent-ruby/pull/336 # # @return [Object] the new value # # @raise [Concurrent::ConcurrentUpdateError] if the update fails def try_update! old_value = get new_value = yield old_value unless compare_and_set(old_value, new_value) if $VERBOSE raise ConcurrentUpdateError, "Update failed" else raise ConcurrentUpdateError, "Update failed", ConcurrentUpdateError::CONC_UP_ERR_BACKTRACE end end new_value end end end concurrent-ruby-1.0.5/lib/concurrent/atomic_reference/jruby+truffle.rb000066400000000000000000000000731305460430400262220ustar00rootroot00000000000000require 'atomic' require 'concurrent/atomic_reference/rbx' concurrent-ruby-1.0.5/lib/concurrent/atomic_reference/jruby.rb000066400000000000000000000005471305460430400245650ustar00rootroot00000000000000require 'concurrent/synchronization' if defined?(Concurrent::JavaAtomicReference) require 'concurrent/atomic_reference/direct_update' module Concurrent # @!macro atomic_reference # # @!visibility private # @!macro internal_implementation_note class JavaAtomicReference include Concurrent::AtomicDirectUpdate end end end concurrent-ruby-1.0.5/lib/concurrent/atomic_reference/mutex_atomic.rb000066400000000000000000000026141305460430400261250ustar00rootroot00000000000000require 'concurrent/synchronization' require 'concurrent/atomic_reference/direct_update' require 'concurrent/atomic_reference/numeric_cas_wrapper' module Concurrent # @!macro atomic_reference # # @!visibility private # @!macro internal_implementation_note class MutexAtomicReference < Synchronization::LockableObject include Concurrent::AtomicDirectUpdate include Concurrent::AtomicNumericCompareAndSetWrapper # @!macro atomic_reference_method_initialize def initialize(value = nil) super() synchronize { ns_initialize(value) } end # @!macro atomic_reference_method_get def get synchronize { @value } end alias_method :value, :get # @!macro atomic_reference_method_set def set(new_value) synchronize { @value = new_value } end alias_method :value=, :set # @!macro atomic_reference_method_get_and_set def get_and_set(new_value) synchronize do old_value = @value @value = new_value old_value end end alias_method :swap, :get_and_set # @!macro atomic_reference_method_compare_and_set def _compare_and_set(old_value, new_value) synchronize do if @value.equal? old_value @value = new_value true else false end end end protected def ns_initialize(value) @value = value end end end concurrent-ruby-1.0.5/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb000066400000000000000000000013001305460430400274460ustar00rootroot00000000000000module Concurrent # Special "compare and set" handling of numeric values. # # @!visibility private # @!macro internal_implementation_note module AtomicNumericCompareAndSetWrapper # @!macro atomic_reference_method_compare_and_set def compare_and_set(old_value, new_value) if old_value.kind_of? Numeric while true old = get return false unless old.kind_of? Numeric return false unless old == old_value result = _compare_and_set(old, new_value) return result if result end else _compare_and_set(old_value, new_value) end end alias_method :compare_and_swap, :compare_and_set end end concurrent-ruby-1.0.5/lib/concurrent/atomic_reference/rbx.rb000066400000000000000000000011731305460430400242210ustar00rootroot00000000000000require 'concurrent/atomic_reference/direct_update' require 'concurrent/atomic_reference/numeric_cas_wrapper' module Concurrent # @!macro atomic_reference # # @note Extends `Rubinius::AtomicReference` version adding aliases # and numeric logic. # # @!visibility private # @!macro internal_implementation_note class RbxAtomicReference < Rubinius::AtomicReference alias _compare_and_set compare_and_set include Concurrent::AtomicDirectUpdate include Concurrent::AtomicNumericCompareAndSetWrapper alias_method :value, :get alias_method :value=, :set alias_method :swap, :get_and_set end end concurrent-ruby-1.0.5/lib/concurrent/atomic_reference/ruby.rb000066400000000000000000000015441305460430400244110ustar00rootroot00000000000000if defined? Concurrent::CAtomicReference require 'concurrent/synchronization' require 'concurrent/atomic_reference/direct_update' require 'concurrent/atomic_reference/numeric_cas_wrapper' module Concurrent # @!macro atomic_reference # # @!visibility private # @!macro internal_implementation_note class CAtomicReference include Concurrent::AtomicDirectUpdate include Concurrent::AtomicNumericCompareAndSetWrapper # @!method initialize # @!macro atomic_reference_method_initialize # @!method get # @!macro atomic_reference_method_get # @!method set # @!macro atomic_reference_method_set # @!method get_and_set # @!macro atomic_reference_method_get_and_set # @!method _compare_and_set # @!macro atomic_reference_method_compare_and_set end end end concurrent-ruby-1.0.5/lib/concurrent/atomics.rb000066400000000000000000000037021305460430400215730ustar00rootroot00000000000000# @!macro [new] atomic_reference # # An object reference that may be updated atomically. All read and write # operations have java volatile semantic. # # @!macro thread_safe_variable_comparison # # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicReference.html # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/package-summary.html # # @!method initialize # @!macro [new] atomic_reference_method_initialize # @param [Object] value The initial value. # # @!method get # @!macro [new] atomic_reference_method_get # Gets the current value. # @return [Object] the current value # # @!method set # @!macro [new] atomic_reference_method_set # Sets to the given value. # @param [Object] new_value the new value # @return [Object] the new value # # @!method get_and_set # @!macro [new] atomic_reference_method_get_and_set # Atomically sets to the given value and returns the old value. # @param [Object] new_value the new value # @return [Object] the old value # # @!method compare_and_set # @!macro [new] atomic_reference_method_compare_and_set # # Atomically sets the value to the given updated value if # the current value == the expected value. # # @param [Object] old_value the expected value # @param [Object] new_value the new value # # @return [Boolean] `true` if successful. A `false` return indicates # that the actual value was not equal to the expected value. require 'concurrent/atomic/atomic_reference' require 'concurrent/atomic/atomic_boolean' require 'concurrent/atomic/atomic_fixnum' require 'concurrent/atomic/cyclic_barrier' require 'concurrent/atomic/count_down_latch' require 'concurrent/atomic/event' require 'concurrent/atomic/read_write_lock' require 'concurrent/atomic/reentrant_read_write_lock' require 'concurrent/atomic/semaphore' require 'concurrent/atomic/thread_local_var' concurrent-ruby-1.0.5/lib/concurrent/channel.rb000066400000000000000000000147651305460430400215570ustar00rootroot00000000000000require 'forwardable' require 'concurrent/channel/buffer' require 'concurrent/channel/selector' require 'concurrent/maybe' require 'concurrent/executor/cached_thread_pool' module Concurrent # {include:file:doc/channel.md} class Channel extend Forwardable include Enumerable # NOTE: Move to global IO pool once stable GOROUTINES = Concurrent::CachedThreadPool.new(auto_terminate: true) private_constant :GOROUTINES BUFFER_TYPES = { unbuffered: Buffer::Unbuffered, buffered: Buffer::Buffered, dropping: Buffer::Dropping, sliding: Buffer::Sliding }.freeze private_constant :BUFFER_TYPES DEFAULT_VALIDATOR = ->(value){ true } private_constant :DEFAULT_VALIDATOR Error = Class.new(StandardError) class ValidationError < Error def initialize(message = nil) message ||= 'invalid value' end end def_delegators :buffer, :size, :capacity, :close, :closed?, :blocking?, :empty?, :full? alias_method :length, :size alias_method :stop, :close def initialize(opts = {}) # undocumented -- for internal use only if opts.is_a? Buffer::Base self.buffer = opts return end capacity = opts[:capacity] || opts[:size] buffer = opts[:buffer] if capacity && buffer == :unbuffered raise ArgumentError.new('unbuffered channels cannot have a capacity') elsif capacity.nil? && buffer.nil? self.buffer = BUFFER_TYPES[:unbuffered].new elsif capacity == 0 && buffer == :buffered self.buffer = BUFFER_TYPES[:unbuffered].new elsif buffer == :unbuffered self.buffer = BUFFER_TYPES[:unbuffered].new elsif capacity.nil? || capacity < 1 raise ArgumentError.new('capacity must be at least 1 for this buffer type') else buffer ||= :buffered self.buffer = BUFFER_TYPES[buffer].new(capacity) end self.validator = opts.fetch(:validator, DEFAULT_VALIDATOR) end def put(item) return false unless validate(item, false, false) do_put(item) end alias_method :send, :put alias_method :<<, :put def put!(item) validate(item, false, true) ok = do_put(item) raise Error if !ok ok end def put?(item) if !validate(item, true, false) Concurrent::Maybe.nothing('invalid value') elsif do_put(item) Concurrent::Maybe.just(true) else Concurrent::Maybe.nothing end end def offer(item) return false unless validate(item, false, false) do_offer(item) end def offer!(item) validate(item, false, true) ok = do_offer(item) raise Error if !ok ok end def offer?(item) if !validate(item, true, false) Concurrent::Maybe.nothing('invalid value') elsif do_offer(item) Concurrent::Maybe.just(true) else Concurrent::Maybe.nothing end end def take item = do_take item == Concurrent::NULL ? nil : item end alias_method :receive, :take alias_method :~, :take def take! item = do_take raise Error if item == Concurrent::NULL item end def take? item = do_take item = if item == Concurrent::NULL Concurrent::Maybe.nothing else Concurrent::Maybe.just(item) end item end # @example # # jobs = Channel.new # # Channel.go do # loop do # j, more = jobs.next # if more # print "received job #{j}\n" # else # print "received all jobs\n" # break # end # end # end def next item, more = do_next item = nil if item == Concurrent::NULL return item, more end def next? item, more = do_next item = if item == Concurrent::NULL Concurrent::Maybe.nothing else Concurrent::Maybe.just(item) end return item, more end def poll (item = do_poll) == Concurrent::NULL ? nil : item end def poll! item = do_poll raise Error if item == Concurrent::NULL item end def poll? if (item = do_poll) == Concurrent::NULL Concurrent::Maybe.nothing else Concurrent::Maybe.just(item) end end def each raise ArgumentError.new('no block given') unless block_given? loop do item, more = do_next if item != Concurrent::NULL yield(item) elsif !more break end end end class << self def timer(seconds) Channel.new(Buffer::Timer.new(seconds)) end alias_method :after, :timer def ticker(interval) Channel.new(Buffer::Ticker.new(interval)) end alias_method :tick, :ticker def select(*args) raise ArgumentError.new('no block given') unless block_given? selector = Selector.new yield(selector, *args) selector.execute end alias_method :alt, :select def go(*args, &block) go_via(GOROUTINES, *args, &block) end def go_via(executor, *args, &block) raise ArgumentError.new('no block given') unless block_given? executor.post(*args, &block) end def go_loop(*args, &block) go_loop_via(GOROUTINES, *args, &block) end def go_loop_via(executor, *args, &block) raise ArgumentError.new('no block given') unless block_given? executor.post(block, *args) do loop do break unless block.call(*args) end end end end private def validator @validator end def validator=(value) @validator = value end def buffer @buffer end def buffer=(value) @buffer = value end def validate(value, allow_nil, raise_error) if !allow_nil && value.nil? raise_error ? raise(ValidationError.new('nil is not a valid value')) : false elsif !validator.call(value) raise_error ? raise(ValidationError) : false else true end rescue => ex # the validator raised an exception return raise_error ? raise(ex) : false end def do_put(item) buffer.put(item) end def do_offer(item) buffer.offer(item) end def do_take buffer.take end def do_next buffer.next end def do_poll buffer.poll end end end concurrent-ruby-1.0.5/lib/concurrent/channel/000077500000000000000000000000001305460430400212155ustar00rootroot00000000000000concurrent-ruby-1.0.5/lib/concurrent/channel/buffer.rb000066400000000000000000000004651305460430400230200ustar00rootroot00000000000000require 'concurrent/channel/buffer/base' require 'concurrent/channel/buffer/buffered' require 'concurrent/channel/buffer/dropping' require 'concurrent/channel/buffer/sliding' require 'concurrent/channel/buffer/unbuffered' require 'concurrent/channel/buffer/ticker' require 'concurrent/channel/buffer/timer' concurrent-ruby-1.0.5/lib/concurrent/channel/buffer/000077500000000000000000000000001305460430400224665ustar00rootroot00000000000000concurrent-ruby-1.0.5/lib/concurrent/channel/buffer/base.rb000066400000000000000000000201311305460430400237220ustar00rootroot00000000000000require 'concurrent/synchronization/lockable_object' module Concurrent class Channel module Buffer # Abstract base class for all Channel buffers. # # {Concurrent::Channel} objects maintain an internal, queue-like # object called a buffer. It's the storage bin for values put onto or # taken from the channel. Different buffer types have different # characteristics. Subsequently, the behavior of any given channel is # highly dependent uping the type of its buffer. This is the base class # which defines the common buffer interface. Any class intended to be # used as a channel buffer should extend this class. class Base < Synchronization::LockableObject # @!macro [attach] channel_buffer_capacity_reader # # The maximum number of values which can be {#put} onto the buffer # it becomes full. attr_reader :capacity # @!macro [attach] channel_buffer_initialize # # Creates a new buffer. def initialize(*args) super() synchronize do @closed = false @size = 0 @capacity = 0 @buffer = nil ns_initialize(*args) end end # @!macro [attach] channel_buffer_blocking_question # # Predicate indicating if this buffer will block {#put} operations # once it reaches its maximum capacity. # # @return [Boolean] true if this buffer blocks else false def blocking? true end # @!macro [attach] channel_buffer_size_reader # # The number of items currently in the buffer. def size synchronize { ns_size } end # @!macro [attach] channel_buffer_empty_question # # Predicate indicating if the buffer is empty. # # @return [Boolean] true if this buffer is empty else false # # @raise [NotImplementedError] until overridden in a subclass. def empty? synchronize { ns_empty? } end # @!macro [attach] channel_buffer_full_question # # Predicate indicating if the buffer is full. # # @return [Boolean] true if this buffer is full else false # # @raise [NotImplementedError] until overridden in a subclass. def full? synchronize { ns_full? } end # @!macro [attach] channel_buffer_put # # Put an item onto the buffer if possible. If the buffer is open # but not able to accept the item the calling thread will block # until the item can be put onto the buffer. # # @param [Object] item the item/value to put onto the buffer. # @return [Boolean] true if the item was added to the buffer else # false (always false when closed). # # @raise [NotImplementedError] until overridden in a subclass. def put(item) raise NotImplementedError end # @!macro [attach] channel_buffer_offer # # Put an item onto the buffer is possible. If the buffer is open but # unable to add an item, probably due to being full, the method will # return immediately. Similarly, the method will return immediately # when the buffer is closed. A return value of `false` does not # necessarily indicate that the buffer is closed, just that the item # could not be added. # # @param [Object] item the item/value to put onto the buffer. # @return [Boolean] true if the item was added to the buffer else # false (always false when closed). # # @raise [NotImplementedError] until overridden in a subclass. def offer(item) raise NotImplementedError end # @!macro [attach] channel_buffer_take # # Take an item from the buffer if one is available. If the buffer # is open and no item is available the calling thread will block # until an item is available. If the buffer is closed but items # are available the remaining items can still be taken. Once the # buffer closes, no remaining items can be taken. # # @return [Object] the item removed from the buffer; `Concurrent::NULL` once # the buffer has closed. # # @raise [NotImplementedError] until overridden in a subclass. def take raise NotImplementedError end # @!macro [attach] channel_buffer_next # # Take the next "item" from the buffer and also return a boolean # indicating if "more" items can be taken. Used for iterating # over a buffer until it is closed and empty. # # If the buffer is open but no items remain the calling thread will # block until an item is available. The second of the two return # values, "more" (a boolean), will always be `true` when the buffer is # open. The "more" value will be `false` when the channel has been # closed and all values have already been received. When "more" is # false the returned item will be `Concurrent::NULL`. # # Note that when multiple threads access the same channel a race # condition can occur when using this method. A call to `next` from # one thread may return `true` for the second return value, but # another thread may `take` the last value before the original # thread makes another call. Code which iterates over a channel # must be programmed to properly handle these race conditions. # # @return [Object, Boolean] the first return value will be the item # taken from the buffer and the second return value will be a # boolean indicating whether or not more items remain. # # @raise [NotImplementedError] until overridden in a subclass. def next raise NotImplementedError end # @!macro [attach] channel_buffer_poll # # Take the next item from the buffer if one is available else return # immediately. Failing to return a value does not necessarily # indicate that the buffer is closed, just that it is empty. # # @return [Object] the next item from the buffer or `Concurrent::NULL` if # the buffer is empty. # # @raise [NotImplementedError] until overridden in a subclass. def poll raise NotImplementedError end # @!macro [attach] channel_buffer_close # # Close the buffer, preventing new items from being added. Once a # buffer is closed it cannot be opened again. # # @return [Boolean] true if the buffer was open and successfully # closed else false. def close synchronize do @closed ? false : @closed = true end end # @!macro [attach] channel_buffer_closed_question # # Predicate indicating is this buffer closed. # # @return [Boolea] true when closed else false. def closed? synchronize { ns_closed? } end private def buffer @buffer end def buffer=(value) @buffer = value end def closed=(value) @closed = value end def capacity=(value) @capacity = value end def size=(value) @size = value end def ns_initialize(*args) end # @!macro channel_buffer_size_reader def ns_size raise NotImplementedError end # @!macro channel_buffer_empty_question def ns_empty? raise NotImplementedError end # @!macro channel_buffer_full_question def ns_full? raise NotImplementedError end # @!macro channel_buffer_closed_question def ns_closed? @closed end end end end end concurrent-ruby-1.0.5/lib/concurrent/channel/buffer/buffered.rb000066400000000000000000000057341305460430400246060ustar00rootroot00000000000000require 'concurrent/constants' require 'concurrent/channel/buffer/base' module Concurrent class Channel module Buffer # A buffer with a fixed internal capacity. Items can be put onto the # buffer without blocking until the internal capacity is reached. Once # the buffer is at capacity, subsequent calls to {#put} will block until # an item is removed from the buffer, creating spare capacity. class Buffered < Base # @!macro channel_buffer_put # # New items can be put onto the buffer until the number of items in # the buffer reaches the {#size} value specified during # initialization. def put(item) loop do synchronize do if ns_closed? return false elsif !ns_full? ns_put_onto_buffer(item) return true end end Thread.pass end end # @!macro channel_buffer_offer # # New items can be put onto the buffer until the number of items in # the buffer reaches the {#size} value specified during # initialization. def offer(item) synchronize do if ns_closed? || ns_full? return false else ns_put_onto_buffer(item) return true end end end # @!macro channel_buffer_take def take item, _ = self.next item end # @!macro channel_buffer_next def next loop do synchronize do if ns_closed? && ns_empty? return Concurrent::NULL, false elsif !ns_empty? item = buffer.shift return item, true end end Thread.pass end end # @!macro channel_buffer_poll def poll synchronize do if ns_empty? Concurrent::NULL else buffer.shift end end end private # @!macro channel_buffer_initialize # # @param [Integer] size the maximum capacity of the buffer; must be # greater than zero. # @raise [ArgumentError] when the size is zero (0) or less. def ns_initialize(size) raise ArgumentError.new('size must be greater than 0') if size.to_i <= 0 self.capacity = size.to_i self.buffer = [] end # @!macro channel_buffer_size_reader def ns_size buffer.size end # @!macro channel_buffer_empty_question def ns_empty? ns_size == 0 end # @!macro channel_buffer_full_question def ns_full? ns_size == capacity end # @!macro channel_buffer_put def ns_put_onto_buffer(item) buffer.push(item) end end end end end concurrent-ruby-1.0.5/lib/concurrent/channel/buffer/dropping.rb000066400000000000000000000027421305460430400246420ustar00rootroot00000000000000require 'concurrent/channel/buffer/base' module Concurrent class Channel module Buffer # A non-blocking, buffered buffer of fixed maximum capacity. When the # maximum capacity is reached subsequent {#put} and {#offer} operations # will complete but the `put` item will be discarded; no transfer will # occur. class Dropping < Buffered # @!method put(item) # @!macro channel_buffer_put # # When the buffer is full, this method will return `true` # immediately but the item will be discarded. The item will *not* # be placed into the buffer (no transfer will occur). # @!method offer(item) # @!macro channel_buffer_offer # # When the buffer is full, this method will return `true` # immediately but the item will be discarded. The item will *not* # be placed into the buffer (no transfer will occur). # @!method full? # @!macro channel_buffer_full_question # # Always returns `false`. # @!macro channel_buffer_blocking_question # # Always returns `false`. def blocking? false end private # @!macro channel_buffer_full_question def ns_full? false end # @!macro channel_buffer_put def ns_put_onto_buffer(item) buffer.push(item) unless buffer.size == capacity end end end end end concurrent-ruby-1.0.5/lib/concurrent/channel/buffer/sliding.rb000066400000000000000000000030411305460430400244420ustar00rootroot00000000000000require 'concurrent/channel/buffer/base' module Concurrent class Channel module Buffer # A non-blocking, buffered buffer of fixed maximum capacity. When the # maximum capacity is reached subsequent {#put} and {#offer} operations # will complete and the item will be `put`, but the oldest elements in # the buffer will be discarded (not transferred). class Sliding < Buffered # @!method put(item) # @!macro channel_buffer_put # # When the buffer is full, this method will return `true` # immediately and the item will be inserted, but the oldest # elements in the buffer will be discarded (not transferred). # @!method offer(item) # @!macro channel_buffer_offer # # When the buffer is full, this method will return `true` # immediately and the item will be inserted, but the oldest # elements in the buffer will be discarded (not transferred). # @!method full? # @!macro channel_buffer_full_question # # Always returns `false`. # @!macro channel_buffer_blocking_question # # Always returns `false`. def blocking? false end private # @!macro channel_buffer_full_question def ns_full? false end # @!macro channel_buffer_put def ns_put_onto_buffer(item) buffer.shift if buffer.size == capacity buffer.push(item) end end end end end concurrent-ruby-1.0.5/lib/concurrent/channel/buffer/ticker.rb000066400000000000000000000015351305460430400243000ustar00rootroot00000000000000require 'concurrent/constants' require 'concurrent/utility/monotonic_time' require 'concurrent/channel/tick' require 'concurrent/channel/buffer/timer' module Concurrent class Channel module Buffer class Ticker < Timer private def ns_initialize(interval) @interval = interval.to_f @next_tick = Concurrent.monotonic_time + interval self.capacity = 1 end def do_poll synchronize do if ns_closed? return Concurrent::NULL, false elsif (now = Concurrent.monotonic_time) >= @next_tick tick = Concurrent::Channel::Tick.new(@next_tick) @next_tick = now + @interval return tick, true else return nil, true end end end end end end end concurrent-ruby-1.0.5/lib/concurrent/channel/buffer/timer.rb000066400000000000000000000027751305460430400241460ustar00rootroot00000000000000require 'concurrent/constants' require 'concurrent/utility/monotonic_time' require 'concurrent/channel/tick' require 'concurrent/channel/buffer/base' module Concurrent class Channel module Buffer class Timer < Base def put(item) false end def offer(item) false end def take loop do tick, _ = do_poll if tick return tick else Thread.pass end end end def next loop do tick, more = do_poll return tick, more if tick Thread.pass end end def poll tick, _ = do_poll tick = Concurrent::NULL unless tick tick end private def ns_initialize(delay) @tick = Concurrent.monotonic_time + delay.to_f self.capacity = 1 end def ns_size 0 end def ns_empty? false end def ns_full? true end def do_poll synchronize do if ns_closed? return Concurrent::NULL, false elsif Concurrent.monotonic_time >= @tick # only one listener gets notified self.closed = true return Concurrent::Channel::Tick.new(@tick), false else return nil, true end end end end end end end concurrent-ruby-1.0.5/lib/concurrent/channel/buffer/unbuffered.rb000066400000000000000000000120221305460430400251350ustar00rootroot00000000000000require 'concurrent/constants' require 'concurrent/channel/buffer/base' require 'concurrent/atomic/atomic_reference' module Concurrent class Channel module Buffer # A blocking buffer with a size of zero. An item can only be put onto # the buffer when a thread is waiting to take. Similarly, an item can # only be put onto the buffer when a thread is waiting to put. When # either {#put} or {#take} is called and there is no corresponding call # in progress, the call will block indefinitely. Any other calls to the # same method will queue behind the first call and block as well. As # soon as a corresponding put/take call is made an exchange will occur # and the first blocked call will return. class Unbuffered < Base # @!macro channel_buffer_size_reader def size synchronize do putting.empty? ? 0 : 1 end end # @!macro channel_buffer_empty_question def empty? size == 0 end # @!macro channel_buffer_full_question def full? !empty? end # @!macro channel_buffer_put # # Items can only be put onto the buffer when one or more threads are # waiting to {#take} items off the buffer. When there is a thread # waiting to take an item this method will give its item and return # immediately. When there are no threads waiting to take, this method # will block. As soon as a thread calls `take` the exchange will # occur and this method will return. def put(item) mine = synchronize do return false if ns_closed? ref = Concurrent::AtomicReference.new(item) if taking.empty? putting.push(ref) else taken = taking.shift taken.value = item ref.value = nil end ref end loop do return true if mine.value.nil? Thread.pass end end # @!macro channel_buffer_offer # # Items can only be put onto the buffer when one or more threads are # waiting to {#take} items off the buffer. When there is a thread # waiting to take an item this method will give its item and return # `true` immediately. When there are no threads waiting to take or the # buffer is closed, this method will return `false` immediately. def offer(item) synchronize do return false if ns_closed? || taking.empty? taken = taking.shift taken.value = item true end end # @!macro channel_buffer_take # # Items can only be taken from the buffer when one or more threads are # waiting to {#put} items onto the buffer. When there is a thread # waiting to put an item this method will take that item and return it # immediately. When there are no threads waiting to put, this method # will block. As soon as a thread calls `pur` the exchange will occur # and this method will return. def take mine = synchronize do return Concurrent::NULL if ns_closed? && putting.empty? ref = Concurrent::AtomicReference.new(nil) if putting.empty? taking.push(ref) else put = putting.shift ref.value = put.value put.value = nil end ref end loop do item = mine.value return item if item Thread.pass end end # @!macro channel_buffer_poll # # Items can only be taken off the buffer when one or more threads are # waiting to {#put} items onto the buffer. When there is a thread # waiting to put an item this method will take the item and return # it immediately. When there are no threads waiting to put or the # buffer is closed, this method will return `Concurrent::NULL` immediately. def poll synchronize do return Concurrent::NULL if putting.empty? put = putting.shift value = put.value put.value = nil value end end # @!macro channel_buffer_next # # Items can only be taken from the buffer when one or more threads are # waiting to {#put} items onto the buffer. This method exhibits the # same blocking behavior as {#take}. # # @see {#take} def next item = take more = (item != Concurrent::NULL) return item, more end private def putting() @putting; end def taking() @taking; end # @!macro channel_buffer_initialize def ns_initialize # one will always be empty @putting = [] @taking = [] self.closed = false self.capacity = 1 end end end end end concurrent-ruby-1.0.5/lib/concurrent/channel/selector.rb000066400000000000000000000040101305460430400233550ustar00rootroot00000000000000require 'concurrent/maybe' require 'concurrent/channel/selector/after_clause' require 'concurrent/channel/selector/default_clause' require 'concurrent/channel/selector/put_clause' require 'concurrent/channel/selector/take_clause' module Concurrent class Channel # @!visibility private class Selector def initialize @clauses = [] @error_handler = nil end def case(channel, action, message = nil, &block) if [:take, :poll, :receive, :~].include?(action) take(channel, &block) elsif [:put, :offer, :send, :<<].include?(action) put(channel, message, &block) else raise ArgumentError.new('invalid action') end end def take(channel, &block) raise ArgumentError.new('no block given') unless block_given? @clauses << TakeClause.new(channel, block) end alias_method :receive, :take def put(channel, message, &block) @clauses << PutClause.new(channel, message, block) end alias_method :send, :put def after(seconds, &block) @clauses << AfterClause.new(seconds, block) end alias_method :timeout, :after def default(&block) raise ArgumentError.new('no block given') unless block_given? @clauses << DefaultClause.new(block) end def error(&block) raise ArgumentError.new('no block given') unless block_given? raise ArgumentError.new('only one error handler allowed') if @error_handler @error_handler = block end def execute raise Channel::Error.new('no clauses given') if @clauses.empty? loop do done = @clauses.each do |clause| result = clause.execute break result if result.just? end break done.value if done.is_a?(Concurrent::Maybe) Thread.pass end rescue => ex if @error_handler @error_handler.call(ex) else raise ex end end end end end concurrent-ruby-1.0.5/lib/concurrent/channel/selector/000077500000000000000000000000001305460430400230355ustar00rootroot00000000000000concurrent-ruby-1.0.5/lib/concurrent/channel/selector/after_clause.rb000066400000000000000000000011721305460430400260200ustar00rootroot00000000000000require 'concurrent/maybe' require 'concurrent/utility/monotonic_time' module Concurrent class Channel class Selector class AfterClause def initialize(seconds, block) raise ArgumentError.new('timeout must 0.0 or more') if seconds.to_f < 0.0 @end = Concurrent.monotonic_time + seconds.to_f @block = block end def execute if Concurrent.monotonic_time > @end result = @block ? @block.call : nil Concurrent::Maybe.just(result) else Concurrent::Maybe.nothing end end end end end end concurrent-ruby-1.0.5/lib/concurrent/channel/selector/default_clause.rb000066400000000000000000000004331305460430400263420ustar00rootroot00000000000000require 'concurrent/maybe' module Concurrent class Channel class Selector class DefaultClause def initialize(block) @block = block end def execute Concurrent::Maybe.just(@block.call) end end end end end concurrent-ruby-1.0.5/lib/concurrent/channel/selector/error_clause.rb000066400000000000000000000005071305460430400260510ustar00rootroot00000000000000module Concurrent class Channel class Selector class ErrorClause def initialize(block) @block = block end def execute(error) @block.call(error) rescue # suppress and move on ensure return nil end end end end end concurrent-ruby-1.0.5/lib/concurrent/channel/selector/put_clause.rb000066400000000000000000000010001305460430400255150ustar00rootroot00000000000000require 'concurrent/maybe' module Concurrent class Channel class Selector class PutClause def initialize(channel, message, block) @channel = channel @message = message @block = block end def execute if @channel.offer?(@message).just? result = @block ? @block.call : nil Concurrent::Maybe.just(result) else Concurrent::Maybe.nothing end end end end end end concurrent-ruby-1.0.5/lib/concurrent/channel/selector/take_clause.rb000066400000000000000000000006761305460430400256530ustar00rootroot00000000000000require 'concurrent/maybe' module Concurrent class Channel class Selector class TakeClause def initialize(channel, block) @channel = channel @block = block end def execute if (result = @channel.poll?).just? Concurrent::Maybe.just(@block.call(result.value)) else Concurrent::Maybe.nothing end end end end end end concurrent-ruby-1.0.5/lib/concurrent/channel/tick.rb000066400000000000000000000024451305460430400225010ustar00rootroot00000000000000require 'concurrent/synchronization' require 'concurrent/utility/monotonic_time' module Concurrent class Channel # A convenience class representing a single moment in monotonic time. # Returned by {Concurrent::Channel} tickers and timers when they # resolve. # # Includes `Comparable` and can be compared to monotonic_time, UTC # time, or epoch time. # # @see Concurrent.monotonic_time # @see Concurrent::Channel.ticker # @see Concurrent::Channel.timer class Tick < Synchronization::Object include Comparable safe_initialization! STRING_FORMAT = '%F %T.%6N %z %Z'.freeze attr_reader :monotonic, :utc def initialize(tick = Concurrent.monotonic_time) @monotonic = tick @utc = monotonic_to_utc(tick).freeze end def epoch @utc.to_f end def to_s @utc.strftime(STRING_FORMAT) end def <=>(other) if other.is_a? Numeric @monotonic <=> other elsif other.is_a? Time @utc <=> other.utc elsif other.is_a? Tick @monotonic <=> other.monotonic else nil end end private def monotonic_to_utc(tick) Time.now.utc + Concurrent.monotonic_time - tick end end end end concurrent-ruby-1.0.5/lib/concurrent/collection/000077500000000000000000000000001305460430400217405ustar00rootroot00000000000000concurrent-ruby-1.0.5/lib/concurrent/collection/copy_on_notify_observer_set.rb000066400000000000000000000054601305460430400301120ustar00rootroot00000000000000require 'concurrent/synchronization' module Concurrent module Collection # A thread safe observer set implemented using copy-on-read approach: # observers are added and removed from a thread safe collection; every time # a notification is required the internal data structure is copied to # prevent concurrency issues # # @api private class CopyOnNotifyObserverSet < Synchronization::LockableObject def initialize super() synchronize { ns_initialize } end # @!macro observable_add_observer def add_observer(observer = nil, func = :update, &block) if observer.nil? && block.nil? raise ArgumentError, 'should pass observer as a first argument or block' elsif observer && block raise ArgumentError.new('cannot provide both an observer and a block') end if block observer = block func = :call end synchronize do @observers[observer] = func observer end end # @!macro observable_delete_observer def delete_observer(observer) synchronize do @observers.delete(observer) observer end end # @!macro observable_delete_observers def delete_observers synchronize do @observers.clear self end end # @!macro observable_count_observers def count_observers synchronize { @observers.count } end # Notifies all registered observers with optional args # @param [Object] args arguments to be passed to each observer # @return [CopyOnWriteObserverSet] self def notify_observers(*args, &block) observers = duplicate_observers notify_to(observers, *args, &block) self end # Notifies all registered observers with optional args and deletes them. # # @param [Object] args arguments to be passed to each observer # @return [CopyOnWriteObserverSet] self def notify_and_delete_observers(*args, &block) observers = duplicate_and_clear_observers notify_to(observers, *args, &block) self end protected def ns_initialize @observers = {} end private def duplicate_and_clear_observers synchronize do observers = @observers.dup @observers.clear observers end end def duplicate_observers synchronize { @observers.dup } end def notify_to(observers, *args) raise ArgumentError.new('cannot give arguments and a block') if block_given? && !args.empty? observers.each do |observer, function| args = yield if block_given? observer.send(function, *args) end end end end end concurrent-ruby-1.0.5/lib/concurrent/collection/copy_on_write_observer_set.rb000066400000000000000000000055731305460430400277410ustar00rootroot00000000000000require 'concurrent/synchronization' module Concurrent module Collection # A thread safe observer set implemented using copy-on-write approach: # every time an observer is added or removed the whole internal data structure is # duplicated and replaced with a new one. # # @api private class CopyOnWriteObserverSet < Synchronization::LockableObject def initialize super() synchronize { ns_initialize } end # @!macro observable_add_observer def add_observer(observer = nil, func = :update, &block) if observer.nil? && block.nil? raise ArgumentError, 'should pass observer as a first argument or block' elsif observer && block raise ArgumentError.new('cannot provide both an observer and a block') end if block observer = block func = :call end synchronize do new_observers = @observers.dup new_observers[observer] = func @observers = new_observers observer end end # @!macro observable_delete_observer def delete_observer(observer) synchronize do new_observers = @observers.dup new_observers.delete(observer) @observers = new_observers observer end end # @!macro observable_delete_observers def delete_observers self.observers = {} self end # @!macro observable_count_observers def count_observers observers.count end # Notifies all registered observers with optional args # @param [Object] args arguments to be passed to each observer # @return [CopyOnWriteObserverSet] self def notify_observers(*args, &block) notify_to(observers, *args, &block) self end # Notifies all registered observers with optional args and deletes them. # # @param [Object] args arguments to be passed to each observer # @return [CopyOnWriteObserverSet] self def notify_and_delete_observers(*args, &block) old = clear_observers_and_return_old notify_to(old, *args, &block) self end protected def ns_initialize @observers = {} end private def notify_to(observers, *args) raise ArgumentError.new('cannot give arguments and a block') if block_given? && !args.empty? observers.each do |observer, function| args = yield if block_given? observer.send(function, *args) end end def observers synchronize { @observers } end def observers=(new_set) synchronize { @observers = new_set } end def clear_observers_and_return_old synchronize do old_observers = @observers @observers = {} old_observers end end end end end concurrent-ruby-1.0.5/lib/concurrent/collection/java_non_concurrent_priority_queue.rb000066400000000000000000000040241305460430400314670ustar00rootroot00000000000000if Concurrent.on_jruby? module Concurrent module Collection # @!macro priority_queue # # @!visibility private # @!macro internal_implementation_note class JavaNonConcurrentPriorityQueue # @!macro priority_queue_method_initialize def initialize(opts = {}) order = opts.fetch(:order, :max) if [:min, :low].include?(order) @queue = java.util.PriorityQueue.new(11) # 11 is the default initial capacity else @queue = java.util.PriorityQueue.new(11, java.util.Collections.reverseOrder()) end end # @!macro priority_queue_method_clear def clear @queue.clear true end # @!macro priority_queue_method_delete def delete(item) found = false while @queue.remove(item) do found = true end found end # @!macro priority_queue_method_empty def empty? @queue.size == 0 end # @!macro priority_queue_method_include def include?(item) @queue.contains(item) end alias_method :has_priority?, :include? # @!macro priority_queue_method_length def length @queue.size end alias_method :size, :length # @!macro priority_queue_method_peek def peek @queue.peek end # @!macro priority_queue_method_pop def pop @queue.poll end alias_method :deq, :pop alias_method :shift, :pop # @!macro priority_queue_method_push def push(item) raise ArgumentError.new('cannot enqueue nil') if item.nil? @queue.add(item) end alias_method :<<, :push alias_method :enq, :push # @!macro priority_queue_method_from_list def self.from_list(list, opts = {}) queue = new(opts) list.each{|item| queue << item } queue end end end end end concurrent-ruby-1.0.5/lib/concurrent/collection/map/000077500000000000000000000000001305460430400225155ustar00rootroot00000000000000concurrent-ruby-1.0.5/lib/concurrent/collection/map/atomic_reference_map_backend.rb000066400000000000000000001105311305460430400306410ustar00rootroot00000000000000require 'concurrent/constants' require 'concurrent/thread_safe/util' require 'concurrent/thread_safe/util/adder' require 'concurrent/thread_safe/util/cheap_lockable' require 'concurrent/thread_safe/util/power_of_two_tuple' require 'concurrent/thread_safe/util/volatile' require 'concurrent/thread_safe/util/xor_shift_random' module Concurrent # @!visibility private module Collection # A Ruby port of the Doug Lea's jsr166e.ConcurrentHashMapV8 class version 1.59 # available in public domain. # # Original source code available here: # http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/ConcurrentHashMapV8.java?revision=1.59 # # The Ruby port skips out the +TreeBin+ (red-black trees for use in bins whose # size exceeds a threshold). # # A hash table supporting full concurrency of retrievals and high expected # concurrency for updates. However, even though all operations are # thread-safe, retrieval operations do _not_ entail locking, and there is # _not_ any support for locking the entire table in a way that prevents all # access. # # Retrieval operations generally do not block, so may overlap with update # operations. Retrievals reflect the results of the most recently _completed_ # update operations holding upon their onset. (More formally, an update # operation for a given key bears a _happens-before_ relation with any (non # +nil+) retrieval for that key reporting the updated value.) For aggregate # operations such as +clear()+, concurrent retrievals may reflect insertion or # removal of only some entries. Similarly, the +each_pair+ iterator yields # elements reflecting the state of the hash table at some point at or since # the start of the +each_pair+. Bear in mind that the results of aggregate # status methods including +size()+ and +empty?+} are typically useful only # when a map is not undergoing concurrent updates in other threads. Otherwise # the results of these methods reflect transient states that may be adequate # for monitoring or estimation purposes, but not for program control. # # The table is dynamically expanded when there are too many collisions (i.e., # keys that have distinct hash codes but fall into the same slot modulo the # table size), with the expected average effect of maintaining roughly two # bins per mapping (corresponding to a 0.75 load factor threshold for # resizing). There may be much variance around this average as mappings are # added and removed, but overall, this maintains a commonly accepted # time/space tradeoff for hash tables. However, resizing this or any other # kind of hash table may be a relatively slow operation. When possible, it is # a good idea to provide a size estimate as an optional :initial_capacity # initializer argument. An additional optional :load_factor constructor # argument provides a further means of customizing initial table capacity by # specifying the table density to be used in calculating the amount of space # to allocate for the given number of elements. Note that using many keys with # exactly the same +hash+ is a sure way to slow down performance of any hash # table. # # ## Design overview # # The primary design goal of this hash table is to maintain concurrent # readability (typically method +[]+, but also iteration and related methods) # while minimizing update contention. Secondary goals are to keep space # consumption about the same or better than plain +Hash+, and to support high # initial insertion rates on an empty table by many threads. # # Each key-value mapping is held in a +Node+. The validation-based approach # explained below leads to a lot of code sprawl because retry-control # precludes factoring into smaller methods. # # The table is lazily initialized to a power-of-two size upon the first # insertion. Each bin in the table normally contains a list of +Node+s (most # often, the list has only zero or one +Node+). Table accesses require # volatile/atomic reads, writes, and CASes. The lists of nodes within bins are # always accurately traversable under volatile reads, so long as lookups check # hash code and non-nullness of value before checking key equality. # # We use the top two bits of +Node+ hash fields for control purposes -- they # are available anyway because of addressing constraints. As explained further # below, these top bits are used as follows: # # - 00 - Normal # - 01 - Locked # - 11 - Locked and may have a thread waiting for lock # - 10 - +Node+ is a forwarding node # # The lower 28 bits of each +Node+'s hash field contain a the key's hash code, # except for forwarding nodes, for which the lower bits are zero (and so # always have hash field == +MOVED+). # # Insertion (via +[]=+ or its variants) of the first node in an empty bin is # performed by just CASing it to the bin. This is by far the most common case # for put operations under most key/hash distributions. Other update # operations (insert, delete, and replace) require locks. We do not want to # waste the space required to associate a distinct lock object with each bin, # so instead use the first node of a bin list itself as a lock. Blocking # support for these locks relies +Concurrent::ThreadSafe::Util::CheapLockable. However, we also need a # +try_lock+ construction, so we overlay these by using bits of the +Node+ # hash field for lock control (see above), and so normally use builtin # monitors only for blocking and signalling using # +cheap_wait+/+cheap_broadcast+ constructions. See +Node#try_await_lock+. # # Using the first node of a list as a lock does not by itself suffice though: # When a node is locked, any update must first validate that it is still the # first node after locking it, and retry if not. Because new nodes are always # appended to lists, once a node is first in a bin, it remains first until # deleted or the bin becomes invalidated (upon resizing). However, operations # that only conditionally update may inspect nodes until the point of update. # This is a converse of sorts to the lazy locking technique described by # Herlihy & Shavit. # # The main disadvantage of per-bin locks is that other update operations on # other nodes in a bin list protected by the same lock can stall, for example # when user +eql?+ or mapping functions take a long time. However, # statistically, under random hash codes, this is not a common problem. # Ideally, the frequency of nodes in bins follows a Poisson distribution # (http://en.wikipedia.org/wiki/Poisson_distribution) with a parameter of # about 0.5 on average, given the resizing threshold of 0.75, although with a # large variance because of resizing granularity. Ignoring variance, the # expected occurrences of list size k are (exp(-0.5) * pow(0.5, k) / # factorial(k)). The first values are: # # - 0: 0.60653066 # - 1: 0.30326533 # - 2: 0.07581633 # - 3: 0.01263606 # - 4: 0.00157952 # - 5: 0.00015795 # - 6: 0.00001316 # - 7: 0.00000094 # - 8: 0.00000006 # - more: less than 1 in ten million # # Lock contention probability for two threads accessing distinct elements is # roughly 1 / (8 * #elements) under random hashes. # # The table is resized when occupancy exceeds a percentage threshold # (nominally, 0.75, but see below). Only a single thread performs the resize # (using field +size_control+, to arrange exclusion), but the table otherwise # remains usable for reads and updates. Resizing proceeds by transferring # bins, one by one, from the table to the next table. Because we are using # power-of-two expansion, the elements from each bin must either stay at same # index, or move with a power of two offset. We eliminate unnecessary node # creation by catching cases where old nodes can be reused because their next # fields won't change. On average, only about one-sixth of them need cloning # when a table doubles. The nodes they replace will be garbage collectable as # soon as they are no longer referenced by any reader thread that may be in # the midst of concurrently traversing table. Upon transfer, the old table bin # contains only a special forwarding node (with hash field +MOVED+) that # contains the next table as its key. On encountering a forwarding node, # access and update operations restart, using the new table. # # Each bin transfer requires its bin lock. However, unlike other cases, a # transfer can skip a bin if it fails to acquire its lock, and revisit it # later. Method +rebuild+ maintains a buffer of TRANSFER_BUFFER_SIZE bins that # have been skipped because of failure to acquire a lock, and blocks only if # none are available (i.e., only very rarely). The transfer operation must # also ensure that all accessible bins in both the old and new table are # usable by any traversal. When there are no lock acquisition failures, this # is arranged simply by proceeding from the last bin (+table.size - 1+) up # towards the first. Upon seeing a forwarding node, traversals arrange to move # to the new table without revisiting nodes. However, when any node is skipped # during a transfer, all earlier table bins may have become visible, so are # initialized with a reverse-forwarding node back to the old table until the # new ones are established. (This sometimes requires transiently locking a # forwarding node, which is possible under the above encoding.) These more # expensive mechanics trigger only when necessary. # # The traversal scheme also applies to partial traversals of # ranges of bins (via an alternate Traverser constructor) # to support partitioned aggregate operations. Also, read-only # operations give up if ever forwarded to a null table, which # provides support for shutdown-style clearing, which is also not # currently implemented. # # Lazy table initialization minimizes footprint until first use. # # The element count is maintained using a +Concurrent::ThreadSafe::Util::Adder+, # which avoids contention on updates but can encounter cache thrashing # if read too frequently during concurrent access. To avoid reading so # often, resizing is attempted either when a bin lock is # contended, or upon adding to a bin already holding two or more # nodes (checked before adding in the +x_if_absent+ methods, after # adding in others). Under uniform hash distributions, the # probability of this occurring at threshold is around 13%, # meaning that only about 1 in 8 puts check threshold (and after # resizing, many fewer do so). But this approximation has high # variance for small table sizes, so we check on any collision # for sizes <= 64. The bulk putAll operation further reduces # contention by only committing count updates upon these size # checks. # # @!visibility private class AtomicReferenceMapBackend # @!visibility private class Table < Concurrent::ThreadSafe::Util::PowerOfTwoTuple def cas_new_node(i, hash, key, value) cas(i, nil, Node.new(hash, key, value)) end def try_to_cas_in_computed(i, hash, key) succeeded = false new_value = nil new_node = Node.new(locked_hash = hash | LOCKED, key, NULL) if cas(i, nil, new_node) begin if NULL == (new_value = yield(NULL)) was_null = true else new_node.value = new_value end succeeded = true ensure volatile_set(i, nil) if !succeeded || was_null new_node.unlock_via_hash(locked_hash, hash) end end return succeeded, new_value end def try_lock_via_hash(i, node, node_hash) node.try_lock_via_hash(node_hash) do yield if volatile_get(i) == node end end def delete_node_at(i, node, predecessor_node) if predecessor_node predecessor_node.next = node.next else volatile_set(i, node.next) end end end # Key-value entry. Nodes with a hash field of +MOVED+ are special, and do # not contain user keys or values. Otherwise, keys are never +nil+, and # +NULL+ +value+ fields indicate that a node is in the process of being # deleted or created. For purposes of read-only access, a key may be read # before a value, but can only be used after checking value to be +!= NULL+. # # @!visibility private class Node extend Concurrent::ThreadSafe::Util::Volatile attr_volatile :hash, :value, :next include Concurrent::ThreadSafe::Util::CheapLockable bit_shift = Concurrent::ThreadSafe::Util::FIXNUM_BIT_SIZE - 2 # need 2 bits for ourselves # Encodings for special uses of Node hash fields. See above for explanation. MOVED = ('10' << ('0' * bit_shift)).to_i(2) # hash field for forwarding nodes LOCKED = ('01' << ('0' * bit_shift)).to_i(2) # set/tested only as a bit WAITING = ('11' << ('0' * bit_shift)).to_i(2) # both bits set/tested together HASH_BITS = ('00' << ('1' * bit_shift)).to_i(2) # usable bits of normal node hash SPIN_LOCK_ATTEMPTS = Concurrent::ThreadSafe::Util::CPU_COUNT > 1 ? Concurrent::ThreadSafe::Util::CPU_COUNT * 2 : 0 attr_reader :key def initialize(hash, key, value, next_node = nil) super() @key = key self.lazy_set_hash(hash) self.lazy_set_value(value) self.next = next_node end # Spins a while if +LOCKED+ bit set and this node is the first of its bin, # and then sets +WAITING+ bits on hash field and blocks (once) if they are # still set. It is OK for this method to return even if lock is not # available upon exit, which enables these simple single-wait mechanics. # # The corresponding signalling operation is performed within callers: Upon # detecting that +WAITING+ has been set when unlocking lock (via a failed # CAS from non-waiting +LOCKED+ state), unlockers acquire the # +cheap_synchronize+ lock and perform a +cheap_broadcast+. def try_await_lock(table, i) if table && i >= 0 && i < table.size # bounds check, TODO: why are we bounds checking? spins = SPIN_LOCK_ATTEMPTS randomizer = base_randomizer = Concurrent::ThreadSafe::Util::XorShiftRandom.get while equal?(table.volatile_get(i)) && self.class.locked_hash?(my_hash = hash) if spins >= 0 if (randomizer = (randomizer >> 1)).even? # spin at random if (spins -= 1) == 0 Thread.pass # yield before blocking else randomizer = base_randomizer = Concurrent::ThreadSafe::Util::XorShiftRandom.xorshift(base_randomizer) if randomizer.zero? end end elsif cas_hash(my_hash, my_hash | WAITING) force_aquire_lock(table, i) break end end end end def key?(key) @key.eql?(key) end def matches?(key, hash) pure_hash == hash && key?(key) end def pure_hash hash & HASH_BITS end def try_lock_via_hash(node_hash = hash) if cas_hash(node_hash, locked_hash = node_hash | LOCKED) begin yield ensure unlock_via_hash(locked_hash, node_hash) end end end def locked? self.class.locked_hash?(hash) end def unlock_via_hash(locked_hash, node_hash) unless cas_hash(locked_hash, node_hash) self.hash = node_hash cheap_synchronize { cheap_broadcast } end end private def force_aquire_lock(table, i) cheap_synchronize do if equal?(table.volatile_get(i)) && (hash & WAITING) == WAITING cheap_wait else cheap_broadcast # possibly won race vs signaller end end end class << self def locked_hash?(hash) (hash & LOCKED) != 0 end end end # shorthands MOVED = Node::MOVED LOCKED = Node::LOCKED WAITING = Node::WAITING HASH_BITS = Node::HASH_BITS NOW_RESIZING = -1 DEFAULT_CAPACITY = 16 MAX_CAPACITY = Concurrent::ThreadSafe::Util::MAX_INT # The buffer size for skipped bins during transfers. The # value is arbitrary but should be large enough to avoid # most locking stalls during resizes. TRANSFER_BUFFER_SIZE = 32 extend Concurrent::ThreadSafe::Util::Volatile attr_volatile :table, # The array of bins. Lazily initialized upon first insertion. Size is always a power of two. # Table initialization and resizing control. When negative, the # table is being initialized or resized. Otherwise, when table is # null, holds the initial table size to use upon creation, or 0 # for default. After initialization, holds the next element count # value upon which to resize the table. :size_control def initialize(options = nil) super() @counter = Concurrent::ThreadSafe::Util::Adder.new initial_capacity = options && options[:initial_capacity] || DEFAULT_CAPACITY self.size_control = (capacity = table_size_for(initial_capacity)) > MAX_CAPACITY ? MAX_CAPACITY : capacity end def get_or_default(key, else_value = nil) hash = key_hash(key) current_table = table while current_table node = current_table.volatile_get_by_hash(hash) current_table = while node if (node_hash = node.hash) == MOVED break node.key elsif (node_hash & HASH_BITS) == hash && node.key?(key) && NULL != (value = node.value) return value end node = node.next end end else_value end def [](key) get_or_default(key) end def key?(key) get_or_default(key, NULL) != NULL end def []=(key, value) get_and_set(key, value) value end def compute_if_absent(key) hash = key_hash(key) current_table = table || initialize_table while true if !(node = current_table.volatile_get(i = current_table.hash_to_index(hash))) succeeded, new_value = current_table.try_to_cas_in_computed(i, hash, key) { yield } if succeeded increment_size return new_value end elsif (node_hash = node.hash) == MOVED current_table = node.key elsif NULL != (current_value = find_value_in_node_list(node, key, hash, node_hash & HASH_BITS)) return current_value elsif Node.locked_hash?(node_hash) try_await_lock(current_table, i, node) else succeeded, value = attempt_internal_compute_if_absent(key, hash, current_table, i, node, node_hash) { yield } return value if succeeded end end end def compute_if_present(key) new_value = nil internal_replace(key) do |old_value| if (new_value = yield(NULL == old_value ? nil : old_value)).nil? NULL else new_value end end new_value end def compute(key) internal_compute(key) do |old_value| if (new_value = yield(NULL == old_value ? nil : old_value)).nil? NULL else new_value end end end def merge_pair(key, value) internal_compute(key) do |old_value| if NULL == old_value || !(value = yield(old_value)).nil? value else NULL end end end def replace_pair(key, old_value, new_value) NULL != internal_replace(key, old_value) { new_value } end def replace_if_exists(key, new_value) if (result = internal_replace(key) { new_value }) && NULL != result result end end def get_and_set(key, value) # internalPut in the original CHMV8 hash = key_hash(key) current_table = table || initialize_table while true if !(node = current_table.volatile_get(i = current_table.hash_to_index(hash))) if current_table.cas_new_node(i, hash, key, value) increment_size break end elsif (node_hash = node.hash) == MOVED current_table = node.key elsif Node.locked_hash?(node_hash) try_await_lock(current_table, i, node) else succeeded, old_value = attempt_get_and_set(key, value, hash, current_table, i, node, node_hash) break old_value if succeeded end end end def delete(key) replace_if_exists(key, NULL) end def delete_pair(key, value) result = internal_replace(key, value) { NULL } if result && NULL != result !!result else false end end def each_pair return self unless current_table = table current_table_size = base_size = current_table.size i = base_index = 0 while base_index < base_size if node = current_table.volatile_get(i) if node.hash == MOVED current_table = node.key current_table_size = current_table.size else begin if NULL != (value = node.value) # skip deleted or special nodes yield node.key, value end end while node = node.next end end if (i_with_base = i + base_size) < current_table_size i = i_with_base # visit upper slots if present else i = base_index += 1 end end self end def size (sum = @counter.sum) < 0 ? 0 : sum # ignore transient negative values end def empty? size == 0 end # Implementation for clear. Steps through each bin, removing all nodes. def clear return self unless current_table = table current_table_size = current_table.size deleted_count = i = 0 while i < current_table_size if !(node = current_table.volatile_get(i)) i += 1 elsif (node_hash = node.hash) == MOVED current_table = node.key current_table_size = current_table.size elsif Node.locked_hash?(node_hash) decrement_size(deleted_count) # opportunistically update count deleted_count = 0 node.try_await_lock(current_table, i) else current_table.try_lock_via_hash(i, node, node_hash) do begin deleted_count += 1 if NULL != node.value # recheck under lock node.value = nil end while node = node.next current_table.volatile_set(i, nil) i += 1 end end end decrement_size(deleted_count) self end private # Internal versions of the insertion methods, each a # little more complicated than the last. All have # the same basic structure: # 1. If table uninitialized, create # 2. If bin empty, try to CAS new node # 3. If bin stale, use new table # 4. Lock and validate; if valid, scan and add or update # # The others interweave other checks and/or alternative actions: # * Plain +get_and_set+ checks for and performs resize after insertion. # * compute_if_absent prescans for mapping without lock (and fails to add # if present), which also makes pre-emptive resize checks worthwhile. # # Someday when details settle down a bit more, it might be worth # some factoring to reduce sprawl. def internal_replace(key, expected_old_value = NULL, &block) hash = key_hash(key) current_table = table while current_table if !(node = current_table.volatile_get(i = current_table.hash_to_index(hash))) break elsif (node_hash = node.hash) == MOVED current_table = node.key elsif (node_hash & HASH_BITS) != hash && !node.next # precheck break # rules out possible existence elsif Node.locked_hash?(node_hash) try_await_lock(current_table, i, node) else succeeded, old_value = attempt_internal_replace(key, expected_old_value, hash, current_table, i, node, node_hash, &block) return old_value if succeeded end end NULL end def attempt_internal_replace(key, expected_old_value, hash, current_table, i, node, node_hash) current_table.try_lock_via_hash(i, node, node_hash) do predecessor_node = nil old_value = NULL begin if node.matches?(key, hash) && NULL != (current_value = node.value) if NULL == expected_old_value || expected_old_value == current_value # NULL == expected_old_value means whatever value old_value = current_value if NULL == (node.value = yield(old_value)) current_table.delete_node_at(i, node, predecessor_node) decrement_size end end break end predecessor_node = node end while node = node.next return true, old_value end end def find_value_in_node_list(node, key, hash, pure_hash) do_check_for_resize = false while true if pure_hash == hash && node.key?(key) && NULL != (value = node.value) return value elsif node = node.next do_check_for_resize = true # at least 2 nodes -> check for resize pure_hash = node.pure_hash else return NULL end end ensure check_for_resize if do_check_for_resize end def internal_compute(key, &block) hash = key_hash(key) current_table = table || initialize_table while true if !(node = current_table.volatile_get(i = current_table.hash_to_index(hash))) succeeded, new_value = current_table.try_to_cas_in_computed(i, hash, key, &block) if succeeded if NULL == new_value break nil else increment_size break new_value end end elsif (node_hash = node.hash) == MOVED current_table = node.key elsif Node.locked_hash?(node_hash) try_await_lock(current_table, i, node) else succeeded, new_value = attempt_compute(key, hash, current_table, i, node, node_hash, &block) break new_value if succeeded end end end def attempt_internal_compute_if_absent(key, hash, current_table, i, node, node_hash) added = false current_table.try_lock_via_hash(i, node, node_hash) do while true if node.matches?(key, hash) && NULL != (value = node.value) return true, value end last = node unless node = node.next last.next = Node.new(hash, key, value = yield) added = true increment_size return true, value end end end ensure check_for_resize if added end def attempt_compute(key, hash, current_table, i, node, node_hash) added = false current_table.try_lock_via_hash(i, node, node_hash) do predecessor_node = nil while true if node.matches?(key, hash) && NULL != (value = node.value) if NULL == (node.value = value = yield(value)) current_table.delete_node_at(i, node, predecessor_node) decrement_size value = nil end return true, value end predecessor_node = node unless node = node.next if NULL == (value = yield(NULL)) value = nil else predecessor_node.next = Node.new(hash, key, value) added = true increment_size end return true, value end end end ensure check_for_resize if added end def attempt_get_and_set(key, value, hash, current_table, i, node, node_hash) node_nesting = nil current_table.try_lock_via_hash(i, node, node_hash) do node_nesting = 1 old_value = nil found_old_value = false while node if node.matches?(key, hash) && NULL != (old_value = node.value) found_old_value = true node.value = value break end last = node unless node = node.next last.next = Node.new(hash, key, value) break end node_nesting += 1 end return true, old_value if found_old_value increment_size true end ensure check_for_resize if node_nesting && (node_nesting > 1 || current_table.size <= 64) end def initialize_copy(other) super @counter = Concurrent::ThreadSafe::Util::Adder.new self.table = nil self.size_control = (other_table = other.table) ? other_table.size : DEFAULT_CAPACITY self end def try_await_lock(current_table, i, node) check_for_resize # try resizing if can't get lock node.try_await_lock(current_table, i) end def key_hash(key) key.hash & HASH_BITS end # Returns a power of two table size for the given desired capacity. def table_size_for(entry_count) size = 2 size <<= 1 while size < entry_count size end # Initializes table, using the size recorded in +size_control+. def initialize_table until current_table ||= table if (size_ctrl = size_control) == NOW_RESIZING Thread.pass # lost initialization race; just spin else try_in_resize_lock(current_table, size_ctrl) do initial_size = size_ctrl > 0 ? size_ctrl : DEFAULT_CAPACITY current_table = self.table = Table.new(initial_size) initial_size - (initial_size >> 2) # 75% load factor end end end current_table end # If table is too small and not already resizing, creates next table and # transfers bins. Rechecks occupancy after a transfer to see if another # resize is already needed because resizings are lagging additions. def check_for_resize while (current_table = table) && MAX_CAPACITY > (table_size = current_table.size) && NOW_RESIZING != (size_ctrl = size_control) && size_ctrl < @counter.sum try_in_resize_lock(current_table, size_ctrl) do self.table = rebuild(current_table) (table_size << 1) - (table_size >> 1) # 75% load factor end end end def try_in_resize_lock(current_table, size_ctrl) if cas_size_control(size_ctrl, NOW_RESIZING) begin if current_table == table # recheck under lock size_ctrl = yield # get new size_control end ensure self.size_control = size_ctrl end end end # Moves and/or copies the nodes in each bin to new table. See above for explanation. def rebuild(table) old_table_size = table.size new_table = table.next_in_size_table # puts "#{old_table_size} -> #{new_table.size}" forwarder = Node.new(MOVED, new_table, NULL) rev_forwarder = nil locked_indexes = nil # holds bins to revisit; nil until needed locked_arr_idx = 0 bin = old_table_size - 1 i = bin while true if !(node = table.volatile_get(i)) # no lock needed (or available) if bin >= 0, because we're not popping values from locked_indexes until we've run through the whole table redo unless (bin >= 0 ? table.cas(i, nil, forwarder) : lock_and_clean_up_reverse_forwarders(table, old_table_size, new_table, i, forwarder)) elsif Node.locked_hash?(node_hash = node.hash) locked_indexes ||= Array.new if bin < 0 && locked_arr_idx > 0 locked_arr_idx -= 1 i, locked_indexes[locked_arr_idx] = locked_indexes[locked_arr_idx], i # swap with another bin redo end if bin < 0 || locked_indexes.size >= TRANSFER_BUFFER_SIZE node.try_await_lock(table, i) # no other options -- block redo end rev_forwarder ||= Node.new(MOVED, table, NULL) redo unless table.volatile_get(i) == node && node.locked? # recheck before adding to list locked_indexes << i new_table.volatile_set(i, rev_forwarder) new_table.volatile_set(i + old_table_size, rev_forwarder) else redo unless split_old_bin(table, new_table, i, node, node_hash, forwarder) end if bin > 0 i = (bin -= 1) elsif locked_indexes && !locked_indexes.empty? bin = -1 i = locked_indexes.pop locked_arr_idx = locked_indexes.size - 1 else return new_table end end end def lock_and_clean_up_reverse_forwarders(old_table, old_table_size, new_table, i, forwarder) # transiently use a locked forwarding node locked_forwarder = Node.new(moved_locked_hash = MOVED | LOCKED, new_table, NULL) if old_table.cas(i, nil, locked_forwarder) new_table.volatile_set(i, nil) # kill the potential reverse forwarders new_table.volatile_set(i + old_table_size, nil) # kill the potential reverse forwarders old_table.volatile_set(i, forwarder) locked_forwarder.unlock_via_hash(moved_locked_hash, MOVED) true end end # Splits a normal bin with list headed by e into lo and hi parts; installs in given table. def split_old_bin(table, new_table, i, node, node_hash, forwarder) table.try_lock_via_hash(i, node, node_hash) do split_bin(new_table, i, node, node_hash) table.volatile_set(i, forwarder) end end def split_bin(new_table, i, node, node_hash) bit = new_table.size >> 1 # bit to split on run_bit = node_hash & bit last_run = nil low = nil high = nil current_node = node # this optimises for the lowest amount of volatile writes and objects created while current_node = current_node.next unless (b = current_node.hash & bit) == run_bit run_bit = b last_run = current_node end end if run_bit == 0 low = last_run else high = last_run end current_node = node until current_node == last_run pure_hash = current_node.pure_hash if (pure_hash & bit) == 0 low = Node.new(pure_hash, current_node.key, current_node.value, low) else high = Node.new(pure_hash, current_node.key, current_node.value, high) end current_node = current_node.next end new_table.volatile_set(i, low) new_table.volatile_set(i + bit, high) end def increment_size @counter.increment end def decrement_size(by = 1) @counter.add(-by) end end end end concurrent-ruby-1.0.5/lib/concurrent/collection/map/mri_map_backend.rb000066400000000000000000000026031305460430400261360ustar00rootroot00000000000000require 'thread' require 'concurrent/collection/map/non_concurrent_map_backend' module Concurrent # @!visibility private module Collection # @!visibility private class MriMapBackend < NonConcurrentMapBackend def initialize(options = nil) super(options) @write_lock = Mutex.new end def []=(key, value) @write_lock.synchronize { super } end def compute_if_absent(key) if stored_value = _get(key) # fast non-blocking path for the most likely case stored_value else @write_lock.synchronize { super } end end def compute_if_present(key) @write_lock.synchronize { super } end def compute(key) @write_lock.synchronize { super } end def merge_pair(key, value) @write_lock.synchronize { super } end def replace_pair(key, old_value, new_value) @write_lock.synchronize { super } end def replace_if_exists(key, new_value) @write_lock.synchronize { super } end def get_and_set(key, value) @write_lock.synchronize { super } end def delete(key) @write_lock.synchronize { super } end def delete_pair(key, value) @write_lock.synchronize { super } end def clear @write_lock.synchronize { super } end end end end concurrent-ruby-1.0.5/lib/concurrent/collection/map/non_concurrent_map_backend.rb000066400000000000000000000057501305460430400304110ustar00rootroot00000000000000require 'concurrent/constants' module Concurrent # @!visibility private module Collection # @!visibility private class NonConcurrentMapBackend # WARNING: all public methods of the class must operate on the @backend # directly without calling each other. This is important because of the # SynchronizedMapBackend which uses a non-reentrant mutex for perfomance # reasons. def initialize(options = nil) @backend = {} end def [](key) @backend[key] end def []=(key, value) @backend[key] = value end def compute_if_absent(key) if NULL != (stored_value = @backend.fetch(key, NULL)) stored_value else @backend[key] = yield end end def replace_pair(key, old_value, new_value) if pair?(key, old_value) @backend[key] = new_value true else false end end def replace_if_exists(key, new_value) if NULL != (stored_value = @backend.fetch(key, NULL)) @backend[key] = new_value stored_value end end def compute_if_present(key) if NULL != (stored_value = @backend.fetch(key, NULL)) store_computed_value(key, yield(stored_value)) end end def compute(key) store_computed_value(key, yield(@backend[key])) end def merge_pair(key, value) if NULL == (stored_value = @backend.fetch(key, NULL)) @backend[key] = value else store_computed_value(key, yield(stored_value)) end end def get_and_set(key, value) stored_value = @backend[key] @backend[key] = value stored_value end def key?(key) @backend.key?(key) end def delete(key) @backend.delete(key) end def delete_pair(key, value) if pair?(key, value) @backend.delete(key) true else false end end def clear @backend.clear self end def each_pair return enum_for :each_pair unless block_given? dupped_backend.each_pair do |k, v| yield k, v end self end def size @backend.size end def get_or_default(key, default_value) @backend.fetch(key, default_value) end alias_method :_get, :[] alias_method :_set, :[]= private :_get, :_set private def initialize_copy(other) super @backend = {} self end def dupped_backend @backend.dup end def pair?(key, expected_value) NULL != (stored_value = @backend.fetch(key, NULL)) && expected_value.equal?(stored_value) end def store_computed_value(key, new_value) if new_value.nil? @backend.delete(key) nil else @backend[key] = new_value end end end end end concurrent-ruby-1.0.5/lib/concurrent/collection/map/synchronized_map_backend.rb000066400000000000000000000030101305460430400300570ustar00rootroot00000000000000require 'concurrent/collection/map/non_concurrent_map_backend' module Concurrent # @!visibility private module Collection # @!visibility private class SynchronizedMapBackend < NonConcurrentMapBackend require 'mutex_m' include Mutex_m # WARNING: Mutex_m is a non-reentrant lock, so the synchronized methods are # not allowed to call each other. def [](key) synchronize { super } end def []=(key, value) synchronize { super } end def compute_if_absent(key) synchronize { super } end def compute_if_present(key) synchronize { super } end def compute(key) synchronize { super } end def merge_pair(key, value) synchronize { super } end def replace_pair(key, old_value, new_value) synchronize { super } end def replace_if_exists(key, new_value) synchronize { super } end def get_and_set(key, value) synchronize { super } end def key?(key) synchronize { super } end def delete(key) synchronize { super } end def delete_pair(key, value) synchronize { super } end def clear synchronize { super } end def size synchronize { super } end def get_or_default(key, default_value) synchronize { super } end private def dupped_backend synchronize { super } end end end end concurrent-ruby-1.0.5/lib/concurrent/collection/non_concurrent_priority_queue.rb000066400000000000000000000126621305460430400304750ustar00rootroot00000000000000require 'concurrent/collection/java_non_concurrent_priority_queue' require 'concurrent/collection/ruby_non_concurrent_priority_queue' require 'concurrent/utility/engine' module Concurrent module Collection # @!visibility private # @!macro internal_implementation_note NonConcurrentPriorityQueueImplementation = case when Concurrent.on_jruby? JavaNonConcurrentPriorityQueue else RubyNonConcurrentPriorityQueue end private_constant :NonConcurrentPriorityQueueImplementation # @!macro [attach] priority_queue # # A queue collection in which the elements are sorted based on their # comparison (spaceship) operator `<=>`. Items are added to the queue # at a position relative to their priority. On removal the element # with the "highest" priority is removed. By default the sort order is # from highest to lowest, but a lowest-to-highest sort order can be # set on construction. # # The API is based on the `Queue` class from the Ruby standard library. # # The pure Ruby implementation, `RubyNonConcurrentPriorityQueue` uses a heap algorithm # stored in an array. The algorithm is based on the work of Robert Sedgewick # and Kevin Wayne. # # The JRuby native implementation is a thin wrapper around the standard # library `java.util.NonConcurrentPriorityQueue`. # # When running under JRuby the class `NonConcurrentPriorityQueue` extends `JavaNonConcurrentPriorityQueue`. # When running under all other interpreters it extends `RubyNonConcurrentPriorityQueue`. # # @note This implementation is *not* thread safe. # # @see http://en.wikipedia.org/wiki/Priority_queue # @see http://ruby-doc.org/stdlib-2.0.0/libdoc/thread/rdoc/Queue.html # # @see http://algs4.cs.princeton.edu/24pq/index.php#2.6 # @see http://algs4.cs.princeton.edu/24pq/MaxPQ.java.html # # @see http://docs.oracle.com/javase/7/docs/api/java/util/PriorityQueue.html # # @!visibility private class NonConcurrentPriorityQueue < NonConcurrentPriorityQueueImplementation alias_method :has_priority?, :include? alias_method :size, :length alias_method :deq, :pop alias_method :shift, :pop alias_method :<<, :push alias_method :enq, :push # @!method initialize(opts = {}) # @!macro [new] priority_queue_method_initialize # # Create a new priority queue with no items. # # @param [Hash] opts the options for creating the queue # @option opts [Symbol] :order (:max) dictates the order in which items are # stored: from highest to lowest when `:max` or `:high`; from lowest to # highest when `:min` or `:low` # @!method clear # @!macro [new] priority_queue_method_clear # # Removes all of the elements from this priority queue. # @!method delete(item) # @!macro [new] priority_queue_method_delete # # Deletes all items from `self` that are equal to `item`. # # @param [Object] item the item to be removed from the queue # @return [Object] true if the item is found else false # @!method empty? # @!macro [new] priority_queue_method_empty # # Returns `true` if `self` contains no elements. # # @return [Boolean] true if there are no items in the queue else false # @!method include?(item) # @!macro [new] priority_queue_method_include # # Returns `true` if the given item is present in `self` (that is, if any # element == `item`), otherwise returns false. # # @param [Object] item the item to search for # # @return [Boolean] true if the item is found else false # @!method length # @!macro [new] priority_queue_method_length # # The current length of the queue. # # @return [Fixnum] the number of items in the queue # @!method peek # @!macro [new] priority_queue_method_peek # # Retrieves, but does not remove, the head of this queue, or returns `nil` # if this queue is empty. # # @return [Object] the head of the queue or `nil` when empty # @!method pop # @!macro [new] priority_queue_method_pop # # Retrieves and removes the head of this queue, or returns `nil` if this # queue is empty. # # @return [Object] the head of the queue or `nil` when empty # @!method push(item) # @!macro [new] priority_queue_method_push # # Inserts the specified element into this priority queue. # # @param [Object] item the item to insert onto the queue # @!method self.from_list(list, opts = {}) # @!macro [new] priority_queue_method_from_list # # Create a new priority queue from the given list. # # @param [Enumerable] list the list to build the queue from # @param [Hash] opts the options for creating the queue # # @return [NonConcurrentPriorityQueue] the newly created and populated queue end end end concurrent-ruby-1.0.5/lib/concurrent/collection/ruby_non_concurrent_priority_queue.rb000066400000000000000000000072011305460430400315270ustar00rootroot00000000000000module Concurrent module Collection # @!macro priority_queue # # @!visibility private # @!macro internal_implementation_note class RubyNonConcurrentPriorityQueue # @!macro priority_queue_method_initialize def initialize(opts = {}) order = opts.fetch(:order, :max) @comparator = [:min, :low].include?(order) ? -1 : 1 clear end # @!macro priority_queue_method_clear def clear @queue = [nil] @length = 0 true end # @!macro priority_queue_method_delete def delete(item) return false if empty? original_length = @length k = 1 while k <= @length if @queue[k] == item swap(k, @length) @length -= 1 sink(k) @queue.pop else k += 1 end end @length != original_length end # @!macro priority_queue_method_empty def empty? size == 0 end # @!macro priority_queue_method_include def include?(item) @queue.include?(item) end alias_method :has_priority?, :include? # @!macro priority_queue_method_length def length @length end alias_method :size, :length # @!macro priority_queue_method_peek def peek empty? ? nil : @queue[1] end # @!macro priority_queue_method_pop def pop return nil if empty? max = @queue[1] swap(1, @length) @length -= 1 sink(1) @queue.pop max end alias_method :deq, :pop alias_method :shift, :pop # @!macro priority_queue_method_push def push(item) raise ArgumentError.new('cannot enqueue nil') if item.nil? @length += 1 @queue << item swim(@length) true end alias_method :<<, :push alias_method :enq, :push # @!macro priority_queue_method_from_list def self.from_list(list, opts = {}) queue = new(opts) list.each{|item| queue << item } queue end private # Exchange the values at the given indexes within the internal array. # # @param [Integer] x the first index to swap # @param [Integer] y the second index to swap # # @!visibility private def swap(x, y) temp = @queue[x] @queue[x] = @queue[y] @queue[y] = temp end # Are the items at the given indexes ordered based on the priority # order specified at construction? # # @param [Integer] x the first index from which to retrieve a comparable value # @param [Integer] y the second index from which to retrieve a comparable value # # @return [Boolean] true if the two elements are in the correct priority order # else false # # @!visibility private def ordered?(x, y) (@queue[x] <=> @queue[y]) == @comparator end # Percolate down to maintain heap invariant. # # @param [Integer] k the index at which to start the percolation # # @!visibility private def sink(k) while (j = (2 * k)) <= @length do j += 1 if j < @length && ! ordered?(j, j+1) break if ordered?(k, j) swap(k, j) k = j end end # Percolate up to maintain heap invariant. # # @param [Integer] k the index at which to start the percolation # # @!visibility private def swim(k) while k > 1 && ! ordered?(k/2, k) do swap(k, k/2) k = k/2 end end end end end concurrent-ruby-1.0.5/lib/concurrent/concern/000077500000000000000000000000001305460430400212345ustar00rootroot00000000000000concurrent-ruby-1.0.5/lib/concurrent/concern/deprecation.rb000066400000000000000000000020511305460430400240540ustar00rootroot00000000000000require 'concurrent/concern/logging' module Concurrent module Concern # @!visibility private # @!macro internal_implementation_note module Deprecation # TODO require additional parameter: a version. Display when it'll be removed based on that. Error if not removed. include Concern::Logging def deprecated(message, strip = 2) caller_line = caller(strip).first if strip > 0 klass = if Module === self self else self.class end message = if strip > 0 format("[DEPRECATED] %s\ncalled on: %s", message, caller_line) else format('[DEPRECATED] %s', message) end log WARN, klass.to_s, message end def deprecated_method(old_name, new_name) deprecated "`#{old_name}` is deprecated and it'll removed in next release, use `#{new_name}` instead", 3 end extend self end end end concurrent-ruby-1.0.5/lib/concurrent/concern/dereferenceable.rb000066400000000000000000000055771305460430400246720ustar00rootroot00000000000000module Concurrent module Concern # Object references in Ruby are mutable. This can lead to serious problems when # the `#value` of a concurrent object is a mutable reference. Which is always the # case unless the value is a `Fixnum`, `Symbol`, or similar "primitive" data type. # Most classes in this library that expose a `#value` getter method do so using the # `Dereferenceable` mixin module. # # @!macro copy_options module Dereferenceable # NOTE: This module is going away in 2.0. In the mean time we need it to # play nicely with the synchronization layer. This means that the # including class SHOULD be synchronized and it MUST implement a # `#synchronize` method. Not doing so will lead to runtime errors. # Return the value this object represents after applying the options specified # by the `#set_deref_options` method. # # @return [Object] the current value of the object def value synchronize { apply_deref_options(@value) } end alias_method :deref, :value protected # Set the internal value of this object # # @param [Object] value the new value def value=(value) synchronize{ @value = value } end # @!macro [attach] dereferenceable_set_deref_options # Set the options which define the operations #value performs before # returning data to the caller (dereferencing). # # @note Most classes that include this module will call `#set_deref_options` # from within the constructor, thus allowing these options to be set at # object creation. # # @param [Hash] opts the options defining dereference behavior. # @option opts [String] :dup_on_deref (false) call `#dup` before returning the data # @option opts [String] :freeze_on_deref (false) call `#freeze` before returning the data # @option opts [String] :copy_on_deref (nil) call the given `Proc` passing # the internal value and returning the value returned from the proc def set_deref_options(opts = {}) synchronize{ ns_set_deref_options(opts) } end # @!macro dereferenceable_set_deref_options # @!visibility private def ns_set_deref_options(opts) @dup_on_deref = opts[:dup_on_deref] || opts[:dup] @freeze_on_deref = opts[:freeze_on_deref] || opts[:freeze] @copy_on_deref = opts[:copy_on_deref] || opts[:copy] @do_nothing_on_deref = !(@dup_on_deref || @freeze_on_deref || @copy_on_deref) nil end # @!visibility private def apply_deref_options(value) return nil if value.nil? return value if @do_nothing_on_deref value = @copy_on_deref.call(value) if @copy_on_deref value = value.dup if @dup_on_deref value = value.freeze if @freeze_on_deref value end end end end concurrent-ruby-1.0.5/lib/concurrent/concern/logging.rb000066400000000000000000000020441305460430400232070ustar00rootroot00000000000000require 'logger' module Concurrent module Concern # Include where logging is needed # # @!visibility private module Logging include Logger::Severity # Logs through {Concurrent.global_logger}, it can be overridden by setting @logger # @param [Integer] level one of Logger::Severity constants # @param [String] progname e.g. a path of an Actor # @param [String, nil] message when nil block is used to generate the message # @yieldreturn [String] a message def log(level, progname, message = nil, &block) #NOTE: Cannot require 'concurrent/configuration' above due to circular references. # Assume that the gem has been initialized if we've gotten this far. (@logger || Concurrent.global_logger).call level, progname, message, &block rescue => error $stderr.puts "`Concurrent.configuration.logger` failed to log #{[level, progname, message, block]}\n" + "#{error.message} (#{error.class})\n#{error.backtrace.join "\n"}" end end end end concurrent-ruby-1.0.5/lib/concurrent/concern/obligation.rb000066400000000000000000000135521305460430400237160ustar00rootroot00000000000000require 'thread' require 'timeout' require 'concurrent/atomic/event' require 'concurrent/concern/dereferenceable' module Concurrent module Concern module Obligation include Concern::Dereferenceable # NOTE: The Dereferenceable module is going away in 2.0. In the mean time # we need it to place nicely with the synchronization layer. This means # that the including class SHOULD be synchronized and it MUST implement a # `#synchronize` method. Not doing so will lead to runtime errors. # Has the obligation been fulfilled? # # @return [Boolean] def fulfilled? state == :fulfilled end alias_method :realized?, :fulfilled? # Has the obligation been rejected? # # @return [Boolean] def rejected? state == :rejected end # Is obligation completion still pending? # # @return [Boolean] def pending? state == :pending end # Is the obligation still unscheduled? # # @return [Boolean] def unscheduled? state == :unscheduled end # Has the obligation completed processing? # # @return [Boolean] def complete? [:fulfilled, :rejected].include? state end # Is the obligation still awaiting completion of processing? # # @return [Boolean] def incomplete? ! complete? end # The current value of the obligation. Will be `nil` while the state is # pending or the operation has been rejected. # # @param [Numeric] timeout the maximum time in seconds to wait. # @return [Object] see Dereferenceable#deref def value(timeout = nil) wait timeout deref end # Wait until obligation is complete or the timeout has been reached. # # @param [Numeric] timeout the maximum time in seconds to wait. # @return [Obligation] self def wait(timeout = nil) event.wait(timeout) if timeout != 0 && incomplete? self end # Wait until obligation is complete or the timeout is reached. Will re-raise # any exceptions raised during processing (but will not raise an exception # on timeout). # # @param [Numeric] timeout the maximum time in seconds to wait. # @return [Obligation] self # @raise [Exception] raises the reason when rejected def wait!(timeout = nil) wait(timeout).tap { raise self if rejected? } end alias_method :no_error!, :wait! # The current value of the obligation. Will be `nil` while the state is # pending or the operation has been rejected. Will re-raise any exceptions # raised during processing (but will not raise an exception on timeout). # # @param [Numeric] timeout the maximum time in seconds to wait. # @return [Object] see Dereferenceable#deref # @raise [Exception] raises the reason when rejected def value!(timeout = nil) wait(timeout) if rejected? raise self else deref end end # The current state of the obligation. # # @return [Symbol] the current state def state synchronize { @state } end # If an exception was raised during processing this will return the # exception object. Will return `nil` when the state is pending or if # the obligation has been successfully fulfilled. # # @return [Exception] the exception raised during processing or `nil` def reason synchronize { @reason } end # @example allows Obligation to be risen # rejected_ivar = Ivar.new.fail # raise rejected_ivar def exception(*args) raise 'obligation is not rejected' unless rejected? reason.exception(*args) end protected # @!visibility private def get_arguments_from(opts = {}) [*opts.fetch(:args, [])] end # @!visibility private def init_obligation @event = Event.new @value = @reason = nil end # @!visibility private def event @event end # @!visibility private def set_state(success, value, reason) if success @value = value @state = :fulfilled else @reason = reason @state = :rejected end end # @!visibility private def state=(value) synchronize { ns_set_state(value) } end # Atomic compare and set operation # State is set to `next_state` only if `current state == expected_current`. # # @param [Symbol] next_state # @param [Symbol] expected_current # # @return [Boolean] true is state is changed, false otherwise # # @!visibility private def compare_and_set_state(next_state, *expected_current) synchronize do if expected_current.include? @state @state = next_state true else false end end end # Executes the block within mutex if current state is included in expected_states # # @return block value if executed, false otherwise # # @!visibility private def if_state(*expected_states) synchronize do raise ArgumentError.new('no block given') unless block_given? if expected_states.include? @state yield else false end end end protected # Am I in the current state? # # @param [Symbol] expected The state to check against # @return [Boolean] true if in the expected state else false # # @!visibility private def ns_check_state?(expected) @state == expected end # @!visibility private def ns_set_state(value) @state = value end end end end concurrent-ruby-1.0.5/lib/concurrent/concern/observable.rb000066400000000000000000000074321305460430400237130ustar00rootroot00000000000000require 'concurrent/collection/copy_on_notify_observer_set' require 'concurrent/collection/copy_on_write_observer_set' module Concurrent module Concern # The [observer pattern](http://en.wikipedia.org/wiki/Observer_pattern) is one # of the most useful design patterns. # # The workflow is very simple: # - an `observer` can register itself to a `subject` via a callback # - many `observers` can be registered to the same `subject` # - the `subject` notifies all registered observers when its status changes # - an `observer` can deregister itself when is no more interested to receive # event notifications # # In a single threaded environment the whole pattern is very easy: the # `subject` can use a simple data structure to manage all its subscribed # `observer`s and every `observer` can react directly to every event without # caring about synchronization. # # In a multi threaded environment things are more complex. The `subject` must # synchronize the access to its data structure and to do so currently we're # using two specialized ObserverSet: {Concurrent::Concern::CopyOnWriteObserverSet} # and {Concurrent::Concern::CopyOnNotifyObserverSet}. # # When implementing and `observer` there's a very important rule to remember: # **there are no guarantees about the thread that will execute the callback** # # Let's take this example # ``` # class Observer # def initialize # @count = 0 # end # # def update # @count += 1 # end # end # # obs = Observer.new # [obj1, obj2, obj3, obj4].each { |o| o.add_observer(obs) } # # execute [obj1, obj2, obj3, obj4] # ``` # # `obs` is wrong because the variable `@count` can be accessed by different # threads at the same time, so it should be synchronized (using either a Mutex # or an AtomicFixum) module Observable # @!macro [attach] observable_add_observer # # Adds an observer to this set. If a block is passed, the observer will be # created by this method and no other params should be passed. # # @param [Object] observer the observer to add # @param [Symbol] func the function to call on the observer during notification. # Default is :update # @return [Object] the added observer def add_observer(observer = nil, func = :update, &block) observers.add_observer(observer, func, &block) end # As `#add_observer` but can be used for chaining. # # @param [Object] observer the observer to add # @param [Symbol] func the function to call on the observer during notification. # @return [Observable] self def with_observer(observer = nil, func = :update, &block) add_observer(observer, func, &block) self end # @!macro [attach] observable_delete_observer # # Remove `observer` as an observer on this object so that it will no # longer receive notifications. # # @param [Object] observer the observer to remove # @return [Object] the deleted observer def delete_observer(observer) observers.delete_observer(observer) end # @!macro [attach] observable_delete_observers # # Remove all observers associated with this object. # # @return [Observable] self def delete_observers observers.delete_observers self end # @!macro [attach] observable_count_observers # # Return the number of observers associated with this object. # # @return [Integer] the observers count def count_observers observers.count_observers end protected attr_accessor :observers end end end concurrent-ruby-1.0.5/lib/concurrent/configuration.rb000066400000000000000000000151041305460430400230020ustar00rootroot00000000000000require 'thread' require 'concurrent/delay' require 'concurrent/errors' require 'concurrent/atomic/atomic_reference' require 'concurrent/concern/logging' require 'concurrent/executor/immediate_executor' require 'concurrent/utility/at_exit' require 'concurrent/utility/processor_counter' module Concurrent extend Concern::Logging autoload :Options, 'concurrent/options' autoload :TimerSet, 'concurrent/executor/timer_set' autoload :ThreadPoolExecutor, 'concurrent/executor/thread_pool_executor' # @return [Logger] Logger with provided level and output. def self.create_simple_logger(level = Logger::FATAL, output = $stderr) # TODO (pitr-ch 24-Dec-2016): figure out why it had to be replaced, stdlogger was deadlocking lambda do |severity, progname, message = nil, &block| return false if severity < level message = block ? block.call : message formatted_message = case message when String message when Exception format "%s (%s)\n%s", message.message, message.class, (message.backtrace || []).join("\n") else message.inspect end output.print format "[%s] %5s -- %s: %s\n", Time.now.strftime('%Y-%m-%d %H:%M:%S.%L'), Logger::SEV_LABEL[severity], progname, formatted_message true end end # Use logger created by #create_simple_logger to log concurrent-ruby messages. def self.use_simple_logger(level = Logger::FATAL, output = $stderr) Concurrent.global_logger = create_simple_logger level, output end # @return [Logger] Logger with provided level and output. # @deprecated def self.create_stdlib_logger(level = Logger::FATAL, output = $stderr) logger = Logger.new(output) logger.level = level logger.formatter = lambda do |severity, datetime, progname, msg| formatted_message = case msg when String msg when Exception format "%s (%s)\n%s", msg.message, msg.class, (msg.backtrace || []).join("\n") else msg.inspect end format "[%s] %5s -- %s: %s\n", datetime.strftime('%Y-%m-%d %H:%M:%S.%L'), severity, progname, formatted_message end lambda do |loglevel, progname, message = nil, &block| logger.add loglevel, message, progname, &block end end # Use logger created by #create_stdlib_logger to log concurrent-ruby messages. # @deprecated def self.use_stdlib_logger(level = Logger::FATAL, output = $stderr) Concurrent.global_logger = create_stdlib_logger level, output end # TODO (pitr-ch 27-Dec-2016): remove deadlocking stdlib_logger methods # Suppresses all output when used for logging. NULL_LOGGER = lambda { |level, progname, message = nil, &block| } # @!visibility private GLOBAL_LOGGER = AtomicReference.new(create_simple_logger(Logger::WARN)) private_constant :GLOBAL_LOGGER def self.global_logger GLOBAL_LOGGER.value end def self.global_logger=(value) GLOBAL_LOGGER.value = value end # @!visibility private GLOBAL_FAST_EXECUTOR = Delay.new { Concurrent.new_fast_executor(auto_terminate: true) } private_constant :GLOBAL_FAST_EXECUTOR # @!visibility private GLOBAL_IO_EXECUTOR = Delay.new { Concurrent.new_io_executor(auto_terminate: true) } private_constant :GLOBAL_IO_EXECUTOR # @!visibility private GLOBAL_TIMER_SET = Delay.new { TimerSet.new(auto_terminate: true) } private_constant :GLOBAL_TIMER_SET # @!visibility private GLOBAL_IMMEDIATE_EXECUTOR = ImmediateExecutor.new private_constant :GLOBAL_IMMEDIATE_EXECUTOR # Disables AtExit handlers including pool auto-termination handlers. # When disabled it will be the application programmer's responsibility # to ensure that the handlers are shutdown properly prior to application # exit by calling {AtExit.run} method. # # @note this option should be needed only because of `at_exit` ordering # issues which may arise when running some of the testing frameworks. # E.g. Minitest's test-suite runs itself in `at_exit` callback which # executes after the pools are already terminated. Then auto termination # needs to be disabled and called manually after test-suite ends. # @note This method should *never* be called # from within a gem. It should *only* be used from within the main # application and even then it should be used only when necessary. # @see AtExit def self.disable_at_exit_handlers! AtExit.enabled = false end # Global thread pool optimized for short, fast *operations*. # # @return [ThreadPoolExecutor] the thread pool def self.global_fast_executor GLOBAL_FAST_EXECUTOR.value end # Global thread pool optimized for long, blocking (IO) *tasks*. # # @return [ThreadPoolExecutor] the thread pool def self.global_io_executor GLOBAL_IO_EXECUTOR.value end def self.global_immediate_executor GLOBAL_IMMEDIATE_EXECUTOR end # Global thread pool user for global *timers*. # # @return [Concurrent::TimerSet] the thread pool def self.global_timer_set GLOBAL_TIMER_SET.value end # General access point to global executors. # @param [Symbol, Executor] executor_identifier symbols: # - :fast - {Concurrent.global_fast_executor} # - :io - {Concurrent.global_io_executor} # - :immediate - {Concurrent.global_immediate_executor} # @return [Executor] def self.executor(executor_identifier) Options.executor(executor_identifier) end def self.new_fast_executor(opts = {}) FixedThreadPool.new( [2, Concurrent.processor_count].max, auto_terminate: opts.fetch(:auto_terminate, true), idletime: 60, # 1 minute max_queue: 0, # unlimited fallback_policy: :abort # shouldn't matter -- 0 max queue ) end def self.new_io_executor(opts = {}) ThreadPoolExecutor.new( min_threads: [2, Concurrent.processor_count].max, max_threads: ThreadPoolExecutor::DEFAULT_MAX_POOL_SIZE, # max_threads: 1000, auto_terminate: opts.fetch(:auto_terminate, true), idletime: 60, # 1 minute max_queue: 0, # unlimited fallback_policy: :abort # shouldn't matter -- 0 max queue ) end end concurrent-ruby-1.0.5/lib/concurrent/constants.rb000066400000000000000000000003141305460430400221440ustar00rootroot00000000000000module Concurrent # Various classes within allows for +nil+ values to be stored, # so a special +NULL+ token is required to indicate the "nil-ness". # @!visibility private NULL = Object.new end concurrent-ruby-1.0.5/lib/concurrent/dataflow.rb000066400000000000000000000042361305460430400217400ustar00rootroot00000000000000require 'concurrent/future' require 'concurrent/atomic/atomic_fixnum' module Concurrent # @!visibility private class DependencyCounter # :nodoc: def initialize(count, &block) @counter = AtomicFixnum.new(count) @block = block end def update(time, value, reason) if @counter.decrement == 0 @block.call end end end # {include:file:doc/dataflow.md} # # @param [Future] inputs zero or more `Future` operations that this dataflow depends upon # # @yield The operation to perform once all the dependencies are met # @yieldparam [Future] inputs each of the `Future` inputs to the dataflow # @yieldreturn [Object] the result of the block operation # # @return [Object] the result of all the operations # # @raise [ArgumentError] if no block is given # @raise [ArgumentError] if any of the inputs are not `IVar`s def dataflow(*inputs, &block) dataflow_with(Concurrent.global_io_executor, *inputs, &block) end module_function :dataflow def dataflow_with(executor, *inputs, &block) call_dataflow(:value, executor, *inputs, &block) end module_function :dataflow_with def dataflow!(*inputs, &block) dataflow_with!(Concurrent.global_io_executor, *inputs, &block) end module_function :dataflow! def dataflow_with!(executor, *inputs, &block) call_dataflow(:value!, executor, *inputs, &block) end module_function :dataflow_with! private def call_dataflow(method, executor, *inputs, &block) raise ArgumentError.new('an executor must be provided') if executor.nil? raise ArgumentError.new('no block given') unless block_given? unless inputs.all? { |input| input.is_a? IVar } raise ArgumentError.new("Not all dependencies are IVars.\nDependencies: #{ inputs.inspect }") end result = Future.new(executor: executor) do values = inputs.map { |input| input.send(method) } block.call(*values) end if inputs.empty? result.execute else counter = DependencyCounter.new(inputs.size) { result.execute } inputs.each do |input| input.add_observer counter end end result end module_function :call_dataflow end concurrent-ruby-1.0.5/lib/concurrent/delay.rb000066400000000000000000000153521305460430400212360ustar00rootroot00000000000000require 'thread' require 'concurrent/concern/obligation' require 'concurrent/executor/immediate_executor' require 'concurrent/synchronization' module Concurrent # This file has circular require issues. It must be autoloaded here. autoload :Options, 'concurrent/options' # Lazy evaluation of a block yielding an immutable result. Useful for # expensive operations that may never be needed. It may be non-blocking, # supports the `Concern::Obligation` interface, and accepts the injection of # custom executor upon which to execute the block. Processing of # block will be deferred until the first time `#value` is called. # At that time the caller can choose to return immediately and let # the block execute asynchronously, block indefinitely, or block # with a timeout. # # When a `Delay` is created its state is set to `pending`. The value and # reason are both `nil`. The first time the `#value` method is called the # enclosed opration will be run and the calling thread will block. Other # threads attempting to call `#value` will block as well. Once the operation # is complete the *value* will be set to the result of the operation or the # *reason* will be set to the raised exception, as appropriate. All threads # blocked on `#value` will return. Subsequent calls to `#value` will immediately # return the cached value. The operation will only be run once. This means that # any side effects created by the operation will only happen once as well. # # `Delay` includes the `Concurrent::Concern::Dereferenceable` mixin to support thread # safety of the reference returned by `#value`. # # @!macro copy_options # # @!macro [attach] delay_note_regarding_blocking # @note The default behavior of `Delay` is to block indefinitely when # calling either `value` or `wait`, executing the delayed operation on # the current thread. This makes the `timeout` value completely # irrelevant. To enable non-blocking behavior, use the `executor` # constructor option. This will cause the delayed operation to be # execute on the given executor, allowing the call to timeout. # # @see Concurrent::Concern::Dereferenceable class Delay < Synchronization::LockableObject include Concern::Obligation # NOTE: Because the global thread pools are lazy-loaded with these objects # there is a performance hit every time we post a new task to one of these # thread pools. Subsequently it is critical that `Delay` perform as fast # as possible post-completion. This class has been highly optimized using # the benchmark script `examples/lazy_and_delay.rb`. Do NOT attempt to # DRY-up this class or perform other refactoring with running the # benchmarks and ensuring that performance is not negatively impacted. # Create a new `Delay` in the `:pending` state. # # @!macro executor_and_deref_options # # @yield the delayed operation to perform # # @raise [ArgumentError] if no block is given def initialize(opts = {}, &block) raise ArgumentError.new('no block given') unless block_given? super(&nil) synchronize { ns_initialize(opts, &block) } end # Return the value this object represents after applying the options # specified by the `#set_deref_options` method. If the delayed operation # raised an exception this method will return nil. The execption object # can be accessed via the `#reason` method. # # @param [Numeric] timeout the maximum number of seconds to wait # @return [Object] the current value of the object # # @!macro delay_note_regarding_blocking def value(timeout = nil) if @executor # TODO (pitr 12-Sep-2015): broken unsafe read? super else # this function has been optimized for performance and # should not be modified without running new benchmarks synchronize do execute = @computing = true unless @computing if execute begin set_state(true, @task.call, nil) rescue => ex set_state(false, nil, ex) end end end if @do_nothing_on_deref @value else apply_deref_options(@value) end end end # Return the value this object represents after applying the options # specified by the `#set_deref_options` method. If the delayed operation # raised an exception, this method will raise that exception (even when) # the operation has already been executed). # # @param [Numeric] timeout the maximum number of seconds to wait # @return [Object] the current value of the object # @raise [Exception] when `#rejected?` raises `#reason` # # @!macro delay_note_regarding_blocking def value!(timeout = nil) if @executor super else result = value raise @reason if @reason result end end # Return the value this object represents after applying the options # specified by the `#set_deref_options` method. # # @param [Integer] timeout (nil) the maximum number of seconds to wait for # the value to be computed. When `nil` the caller will block indefinitely. # # @return [Object] self # # @!macro delay_note_regarding_blocking def wait(timeout = nil) if @executor execute_task_once super(timeout) else value end self end # Reconfigures the block returning the value if still `#incomplete?` # # @yield the delayed operation to perform # @return [true, false] if success def reconfigure(&block) synchronize do raise ArgumentError.new('no block given') unless block_given? unless @computing @task = block true else false end end end protected def ns_initialize(opts, &block) init_obligation set_deref_options(opts) @executor = opts[:executor] @task = block @state = :pending @computing = false end private # @!visibility private def execute_task_once # :nodoc: # this function has been optimized for performance and # should not be modified without running new benchmarks execute = task = nil synchronize do execute = @computing = true unless @computing task = @task end if execute executor = Options.executor_from_options(executor: @executor) executor.post do begin result = task.call success = true rescue => ex reason = ex end synchronize do set_state(success, result, reason) event.set end end end end end end concurrent-ruby-1.0.5/lib/concurrent/edge.rb000066400000000000000000000024141305460430400210370ustar00rootroot00000000000000module Concurrent # A submodule for unstable, highly experimental features that are likely to # change often and which may never become part of the core gem. Also for # new, experimental version of abstractions already in the core gem. # # Most new features should start in this module, clearly indicating the # experimental and unstable nature of the feature. Once a feature becomes # more stable and is a candidate for inclusion in the core gem it should # be moved up to the `Concurrent` module, where it would reside once merged # into the core gem. # # The only exception to this is for features which *replace* features from # the core gem in ways that are breaking and not backward compatible. These # features should remain in this module until merged into the core gem. This # will prevent namespace collisions. # # @!macro [attach] edge_warning # @api Edge # @note **Edge Feature:** Edge features are under active development and may change frequently. They are expected not to # keep backward compatibility (there may also lack tests and documentation). Semantic versions will # be obeyed though. Features developed in `concurrent-ruby-edge` are expected to move # to `concurrent-ruby` when final. module Edge end end concurrent-ruby-1.0.5/lib/concurrent/edge/000077500000000000000000000000001305460430400205115ustar00rootroot00000000000000concurrent-ruby-1.0.5/lib/concurrent/edge/atomic_markable_reference.rb000066400000000000000000000153101305460430400261660ustar00rootroot00000000000000module Concurrent module Edge # @!macro [attach] atomic_markable_reference # # An atomic reference which maintains an object reference along with a mark bit # that can be updated atomically. # # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicMarkableReference.html # java.util.concurrent.atomic.AtomicMarkableReference class AtomicMarkableReference < ::Concurrent::Synchronization::Object private(*attr_atomic(:reference)) # @!macro [attach] atomic_markable_reference_method_initialize def initialize(value = nil, mark = false) super() self.reference = ImmutableArray[value, mark] end # @!macro [attach] atomic_markable_reference_method_compare_and_set # # Atomically sets the value and mark to the given updated value and # mark given both: # - the current value == the expected value && # - the current mark == the expected mark # # @param [Object] expected_val the expected value # @param [Object] new_val the new value # @param [Boolean] expected_mark the expected mark # @param [Boolean] new_mark the new mark # # @return [Boolean] `true` if successful. A `false` return indicates # that the actual value was not equal to the expected value or the # actual mark was not equal to the expected mark def compare_and_set(expected_val, new_val, expected_mark, new_mark) # Memoize a valid reference to the current AtomicReference for # later comparison. current = reference curr_val, curr_mark = current # Ensure that that the expected marks match. return false unless expected_mark == curr_mark if expected_val.is_a? Numeric # If the object is a numeric, we need to ensure we are comparing # the numerical values return false unless expected_val == curr_val else # Otherwise, we need to ensure we are comparing the object identity. # Theoretically, this could be incorrect if a user monkey-patched # `Object#equal?`, but they should know that they are playing with # fire at that point. return false unless expected_val.equal? curr_val end prospect = ImmutableArray[new_val, new_mark] compare_and_set_reference current, prospect end alias_method :compare_and_swap, :compare_and_set # @!macro [attach] atomic_markable_reference_method_get # # Gets the current reference and marked values. # # @return [ImmutableArray] the current reference and marked values def get reference end # @!macro [attach] atomic_markable_reference_method_value # # Gets the current value of the reference # # @return [Object] the current value of the reference def value reference[0] end # @!macro [attach] atomic_markable_reference_method_mark # # Gets the current marked value # # @return [Boolean] the current marked value def mark reference[1] end alias_method :marked?, :mark # @!macro [attach] atomic_markable_reference_method_set # # _Unconditionally_ sets to the given value of both the reference and # the mark. # # @param [Object] new_val the new value # @param [Boolean] new_mark the new mark # # @return [ImmutableArray] both the new value and the new mark def set(new_val, new_mark) self.reference = ImmutableArray[new_val, new_mark] end # @!macro [attach] atomic_markable_reference_method_update # # Pass the current value and marked state to the given block, replacing it # with the block's results. May retry if the value changes during the # block's execution. # # @yield [Object] Calculate a new value and marked state for the atomic # reference using given (old) value and (old) marked # @yieldparam [Object] old_val the starting value of the atomic reference # @yieldparam [Boolean] old_mark the starting state of marked # # @return [ImmutableArray] the new value and new mark def update loop do old_val, old_mark = reference new_val, new_mark = yield old_val, old_mark if compare_and_set old_val, new_val, old_mark, new_mark return ImmutableArray[new_val, new_mark] end end end # @!macro [attach] atomic_markable_reference_method_try_update! # # Pass the current value to the given block, replacing it # with the block's result. Raise an exception if the update # fails. # # @yield [Object] Calculate a new value and marked state for the atomic # reference using given (old) value and (old) marked # @yieldparam [Object] old_val the starting value of the atomic reference # @yieldparam [Boolean] old_mark the starting state of marked # # @return [ImmutableArray] the new value and marked state # # @raise [Concurrent::ConcurrentUpdateError] if the update fails def try_update! old_val, old_mark = reference new_val, new_mark = yield old_val, old_mark unless compare_and_set old_val, new_val, old_mark, new_mark fail ::Concurrent::ConcurrentUpdateError, 'AtomicMarkableReference: Update failed due to race condition.', 'Note: If you would like to guarantee an update, please use ' \ 'the `AtomicMarkableReference#update` method.' end ImmutableArray[new_val, new_mark] end # @!macro [attach] atomic_markable_reference_method_try_update # # Pass the current value to the given block, replacing it with the # block's result. Simply return nil if update fails. # # @yield [Object] Calculate a new value and marked state for the atomic # reference using given (old) value and (old) marked # @yieldparam [Object] old_val the starting value of the atomic reference # @yieldparam [Boolean] old_mark the starting state of marked # # @return [ImmutableArray] the new value and marked state, or nil if # the update failed def try_update old_val, old_mark = reference new_val, new_mark = yield old_val, old_mark return unless compare_and_set old_val, new_val, old_mark, new_mark ImmutableArray[new_val, new_mark] end # Internal/private ImmutableArray for representing pairs class ImmutableArray < ::Array def self.new(*args) super(*args).freeze end end end end end concurrent-ruby-1.0.5/lib/concurrent/edge/cancellation.rb000066400000000000000000000106121305460430400234720ustar00rootroot00000000000000module Concurrent # Provides tools for cooperative cancellation. # Inspired by # # @example # # Create new cancellation. `cancellation` is used for cancelling, `token` is passed down to # # tasks for cooperative cancellation # cancellation, token = Concurrent::Cancellation.create # Thread.new(token) do |token| # # Count 1+1 (simulating some other meaningful work) repeatedly # # until the token is cancelled through cancellation. # token.loop_until_canceled { 1+1 } # end # sleep 0.1 # cancellation.cancel # Stop the thread by cancelling class Cancellation < Synchronization::Object safe_initialization! # Creates the cancellation object. Returns both the cancellation and the token for convenience. # @param [Object] resolve_args resolve_args Arguments which are used when resolve method is called on # resolvable_future_or_event # @param [Promises::Resolvable] resolvable_future_or_event resolvable used to track cancellation. # Can be retrieved by `token.to_future` ot `token.to_event`. # @example # cancellation, token = Concurrent::Cancellation.create # @return [Array(Cancellation, Cancellation::Token)] def self.create(resolvable_future_or_event = Promises.resolvable_event, *resolve_args) cancellation = new(resolvable_future_or_event, *resolve_args) [cancellation, cancellation.token] end private_class_method :new # Returns the token associated with the cancellation. # @return [Token] def token @Token end # Cancel this cancellation. All executions depending on the token will cooperatively stop. # @return [true, false] # @raise when cancelling for the second tim def cancel(raise_on_repeated_call = true) !!@Cancel.resolve(*@ResolveArgs, raise_on_repeated_call) end # Is the cancellation cancelled? # @return [true, false] def canceled? @Cancel.resolved? end # Short string representation. # @return [String] def to_s format '<#%s:0x%x canceled:%s>', self.class, object_id << 1, canceled? end alias_method :inspect, :to_s private def initialize(future, *resolve_args) raise ArgumentError, 'future is not Resolvable' unless future.is_a?(Promises::Resolvable) @Cancel = future @Token = Token.new @Cancel.with_hidden_resolvable @ResolveArgs = resolve_args end # Created through {Cancellation.create}, passed down to tasks to be able to check if canceled. class Token < Synchronization::Object safe_initialization! # @return [Event] Event which will be resolved when the token is cancelled. def to_event @Cancel.to_event end # @return [Future] Future which will be resolved when the token is cancelled with arguments passed in # {Cancellation.create} . def to_future @Cancel.to_future end # Is the token cancelled? # @return [true, false] def canceled? @Cancel.resolved? end # Repeatedly evaluates block until the token is {#canceled?}. # @yield to the block repeatedly. # @yieldreturn [Object] # @return [Object] last result of the block def loop_until_canceled(&block) until canceled? result = block.call end result end # Raise error when cancelled # @param [#exception] error to be risen # @raise the error # @return [self] def raise_if_canceled(error = CancelledOperationError) raise error if canceled? self end # Creates a new token which is cancelled when any of the tokens is. # @param [Token] tokens to combine # @return [Token] new token def join(*tokens, &block) block ||= -> tokens { Promises.any_event(*tokens.map(&:to_event)) } self.class.new block.call([@Cancel, *tokens]) end # Short string representation. # @return [String] def to_s format '<#%s:0x%x canceled:%s>', self.class, object_id << 1, canceled? end alias_method :inspect, :to_s private def initialize(cancel) @Cancel = cancel end end # FIXME (pitr-ch 27-Mar-2016): cooperation with mutex, condition, select etc? # TODO (pitr-ch 27-Mar-2016): examples (scheduled to be cancelled in 10 sec) end end concurrent-ruby-1.0.5/lib/concurrent/edge/lock_free_linked_set.rb000066400000000000000000000113611305460430400251720ustar00rootroot00000000000000require 'concurrent/edge/lock_free_linked_set/node' require 'concurrent/edge/lock_free_linked_set/window' module Concurrent module Edge # This class implements a lock-free linked set. The general idea of this # implementation is this: each node has a successor which is an Atomic # Markable Reference. This is used to ensure that all modifications to the # list are atomic, preserving the structure of the linked list under _any_ # circumstance in a multithreaded application. # # One interesting aspect of this algorithm occurs with removing a node. # Instead of physically removing a node when remove is called, a node is # logically removed, by 'marking it.' By doing this, we prevent calls to # `remove` from traversing the list twice to perform a physical removal. # Instead, we have have calls to `add` and `remove` clean up all marked # nodes they encounter while traversing the list. # # This algorithm is a variation of the Nonblocking Linked Set found in # 'The Art of Multiprocessor Programming' by Herlihy and Shavit. class LockFreeLinkedSet include Enumerable # @!macro [attach] lock_free_linked_list_method_initialize # # @param [Fixnum] initial_size the size of the linked_list to initialize def initialize(initial_size = 0, val = nil) @head = Head.new initial_size.times do val = block_given? ? yield : val add val end end # @!macro [attach] lock_free_linked_list_method_add # # Atomically adds the item to the set if it does not yet exist. Note: # internally the set uses `Object#hash` to compare equality of items, # meaning that Strings and other objects will be considered equal # despite being different objects. # # @param [Object] item the item you wish to insert # # @return [Boolean] `true` if successful. A `false` return indicates # that the item was already in the set. def add(item) loop do window = Window.find @head, item pred, curr = window.pred, window.curr # Item already in set return false if curr == item node = Node.new item, curr if pred.successor_reference.compare_and_set curr, node, false, false return true end end end # @!macro [attach] lock_free_linked_list_method_<< # # Atomically adds the item to the set if it does not yet exist. # # @param [Object] item the item you wish to insert # # @return [Object] the set on which the :<< method was invoked def <<(item) add item self end # @!macro [attach] lock_free_linked_list_method_contains # # Atomically checks to see if the set contains an item. This method # compares equality based on the `Object#hash` method, meaning that the # hashed contents of an object is what determines equality instead of # `Object#object_id` # # @param [Object] item the item you to check for presence in the set # # @return [Boolean] whether or not the item is in the set def contains?(item) curr = @head while curr < item curr = curr.next_node marked = curr.successor_reference.marked? end curr == item && !marked end # @!macro [attach] lock_free_linked_list_method_remove # # Atomically attempts to remove an item, comparing using `Object#hash`. # # @param [Object] item the item you to remove from the set # # @return [Boolean] whether or not the item was removed from the set def remove(item) loop do window = Window.find @head, item pred, curr = window.pred, window.curr return false if curr != item succ = curr.next_node removed = curr.successor_reference.compare_and_set succ, succ, false, true #next_node unless removed next unless removed pred.successor_reference.compare_and_set curr, succ, false, false return true end end # @!macro [attach] lock_free_linked_list_method_each # # An iterator to loop through the set. # # @yield [item] each item in the set # @yieldparam [Object] item the item you to remove from the set # # @return [Object] self: the linked set on which each was called def each return to_enum unless block_given? curr = @head until curr.last? curr = curr.next_node marked = curr.successor_reference.marked? yield curr.data unless marked end self end end end end concurrent-ruby-1.0.5/lib/concurrent/edge/lock_free_linked_set/000077500000000000000000000000001305460430400246435ustar00rootroot00000000000000concurrent-ruby-1.0.5/lib/concurrent/edge/lock_free_linked_set/node.rb000066400000000000000000000043251305460430400261210ustar00rootroot00000000000000require 'concurrent/edge/atomic_markable_reference' module Concurrent module Edge class LockFreeLinkedSet class Node < Synchronization::Object include Comparable safe_initialization! def initialize(data = nil, successor = nil) super() @SuccessorReference = AtomicMarkableReference.new(successor || Tail.new) @Data = data @Key = key_for data end def data @Data end def successor_reference @SuccessorReference end def key @Key end # Check to see if the node is the last in the list. def last? @SuccessorReference.value.is_a? Tail end # Next node in the list. Note: this is not the AtomicMarkableReference # of the next node, this is the actual Node itself. def next_node @SuccessorReference.value end # This method provides a unqiue key for the data which will be used for # ordering. This is configurable, and changes depending on how you wish # the nodes to be ordered. def key_for(data) data.hash end # We use `Object#hash` as a way to enforce ordering on the nodes. This # can be configurable in the future; for example, you could enforce a # split-ordering on the nodes in the set. def <=>(other) @Key <=> other.hash end end # Internal sentinel node for the Tail. It is always greater than all # other nodes, and it is self-referential; meaning its successor is # a self-loop. class Tail < Node def initialize(_data = nil, _succ = nil) @SuccessorReference = AtomicMarkableReference.new self end # Always greater than other nodes. This means that traversal will end # at the tail node since we are comparing node size in the traversal. def <=>(_other) 1 end end # Internal sentinel node for the Head of the set. Head is always smaller # than any other node. class Head < Node def <=>(_other) -1 end end end end end concurrent-ruby-1.0.5/lib/concurrent/edge/lock_free_linked_set/window.rb000066400000000000000000000026661305460430400265110ustar00rootroot00000000000000module Concurrent module Edge class LockFreeLinkedSet class Window attr_accessor :pred, :curr def initialize(pred, curr) @pred, @curr = pred, curr end # This method is used to find a 'window' for which `add` and `remove` # methods can use to know where to add and remove from the list. However, # it has another responsibilility, which is to physically unlink any # nodes marked for removal in the set. This prevents adds/removes from # having to retraverse the list to physically unlink nodes. def self.find(head, item) loop do break_inner_loops = false pred = head curr = pred.next_node loop do succ, marked = curr.successor_reference.get # Remove sequence of marked nodes while marked removed = pred.successor_reference.compare_and_set curr, succ, false, false # If could not remove node, try again break_inner_loops = true && break unless removed curr = succ succ, marked = curr.successor_reference.get end break if break_inner_loops # We have found a window return new pred, curr if curr >= item pred = curr curr = succ end end end end end end end concurrent-ruby-1.0.5/lib/concurrent/edge/lock_free_queue.rb000066400000000000000000000066441305460430400242050ustar00rootroot00000000000000module Concurrent # @!visibility private class LockFreeQueue < Synchronization::Object class Node < Synchronization::Object attr_atomic :successor def initialize(item, successor) super() # published through queue, no need to be volatile or final @Item = item self.successor = successor end def item @Item end end safe_initialization! attr_atomic :head, :tail def initialize super() dummy_node = Node.new(:dummy, nil) self.head = dummy_node self.tail = dummy_node end def push(item) # allocate a new node with the item embedded new_node = Node.new(item, nil) # keep trying until the operation succeeds while true current_tail_node = tail current_tail_successor = current_tail_node.successor # if our stored tail is still the current tail if current_tail_node == tail # if that tail was really the last node if current_tail_successor.nil? # if we can update the previous successor of tail to point to this new node if current_tail_node.compare_and_set_successor(nil, new_node) # then update tail to point to this node as well compare_and_set_tail(current_tail_node, new_node) # and return return true # else, start the loop over end else # in this case, the tail ref we had wasn't the real tail # so we try to set its successor as the real tail, then start the loop again compare_and_set_tail(current_tail_node, current_tail_successor) end end end end def pop # retry until some value can be returned while true # the value in @head is just a dummy node that always sits in that position, # the real 'head' is in its successor current_dummy_node = head current_tail_node = tail current_head_node = current_dummy_node.successor # if our local head is still consistent with the head node, continue # otherwise, start over if current_dummy_node == head # if either the queue is empty, or falling behind if current_dummy_node == current_tail_node # if there's nothing after the 'dummy' head node if current_head_node.nil? # just return nil return nil else # here the head element succeeding head is not nil, but the head and tail are equal # so tail is falling behind, update it, then start over compare_and_set_tail(current_tail_node, current_head_node) end # the queue isn't empty # if we can set the dummy head to the 'real' head, we're free to return the value in that real head, success elsif compare_and_set_head(current_dummy_node, current_head_node) # grab the item from the popped node item = current_head_node.item # return it, success! return item end end end end # approximate def size successor = head.successor count = 0 while true break if successor.nil? current_node = successor successor = current_node.successor count += 1 end count end end end concurrent-ruby-1.0.5/lib/concurrent/edge/lock_free_stack.rb000066400000000000000000000050741305460430400241620ustar00rootroot00000000000000module Concurrent # @!visibility private class LockFreeStack < Synchronization::Object safe_initialization! class Node # TODO (pitr-ch 20-Dec-2016): Could be unified with Stack class? attr_reader :value, :next_node # allow to nil-ify to free GC when the entry is no longer relevant, not synchronised attr_writer :value def initialize(value, next_node) @value = value @next_node = next_node end singleton_class.send :alias_method, :[], :new end class Empty < Node def next_node self end end EMPTY = Empty[nil, nil] private(*attr_atomic(:head)) def self.of1(value) new Node[value, EMPTY] end def self.of2(value1, value2) new Node[value1, Node[value2, EMPTY]] end def initialize(head = EMPTY) super() self.head = head end def empty?(head = self.head) head.equal? EMPTY end def compare_and_push(head, value) compare_and_set_head head, Node[value, head] end def push(value) while true current_head = head return self if compare_and_set_head current_head, Node[value, current_head] end end def peek head end def compare_and_pop(head) compare_and_set_head head, head.next_node end def pop while true current_head = head return current_head.value if compare_and_set_head current_head, current_head.next_node end end def compare_and_clear(head) compare_and_set_head head, EMPTY end include Enumerable def each(head = nil) return to_enum(:each, head) unless block_given? it = head || peek until it.equal?(EMPTY) yield it.value it = it.next_node end self end def clear while true current_head = head return false if current_head == EMPTY return true if compare_and_set_head current_head, EMPTY end end def clear_if(head) compare_and_set_head head, EMPTY end def replace_if(head, new_head) compare_and_set_head head, new_head end def clear_each(&block) while true current_head = head return self if current_head == EMPTY if compare_and_set_head current_head, EMPTY each current_head, &block return self end end end # @return [String] Short string representation. def to_s format '<#%s:0x%x %s>', self.class, object_id << 1, to_a.to_s end alias_method :inspect, :to_s end end concurrent-ruby-1.0.5/lib/concurrent/edge/old_channel_integration.rb000066400000000000000000000024071305460430400257120ustar00rootroot00000000000000module Concurrent module Promises module FactoryMethods # @!visibility private module OldChannelIntegration # @!visibility private # only proof of concept # @return [Future] def select(*channels) # TODO (pitr-ch 26-Mar-2016): re-do, has to be non-blocking future do # noinspection RubyArgCount Channel.select do |s| channels.each do |ch| s.take(ch) { |value| [value, ch] } end end end end end include OldChannelIntegration end class Future < AbstractEventFuture # @!visibility private module OldChannelIntegration # @!visibility private # Zips with selected value form the suplied channels # @return [Future] def then_select(*channels) future = Concurrent::Promises.select(*channels) ZipFuturesPromise.new_blocked_by2(self, future, @DefaultExecutor).future end # @note may block # @note only proof of concept def then_put(channel) on_fulfillment_using(:io, channel) { |value, channel| channel.put value } end end include OldChannelIntegration end end end concurrent-ruby-1.0.5/lib/concurrent/edge/processing_actor.rb000066400000000000000000000147711305460430400244140ustar00rootroot00000000000000module Concurrent # A new implementation of actor which also simulates the process, therefore it can be used # in the same way as Erlang's actors but **without** occupying thread. A tens of thousands # ProcessingActors can run at the same time sharing a thread pool. # @example # # Runs on a pool, does not consume 50_000 threads # actors = 50_000.times.map do |i| # Concurrent::ProcessingActor.act(i) { |a, i| a.receive.then_on(:fast, i) { |m, i| m + i } } # end # # actors.each { |a| a.tell 1 } # values = actors.map(&:termination).map(&:value) # values[0,5] # => [1, 2, 3, 4, 5] # values[-5, 5] # => [49996, 49997, 49998, 49999, 50000] # @!macro edge_warning class ProcessingActor < Synchronization::Object # TODO (pitr-ch 18-Dec-2016): (un)linking, bidirectional, sends special message, multiple link calls has no effect, # TODO (pitr-ch 21-Dec-2016): Make terminated a cancellation token? # link_spawn atomic, Can it be fixed by sending exit when linked dead actor? safe_initialization! # @return [Promises::Channel] actor's mailbox. def mailbox @Mailbox end # @return [Promises::Future(Object)] a future which is resolved when the actor ends its processing. # It can either be fulfilled with a value when actor ends normally or rejected with # a reason (exception) when actor fails. def termination @Terminated.with_hidden_resolvable end # Creates an actor. # @see #act_listening Behaves the same way, but does not take mailbox as a first argument. # @return [ProcessingActor] # @example # actor = Concurrent::ProcessingActor.act do |actor| # actor.receive.then do |message| # # the actor ends normally with message # message # end # end # # actor.tell :a_message # # => <#Concurrent::ProcessingActor:0x7fff11280560 termination:pending> # actor.termination.value! # => :a_message def self.act(*args, &process) act_listening Promises::Channel.new, *args, &process end # Creates an actor listening to a specified channel (mailbox). # @param [Object] args Arguments passed to the process. # @param [Promises::Channel] channel which serves as mailing box. The channel can have limited # size to achieve backpressure. # @yield args to the process to get back a future which represents the actors execution. # @yieldparam [Object] *args # @yieldreturn [Promises::Future(Object)] a future representing next step of execution # @return [ProcessingActor] # @example # # TODO (pitr-ch 19-Jan-2017): actor with limited mailbox def self.act_listening(channel, *args, &process) actor = ProcessingActor.new channel Promises. future(actor, *args, &process). run. chain_resolvable(actor.instance_variable_get(:@Terminated)) actor end # Receives a message when available, used in the actor's process. # @return [Promises::Future(Object)] a future which will be fulfilled with a message from # mailbox when it is available. def receive(probe = Promises.resolvable_future) # TODO (pitr-ch 27-Dec-2016): patterns @Mailbox.pop probe end # Tells a message to the actor. May block current thread if the mailbox is full. # {#tell} is a better option since it does not block. It's usually used to integrate with # threading code. # @example # Thread.new(actor) do |actor| # # ... # actor.tell! :a_message # blocks until the message is told # # (there is a space for it in the channel) # # ... # end # @param [Object] message # @return [self] def tell!(message) @Mailbox.push(message).wait! self end # Tells a message to the actor. # @param [Object] message # @return [Promises::Future(ProcessingActor)] a future which will be fulfilled with the actor # when the message is pushed to mailbox. def tell(message) @Mailbox.push(message).then(self) { |_, actor| actor } end # Simplifies common pattern when a message sender also requires an answer to the message # from the actor. It appends a resolvable_future for the answer after the message. # @todo has to be nice also on the receive side, cannot make structure like this [message = [...], answer] # all receives should receive something friendly # @param [Object] message # @param [Promises::ResolvableFuture] answer # @return [Promises::Future] a future which will be fulfilled with the answer to the message # @example # add_once_actor = Concurrent::ProcessingActor.act do |actor| # actor.receive.then do |(a, b), answer| # result = a + b # answer.fulfill result # # terminate with result value # result # end # end # # => <#Concurrent::ProcessingActor:0x7fcd1315f6e8 termination:pending> # # add_once_actor.ask([1, 2]).value! # => 3 # # fails the actor already added once # add_once_actor.ask(%w(ab cd)).reason # # => # # add_once_actor.termination.value! # => 3 def ask(message, answer = Promises.resolvable_future) tell [message, answer] # do not leave answers unanswered when actor terminates. Promises.any( Promises.fulfilled_future(:answer).zip(answer), Promises.fulfilled_future(:termination).zip(@Terminated) ).chain do |fulfilled, (which, value), (_, reason)| # TODO (pitr-ch 20-Jan-2017): we have to know which future was resolved # TODO (pitr-ch 20-Jan-2017): make the combinator programmable, so anyone can create what is needed # TODO (pitr-ch 19-Jan-2017): ensure no callbacks are accumulated on @Terminated if which == :termination raise reason.nil? ? format('actor terminated normally before answering with a value: %s', value) : reason else fulfilled ? value : raise(reason) end end end # @return [String] string representation. def inspect format '<#%s:0x%x termination:%s>', self.class, object_id << 1, termination.state end private def initialize(channel = Promises::Channel.new) @Mailbox = channel @Terminated = Promises.resolvable_future super() end end end concurrent-ruby-1.0.5/lib/concurrent/edge/promises.rb000066400000000000000000001777101305460430400227140ustar00rootroot00000000000000require 'concurrent/synchronization' require 'concurrent/atomic/atomic_boolean' require 'concurrent/atomic/atomic_fixnum' require 'concurrent/edge/lock_free_stack' require 'concurrent/errors' module Concurrent # {include:file:doc/promises-main.md} module Promises # TODO (pitr-ch 23-Dec-2016): move out # @!visibility private module ReInclude def included(base) included_into << [:include, base] super(base) end def extended(base) included_into << [:extend, base] super(base) end def include(*modules) super(*modules) modules.reverse.each do |module_being_included| included_into.each do |method, mod| mod.send method, module_being_included end end end private def included_into @included_into ||= [] end end # @!macro [new] promises.param.default_executor # @param [Executor, :io, :fast] default_executor Instance of an executor or a name of the # global executor. Default executor propagates to chained futures unless overridden with # executor parameter or changed with {AbstractEventFuture#with_default_executor}. # # @!macro [new] promises.param.executor # @param [Executor, :io, :fast] executor Instance of an executor or a name of the # global executor. The task is executed on it, default executor remains unchanged. # # @!macro [new] promises.param.args # @param [Object] args arguments which are passed to the task when it's executed. # (It might be prepended with other arguments, see the @yeild section). # # @!macro [new] promises.shortcut.on # Shortcut of {#$0_on} with default `:io` executor supplied. # @see #$0_on # # @!macro [new] promises.shortcut.using # Shortcut of {#$0_using} with default `:io` executor supplied. # @see #$0_using # # @!macro [new] promise.param.task-future # @yieldreturn will become result of the returned Future. # Its returned value becomes {Future#value} fulfilling it, # raised exception becomes {Future#reason} rejecting it. # # @!macro [new] promise.param.callback # @yieldreturn is forgotten. # Container of all {Future}, {Event} factory methods. They are never constructed directly with # new. module FactoryMethods extend ReInclude module Configuration # @return [Executor, :io, :fast] the executor which is used when none is supplied # to a factory method. The method can be overridden in the receivers of # `include FactoryMethod` def default_executor :io end end include Configuration # @!macro promises.shortcut.on # @return [ResolvableEvent] def resolvable_event resolvable_event_on default_executor end # Created resolvable event, user is responsible for resolving the event once by # {Promises::ResolvableEvent#resolve}. # # @!macro promises.param.default_executor # @return [ResolvableEvent] def resolvable_event_on(default_executor = self.default_executor) ResolvableEventPromise.new(default_executor).future end # @!macro promises.shortcut.on # @return [ResolvableFuture] def resolvable_future resolvable_future_on default_executor end # Creates resolvable future, user is responsible for resolving the future once by # {Promises::ResolvableFuture#resolve}, {Promises::ResolvableFuture#fulfill}, # or {Promises::ResolvableFuture#reject} # # @!macro promises.param.default_executor # @return [ResolvableFuture] def resolvable_future_on(default_executor = self.default_executor) ResolvableFuturePromise.new(default_executor).future end # @!macro promises.shortcut.on # @return [Future] def future(*args, &task) future_on(default_executor, *args, &task) end # @!macro [new] promises.future-on1 # Constructs new Future which will be resolved after block is evaluated on default executor. # Evaluation begins immediately. # # @!macro [new] promises.future-on2 # @!macro promises.param.default_executor # @!macro promises.param.args # @yield [*args] to the task. # @!macro promise.param.task-future # @return [Future] def future_on(default_executor, *args, &task) ImmediateEventPromise.new(default_executor).future.then(*args, &task) end # Creates resolved future with will be either fulfilled with the given value or rejection with # the given reason. # # @!macro promises.param.default_executor # @return [Future] def resolved_future(fulfilled, value, reason, default_executor = self.default_executor) ImmediateFuturePromise.new(default_executor, fulfilled, value, reason).future end # Creates resolved future with will be fulfilled with the given value. # # @!macro promises.param.default_executor # @return [Future] def fulfilled_future(value, default_executor = self.default_executor) resolved_future true, value, nil, default_executor end # Creates resolved future with will be rejected with the given reason. # # @!macro promises.param.default_executor # @return [Future] def rejected_future(reason, default_executor = self.default_executor) resolved_future false, nil, reason, default_executor end # Creates resolved event. # # @!macro promises.param.default_executor # @return [Event] def resolved_event(default_executor = self.default_executor) ImmediateEventPromise.new(default_executor).event end # General constructor. Behaves differently based on the argument's type. It's provided for convenience # but it's better to be explicit. # # @see rejected_future, resolved_event, fulfilled_future # @!macro promises.param.default_executor # @return [Event, Future] # # @overload create(nil, default_executor = self.default_executor) # @param [nil] nil # @return [Event] resolved event. # # @overload create(a_future, default_executor = self.default_executor) # @param [Future] a_future # @return [Future] a future which will be resolved when a_future is. # # @overload create(an_event, default_executor = self.default_executor) # @param [Event] an_event # @return [Event] an event which will be resolved when an_event is. # # @overload create(exception, default_executor = self.default_executor) # @param [Exception] exception # @return [Future] a rejected future with the exception as its reason. # # @overload create(value, default_executor = self.default_executor) # @param [Object] value when none of the above overloads fits # @return [Future] a fulfilled future with the value. def create(argument = nil, default_executor = self.default_executor) case argument when AbstractEventFuture # returning wrapper would change nothing argument when Exception rejected_future argument, default_executor when nil resolved_event default_executor else fulfilled_future argument, default_executor end end # @!macro promises.shortcut.on # @return [Future] def delay(*args, &task) delay_on default_executor, *args, &task end # @!macro promises.future-on1 # The task will be evaluated only after the future is touched, see {AbstractEventFuture#touch} # # @!macro promises.future-on2 def delay_on(default_executor, *args, &task) DelayPromise.new(default_executor).event.chain(*args, &task) end # @!macro promises.shortcut.on # @return [Future] def schedule(intended_time, *args, &task) schedule_on default_executor, intended_time, *args, &task end # @!macro promises.future-on1 # The task is planned for execution in intended_time. # # @!macro promises.future-on2 # @!macro [new] promises.param.intended_time # @param [Numeric, Time] intended_time `Numeric` means to run in `intended_time` seconds. # `Time` means to run on `intended_time`. def schedule_on(default_executor, intended_time, *args, &task) ScheduledPromise.new(default_executor, intended_time).event.chain(*args, &task) end # @!macro promises.shortcut.on # @return [Future] def zip_futures(*futures_and_or_events) zip_futures_on default_executor, *futures_and_or_events end # Creates new future which is resolved after all futures_and_or_events are resolved. # Its value is array of zipped future values. Its reason is array of reasons for rejection. # If there is an error it rejects. # @!macro [new] promises.event-conversion # If event is supplied, which does not have value and can be only resolved, it's # represented as `:fulfilled` with value `nil`. # # @!macro promises.param.default_executor # @param [AbstractEventFuture] futures_and_or_events # @return [Future] def zip_futures_on(default_executor, *futures_and_or_events) ZipFuturesPromise.new_blocked_by(futures_and_or_events, default_executor).future end alias_method :zip, :zip_futures # @!macro promises.shortcut.on # @return [Event] def zip_events(*futures_and_or_events) zip_events_on default_executor, *futures_and_or_events end # Creates new event which is resolved after all futures_and_or_events are resolved. # (Future is resolved when fulfilled or rejected.) # # @!macro promises.param.default_executor # @param [AbstractEventFuture] futures_and_or_events # @return [Event] def zip_events_on(default_executor, *futures_and_or_events) ZipEventsPromise.new_blocked_by(futures_and_or_events, default_executor).event end # @!macro promises.shortcut.on # @return [Future] def any_resolved_future(*futures_and_or_events) any_resolved_future_on default_executor, *futures_and_or_events end alias_method :any, :any_resolved_future # Creates new future which is resolved after first futures_and_or_events is resolved. # Its result equals result of the first resolved future. # @!macro [new] promises.any-touch # If resolved it does not propagate {AbstractEventFuture#touch}, leaving delayed # futures un-executed if they are not required any more. # @!macro promises.event-conversion # # @!macro promises.param.default_executor # @param [AbstractEventFuture] futures_and_or_events # @return [Future] def any_resolved_future_on(default_executor, *futures_and_or_events) AnyResolvedFuturePromise.new_blocked_by(futures_and_or_events, default_executor).future end # @!macro promises.shortcut.on # @return [Future] def any_fulfilled_future(*futures_and_or_events) any_fulfilled_future_on default_executor, *futures_and_or_events end # Creates new future which is resolved after first of futures_and_or_events is fulfilled. # Its result equals result of the first resolved future or if all futures_and_or_events reject, # it has reason of the last resolved future. # @!macro promises.any-touch # @!macro promises.event-conversion # # @!macro promises.param.default_executor # @param [AbstractEventFuture] futures_and_or_events # @return [Future] def any_fulfilled_future_on(default_executor, *futures_and_or_events) AnyFulfilledFuturePromise.new_blocked_by(futures_and_or_events, default_executor).future end # @!macro promises.shortcut.on # @return [Future] def any_event(*futures_and_or_events) any_event_on default_executor, *futures_and_or_events end # Creates new event which becomes resolved after first of the futures_and_or_events resolves. # @!macro promises.any-touch # # @!macro promises.param.default_executor # @param [AbstractEventFuture] futures_and_or_events # @return [Event] def any_event_on(default_executor, *futures_and_or_events) AnyResolvedEventPromise.new_blocked_by(futures_and_or_events, default_executor).event end # TODO consider adding first(count, *futures) # TODO consider adding zip_by(slice, *futures) processing futures in slices end module InternalStates # @private class State def resolved? raise NotImplementedError end def to_sym raise NotImplementedError end end private_constant :State # @private class Pending < State def resolved? false end def to_sym :pending end end private_constant :Pending # @private class ResolvedWithResult < State def resolved? true end def to_sym :resolved end def result [fulfilled?, value, reason] end def fulfilled? raise NotImplementedError end def value raise NotImplementedError end def reason raise NotImplementedError end def apply raise NotImplementedError end end private_constant :ResolvedWithResult # @private class Fulfilled < ResolvedWithResult def initialize(value) @Value = value end def fulfilled? true end def apply(args, block) block.call value, *args end def value @Value end def reason nil end def to_sym :fulfilled end end private_constant :Fulfilled # @private class FulfilledArray < Fulfilled def apply(args, block) block.call(*value, *args) end end private_constant :FulfilledArray # @private class Rejected < ResolvedWithResult def initialize(reason) @Reason = reason end def fulfilled? false end def value nil end def reason @Reason end def to_sym :rejected end def apply(args, block) block.call reason, *args end end private_constant :Rejected # @private class PartiallyRejected < ResolvedWithResult def initialize(value, reason) super() @Value = value @Reason = reason end def fulfilled? false end def to_sym :rejected end def value @Value end def reason @Reason end def apply(args, block) block.call(*reason, *args) end end private_constant :PartiallyRejected PENDING = Pending.new RESOLVED = Fulfilled.new(nil) def RESOLVED.to_sym :resolved end private_constant :PENDING, :RESOLVED end private_constant :InternalStates # Common ancestor of {Event} and {Future} classes, many shared methods are defined here. class AbstractEventFuture < Synchronization::Object safe_initialization! private(*attr_atomic(:internal_state) - [:internal_state]) include InternalStates def initialize(promise, default_executor) super() @Lock = Mutex.new @Condition = ConditionVariable.new @Promise = promise @DefaultExecutor = default_executor @Callbacks = LockFreeStack.new # noinspection RubyArgCount @Waiters = AtomicFixnum.new 0 self.internal_state = PENDING end private :initialize # @!macro [new] promises.shortcut.event-future # @see Event#$0 # @see Future#$0 # @!macro [new] promises.param.timeout # @param [Numeric] timeout the maximum time in second to wait. # @!macro [new] promises.warn.blocks # @note This function potentially blocks current thread until the Future is resolved. # Be careful it can deadlock. Try to chain instead. # Returns its state. # @return [Symbol] # # @overload an_event.state # @return [:pending, :resolved] # @overload a_future.state # Both :fulfilled, :rejected implies :resolved. # @return [:pending, :fulfilled, :rejected] def state internal_state.to_sym end # Is it in pending state? # @return [Boolean] def pending?(state = internal_state) !state.resolved? end # Is it in resolved state? # @return [Boolean] def resolved?(state = internal_state) state.resolved? end # Propagates touch. Requests all the delayed futures, which it depends on, to be # executed. This method is called by any other method requiring resolved state, like {#wait}. # @return [self] def touch @Promise.touch self end # @!macro [new] promises.touches # Calls {AbstractEventFuture#touch}. # @!macro [new] promises.method.wait # Wait (block the Thread) until receiver is {#resolved?}. # @!macro promises.touches # # @!macro promises.warn.blocks # @!macro promises.param.timeout # @return [Future, true, false] self implies timeout was not used, true implies timeout was used # and it was resolved, false implies it was not resolved within timeout. def wait(timeout = nil) result = wait_until_resolved(timeout) timeout ? result : self end # Returns default executor. # @return [Executor] default executor # @see #with_default_executor # @see FactoryMethods#future_on # @see FactoryMethods#resolvable_future # @see FactoryMethods#any_fulfilled_future_on # @see similar def default_executor @DefaultExecutor end # @!macro promises.shortcut.on # @return [Future] def chain(*args, &task) chain_on @DefaultExecutor, *args, &task end # Chains the task to be executed asynchronously on executor after it is resolved. # # @!macro promises.param.executor # @!macro promises.param.args # @return [Future] # @!macro promise.param.task-future # # @overload an_event.chain_on(executor, *args, &task) # @yield [*args] to the task. # @overload a_future.chain_on(executor, *args, &task) # @yield [fulfilled, value, reason, *args] to the task. # @yieldparam [true, false] fulfilled # @yieldparam [Object] value # @yieldparam [Exception] reason def chain_on(executor, *args, &task) ChainPromise.new_blocked_by1(self, @DefaultExecutor, executor, args, &task).future end # @return [String] Short string representation. def to_s format '<#%s:0x%x %s>', self.class, object_id << 1, state end alias_method :inspect, :to_s # Resolves the resolvable when receiver is resolved. # # @param [Resolvable] resolvable # @return [self] def chain_resolvable(resolvable) on_resolution! { resolvable.resolve_with internal_state } end alias_method :tangle, :chain_resolvable # @!macro promises.shortcut.using # @return [self] def on_resolution(*args, &callback) on_resolution_using @DefaultExecutor, *args, &callback end # Stores the callback to be executed synchronously on resolving thread after it is # resolved. # # @!macro promises.param.args # @!macro promise.param.callback # @return [self] # # @overload an_event.on_resolution!(*args, &callback) # @yield [*args] to the callback. # @overload a_future.on_resolution!(*args, &callback) # @yield [fulfilled, value, reason, *args] to the callback. # @yieldparam [true, false] fulfilled # @yieldparam [Object] value # @yieldparam [Exception] reason def on_resolution!(*args, &callback) add_callback :callback_on_resolution, args, callback end # Stores the callback to be executed asynchronously on executor after it is resolved. # # @!macro promises.param.executor # @!macro promises.param.args # @!macro promise.param.callback # @return [self] # # @overload an_event.on_resolution_using(executor, *args, &callback) # @yield [*args] to the callback. # @overload a_future.on_resolution_using(executor, *args, &callback) # @yield [fulfilled, value, reason, *args] to the callback. # @yieldparam [true, false] fulfilled # @yieldparam [Object] value # @yieldparam [Exception] reason def on_resolution_using(executor, *args, &callback) add_callback :async_callback_on_resolution, executor, args, callback end # @!macro [new] promises.method.with_default_executor # Crates new object with same class with the executor set as its new default executor. # Any futures depending on it will use the new default executor. # @!macro promises.shortcut.event-future # @abstract # @return [AbstractEventFuture] def with_default_executor(executor) raise NotImplementedError end # @!visibility private def resolve_with(state, raise_on_reassign = true) if compare_and_set_internal_state(PENDING, state) # go to synchronized block only if there were waiting threads @Lock.synchronize { @Condition.broadcast } unless @Waiters.value == 0 call_callbacks state else return rejected_resolution(raise_on_reassign, state) end self end # For inspection. # @!visibility private # @return [Array] def blocks @Callbacks.each_with_object([]) do |(method, args), promises| promises.push(args[0]) if method == :callback_notify_blocked end end # For inspection. # @!visibility private def callbacks @Callbacks.each.to_a end # For inspection. # @!visibility private def promise @Promise end # For inspection. # @!visibility private def touched? promise.touched? end # For inspection. # @!visibility private def waiting_threads @Waiters.each.to_a end # # @!visibility private def add_callback_notify_blocked(promise, index) add_callback :callback_notify_blocked, promise, index end # @!visibility private def add_callback_clear_delayed_node(node) add_callback(:callback_clear_delayed_node, node) end private def add_callback(method, *args) state = internal_state if resolved?(state) call_callback method, state, args else @Callbacks.push [method, args] state = internal_state # take back if it was resolved in the meanwhile call_callbacks state if resolved?(state) end self end def callback_clear_delayed_node(state, node) node.value = nil end # @return [Boolean] def wait_until_resolved(timeout) return true if resolved? touch @Lock.synchronize do @Waiters.increment begin unless resolved? @Condition.wait @Lock, timeout end ensure # JRuby may raise ConcurrencyError @Waiters.decrement end end resolved? end def call_callback(method, state, args) self.send method, state, *args end def call_callbacks(state) method, args = @Callbacks.pop while method call_callback method, state, args method, args = @Callbacks.pop end end def with_async(executor, *args, &block) Concurrent.executor(executor).post(*args, &block) end def async_callback_on_resolution(state, executor, args, callback) with_async(executor, state, args, callback) do |st, ar, cb| callback_on_resolution st, ar, cb end end def callback_notify_blocked(state, promise, index) promise.on_blocker_resolution self, index end end # Represents an event which will happen in future (will be resolved). The event is either # pending or resolved. It should be always resolved. Use {Future} to communicate rejections and # cancellation. class Event < AbstractEventFuture alias_method :then, :chain # @!macro [new] promises.method.zip # Creates a new event or a future which will be resolved when receiver and other are. # Returns an event if receiver and other are events, otherwise returns a future. # If just one of the parties is Future then the result # of the returned future is equal to the result of the supplied future. If both are futures # then the result is as described in {FactoryMethods#zip_futures_on}. # # @return [Future, Event] def zip(other) if other.is_a?(Future) ZipFutureEventPromise.new_blocked_by2(other, self, @DefaultExecutor).future else ZipEventEventPromise.new_blocked_by2(self, other, @DefaultExecutor).event end end alias_method :&, :zip # Creates a new event which will be resolved when the first of receiver, `event_or_future` # resolves. # # @return [Event] def any(event_or_future) AnyResolvedEventPromise.new_blocked_by2(self, event_or_future, @DefaultExecutor).event end alias_method :|, :any # Creates new event dependent on receiver which will not evaluate until touched, see {#touch}. # In other words, it inserts delay into the chain of Futures making rest of it lazy evaluated. # # @return [Event] def delay event = DelayPromise.new(@DefaultExecutor).event ZipEventEventPromise.new_blocked_by2(self, event, @DefaultExecutor).event end # @!macro [new] promise.method.schedule # Creates new event dependent on receiver scheduled to execute on/in intended_time. # In time is interpreted from the moment the receiver is resolved, therefore it inserts # delay into the chain. # # @!macro promises.param.intended_time # @return [Event] def schedule(intended_time) chain do event = ScheduledPromise.new(@DefaultExecutor, intended_time).event ZipEventEventPromise.new_blocked_by2(self, event, @DefaultExecutor).event end.flat_event end # Converts event to a future. The future is fulfilled when the event is resolved, the future may never fail. # # @return [Future] def to_future future = Promises.resolvable_future ensure chain_resolvable(future) end # Returns self, since this is event # @return [Event] def to_event self end # @!macro promises.method.with_default_executor # @return [Event] def with_default_executor(executor) EventWrapperPromise.new_blocked_by1(self, executor).event end private def rejected_resolution(raise_on_reassign, state) Concurrent::MultipleAssignmentError.new('Event can be resolved only once') if raise_on_reassign return false end def callback_on_resolution(state, args, callback) callback.call *args end end # Represents a value which will become available in future. May reject with a reason instead, # e.g. when the tasks raises an exception. class Future < AbstractEventFuture # Is it in fulfilled state? # @return [Boolean] def fulfilled?(state = internal_state) state.resolved? && state.fulfilled? end # Is it in rejected state? # @return [Boolean] def rejected?(state = internal_state) state.resolved? && !state.fulfilled? end # @!macro [new] promises.warn.nil # @note Make sure returned `nil` is not confused with timeout, no value when rejected, # no reason when fulfilled, etc. # Use more exact methods if needed, like {#wait}, {#value!}, {#result}, etc. # @!macro [new] promises.method.value # Return value of the future. # @!macro promises.touches # # @!macro promises.warn.blocks # @!macro promises.warn.nil # @!macro promises.param.timeout # @return [Object, nil] the value of the Future when fulfilled, nil on timeout or rejection. def value(timeout = nil) internal_state.value if wait_until_resolved timeout end # Returns reason of future's rejection. # @!macro promises.touches # # @!macro promises.warn.blocks # @!macro promises.warn.nil # @!macro promises.param.timeout # @return [Exception, nil] nil on timeout or fulfillment. def reason(timeout = nil) internal_state.reason if wait_until_resolved timeout end # Returns triplet fulfilled?, value, reason. # @!macro promises.touches # # @!macro promises.warn.blocks # @!macro promises.param.timeout # @return [Array(Boolean, Object, Exception), nil] triplet of fulfilled?, value, reason, or nil # on timeout. def result(timeout = nil) internal_state.result if wait_until_resolved timeout end # @!macro promises.method.wait # @raise [Exception] {#reason} on rejection def wait!(timeout = nil) result = wait_until_resolved!(timeout) timeout ? result : self end # @!macro promises.method.value # @return [Object, nil] the value of the Future when fulfilled, nil on timeout. # @raise [Exception] {#reason} on rejection def value!(timeout = nil) internal_state.value if wait_until_resolved! timeout end # Allows rejected Future to be risen with `raise` method. # @example # raise Promises.rejected_future(StandardError.new("boom")) # @raise [StandardError] when raising not rejected future # @return [Exception] def exception(*args) raise Concurrent::Error, 'it is not rejected' unless rejected? reason = Array(internal_state.reason).compact if reason.size > 1 Concurrent::MultipleErrors.new reason else ex = reason[0].exception(*args) ex.set_backtrace ex.backtrace + caller ex end end # @!macro promises.shortcut.on # @return [Future] def then(*args, &task) then_on @DefaultExecutor, *args, &task end # Chains the task to be executed asynchronously on executor after it fulfills. Does not run # the task if it rejects. It will resolve though, triggering any dependent futures. # # @!macro promises.param.executor # @!macro promises.param.args # @!macro promise.param.task-future # @return [Future] # @yield [value, *args] to the task. def then_on(executor, *args, &task) ThenPromise.new_blocked_by1(self, @DefaultExecutor, executor, args, &task).future end # @!macro promises.shortcut.on # @return [Future] def rescue(*args, &task) rescue_on @DefaultExecutor, *args, &task end # Chains the task to be executed asynchronously on executor after it rejects. Does not run # the task if it fulfills. It will resolve though, triggering any dependent futures. # # @!macro promises.param.executor # @!macro promises.param.args # @!macro promise.param.task-future # @return [Future] # @yield [reason, *args] to the task. def rescue_on(executor, *args, &task) RescuePromise.new_blocked_by1(self, @DefaultExecutor, executor, args, &task).future end # @!macro promises.method.zip # @return [Future] def zip(other) if other.is_a?(Future) ZipFuturesPromise.new_blocked_by2(self, other, @DefaultExecutor).future else ZipFutureEventPromise.new_blocked_by2(self, other, @DefaultExecutor).future end end alias_method :&, :zip # Creates a new event which will be resolved when the first of receiver, `event_or_future` # resolves. Returning future will have value nil if event_or_future is event and resolves # first. # # @return [Future] def any(event_or_future) AnyResolvedFuturePromise.new_blocked_by2(self, event_or_future, @DefaultExecutor).future end alias_method :|, :any # Creates new future dependent on receiver which will not evaluate until touched, see {#touch}. # In other words, it inserts delay into the chain of Futures making rest of it lazy evaluated. # # @return [Future] def delay event = DelayPromise.new(@DefaultExecutor).event ZipFutureEventPromise.new_blocked_by2(self, event, @DefaultExecutor).future end # @!macro promise.method.schedule # @return [Future] def schedule(intended_time) chain do event = ScheduledPromise.new(@DefaultExecutor, intended_time).event ZipFutureEventPromise.new_blocked_by2(self, event, @DefaultExecutor).future end.flat end # @!macro promises.method.with_default_executor # @return [Future] def with_default_executor(executor) FutureWrapperPromise.new_blocked_by1(self, executor).future end # Creates new future which will have result of the future returned by receiver. If receiver # rejects it will have its rejection. # # @param [Integer] level how many levels of futures should flatten # @return [Future] def flat_future(level = 1) FlatFuturePromise.new_blocked_by1(self, level, @DefaultExecutor).future end alias_method :flat, :flat_future # Creates new event which will be resolved when the returned event by receiver is. # Be careful if the receiver rejects it will just resolve since Event does not hold reason. # # @return [Event] def flat_event FlatEventPromise.new_blocked_by1(self, @DefaultExecutor).event end # @!macro promises.shortcut.using # @return [self] def on_fulfillment(*args, &callback) on_fulfillment_using @DefaultExecutor, *args, &callback end # Stores the callback to be executed synchronously on resolving thread after it is # fulfilled. Does nothing on rejection. # # @!macro promises.param.args # @!macro promise.param.callback # @return [self] # @yield [value, *args] to the callback. def on_fulfillment!(*args, &callback) add_callback :callback_on_fulfillment, args, callback end # Stores the callback to be executed asynchronously on executor after it is # fulfilled. Does nothing on rejection. # # @!macro promises.param.executor # @!macro promises.param.args # @!macro promise.param.callback # @return [self] # @yield [value, *args] to the callback. def on_fulfillment_using(executor, *args, &callback) add_callback :async_callback_on_fulfillment, executor, args, callback end # @!macro promises.shortcut.using # @return [self] def on_rejection(*args, &callback) on_rejection_using @DefaultExecutor, *args, &callback end # Stores the callback to be executed synchronously on resolving thread after it is # rejected. Does nothing on fulfillment. # # @!macro promises.param.args # @!macro promise.param.callback # @return [self] # @yield [reason, *args] to the callback. def on_rejection!(*args, &callback) add_callback :callback_on_rejection, args, callback end # Stores the callback to be executed asynchronously on executor after it is # rejected. Does nothing on fulfillment. # # @!macro promises.param.executor # @!macro promises.param.args # @!macro promise.param.callback # @return [self] # @yield [reason, *args] to the callback. def on_rejection_using(executor, *args, &callback) add_callback :async_callback_on_rejection, executor, args, callback end # Allows to use futures as green threads. The receiver has to evaluate to a future which # represents what should be done next. It basically flattens indefinitely until non Future # values is returned which becomes result of the returned future. Any encountered exception # will become reason of the returned future. # # @return [Future] # @example # body = lambda do |v| # v += 1 # v < 5 ? Promises.future(v, &body) : v # end # Promises.future(0, &body).run.value! # => 5 def run RunFuturePromise.new_blocked_by1(self, @DefaultExecutor).future end # @!visibility private def apply(args, block) internal_state.apply args, block end # Converts future to event which is resolved when future is resolved by fulfillment or rejection. # # @return [Event] def to_event event = Promises.resolvable_event ensure chain_resolvable(event) end # Returns self, since this is a future # @return [Future] def to_future self end private def rejected_resolution(raise_on_reassign, state) if raise_on_reassign raise Concurrent::MultipleAssignmentError.new( "Future can be resolved only once. It's #{result}, trying to set #{state.result}.", current_result: result, new_result: state.result) end return false end def wait_until_resolved!(timeout = nil) result = wait_until_resolved(timeout) raise self if rejected? result end def async_callback_on_fulfillment(state, executor, args, callback) with_async(executor, state, args, callback) do |st, ar, cb| callback_on_fulfillment st, ar, cb end end def async_callback_on_rejection(state, executor, args, callback) with_async(executor, state, args, callback) do |st, ar, cb| callback_on_rejection st, ar, cb end end def callback_on_fulfillment(state, args, callback) state.apply args, callback if state.fulfilled? end def callback_on_rejection(state, args, callback) state.apply args, callback unless state.fulfilled? end def callback_on_resolution(state, args, callback) callback.call *state.result, *args end end # Marker module of Future, Event resolved manually by user. module Resolvable end # A Event which can be resolved by user. class ResolvableEvent < Event include Resolvable # @!macro [new] raise_on_reassign # @raise [MultipleAssignmentError] when already resolved and raise_on_reassign is true. # @!macro [new] promise.param.raise_on_reassign # @param [Boolean] raise_on_reassign should method raise exception if already resolved # @return [self, false] false is returner when raise_on_reassign is false and the receiver # is already resolved. # # Makes the event resolved, which triggers all dependent futures. # # @!macro promise.param.raise_on_reassign def resolve(raise_on_reassign = true) resolve_with RESOLVED, raise_on_reassign end # Creates new event wrapping receiver, effectively hiding the resolve method. # # @return [Event] def with_hidden_resolvable @with_hidden_resolvable ||= EventWrapperPromise.new_blocked_by1(self, @DefaultExecutor).event end end # A Future which can be resolved by user. class ResolvableFuture < Future include Resolvable # Makes the future resolved with result of triplet `fulfilled?`, `value`, `reason`, # which triggers all dependent futures. # # @!macro promise.param.raise_on_reassign def resolve(fulfilled = true, value = nil, reason = nil, raise_on_reassign = true) resolve_with(fulfilled ? Fulfilled.new(value) : Rejected.new(reason), raise_on_reassign) end # Makes the future fulfilled with `value`, # which triggers all dependent futures. # # @!macro promise.param.raise_on_reassign def fulfill(value, raise_on_reassign = true) promise.fulfill(value, raise_on_reassign) end # Makes the future rejected with `reason`, # which triggers all dependent futures. # # @!macro promise.param.raise_on_reassign def reject(reason, raise_on_reassign = true) promise.reject(reason, raise_on_reassign) end # Evaluates the block and sets its result as future's value fulfilling, if the block raises # an exception the future rejects with it. # @yield [*args] to the block. # @yieldreturn [Object] value # @return [self] def evaluate_to(*args, &block) # FIXME (pitr-ch 13-Jun-2016): add raise_on_reassign promise.evaluate_to(*args, block) end # Evaluates the block and sets its result as future's value fulfilling, if the block raises # an exception the future rejects with it. # @yield [*args] to the block. # @yieldreturn [Object] value # @return [self] # @raise [Exception] also raise reason on rejection. def evaluate_to!(*args, &block) promise.evaluate_to!(*args, block) end # Creates new future wrapping receiver, effectively hiding the resolve method and similar. # # @return [Future] def with_hidden_resolvable @with_hidden_resolvable ||= FutureWrapperPromise.new_blocked_by1(self, @DefaultExecutor).future end end # @abstract # @private class AbstractPromise < Synchronization::Object safe_initialization! include InternalStates def initialize(future) super() @Future = future end def future @Future end alias_method :event, :future def default_executor future.default_executor end def state future.state end def touch end alias_method :inspect, :to_s def delayed_because nil end private def resolve_with(new_state, raise_on_reassign = true) @Future.resolve_with(new_state, raise_on_reassign) end # @return [Future] def evaluate_to(*args, block) resolve_with Fulfilled.new(block.call(*args)) rescue Exception => error # TODO (pitr-ch 30-Jul-2016): figure out what should be rescued, there is an issue about it resolve_with Rejected.new(error) end end class ResolvableEventPromise < AbstractPromise def initialize(default_executor) super ResolvableEvent.new(self, default_executor) end end class ResolvableFuturePromise < AbstractPromise def initialize(default_executor) super ResolvableFuture.new(self, default_executor) end def fulfill(value, raise_on_reassign) resolve_with Fulfilled.new(value), raise_on_reassign end def reject(reason, raise_on_reassign) resolve_with Rejected.new(reason), raise_on_reassign end public :evaluate_to def evaluate_to!(*args, block) evaluate_to(*args, block).wait! end end # @abstract class InnerPromise < AbstractPromise end # @abstract class BlockedPromise < InnerPromise private_class_method :new def self.new_blocked_by1(blocker, *args, &block) blocker_delayed = blocker.promise.delayed_because promise = new(blocker_delayed, 1, *args, &block) blocker.add_callback_notify_blocked promise, 0 promise end def self.new_blocked_by2(blocker1, blocker2, *args, &block) blocker_delayed1 = blocker1.promise.delayed_because blocker_delayed2 = blocker2.promise.delayed_because delayed = if blocker_delayed1 && blocker_delayed2 # TODO (pitr-ch 23-Dec-2016): use arrays when we know it will not grow (only flat adds delay) LockFreeStack.of2(blocker_delayed1, blocker_delayed2) else blocker_delayed1 || blocker_delayed2 end promise = new(delayed, 2, *args, &block) blocker1.add_callback_notify_blocked promise, 0 blocker2.add_callback_notify_blocked promise, 1 promise end def self.new_blocked_by(blockers, *args, &block) delayed = blockers.reduce(nil) { |d, f| add_delayed d, f.promise.delayed_because } promise = new(delayed, blockers.size, *args, &block) blockers.each_with_index { |f, i| f.add_callback_notify_blocked promise, i } promise end def self.add_delayed(delayed1, delayed2) if delayed1 && delayed2 delayed1.push delayed2 delayed1 else delayed1 || delayed2 end end def initialize(delayed, blockers_count, future) super(future) @Delayed = delayed # noinspection RubyArgCount @Countdown = AtomicFixnum.new blockers_count end def on_blocker_resolution(future, index) countdown = process_on_blocker_resolution(future, index) resolvable = resolvable?(countdown, future, index) on_resolvable(future, index) if resolvable end def delayed_because @Delayed end def touch clear_and_propagate_touch end # for inspection only def blocked_by blocked_by = [] ObjectSpace.each_object(AbstractEventFuture) { |o| blocked_by.push o if o.blocks.include? self } blocked_by end private def clear_and_propagate_touch(stack_or_element = @Delayed) return if stack_or_element.nil? if stack_or_element.is_a? LockFreeStack stack_or_element.clear_each { |element| clear_and_propagate_touch element } else stack_or_element.touch unless stack_or_element.nil? # if still present end end # @return [true,false] if resolvable def resolvable?(countdown, future, index) countdown.zero? end def process_on_blocker_resolution(future, index) @Countdown.decrement end def on_resolvable(resolved_future, index) raise NotImplementedError end end # @abstract class BlockedTaskPromise < BlockedPromise def initialize(delayed, blockers_count, default_executor, executor, args, &task) raise ArgumentError, 'no block given' unless block_given? super delayed, 1, Future.new(self, default_executor) @Executor = executor @Task = task @Args = args end def executor @Executor end end class ThenPromise < BlockedTaskPromise private def initialize(delayed, blockers_count, default_executor, executor, args, &task) super delayed, blockers_count, default_executor, executor, args, &task end def on_resolvable(resolved_future, index) if resolved_future.fulfilled? Concurrent.executor(@Executor).post(resolved_future, @Args, @Task) do |future, args, task| evaluate_to lambda { future.apply args, task } end else resolve_with resolved_future.internal_state end end end class RescuePromise < BlockedTaskPromise private def initialize(delayed, blockers_count, default_executor, executor, args, &task) super delayed, blockers_count, default_executor, executor, args, &task end def on_resolvable(resolved_future, index) if resolved_future.rejected? Concurrent.executor(@Executor).post(resolved_future, @Args, @Task) do |future, args, task| evaluate_to lambda { future.apply args, task } end else resolve_with resolved_future.internal_state end end end class ChainPromise < BlockedTaskPromise private def on_resolvable(resolved_future, index) if Future === resolved_future Concurrent.executor(@Executor).post(resolved_future, @Args, @Task) do |future, args, task| evaluate_to(*future.result, *args, task) end else Concurrent.executor(@Executor).post(@Args, @Task) do |args, task| evaluate_to *args, task end end end end # will be immediately resolved class ImmediateEventPromise < InnerPromise def initialize(default_executor) super Event.new(self, default_executor).resolve_with(RESOLVED) end end class ImmediateFuturePromise < InnerPromise def initialize(default_executor, fulfilled, value, reason) super Future.new(self, default_executor). resolve_with(fulfilled ? Fulfilled.new(value) : Rejected.new(reason)) end end class AbstractFlatPromise < BlockedPromise def initialize(delayed_because, blockers_count, event_or_future) delayed = LockFreeStack.of1(self) super(delayed, blockers_count, event_or_future) # noinspection RubyArgCount @Touched = AtomicBoolean.new false @DelayedBecause = delayed_because || LockFreeStack.new event_or_future.add_callback_clear_delayed_node delayed.peek end def touch if @Touched.make_true clear_and_propagate_touch @DelayedBecause end end private def touched? @Touched.value end def on_resolvable(resolved_future, index) resolve_with resolved_future.internal_state end def resolvable?(countdown, future, index) !@Future.internal_state.resolved? && super(countdown, future, index) end def add_delayed_of(future) delayed = future.promise.delayed_because if touched? clear_and_propagate_touch delayed else BlockedPromise.add_delayed @DelayedBecause, delayed clear_and_propagate_touch @DelayedBecause if touched? end end end class FlatEventPromise < AbstractFlatPromise private def initialize(delayed, blockers_count, default_executor) super delayed, 2, Event.new(self, default_executor) end def process_on_blocker_resolution(future, index) countdown = super(future, index) if countdown.nonzero? internal_state = future.internal_state unless internal_state.fulfilled? resolve_with RESOLVED return countdown end value = internal_state.value case value when Future, Event add_delayed_of value value.add_callback_notify_blocked self, nil countdown else resolve_with RESOLVED end end countdown end end class FlatFuturePromise < AbstractFlatPromise private def initialize(delayed, blockers_count, levels, default_executor) raise ArgumentError, 'levels has to be higher than 0' if levels < 1 # flat promise may result to a future having delayed futures, therefore we have to have empty stack # to be able to add new delayed futures super delayed || LockFreeStack.new, 1 + levels, Future.new(self, default_executor) end def process_on_blocker_resolution(future, index) countdown = super(future, index) if countdown.nonzero? internal_state = future.internal_state unless internal_state.fulfilled? resolve_with internal_state return countdown end value = internal_state.value case value when Future add_delayed_of value value.add_callback_notify_blocked self, nil countdown when Event evaluate_to(lambda { raise TypeError, 'cannot flatten to Event' }) else evaluate_to(lambda { raise TypeError, "returned value #{value.inspect} is not a Future" }) end end countdown end end class RunFuturePromise < AbstractFlatPromise private def initialize(delayed, blockers_count, default_executor) super delayed, 1, Future.new(self, default_executor) end def process_on_blocker_resolution(future, index) internal_state = future.internal_state unless internal_state.fulfilled? resolve_with internal_state return 0 end value = internal_state.value case value when Future add_delayed_of value value.add_callback_notify_blocked self, nil else resolve_with internal_state end 1 end end class ZipEventEventPromise < BlockedPromise def initialize(delayed, blockers_count, default_executor) super delayed, 2, Event.new(self, default_executor) end private def on_resolvable(resolved_future, index) resolve_with RESOLVED end end class ZipFutureEventPromise < BlockedPromise def initialize(delayed, blockers_count, default_executor) super delayed, 2, Future.new(self, default_executor) @result = nil end private def process_on_blocker_resolution(future, index) # first blocking is future, take its result @result = future.internal_state if index == 0 # super has to be called after above to piggyback on volatile @Countdown super future, index end def on_resolvable(resolved_future, index) resolve_with @result end end class EventWrapperPromise < BlockedPromise def initialize(delayed, blockers_count, default_executor) super delayed, 1, Event.new(self, default_executor) end private def on_resolvable(resolved_future, index) resolve_with RESOLVED end end class FutureWrapperPromise < BlockedPromise def initialize(delayed, blockers_count, default_executor) super delayed, 1, Future.new(self, default_executor) end private def on_resolvable(resolved_future, index) resolve_with resolved_future.internal_state end end class ZipFuturesPromise < BlockedPromise private def initialize(delayed, blockers_count, default_executor) super(delayed, blockers_count, Future.new(self, default_executor)) @Resolutions = ::Array.new(blockers_count) on_resolvable nil, nil if blockers_count == 0 end def process_on_blocker_resolution(future, index) # TODO (pitr-ch 18-Dec-2016): Can we assume that array will never break under parallel access when never re-sized? @Resolutions[index] = future.internal_state # has to be set before countdown in super super future, index end def on_resolvable(resolved_future, index) all_fulfilled = true values = Array.new(@Resolutions.size) reasons = Array.new(@Resolutions.size) @Resolutions.each_with_index do |internal_state, i| fulfilled, values[i], reasons[i] = internal_state.result all_fulfilled &&= fulfilled end if all_fulfilled resolve_with FulfilledArray.new(values) else resolve_with PartiallyRejected.new(values, reasons) end end end class ZipEventsPromise < BlockedPromise private def initialize(delayed, blockers_count, default_executor) super delayed, blockers_count, Event.new(self, default_executor) on_resolvable nil, nil if blockers_count == 0 end def on_resolvable(resolved_future, index) resolve_with RESOLVED end end # @abstract class AbstractAnyPromise < BlockedPromise end class AnyResolvedFuturePromise < AbstractAnyPromise private def initialize(delayed, blockers_count, default_executor) super delayed, blockers_count, Future.new(self, default_executor) end def resolvable?(countdown, future, index) true end def on_resolvable(resolved_future, index) resolve_with resolved_future.internal_state, false end end class AnyResolvedEventPromise < AbstractAnyPromise private def initialize(delayed, blockers_count, default_executor) super delayed, blockers_count, Event.new(self, default_executor) end def resolvable?(countdown, future, index) true end def on_resolvable(resolved_future, index) resolve_with RESOLVED, false end end class AnyFulfilledFuturePromise < AnyResolvedFuturePromise private def resolvable?(countdown, future, index) future.fulfilled? || # inlined super from BlockedPromise countdown.zero? end end class DelayPromise < InnerPromise def initialize(default_executor) event = Event.new(self, default_executor) @Delayed = LockFreeStack.of1(self) super event event.add_callback_clear_delayed_node @Delayed.peek end def touch @Future.resolve_with RESOLVED end def delayed_because @Delayed end end class ScheduledPromise < InnerPromise def intended_time @IntendedTime end def inspect "#{to_s[0..-2]} intended_time: #{@IntendedTime}>" end private def initialize(default_executor, intended_time) super Event.new(self, default_executor) @IntendedTime = intended_time in_seconds = begin now = Time.now schedule_time = if @IntendedTime.is_a? Time @IntendedTime else now + @IntendedTime end [0, schedule_time.to_f - now.to_f].max end Concurrent.global_timer_set.post(in_seconds) do @Future.resolve_with RESOLVED end end end extend FactoryMethods private_constant :AbstractPromise, :ResolvableEventPromise, :ResolvableFuturePromise, :InnerPromise, :BlockedPromise, :BlockedTaskPromise, :ThenPromise, :RescuePromise, :ChainPromise, :ImmediateEventPromise, :ImmediateFuturePromise, :AbstractFlatPromise, :FlatFuturePromise, :FlatEventPromise, :RunFuturePromise, :ZipEventEventPromise, :ZipFutureEventPromise, :EventWrapperPromise, :FutureWrapperPromise, :ZipFuturesPromise, :ZipEventsPromise, :AbstractAnyPromise, :AnyResolvedFuturePromise, :AnyFulfilledFuturePromise, :AnyResolvedEventPromise, :DelayPromise, :ScheduledPromise end end # TODO try stealing pool, each thread has it's own queue # TODO (pitr-ch 18-Dec-2016): doc macro debug method # TODO (pitr-ch 18-Dec-2016): add macro noting that debug methods may change api without warning module Concurrent module Promises class Future < AbstractEventFuture module ActorIntegration # Asks the actor with its value. # @return [Future] new future with the response form the actor def then_ask(actor) self.then { |v| actor.ask(v) }.flat end end include ActorIntegration end class Channel < Concurrent::Synchronization::Object safe_initialization! # Default size of the Channel, makes it accept unlimited number of messages. UNLIMITED = Object.new UNLIMITED.singleton_class.class_eval do include Comparable def <=>(other) 1 end def to_s 'unlimited' end end # A channel to pass messages between promises. The size is limited to support back pressure. # @param [Integer, UNLIMITED] size the maximum number of messages stored in the channel. def initialize(size = UNLIMITED) super() @Size = size # TODO (pitr-ch 26-Dec-2016): replace with lock-free implementation @Mutex = Mutex.new @Probes = [] @Messages = [] @PendingPush = [] end # Returns future which will fulfill when the message is added to the channel. Its value is the message. # @param [Object] message # @return [Future] def push(message) @Mutex.synchronize do while true if @Probes.empty? if @Size > @Messages.size @Messages.push message return Promises.fulfilled_future message else pushed = Promises.resolvable_future @PendingPush.push [message, pushed] return pushed.with_hidden_resolvable end else probe = @Probes.shift if probe.fulfill [self, message], false return Promises.fulfilled_future(message) end end end end end # Returns a future witch will become fulfilled with a value from the channel when one is available. # @param [ResolvableFuture] probe the future which will be fulfilled with a channel value # @return [Future] the probe, its value will be the message when available. def pop(probe = Concurrent::Promises.resolvable_future) # TODO (pitr-ch 26-Dec-2016): improve performance pop_for_select(probe).then(&:last) end # @!visibility private def pop_for_select(probe = Concurrent::Promises.resolvable_future) @Mutex.synchronize do if @Messages.empty? @Probes.push probe else message = @Messages.shift probe.fulfill [self, message] unless @PendingPush.empty? message, pushed = @PendingPush.shift @Messages.push message pushed.fulfill message end end end probe end # @return [String] Short string representation. def to_s format '<#%s:0x%x size:%s>', self.class, object_id << 1, @Size end alias_method :inspect, :to_s end class Future < AbstractEventFuture module NewChannelIntegration # @param [Channel] channel to push to. # @return [Future] a future which is fulfilled after the message is pushed to the channel. # May take a moment if the channel is full. def then_push_channel(channel) self.then { |value| channel.push value }.flat_future end # TODO (pitr-ch 26-Dec-2016): does it make sense to have rescue an chain variants as well, check other integrations as well end include NewChannelIntegration end module FactoryMethods module NewChannelIntegration # Selects a channel which is ready to be read from. # @param [Channel] channels # @return [Future] a future which is fulfilled with pair [channel, message] when one of the channels is # available for reading def select_channel(*channels) probe = Promises.resolvable_future channels.each { |ch| ch.pop_for_select probe } probe end end include NewChannelIntegration end end end concurrent-ruby-1.0.5/lib/concurrent/edge/throttle.rb000066400000000000000000000141441305460430400227070ustar00rootroot00000000000000module Concurrent # @!macro [new] throttle.example.throttled_block # @example # max_two = Throttle.new 2 # 10.times.map do # Thread.new do # max_two.throttled_block do # # Only 2 at the same time # do_stuff # end # end # end # @!macro [new] throttle.example.throttled_future # @example # throttle.throttled_future(1) do |arg| # arg.succ # end # @!macro [new] throttle.example.throttled_future_chain # @example # throttle.throttled_future_chain do |trigger| # trigger. # # 2 throttled promises # chain { 1 }. # then(&:succ) # end # @!macro [new] throttle.example.then_throttled_by # @example # data = (1..5).to_a # db = data.reduce({}) { |h, v| h.update v => v.to_s } # max_two = Throttle.new 2 # # futures = data.map do |data| # Promises.future(data) do |data| # # un-throttled, concurrency level equal data.size # data + 1 # end.then_throttled_by(max_two, db) do |v, db| # # throttled, only 2 tasks executed at the same time # # e.g. limiting access to db # db[v] # end # end # # futures.map(&:value!) # => [2, 3, 4, 5, nil] # A tool manage concurrency level of future tasks. # # @!macro throttle.example.then_throttled_by # @!macro throttle.example.throttled_future # @!macro throttle.example.throttled_future_chain # @!macro throttle.example.throttled_block class Throttle < Synchronization::Object # TODO (pitr-ch 21-Dec-2016): consider using sized channel for implementation instead when available safe_initialization! private *attr_atomic(:can_run) # New throttle. # @param [Integer] limit def initialize(limit) super() @Limit = limit self.can_run = limit @Queue = LockFreeQueue.new end # @return [Integer] The limit. def limit @Limit end # New event which will be resolved when depending tasks can execute. # Has to be used and after the critical work is done {#release} must be called exactly once. # @return [Promises::Event] # @see #release def trigger while true current_can_run = can_run if compare_and_set_can_run current_can_run, current_can_run - 1 if current_can_run > 0 return Promises.resolved_event else event = Promises.resolvable_event @Queue.push event return event end end end end # Has to be called once for each trigger after it is ok to execute another throttled task. # @return [self] # @see #trigger def release while true current_can_run = can_run if compare_and_set_can_run current_can_run, current_can_run + 1 if current_can_run < 0 Thread.pass until (trigger = @Queue.pop) trigger.resolve end return self end end end # Blocks current thread until the block can be executed. # @yield to throttled block # @yieldreturn [Object] is used as a result of the method # @return [Object] the result of the block # @!macro throttle.example.throttled_block def throttled_block(&block) trigger.wait block.call ensure release end # @return [String] Short string representation. def to_s format '<#%s:0x%x limit:%s can_run:%d>', self.class, object_id << 1, @Limit, can_run end alias_method :inspect, :to_s module PromisesIntegration # Allows to throttle a chain of promises. # @yield [trigger] a trigger which has to be used to build up a chain of promises, the last one is result # of the block. When the last one resolves, {Throttle#release} is called on the throttle. # @yieldparam [Promises::Event, Promises::Future] trigger # @yieldreturn [Promises::Event, Promises::Future] The final future of the throttled chain. # @return [Promises::Event, Promises::Future] The final future of the throttled chain. # @!macro throttle.example.throttled_future_chain def throttled_future_chain(&throttled_futures) throttled_futures.call(trigger).on_resolution! { release } end # Behaves as {Promises::FactoryMethods#future} but the future is throttled. # @return [Promises::Future] # @see Promises::FactoryMethods#future # @!macro throttle.example.throttled_future def throttled_future(*args, &task) trigger.chain(*args, &task).on_resolution! { release } end end include PromisesIntegration end module Promises class AbstractEventFuture < Synchronization::Object module ThrottleIntegration def throttled_by(throttle, &throttled_futures) a_trigger = self & self.chain { throttle.trigger }.flat_event throttled_futures.call(a_trigger).on_resolution! { throttle.release } end # Behaves as {Promises::AbstractEventFuture#chain} but the it is throttled. # @return [Promises::Future, Promises::Event] # @see Promises::AbstractEventFuture#chain def chain_throttled_by(throttle, *args, &block) throttled_by(throttle) { |trigger| trigger.chain(*args, &block) } end end include ThrottleIntegration end class Future < AbstractEventFuture module ThrottleIntegration # Behaves as {Promises::Future#then} but the it is throttled. # @return [Promises::Future] # @see Promises::Future#then # @!macro throttle.example.then_throttled_by def then_throttled_by(throttle, *args, &block) throttled_by(throttle) { |trigger| trigger.then(*args, &block) } end # Behaves as {Promises::Future#rescue} but the it is throttled. # @return [Promises::Future] # @see Promises::Future#rescue def rescue_throttled_by(throttle, *args, &block) throttled_by(throttle) { |trigger| trigger.rescue(*args, &block) } end end include ThrottleIntegration end end end concurrent-ruby-1.0.5/lib/concurrent/errors.rb000066400000000000000000000042441305460430400214520ustar00rootroot00000000000000module Concurrent Error = Class.new(StandardError) # Raised when errors occur during configuration. ConfigurationError = Class.new(Error) # Raised when an asynchronous operation is cancelled before execution. CancelledOperationError = Class.new(Error) # Raised when a lifecycle method (such as `stop`) is called in an improper # sequence or when the object is in an inappropriate state. LifecycleError = Class.new(Error) # Raised when an attempt is made to violate an immutability guarantee. ImmutabilityError = Class.new(Error) # Raised when an operation is attempted which is not legal given the # receiver's current state IllegalOperationError = Class.new(Error) # Raised when an object's methods are called when it has not been # properly initialized. InitializationError = Class.new(Error) # Raised when an object with a start/stop lifecycle has been started an # excessive number of times. Often used in conjunction with a restart # policy or strategy. MaxRestartFrequencyError = Class.new(Error) # Raised when an attempt is made to modify an immutable object # (such as an `IVar`) after its final state has been set. class MultipleAssignmentError < Error attr_reader :inspection_data def initialize(message = nil, inspection_data = nil) @inspection_data = inspection_data super message end def inspect format '%s %s>', super[0..-2], @inspection_data.inspect end end # Raised by an `Executor` when it is unable to process a given task, # possibly because of a reject policy or other internal error. RejectedExecutionError = Class.new(Error) # Raised when any finite resource, such as a lock counter, exceeds its # maximum limit/threshold. ResourceLimitError = Class.new(Error) # Raised when an operation times out. TimeoutError = Class.new(Error) # Aggregates multiple exceptions. class MultipleErrors < Error attr_reader :errors def initialize(errors, message = "#{errors.size} errors") @errors = errors super [*message, *errors.map { |e| [format('%s (%s)', e.message, e.class), *e.backtrace] }.flatten(1) ].join("\n") end end end concurrent-ruby-1.0.5/lib/concurrent/exchanger.rb000066400000000000000000000315021305460430400220770ustar00rootroot00000000000000require 'concurrent/constants' require 'concurrent/errors' require 'concurrent/maybe' require 'concurrent/atomic/atomic_reference' require 'concurrent/atomic/count_down_latch' require 'concurrent/utility/engine' require 'concurrent/utility/monotonic_time' module Concurrent # @!macro [attach] exchanger # # A synchronization point at which threads can pair and swap elements within # pairs. Each thread presents some object on entry to the exchange method, # matches with a partner thread, and receives its partner's object on return. # # @!macro thread_safe_variable_comparison # # This implementation is very simple, using only a single slot for each # exchanger (unlike more advanced implementations which use an "arena"). # This approach will work perfectly fine when there are only a few threads # accessing a single `Exchanger`. Beyond a handful of threads the performance # will degrade rapidly due to contention on the single slot, but the algorithm # will remain correct. # # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Exchanger.html java.util.concurrent.Exchanger # # @!macro edge_warning # # @example # # exchanger = Concurrent::Exchanger.new # # threads = [ # Thread.new { puts "first: " << exchanger.exchange('foo', 1) }, #=> "first: bar" # Thread.new { puts "second: " << exchanger.exchange('bar', 1) } #=> "second: foo" # ] # threads.each {|t| t.join(2) } # # @!visibility private class AbstractExchanger < Synchronization::Object # @!visibility private CANCEL = Object.new private_constant :CANCEL # @!macro [attach] exchanger_method_initialize def initialize super end # @!macro [attach] exchanger_method_do_exchange # # Waits for another thread to arrive at this exchange point (unless the # current thread is interrupted), and then transfers the given object to # it, receiving its object in return. The timeout value indicates the # approximate number of seconds the method should block while waiting # for the exchange. When the timeout value is `nil` the method will # block indefinitely. # # @param [Object] value the value to exchange with another thread # @param [Numeric, nil] timeout in seconds, `nil` blocks indefinitely # # @!macro [attach] exchanger_method_exchange # # In some edge cases when a `timeout` is given a return value of `nil` may be # ambiguous. Specifically, if `nil` is a valid value in the exchange it will # be impossible to tell whether `nil` is the actual return value or if it # signifies timeout. When `nil` is a valid value in the exchange consider # using {#exchange!} or {#try_exchange} instead. # # @return [Object] the value exchanged by the other thread or `nil` on timeout def exchange(value, timeout = nil) (value = do_exchange(value, timeout)) == CANCEL ? nil : value end # @!macro exchanger_method_do_exchange # # @!macro [attach] exchanger_method_exchange_bang # # On timeout a {Concurrent::TimeoutError} exception will be raised. # # @return [Object] the value exchanged by the other thread # @raise [Concurrent::TimeoutError] on timeout def exchange!(value, timeout = nil) if (value = do_exchange(value, timeout)) == CANCEL raise Concurrent::TimeoutError else value end end # @!macro exchanger_method_do_exchange # # @!macro [attach] exchanger_method_try_exchange # # The return value will be a {Concurrent::Maybe} set to `Just` on success or # `Nothing` on timeout. # # @return [Concurrent::Maybe] on success a `Just` maybe will be returned with # the item exchanged by the other thread as `#value`; on timeout a # `Nothing` maybe will be returned with {Concurrent::TimeoutError} as `#reason` # # @example # # exchanger = Concurrent::Exchanger.new # # result = exchanger.exchange(:foo, 0.5) # # if result.just? # puts result.value #=> :bar # else # puts 'timeout' # end def try_exchange(value, timeout = nil) if (value = do_exchange(value, timeout)) == CANCEL Concurrent::Maybe.nothing(Concurrent::TimeoutError) else Concurrent::Maybe.just(value) end end private # @!macro exchanger_method_do_exchange # # @return [Object, CANCEL] the value exchanged by the other thread; {CANCEL} on timeout def do_exchange(value, timeout) raise NotImplementedError end end # @!macro exchanger # @!macro internal_implementation_note # @!visibility private class RubyExchanger < AbstractExchanger # A simplified version of java.util.concurrent.Exchanger written by # Doug Lea, Bill Scherer, and Michael Scott with assistance from members # of JCP JSR-166 Expert Group and released to the public domain. It does # not include the arena or the multi-processor spin loops. # http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/concurrent/Exchanger.java safe_initialization! class Node < Concurrent::Synchronization::Object attr_atomic :value safe_initialization! def initialize(item) super() @Item = item @Latch = Concurrent::CountDownLatch.new self.value = nil end def latch @Latch end def item @Item end end private_constant :Node # @!macro exchanger_method_initialize def initialize super end private attr_atomic(:slot) # @!macro exchanger_method_do_exchange # # @return [Object, CANCEL] the value exchanged by the other thread; {CANCEL} on timeout def do_exchange(value, timeout) # ALGORITHM # # From the original Java version: # # > The basic idea is to maintain a "slot", which is a reference to # > a Node containing both an Item to offer and a "hole" waiting to # > get filled in. If an incoming "occupying" thread sees that the # > slot is null, it CAS'es (compareAndSets) a Node there and waits # > for another to invoke exchange. That second "fulfilling" thread # > sees that the slot is non-null, and so CASes it back to null, # > also exchanging items by CASing the hole, plus waking up the # > occupying thread if it is blocked. In each case CAS'es may # > fail because a slot at first appears non-null but is null upon # > CAS, or vice-versa. So threads may need to retry these # > actions. # # This version: # # An exchange occurs between an "occupier" thread and a "fulfiller" thread. # The "slot" is used to setup this interaction. The first thread in the # exchange puts itself into the slot (occupies) and waits for a fulfiller. # The second thread removes the occupier from the slot and attempts to # perform the exchange. Removing the occupier also frees the slot for # another occupier/fulfiller pair. # # Because the occupier and the fulfiller are operating independently and # because there may be contention with other threads, any failed operation # indicates contention. Both the occupier and the fulfiller operate within # spin loops. Any failed actions along the happy path will cause the thread # to repeat the loop and try again. # # When a timeout value is given the thread must be cognizant of time spent # in the spin loop. The remaining time is checked every loop. When the time # runs out the thread will exit. # # A "node" is the data structure used to perform the exchange. Only the # occupier's node is necessary. It's the node used for the exchange. # Each node has an "item," a "hole" (self), and a "latch." The item is the # node's initial value. It never changes. It's what the fulfiller returns on # success. The occupier's hole is where the fulfiller put its item. It's the # item that the occupier returns on success. The latch is used for synchronization. # Becuase a thread may act as either an occupier or fulfiller (or possibly # both in periods of high contention) every thread creates a node when # the exchange method is first called. # # The following steps occur within the spin loop. If any actions fail # the thread will loop and try again, so long as there is time remaining. # If time runs out the thread will return CANCEL. # # Check the slot for an occupier: # # * If the slot is empty try to occupy # * If the slot is full try to fulfill # # Attempt to occupy: # # * Attempt to CAS myself into the slot # * Go to sleep and wait to be woken by a fulfiller # * If the sleep is successful then the fulfiller completed its happy path # - Return the value from my hole (the value given by the fulfiller) # * When the sleep fails (time ran out) attempt to cancel the operation # - Attempt to CAS myself out of the hole # - If successful there is no contention # - Return CANCEL # - On failure, I am competing with a fulfiller # - Attempt to CAS my hole to CANCEL # - On success # - Let the fulfiller deal with my cancel # - Return CANCEL # - On failure the fulfiller has completed its happy path # - Return th value from my hole (the fulfiller's value) # # Attempt to fulfill: # # * Attempt to CAS the occupier out of the slot # - On failure loop again # * Attempt to CAS my item into the occupier's hole # - On failure the occupier is trying to cancel # - Loop again # - On success we are on the happy path # - Wake the sleeping occupier # - Return the occupier's item value = NULL if value.nil? # The sentinel allows nil to be a valid value me = Node.new(value) # create my node in case I need to occupy end_at = Concurrent.monotonic_time + timeout.to_f # The time to give up result = loop do other = slot if other && compare_and_set_slot(other, nil) # try to fulfill if other.compare_and_set_value(nil, value) # happy path other.latch.count_down break other.item end elsif other.nil? && compare_and_set_slot(nil, me) # try to occupy timeout = end_at - Concurrent.monotonic_time if timeout if me.latch.wait(timeout) # happy path break me.value else # attempt to remove myself from the slot if compare_and_set_slot(me, nil) break CANCEL elsif !me.compare_and_set_value(nil, CANCEL) # I've failed to block the fulfiller break me.value end end end break CANCEL if timeout && Concurrent.monotonic_time >= end_at end result == NULL ? nil : result end end if Concurrent.on_jruby? # @!macro exchanger # @!macro internal_implementation_note # @!visibility private class JavaExchanger < AbstractExchanger # @!macro exchanger_method_initialize def initialize @exchanger = java.util.concurrent.Exchanger.new end private # @!macro exchanger_method_do_exchange # # @return [Object, CANCEL] the value exchanged by the other thread; {CANCEL} on timeout def do_exchange(value, timeout) if timeout.nil? @exchanger.exchange(value) else @exchanger.exchange(value, 1000 * timeout, java.util.concurrent.TimeUnit::MILLISECONDS) end rescue java.util.concurrent.TimeoutException CANCEL end end end # @!visibility private # @!macro internal_implementation_note ExchangerImplementation = case when Concurrent.on_jruby? JavaExchanger else RubyExchanger end private_constant :ExchangerImplementation # @!macro exchanger class Exchanger < ExchangerImplementation # @!method initialize # @!macro exchanger_method_initialize # @!method exchange(value, timeout = nil) # @!macro exchanger_method_do_exchange # @!macro exchanger_method_exchange # @!method exchange!(value, timeout = nil) # @!macro exchanger_method_do_exchange # @!macro exchanger_method_exchange_bang # @!method try_exchange(value, timeout = nil) # @!macro exchanger_method_do_exchange # @!macro exchanger_method_try_exchange end end concurrent-ruby-1.0.5/lib/concurrent/executor/000077500000000000000000000000001305460430400214435ustar00rootroot00000000000000concurrent-ruby-1.0.5/lib/concurrent/executor/abstract_executor_service.rb000066400000000000000000000064471305460430400272440ustar00rootroot00000000000000require 'concurrent/errors' require 'concurrent/executor/executor_service' require 'concurrent/synchronization' require 'concurrent/utility/at_exit' module Concurrent # @!macro abstract_executor_service_public_api # @!visibility private class AbstractExecutorService < Synchronization::LockableObject include ExecutorService # The set of possible fallback policies that may be set at thread pool creation. FALLBACK_POLICIES = [:abort, :discard, :caller_runs].freeze # @!macro executor_service_attr_reader_fallback_policy attr_reader :fallback_policy # Create a new thread pool. def initialize(*args, &block) super(&nil) synchronize { ns_initialize(*args, &block) } end # @!macro executor_service_method_shutdown def shutdown raise NotImplementedError end # @!macro executor_service_method_kill def kill raise NotImplementedError end # @!macro executor_service_method_wait_for_termination def wait_for_termination(timeout = nil) raise NotImplementedError end # @!macro executor_service_method_running_question def running? synchronize { ns_running? } end # @!macro executor_service_method_shuttingdown_question def shuttingdown? synchronize { ns_shuttingdown? } end # @!macro executor_service_method_shutdown_question def shutdown? synchronize { ns_shutdown? } end # @!macro executor_service_method_auto_terminate_question def auto_terminate? synchronize { ns_auto_terminate? } end # @!macro executor_service_method_auto_terminate_setter def auto_terminate=(value) synchronize { self.ns_auto_terminate = value } end private # Handler which executes the `fallback_policy` once the queue size # reaches `max_queue`. # # @param [Array] args the arguments to the task which is being handled. # # @!visibility private def handle_fallback(*args) case fallback_policy when :abort raise RejectedExecutionError when :discard false when :caller_runs begin yield(*args) rescue => ex # let it fail log DEBUG, ex end true else fail "Unknown fallback policy #{fallback_policy}" end end def ns_execute(*args, &task) raise NotImplementedError end # @!macro [attach] executor_service_method_ns_shutdown_execution # # Callback method called when an orderly shutdown has completed. # The default behavior is to signal all waiting threads. def ns_shutdown_execution # do nothing end # @!macro [attach] executor_service_method_ns_kill_execution # # Callback method called when the executor has been killed. # The default behavior is to do nothing. def ns_kill_execution # do nothing end def ns_auto_terminate? !!@auto_terminate end def ns_auto_terminate=(value) case value when true AtExit.add(self) { terminate_at_exit } @auto_terminate = true when false AtExit.delete(self) @auto_terminate = false else raise ArgumentError end end def terminate_at_exit kill # TODO be gentle first wait_for_termination(10) end end end concurrent-ruby-1.0.5/lib/concurrent/executor/cached_thread_pool.rb000066400000000000000000000051241305460430400255610ustar00rootroot00000000000000require 'concurrent/utility/engine' require 'concurrent/executor/thread_pool_executor' module Concurrent # A thread pool that dynamically grows and shrinks to fit the current workload. # New threads are created as needed, existing threads are reused, and threads # that remain idle for too long are killed and removed from the pool. These # pools are particularly suited to applications that perform a high volume of # short-lived tasks. # # On creation a `CachedThreadPool` has zero running threads. New threads are # created on the pool as new operations are `#post`. The size of the pool # will grow until `#max_length` threads are in the pool or until the number # of threads exceeds the number of running and pending operations. When a new # operation is post to the pool the first available idle thread will be tasked # with the new operation. # # Should a thread crash for any reason the thread will immediately be removed # from the pool. Similarly, threads which remain idle for an extended period # of time will be killed and reclaimed. Thus these thread pools are very # efficient at reclaiming unused resources. # # The API and behavior of this class are based on Java's `CachedThreadPool` # # @!macro thread_pool_options class CachedThreadPool < ThreadPoolExecutor # @!macro [attach] cached_thread_pool_method_initialize # # Create a new thread pool. # # @param [Hash] opts the options defining pool behavior. # @option opts [Symbol] :fallback_policy (`:abort`) the fallback policy # # @raise [ArgumentError] if `fallback_policy` is not a known policy # # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newCachedThreadPool-- def initialize(opts = {}) defaults = { idletime: DEFAULT_THREAD_IDLETIMEOUT } overrides = { min_threads: 0, max_threads: DEFAULT_MAX_POOL_SIZE, max_queue: DEFAULT_MAX_QUEUE_SIZE } super(defaults.merge(opts).merge(overrides)) end private # @!macro cached_thread_pool_method_initialize # @!visibility private def ns_initialize(opts) super(opts) if Concurrent.on_jruby? @max_queue = 0 @executor = java.util.concurrent.Executors.newCachedThreadPool @executor.setRejectedExecutionHandler(FALLBACK_POLICY_CLASSES[@fallback_policy].new) @executor.setKeepAliveTime(opts.fetch(:idletime, DEFAULT_THREAD_IDLETIMEOUT), java.util.concurrent.TimeUnit::SECONDS) self.auto_terminate = opts.fetch(:auto_terminate, true) end end end end concurrent-ruby-1.0.5/lib/concurrent/executor/executor_service.rb000066400000000000000000000132301305460430400253450ustar00rootroot00000000000000require 'concurrent/concern/logging' module Concurrent ################################################################### # @!macro [new] executor_service_method_post # # Submit a task to the executor for asynchronous processing. # # @param [Array] args zero or more arguments to be passed to the task # # @yield the asynchronous task to perform # # @return [Boolean] `true` if the task is queued, `false` if the executor # is not running # # @raise [ArgumentError] if no task is given # @!macro [new] executor_service_method_left_shift # # Submit a task to the executor for asynchronous processing. # # @param [Proc] task the asynchronous task to perform # # @return [self] returns itself # @!macro [new] executor_service_method_can_overflow_question # # Does the task queue have a maximum size? # # @return [Boolean] True if the task queue has a maximum size else false. # @!macro [new] executor_service_method_serialized_question # # Does this executor guarantee serialization of its operations? # # @return [Boolean] True if the executor guarantees that all operations # will be post in the order they are received and no two operations may # occur simultaneously. Else false. ################################################################### # @!macro [new] executor_service_public_api # # @!method post(*args, &task) # @!macro executor_service_method_post # # @!method <<(task) # @!macro executor_service_method_left_shift # # @!method can_overflow? # @!macro executor_service_method_can_overflow_question # # @!method serialized? # @!macro executor_service_method_serialized_question ################################################################### # @!macro [new] executor_service_attr_reader_fallback_policy # @return [Symbol] The fallback policy in effect. Either `:abort`, `:discard`, or `:caller_runs`. # @!macro [new] executor_service_method_shutdown # # Begin an orderly shutdown. Tasks already in the queue will be executed, # but no new tasks will be accepted. Has no additional effect if the # thread pool is not running. # @!macro [new] executor_service_method_kill # # Begin an immediate shutdown. In-progress tasks will be allowed to # complete but enqueued tasks will be dismissed and no new tasks # will be accepted. Has no additional effect if the thread pool is # not running. # @!macro [new] executor_service_method_wait_for_termination # # Block until executor shutdown is complete or until `timeout` seconds have # passed. # # @note Does not initiate shutdown or termination. Either `shutdown` or `kill` # must be called before this method (or on another thread). # # @param [Integer] timeout the maximum number of seconds to wait for shutdown to complete # # @return [Boolean] `true` if shutdown complete or false on `timeout` # @!macro [new] executor_service_method_running_question # # Is the executor running? # # @return [Boolean] `true` when running, `false` when shutting down or shutdown # @!macro [new] executor_service_method_shuttingdown_question # # Is the executor shuttingdown? # # @return [Boolean] `true` when not running and not shutdown, else `false` # @!macro [new] executor_service_method_shutdown_question # # Is the executor shutdown? # # @return [Boolean] `true` when shutdown, `false` when shutting down or running # @!macro [new] executor_service_method_auto_terminate_question # # Is the executor auto-terminate when the application exits? # # @return [Boolean] `true` when auto-termination is enabled else `false`. # @!macro [new] executor_service_method_auto_terminate_setter # # Set the auto-terminate behavior for this executor. # # @param [Boolean] value The new auto-terminate value to set for this executor. # # @return [Boolean] `true` when auto-termination is enabled else `false`. ################################################################### # @!macro [new] abstract_executor_service_public_api # # @!macro executor_service_public_api # # @!attribute [r] fallback_policy # @!macro executor_service_attr_reader_fallback_policy # # @!method shutdown # @!macro executor_service_method_shutdown # # @!method kill # @!macro executor_service_method_kill # # @!method wait_for_termination(timeout = nil) # @!macro executor_service_method_wait_for_termination # # @!method running? # @!macro executor_service_method_running_question # # @!method shuttingdown? # @!macro executor_service_method_shuttingdown_question # # @!method shutdown? # @!macro executor_service_method_shutdown_question # # @!method auto_terminate? # @!macro executor_service_method_auto_terminate_question # # @!method auto_terminate=(value) # @!macro executor_service_method_auto_terminate_setter ################################################################### # @!macro executor_service_public_api # @!visibility private module ExecutorService include Concern::Logging # @!macro executor_service_method_post def post(*args, &task) raise NotImplementedError end # @!macro executor_service_method_left_shift def <<(task) post(&task) self end # @!macro executor_service_method_can_overflow_question # # @note Always returns `false` def can_overflow? false end # @!macro executor_service_method_serialized_question # # @note Always returns `false` def serialized? false end end end concurrent-ruby-1.0.5/lib/concurrent/executor/fixed_thread_pool.rb000066400000000000000000000231111305460430400254450ustar00rootroot00000000000000require 'concurrent/utility/engine' require 'concurrent/executor/thread_pool_executor' module Concurrent # @!macro [new] thread_pool_executor_constant_default_max_pool_size # Default maximum number of threads that will be created in the pool. # @!macro [new] thread_pool_executor_constant_default_min_pool_size # Default minimum number of threads that will be retained in the pool. # @!macro [new] thread_pool_executor_constant_default_max_queue_size # Default maximum number of tasks that may be added to the task queue. # @!macro [new] thread_pool_executor_constant_default_thread_timeout # Default maximum number of seconds a thread in the pool may remain idle # before being reclaimed. # @!macro [new] thread_pool_executor_attr_reader_max_length # The maximum number of threads that may be created in the pool. # @return [Integer] The maximum number of threads that may be created in the pool. # @!macro [new] thread_pool_executor_attr_reader_min_length # The minimum number of threads that may be retained in the pool. # @return [Integer] The minimum number of threads that may be retained in the pool. # @!macro [new] thread_pool_executor_attr_reader_largest_length # The largest number of threads that have been created in the pool since construction. # @return [Integer] The largest number of threads that have been created in the pool since construction. # @!macro [new] thread_pool_executor_attr_reader_scheduled_task_count # The number of tasks that have been scheduled for execution on the pool since construction. # @return [Integer] The number of tasks that have been scheduled for execution on the pool since construction. # @!macro [new] thread_pool_executor_attr_reader_completed_task_count # The number of tasks that have been completed by the pool since construction. # @return [Integer] The number of tasks that have been completed by the pool since construction. # @!macro [new] thread_pool_executor_attr_reader_idletime # The number of seconds that a thread may be idle before being reclaimed. # @return [Integer] The number of seconds that a thread may be idle before being reclaimed. # @!macro [new] thread_pool_executor_attr_reader_max_queue # The maximum number of tasks that may be waiting in the work queue at any one time. # When the queue size reaches `max_queue` subsequent tasks will be rejected in # accordance with the configured `fallback_policy`. # # @return [Integer] The maximum number of tasks that may be waiting in the work queue at any one time. # When the queue size reaches `max_queue` subsequent tasks will be rejected in # accordance with the configured `fallback_policy`. # @!macro [new] thread_pool_executor_attr_reader_length # The number of threads currently in the pool. # @return [Integer] The number of threads currently in the pool. # @!macro [new] thread_pool_executor_attr_reader_queue_length # The number of tasks in the queue awaiting execution. # @return [Integer] The number of tasks in the queue awaiting execution. # @!macro [new] thread_pool_executor_attr_reader_remaining_capacity # Number of tasks that may be enqueued before reaching `max_queue` and rejecting # new tasks. A value of -1 indicates that the queue may grow without bound. # # @return [Integer] Number of tasks that may be enqueued before reaching `max_queue` and rejecting # new tasks. A value of -1 indicates that the queue may grow without bound. # @!macro [new] thread_pool_executor_public_api # # @!macro abstract_executor_service_public_api # # @!attribute [r] max_length # @!macro thread_pool_executor_attr_reader_max_length # # @!attribute [r] min_length # @!macro thread_pool_executor_attr_reader_min_length # # @!attribute [r] largest_length # @!macro thread_pool_executor_attr_reader_largest_length # # @!attribute [r] scheduled_task_count # @!macro thread_pool_executor_attr_reader_scheduled_task_count # # @!attribute [r] completed_task_count # @!macro thread_pool_executor_attr_reader_completed_task_count # # @!attribute [r] idletime # @!macro thread_pool_executor_attr_reader_idletime # # @!attribute [r] max_queue # @!macro thread_pool_executor_attr_reader_max_queue # # @!attribute [r] length # @!macro thread_pool_executor_attr_reader_length # # @!attribute [r] queue_length # @!macro thread_pool_executor_attr_reader_queue_length # # @!attribute [r] remaining_capacity # @!macro thread_pool_executor_attr_reader_remaining_capacity # # @!method can_overflow? # @!macro executor_service_method_can_overflow_question # @!macro [new] thread_pool_options # # **Thread Pool Options** # # Thread pools support several configuration options: # # * `idletime`: The number of seconds that a thread may be idle before being reclaimed. # * `max_queue`: The maximum number of tasks that may be waiting in the work queue at # any one time. When the queue size reaches `max_queue` and no new threads can be created, # subsequent tasks will be rejected in accordance with the configured `fallback_policy`. # * `auto_terminate`: When true (default) an `at_exit` handler will be registered which # will stop the thread pool when the application exits. See below for more information # on shutting down thread pools. # * `fallback_policy`: The policy defining how rejected tasks are handled. # # Three fallback policies are supported: # # * `:abort`: Raise a `RejectedExecutionError` exception and discard the task. # * `:discard`: Discard the task and return false. # * `:caller_runs`: Execute the task on the calling thread. # # **Shutting Down Thread Pools** # # Killing a thread pool while tasks are still being processed, either by calling # the `#kill` method or at application exit, will have unpredictable results. There # is no way for the thread pool to know what resources are being used by the # in-progress tasks. When those tasks are killed the impact on those resources # cannot be predicted. The *best* practice is to explicitly shutdown all thread # pools using the provided methods: # # * Call `#shutdown` to initiate an orderly termination of all in-progress tasks # * Call `#wait_for_termination` with an appropriate timeout interval an allow # the orderly shutdown to complete # * Call `#kill` *only when* the thread pool fails to shutdown in the allotted time # # On some runtime platforms (most notably the JVM) the application will not # exit until all thread pools have been shutdown. To prevent applications from # "hanging" on exit all thread pools include an `at_exit` handler that will # stop the thread pool when the application exits. This handler uses a brute # force method to stop the pool and makes no guarantees regarding resources being # used by any tasks still running. Registration of this `at_exit` handler can be # prevented by setting the thread pool's constructor `:auto_terminate` option to # `false` when the thread pool is created. All thread pools support this option. # # ```ruby # pool1 = Concurrent::FixedThreadPool.new(5) # an `at_exit` handler will be registered # pool2 = Concurrent::FixedThreadPool.new(5, auto_terminate: false) # prevent `at_exit` handler registration # ``` # # @note Failure to properly shutdown a thread pool can lead to unpredictable results. # Please read *Shutting Down Thread Pools* for more information. # # @see http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html Java Tutorials: Thread Pools # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html Java Executors class # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html Java ExecutorService interface # @see http://ruby-doc.org//core-2.2.0/Kernel.html#method-i-at_exit Kernel#at_exit # @!macro [attach] fixed_thread_pool # # A thread pool that reuses a fixed number of threads operating off an unbounded queue. # At any point, at most `num_threads` will be active processing tasks. When all threads are busy new # tasks `#post` to the thread pool are enqueued until a thread becomes available. # Should a thread crash for any reason the thread will immediately be removed # from the pool and replaced. # # The API and behavior of this class are based on Java's `FixedThreadPool` # # @!macro thread_pool_options class FixedThreadPool < ThreadPoolExecutor # @!macro [attach] fixed_thread_pool_method_initialize # # Create a new thread pool. # # @param [Integer] num_threads the number of threads to allocate # @param [Hash] opts the options defining pool behavior. # @option opts [Symbol] :fallback_policy (`:abort`) the fallback policy # # @raise [ArgumentError] if `num_threads` is less than or equal to zero # @raise [ArgumentError] if `fallback_policy` is not a known policy # # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newFixedThreadPool-int- def initialize(num_threads, opts = {}) raise ArgumentError.new('number of threads must be greater than zero') if num_threads.to_i < 1 defaults = { max_queue: DEFAULT_MAX_QUEUE_SIZE, idletime: DEFAULT_THREAD_IDLETIMEOUT } overrides = { min_threads: num_threads, max_threads: num_threads } super(defaults.merge(opts).merge(overrides)) end end end concurrent-ruby-1.0.5/lib/concurrent/executor/immediate_executor.rb000066400000000000000000000034641305460430400256530ustar00rootroot00000000000000require 'concurrent/atomic/event' require 'concurrent/executor/abstract_executor_service' require 'concurrent/executor/serial_executor_service' module Concurrent # An executor service which runs all operations on the current thread, # blocking as necessary. Operations are performed in the order they are # received and no two operations can be performed simultaneously. # # This executor service exists mainly for testing an debugging. When used # it immediately runs every `#post` operation on the current thread, blocking # that thread until the operation is complete. This can be very beneficial # during testing because it makes all operations deterministic. # # @note Intended for use primarily in testing and debugging. class ImmediateExecutor < AbstractExecutorService include SerialExecutorService # Creates a new executor def initialize @stopped = Concurrent::Event.new end # @!macro executor_service_method_post def post(*args, &task) raise ArgumentError.new('no block given') unless block_given? return false unless running? task.call(*args) true end # @!macro executor_service_method_left_shift def <<(task) post(&task) self end # @!macro executor_service_method_running_question def running? ! shutdown? end # @!macro executor_service_method_shuttingdown_question def shuttingdown? false end # @!macro executor_service_method_shutdown_question def shutdown? @stopped.set? end # @!macro executor_service_method_shutdown def shutdown @stopped.set true end alias_method :kill, :shutdown # @!macro executor_service_method_wait_for_termination def wait_for_termination(timeout = nil) @stopped.wait(timeout) end end end concurrent-ruby-1.0.5/lib/concurrent/executor/indirect_immediate_executor.rb000066400000000000000000000030501305460430400275230ustar00rootroot00000000000000require 'concurrent/executor/immediate_executor' require 'concurrent/executor/simple_executor_service' module Concurrent # An executor service which runs all operations on a new thread, blocking # until it completes. Operations are performed in the order they are received # and no two operations can be performed simultaneously. # # This executor service exists mainly for testing an debugging. When used it # immediately runs every `#post` operation on a new thread, blocking the # current thread until the operation is complete. This is similar to how the # ImmediateExecutor works, but the operation has the full stack of the new # thread at its disposal. This can be helpful when the operations will spawn # more operations on the same executor and so on - such a situation might # overflow the single stack in case of an ImmediateExecutor, which is # inconsistent with how it would behave for a threaded executor. # # @note Intended for use primarily in testing and debugging. class IndirectImmediateExecutor < ImmediateExecutor # Creates a new executor def initialize super @internal_executor = SimpleExecutorService.new end # @!macro executor_service_method_post def post(*args, &task) raise ArgumentError.new("no block given") unless block_given? return false unless running? event = Concurrent::Event.new @internal_executor.post do begin task.call(*args) ensure event.set end end event.wait true end end end concurrent-ruby-1.0.5/lib/concurrent/executor/java_executor_service.rb000066400000000000000000000050001305460430400263420ustar00rootroot00000000000000if Concurrent.on_jruby? require 'concurrent/errors' require 'concurrent/utility/engine' require 'concurrent/executor/abstract_executor_service' module Concurrent # @!macro abstract_executor_service_public_api # @!visibility private class JavaExecutorService < AbstractExecutorService java_import 'java.lang.Runnable' FALLBACK_POLICY_CLASSES = { abort: java.util.concurrent.ThreadPoolExecutor::AbortPolicy, discard: java.util.concurrent.ThreadPoolExecutor::DiscardPolicy, caller_runs: java.util.concurrent.ThreadPoolExecutor::CallerRunsPolicy }.freeze private_constant :FALLBACK_POLICY_CLASSES def initialize(*args, &block) super ns_make_executor_runnable end def post(*args, &task) raise ArgumentError.new('no block given') unless block_given? return handle_fallback(*args, &task) unless running? @executor.submit_runnable Job.new(args, task) true rescue Java::JavaUtilConcurrent::RejectedExecutionException raise RejectedExecutionError end def wait_for_termination(timeout = nil) if timeout.nil? ok = @executor.awaitTermination(60, java.util.concurrent.TimeUnit::SECONDS) until ok true else @executor.awaitTermination(1000 * timeout, java.util.concurrent.TimeUnit::MILLISECONDS) end end def shutdown synchronize do self.ns_auto_terminate = false @executor.shutdown nil end end def kill synchronize do self.ns_auto_terminate = false @executor.shutdownNow nil end end private def ns_running? !(ns_shuttingdown? || ns_shutdown?) end def ns_shuttingdown? if @executor.respond_to? :isTerminating @executor.isTerminating else false end end def ns_shutdown? @executor.isShutdown || @executor.isTerminated end def ns_make_executor_runnable if !defined?(@executor.submit_runnable) @executor.class.class_eval do java_alias :submit_runnable, :submit, [java.lang.Runnable.java_class] end end end class Job include Runnable def initialize(args, block) @args = args @block = block end def run @block.call(*@args) end end private_constant :Job end end end concurrent-ruby-1.0.5/lib/concurrent/executor/java_single_thread_executor.rb000066400000000000000000000016271305460430400275250ustar00rootroot00000000000000if Concurrent.on_jruby? require 'concurrent/executor/java_executor_service' require 'concurrent/executor/serial_executor_service' module Concurrent # @!macro single_thread_executor # @!macro abstract_executor_service_public_api # @!visibility private class JavaSingleThreadExecutor < JavaExecutorService include SerialExecutorService # @!macro single_thread_executor_method_initialize def initialize(opts = {}) super(opts) end private def ns_initialize(opts) @executor = java.util.concurrent.Executors.newSingleThreadExecutor @fallback_policy = opts.fetch(:fallback_policy, :discard) raise ArgumentError.new("#{@fallback_policy} is not a valid fallback policy") unless FALLBACK_POLICY_CLASSES.keys.include?(@fallback_policy) self.auto_terminate = opts.fetch(:auto_terminate, true) end end end end concurrent-ruby-1.0.5/lib/concurrent/executor/java_thread_pool_executor.rb000066400000000000000000000077671305460430400272300ustar00rootroot00000000000000if Concurrent.on_jruby? require 'concurrent/executor/java_executor_service' module Concurrent # @!macro thread_pool_executor # @!macro thread_pool_options # @!visibility private class JavaThreadPoolExecutor < JavaExecutorService # @!macro thread_pool_executor_constant_default_max_pool_size DEFAULT_MAX_POOL_SIZE = java.lang.Integer::MAX_VALUE # 2147483647 # @!macro thread_pool_executor_constant_default_min_pool_size DEFAULT_MIN_POOL_SIZE = 0 # @!macro thread_pool_executor_constant_default_max_queue_size DEFAULT_MAX_QUEUE_SIZE = 0 # @!macro thread_pool_executor_constant_default_thread_timeout DEFAULT_THREAD_IDLETIMEOUT = 60 # @!macro thread_pool_executor_attr_reader_max_length attr_reader :max_length # @!macro thread_pool_executor_attr_reader_max_queue attr_reader :max_queue # @!macro thread_pool_executor_method_initialize def initialize(opts = {}) super(opts) end # @!macro executor_service_method_can_overflow_question def can_overflow? @max_queue != 0 end # @!macro thread_pool_executor_attr_reader_min_length def min_length @executor.getCorePoolSize end # @!macro thread_pool_executor_attr_reader_max_length def max_length @executor.getMaximumPoolSize end # @!macro thread_pool_executor_attr_reader_length def length @executor.getPoolSize end # @!macro thread_pool_executor_attr_reader_largest_length def largest_length @executor.getLargestPoolSize end # @!macro thread_pool_executor_attr_reader_scheduled_task_count def scheduled_task_count @executor.getTaskCount end # @!macro thread_pool_executor_attr_reader_completed_task_count def completed_task_count @executor.getCompletedTaskCount end # @!macro thread_pool_executor_attr_reader_idletime def idletime @executor.getKeepAliveTime(java.util.concurrent.TimeUnit::SECONDS) end # @!macro thread_pool_executor_attr_reader_queue_length def queue_length @executor.getQueue.size end # @!macro thread_pool_executor_attr_reader_remaining_capacity def remaining_capacity @max_queue == 0 ? -1 : @executor.getQueue.remainingCapacity end # @!macro executor_service_method_running_question def running? super && !@executor.isTerminating end private def ns_initialize(opts) min_length = opts.fetch(:min_threads, DEFAULT_MIN_POOL_SIZE).to_i max_length = opts.fetch(:max_threads, DEFAULT_MAX_POOL_SIZE).to_i idletime = opts.fetch(:idletime, DEFAULT_THREAD_IDLETIMEOUT).to_i @max_queue = opts.fetch(:max_queue, DEFAULT_MAX_QUEUE_SIZE).to_i @fallback_policy = opts.fetch(:fallback_policy, :abort) raise ArgumentError.new("`max_threads` cannot be less than #{DEFAULT_MIN_POOL_SIZE}") if max_length < DEFAULT_MIN_POOL_SIZE raise ArgumentError.new("`max_threads` cannot be greater than #{DEFAULT_MAX_POOL_SIZE}") if max_length > DEFAULT_MAX_POOL_SIZE raise ArgumentError.new("`min_threads` cannot be less than #{DEFAULT_MIN_POOL_SIZE}") if min_length < DEFAULT_MIN_POOL_SIZE raise ArgumentError.new("`min_threads` cannot be more than `max_threads`") if min_length > max_length raise ArgumentError.new("#{fallback_policy} is not a valid fallback policy") unless FALLBACK_POLICY_CLASSES.include?(@fallback_policy) if @max_queue == 0 queue = java.util.concurrent.LinkedBlockingQueue.new else queue = java.util.concurrent.LinkedBlockingQueue.new(@max_queue) end @executor = java.util.concurrent.ThreadPoolExecutor.new( min_length, max_length, idletime, java.util.concurrent.TimeUnit::SECONDS, queue, FALLBACK_POLICY_CLASSES[@fallback_policy].new) self.auto_terminate = opts.fetch(:auto_terminate, true) end end end end concurrent-ruby-1.0.5/lib/concurrent/executor/ruby_executor_service.rb000066400000000000000000000027631305460430400264170ustar00rootroot00000000000000require 'concurrent/executor/abstract_executor_service' require 'concurrent/atomic/event' module Concurrent # @!macro abstract_executor_service_public_api # @!visibility private class RubyExecutorService < AbstractExecutorService safe_initialization! def initialize(*args, &block) super @StopEvent = Event.new @StoppedEvent = Event.new end def post(*args, &task) raise ArgumentError.new('no block given') unless block_given? synchronize do # If the executor is shut down, reject this task return handle_fallback(*args, &task) unless running? ns_execute(*args, &task) true end end def shutdown synchronize do break unless running? self.ns_auto_terminate = false stop_event.set ns_shutdown_execution end true end def kill synchronize do break if shutdown? self.ns_auto_terminate = false stop_event.set ns_kill_execution stopped_event.set end true end def wait_for_termination(timeout = nil) stopped_event.wait(timeout) end private def stop_event @StopEvent end def stopped_event @StoppedEvent end def ns_shutdown_execution stopped_event.set end def ns_running? !stop_event.set? end def ns_shuttingdown? !(ns_running? || ns_shutdown?) end def ns_shutdown? stopped_event.set? end end end concurrent-ruby-1.0.5/lib/concurrent/executor/ruby_single_thread_executor.rb000066400000000000000000000011371305460430400275610ustar00rootroot00000000000000require 'concurrent/executor/ruby_thread_pool_executor' module Concurrent # @!macro single_thread_executor # @!macro abstract_executor_service_public_api # @!visibility private class RubySingleThreadExecutor < RubyThreadPoolExecutor # @!macro single_thread_executor_method_initialize def initialize(opts = {}) super( min_threads: 1, max_threads: 1, max_queue: 0, idletime: DEFAULT_THREAD_IDLETIMEOUT, fallback_policy: opts.fetch(:fallback_policy, :discard), auto_terminate: opts.fetch(:auto_terminate, true) ) end end end concurrent-ruby-1.0.5/lib/concurrent/executor/ruby_thread_pool_executor.rb000066400000000000000000000237511305460430400272570ustar00rootroot00000000000000require 'thread' require 'concurrent/atomic/event' require 'concurrent/concern/logging' require 'concurrent/executor/ruby_executor_service' require 'concurrent/utility/monotonic_time' module Concurrent # @!macro thread_pool_executor # @!macro thread_pool_options # @!visibility private class RubyThreadPoolExecutor < RubyExecutorService # @!macro thread_pool_executor_constant_default_max_pool_size DEFAULT_MAX_POOL_SIZE = 2_147_483_647 # java.lang.Integer::MAX_VALUE # @!macro thread_pool_executor_constant_default_min_pool_size DEFAULT_MIN_POOL_SIZE = 0 # @!macro thread_pool_executor_constant_default_max_queue_size DEFAULT_MAX_QUEUE_SIZE = 0 # @!macro thread_pool_executor_constant_default_thread_timeout DEFAULT_THREAD_IDLETIMEOUT = 60 # @!macro thread_pool_executor_attr_reader_max_length attr_reader :max_length # @!macro thread_pool_executor_attr_reader_min_length attr_reader :min_length # @!macro thread_pool_executor_attr_reader_idletime attr_reader :idletime # @!macro thread_pool_executor_attr_reader_max_queue attr_reader :max_queue # @!macro thread_pool_executor_method_initialize def initialize(opts = {}) super(opts) end # @!macro thread_pool_executor_attr_reader_largest_length def largest_length synchronize { @largest_length } end # @!macro thread_pool_executor_attr_reader_scheduled_task_count def scheduled_task_count synchronize { @scheduled_task_count } end # @!macro thread_pool_executor_attr_reader_completed_task_count def completed_task_count synchronize { @completed_task_count } end # @!macro executor_service_method_can_overflow_question def can_overflow? synchronize { ns_limited_queue? } end # @!macro thread_pool_executor_attr_reader_length def length synchronize { @pool.length } end # @!macro thread_pool_executor_attr_reader_queue_length def queue_length synchronize { @queue.length } end # @!macro thread_pool_executor_attr_reader_remaining_capacity def remaining_capacity synchronize do if ns_limited_queue? @max_queue - @queue.length else -1 end end end # @!visibility private def remove_busy_worker(worker) synchronize { ns_remove_busy_worker worker } end # @!visibility private def ready_worker(worker) synchronize { ns_ready_worker worker } end # @!visibility private def worker_not_old_enough(worker) synchronize { ns_worker_not_old_enough worker } end # @!visibility private def worker_died(worker) synchronize { ns_worker_died worker } end # @!visibility private def worker_task_completed synchronize { @completed_task_count += 1 } end private # @!visibility private def ns_initialize(opts) @min_length = opts.fetch(:min_threads, DEFAULT_MIN_POOL_SIZE).to_i @max_length = opts.fetch(:max_threads, DEFAULT_MAX_POOL_SIZE).to_i @idletime = opts.fetch(:idletime, DEFAULT_THREAD_IDLETIMEOUT).to_i @max_queue = opts.fetch(:max_queue, DEFAULT_MAX_QUEUE_SIZE).to_i @fallback_policy = opts.fetch(:fallback_policy, :abort) raise ArgumentError.new("#{@fallback_policy} is not a valid fallback policy") unless FALLBACK_POLICIES.include?(@fallback_policy) raise ArgumentError.new("`max_threads` cannot be less than #{DEFAULT_MIN_POOL_SIZE}") if @max_length < DEFAULT_MIN_POOL_SIZE raise ArgumentError.new("`max_threads` cannot be greater than #{DEFAULT_MAX_POOL_SIZE}") if @max_length > DEFAULT_MAX_POOL_SIZE raise ArgumentError.new("`min_threads` cannot be less than #{DEFAULT_MIN_POOL_SIZE}") if @min_length < DEFAULT_MIN_POOL_SIZE raise ArgumentError.new("`min_threads` cannot be more than `max_threads`") if min_length > max_length self.auto_terminate = opts.fetch(:auto_terminate, true) @pool = [] # all workers @ready = [] # used as a stash (most idle worker is at the start) @queue = [] # used as queue # @ready or @queue is empty at all times @scheduled_task_count = 0 @completed_task_count = 0 @largest_length = 0 @ruby_pid = $$ # detects if Ruby has forked @gc_interval = opts.fetch(:gc_interval, @idletime / 2.0).to_i # undocumented @next_gc_time = Concurrent.monotonic_time + @gc_interval end # @!visibility private def ns_limited_queue? @max_queue != 0 end # @!visibility private def ns_execute(*args, &task) ns_reset_if_forked if ns_assign_worker(*args, &task) || ns_enqueue(*args, &task) @scheduled_task_count += 1 else handle_fallback(*args, &task) end ns_prune_pool if @next_gc_time < Concurrent.monotonic_time end # @!visibility private def ns_shutdown_execution ns_reset_if_forked if @pool.empty? # nothing to do stopped_event.set end if @queue.empty? # no more tasks will be accepted, just stop all workers @pool.each(&:stop) end end # @!visibility private def ns_kill_execution # TODO log out unprocessed tasks in queue # TODO try to shutdown first? @pool.each(&:kill) @pool.clear @ready.clear end # tries to assign task to a worker, tries to get one from @ready or to create new one # @return [true, false] if task is assigned to a worker # # @!visibility private def ns_assign_worker(*args, &task) # keep growing if the pool is not at the minimum yet worker = (@ready.pop if @pool.size >= @min_length) || ns_add_busy_worker if worker worker << [task, args] true else false end rescue ThreadError # Raised when the operating system refuses to create the new thread return false end # tries to enqueue task # @return [true, false] if enqueued # # @!visibility private def ns_enqueue(*args, &task) if !ns_limited_queue? || @queue.size < @max_queue @queue << [task, args] true else false end end # @!visibility private def ns_worker_died(worker) ns_remove_busy_worker worker replacement_worker = ns_add_busy_worker ns_ready_worker replacement_worker, false if replacement_worker end # creates new worker which has to receive work to do after it's added # @return [nil, Worker] nil of max capacity is reached # # @!visibility private def ns_add_busy_worker return if @pool.size >= @max_length @pool << (worker = Worker.new(self)) @largest_length = @pool.length if @pool.length > @largest_length worker end # handle ready worker, giving it new job or assigning back to @ready # # @!visibility private def ns_ready_worker(worker, success = true) task_and_args = @queue.shift if task_and_args worker << task_and_args else # stop workers when !running?, do not return them to @ready if running? @ready.push(worker) else worker.stop end end end # returns back worker to @ready which was not idle for enough time # # @!visibility private def ns_worker_not_old_enough(worker) # let's put workers coming from idle_test back to the start (as the oldest worker) @ready.unshift(worker) true end # removes a worker which is not in not tracked in @ready # # @!visibility private def ns_remove_busy_worker(worker) @pool.delete(worker) stopped_event.set if @pool.empty? && !running? true end # try oldest worker if it is idle for enough time, it's returned back at the start # # @!visibility private def ns_prune_pool return if @pool.size <= @min_length last_used = @ready.shift last_used << :idle_test if last_used @next_gc_time = Concurrent.monotonic_time + @gc_interval end def ns_reset_if_forked if $$ != @ruby_pid @queue.clear @ready.clear @pool.clear @scheduled_task_count = 0 @completed_task_count = 0 @largest_length = 0 @ruby_pid = $$ end end # @!visibility private class Worker include Concern::Logging def initialize(pool) # instance variables accessed only under pool's lock so no need to sync here again @queue = Queue.new @pool = pool @thread = create_worker @queue, pool, pool.idletime end def <<(message) @queue << message end def stop @queue << :stop end def kill @thread.kill end private def create_worker(queue, pool, idletime) Thread.new(queue, pool, idletime) do |my_queue, my_pool, my_idletime| last_message = Concurrent.monotonic_time catch(:stop) do loop do case message = my_queue.pop when :idle_test if (Concurrent.monotonic_time - last_message) > my_idletime my_pool.remove_busy_worker(self) throw :stop else my_pool.worker_not_old_enough(self) end when :stop my_pool.remove_busy_worker(self) throw :stop else task, args = message run_task my_pool, task, args last_message = Concurrent.monotonic_time my_pool.ready_worker(self) end end end end end def run_task(pool, task, args) task.call(*args) pool.worker_task_completed rescue => ex # let it fail log DEBUG, ex rescue Exception => ex log ERROR, ex pool.worker_died(self) throw :stop end end private_constant :Worker end end concurrent-ruby-1.0.5/lib/concurrent/executor/safe_task_executor.rb000066400000000000000000000020141305460430400256430ustar00rootroot00000000000000require 'concurrent/synchronization' module Concurrent # A simple utility class that executes a callable and returns and array of three elements: # success - indicating if the callable has been executed without errors # value - filled by the callable result if it has been executed without errors, nil otherwise # reason - the error risen by the callable if it has been executed with errors, nil otherwise class SafeTaskExecutor < Synchronization::LockableObject def initialize(task, opts = {}) @task = task @exception_class = opts.fetch(:rescue_exception, false) ? Exception : StandardError super() # ensures visibility end # @return [Array] def execute(*args) synchronize do success = false value = reason = nil begin value = @task.call(*args) success = true rescue @exception_class => ex reason = ex success = false end [success, value, reason] end end end end concurrent-ruby-1.0.5/lib/concurrent/executor/serial_executor_service.rb000066400000000000000000000017371305460430400267150ustar00rootroot00000000000000require 'concurrent/executor/executor_service' module Concurrent # Indicates that the including `ExecutorService` guarantees # that all operations will occur in the order they are post and that no # two operations may occur simultaneously. This module provides no # functionality and provides no guarantees. That is the responsibility # of the including class. This module exists solely to allow the including # object to be interrogated for its serialization status. # # @example # class Foo # include Concurrent::SerialExecutor # end # # foo = Foo.new # # foo.is_a? Concurrent::ExecutorService #=> true # foo.is_a? Concurrent::SerialExecutor #=> true # foo.serialized? #=> true # # @!visibility private module SerialExecutorService include ExecutorService # @!macro executor_service_method_serialized_question # # @note Always returns `true` def serialized? true end end end concurrent-ruby-1.0.5/lib/concurrent/executor/serialized_execution.rb000066400000000000000000000053571305460430400262200ustar00rootroot00000000000000require 'concurrent/errors' require 'concurrent/concern/logging' require 'concurrent/synchronization' module Concurrent # Ensures passed jobs in a serialized order never running at the same time. class SerializedExecution < Synchronization::LockableObject include Concern::Logging def initialize() super() synchronize { ns_initialize } end Job = Struct.new(:executor, :args, :block) do def call block.call(*args) end end # Submit a task to the executor for asynchronous processing. # # @param [Executor] executor to be used for this job # # @param [Array] args zero or more arguments to be passed to the task # # @yield the asynchronous task to perform # # @return [Boolean] `true` if the task is queued, `false` if the executor # is not running # # @raise [ArgumentError] if no task is given def post(executor, *args, &task) posts [[executor, args, task]] true end # As {#post} but allows to submit multiple tasks at once, it's guaranteed that they will not # be interleaved by other tasks. # # @param [Array, Proc)>] posts array of triplets where # first is a {ExecutorService}, second is array of args for task, third is a task (Proc) def posts(posts) # if can_overflow? # raise ArgumentError, 'SerializedExecution does not support thread-pools which can overflow' # end return nil if posts.empty? jobs = posts.map { |executor, args, task| Job.new executor, args, task } job_to_post = synchronize do if @being_executed @stash.push(*jobs) nil else @being_executed = true @stash.push(*jobs[1..-1]) jobs.first end end call_job job_to_post if job_to_post true end private def ns_initialize @being_executed = false @stash = [] end def call_job(job) did_it_run = begin job.executor.post { work(job) } true rescue RejectedExecutionError => ex false end # TODO not the best idea to run it myself unless did_it_run begin work job rescue => ex # let it fail log DEBUG, ex end end end # ensures next job is executed if any is stashed def work(job) job.call ensure synchronize do job = @stash.shift || (@being_executed = false) end # TODO maybe be able to tell caching pool to just enqueue this job, because the current one end at the end # of this block call_job job if job end end end concurrent-ruby-1.0.5/lib/concurrent/executor/serialized_execution_delegator.rb000066400000000000000000000015331305460430400302360ustar00rootroot00000000000000require 'delegate' require 'concurrent/executor/serial_executor_service' require 'concurrent/executor/serialized_execution' module Concurrent # A wrapper/delegator for any `ExecutorService` that # guarantees serialized execution of tasks. # # @see [SimpleDelegator](http://www.ruby-doc.org/stdlib-2.1.2/libdoc/delegate/rdoc/SimpleDelegator.html) # @see Concurrent::SerializedExecution class SerializedExecutionDelegator < SimpleDelegator include SerialExecutorService def initialize(executor) @executor = executor @serializer = SerializedExecution.new super(executor) end # @!macro executor_service_method_post def post(*args, &task) raise ArgumentError.new('no block given') unless block_given? return false unless running? @serializer.post(@executor, *args, &task) end end end concurrent-ruby-1.0.5/lib/concurrent/executor/simple_executor_service.rb000066400000000000000000000051131305460430400267170ustar00rootroot00000000000000require 'concurrent/atomics' require 'concurrent/executor/executor_service' module Concurrent # An executor service in which every operation spawns a new, # independently operating thread. # # This is perhaps the most inefficient executor service in this # library. It exists mainly for testing an debugging. Thread creation # and management is expensive in Ruby and this executor performs no # resource pooling. This can be very beneficial during testing and # debugging because it decouples the using code from the underlying # executor implementation. In production this executor will likely # lead to suboptimal performance. # # @note Intended for use primarily in testing and debugging. class SimpleExecutorService < RubyExecutorService # @!macro executor_service_method_post def self.post(*args) raise ArgumentError.new('no block given') unless block_given? Thread.new(*args) do Thread.current.abort_on_exception = false yield(*args) end true end # @!macro executor_service_method_left_shift def self.<<(task) post(&task) self end # @!macro executor_service_method_post def post(*args, &task) raise ArgumentError.new('no block given') unless block_given? return false unless running? @count.increment Thread.new(*args) do Thread.current.abort_on_exception = false begin yield(*args) ensure @count.decrement @stopped.set if @running.false? && @count.value == 0 end end end # @!macro executor_service_method_left_shift def <<(task) post(&task) self end # @!macro executor_service_method_running_question def running? @running.true? end # @!macro executor_service_method_shuttingdown_question def shuttingdown? @running.false? && ! @stopped.set? end # @!macro executor_service_method_shutdown_question def shutdown? @stopped.set? end # @!macro executor_service_method_shutdown def shutdown @running.make_false @stopped.set if @count.value == 0 true end # @!macro executor_service_method_kill def kill @running.make_false @stopped.set true end # @!macro executor_service_method_wait_for_termination def wait_for_termination(timeout = nil) @stopped.wait(timeout) end private def ns_initialize @running = Concurrent::AtomicBoolean.new(true) @stopped = Concurrent::Event.new @count = Concurrent::AtomicFixnum.new(0) end end end concurrent-ruby-1.0.5/lib/concurrent/executor/single_thread_executor.rb000066400000000000000000000047351305460430400265270ustar00rootroot00000000000000require 'concurrent/executor/ruby_single_thread_executor' module Concurrent if Concurrent.on_jruby? require 'concurrent/executor/java_single_thread_executor' end SingleThreadExecutorImplementation = case when Concurrent.on_jruby? JavaSingleThreadExecutor else RubySingleThreadExecutor end private_constant :SingleThreadExecutorImplementation # @!macro [attach] single_thread_executor # # A thread pool with a single thread an unlimited queue. Should the thread # die for any reason it will be removed and replaced, thus ensuring that # the executor will always remain viable and available to process jobs. # # A common pattern for background processing is to create a single thread # on which an infinite loop is run. The thread's loop blocks on an input # source (perhaps blocking I/O or a queue) and processes each input as it # is received. This pattern has several issues. The thread itself is highly # susceptible to errors during processing. Also, the thread itself must be # constantly monitored and restarted should it die. `SingleThreadExecutor` # encapsulates all these bahaviors. The task processor is highly resilient # to errors from within tasks. Also, should the thread die it will # automatically be restarted. # # The API and behavior of this class are based on Java's `SingleThreadExecutor`. # # @!macro abstract_executor_service_public_api class SingleThreadExecutor < SingleThreadExecutorImplementation # @!macro [new] single_thread_executor_method_initialize # # Create a new thread pool. # # @option opts [Symbol] :fallback_policy (:discard) the policy for handling new # tasks that are received when the queue size has reached # `max_queue` or the executor has shut down # # @raise [ArgumentError] if `:fallback_policy` is not one of the values specified # in `FALLBACK_POLICIES` # # @see http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html # @!method initialize(opts = {}) # @!macro single_thread_executor_method_initialize end end concurrent-ruby-1.0.5/lib/concurrent/executor/thread_pool_executor.rb000066400000000000000000000103041305460430400262040ustar00rootroot00000000000000require 'concurrent/utility/engine' require 'concurrent/executor/ruby_thread_pool_executor' module Concurrent if Concurrent.on_jruby? require 'concurrent/executor/java_thread_pool_executor' end ThreadPoolExecutorImplementation = case when Concurrent.on_jruby? JavaThreadPoolExecutor else RubyThreadPoolExecutor end private_constant :ThreadPoolExecutorImplementation # @!macro [attach] thread_pool_executor # # An abstraction composed of one or more threads and a task queue. Tasks # (blocks or `proc` objects) are submitted to the pool and added to the queue. # The threads in the pool remove the tasks and execute them in the order # they were received. # # A `ThreadPoolExecutor` will automatically adjust the pool size according # to the bounds set by `min-threads` and `max-threads`. When a new task is # submitted and fewer than `min-threads` threads are running, a new thread # is created to handle the request, even if other worker threads are idle. # If there are more than `min-threads` but less than `max-threads` threads # running, a new thread will be created only if the queue is full. # # Threads that are idle for too long will be garbage collected, down to the # configured minimum options. Should a thread crash it, too, will be garbage collected. # # `ThreadPoolExecutor` is based on the Java class of the same name. From # the official Java documentation; # # > Thread pools address two different problems: they usually provide # > improved performance when executing large numbers of asynchronous tasks, # > due to reduced per-task invocation overhead, and they provide a means # > of bounding and managing the resources, including threads, consumed # > when executing a collection of tasks. Each ThreadPoolExecutor also # > maintains some basic statistics, such as the number of completed tasks. # > # > To be useful across a wide range of contexts, this class provides many # > adjustable parameters and extensibility hooks. However, programmers are # > urged to use the more convenient Executors factory methods # > [CachedThreadPool] (unbounded thread pool, with automatic thread reclamation), # > [FixedThreadPool] (fixed size thread pool) and [SingleThreadExecutor] (single # > background thread), that preconfigure settings for the most common usage # > scenarios. # # @!macro thread_pool_options # # @!macro thread_pool_executor_public_api class ThreadPoolExecutor < ThreadPoolExecutorImplementation # @!macro [new] thread_pool_executor_method_initialize # # Create a new thread pool. # # @param [Hash] opts the options which configure the thread pool. # # @option opts [Integer] :max_threads (DEFAULT_MAX_POOL_SIZE) the maximum # number of threads to be created # @option opts [Integer] :min_threads (DEFAULT_MIN_POOL_SIZE) When a new task is submitted # and fewer than `min_threads` are running, a new thread is created # @option opts [Integer] :idletime (DEFAULT_THREAD_IDLETIMEOUT) the maximum # number of seconds a thread may be idle before being reclaimed # @option opts [Integer] :max_queue (DEFAULT_MAX_QUEUE_SIZE) the maximum # number of tasks allowed in the work queue at any one time; a value of # zero means the queue may grow without bound # @option opts [Symbol] :fallback_policy (:abort) the policy for handling new # tasks that are received when the queue size has reached # `max_queue` or the executor has shut down # # @raise [ArgumentError] if `:max_threads` is less than one # @raise [ArgumentError] if `:min_threads` is less than zero # @raise [ArgumentError] if `:fallback_policy` is not one of the values specified # in `FALLBACK_POLICIES` # # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html # @!method initialize(opts = {}) # @!macro thread_pool_executor_method_initialize end end concurrent-ruby-1.0.5/lib/concurrent/executor/timer_set.rb000066400000000000000000000136571305460430400237770ustar00rootroot00000000000000require 'concurrent/scheduled_task' require 'concurrent/atomic/event' require 'concurrent/collection/non_concurrent_priority_queue' require 'concurrent/executor/executor_service' require 'concurrent/executor/single_thread_executor' require 'concurrent/options' module Concurrent # Executes a collection of tasks, each after a given delay. A master task # monitors the set and schedules each task for execution at the appropriate # time. Tasks are run on the global thread pool or on the supplied executor. # Each task is represented as a `ScheduledTask`. # # @see Concurrent::ScheduledTask # # @!macro monotonic_clock_warning class TimerSet < RubyExecutorService # Create a new set of timed tasks. # # @!macro [attach] executor_options # # @param [Hash] opts the options used to specify the executor on which to perform actions # @option opts [Executor] :executor when set use the given `Executor` instance. # Three special values are also supported: `:task` returns the global task pool, # `:operation` returns the global operation pool, and `:immediate` returns a new # `ImmediateExecutor` object. def initialize(opts = {}) super(opts) end # Post a task to be execute run after a given delay (in seconds). If the # delay is less than 1/100th of a second the task will be immediately post # to the executor. # # @param [Float] delay the number of seconds to wait for before executing the task. # @param [Array] args the arguments passed to the task on execution. # # @yield the task to be performed. # # @return [Concurrent::ScheduledTask, false] IVar representing the task if the post # is successful; false after shutdown. # # @raise [ArgumentError] if the intended execution time is not in the future. # @raise [ArgumentError] if no block is given. def post(delay, *args, &task) raise ArgumentError.new('no block given') unless block_given? return false unless running? opts = { executor: @task_executor, args: args, timer_set: self } task = ScheduledTask.execute(delay, opts, &task) # may raise exception task.unscheduled? ? false : task end # Begin an immediate shutdown. In-progress tasks will be allowed to # complete but enqueued tasks will be dismissed and no new tasks # will be accepted. Has no additional effect if the thread pool is # not running. def kill shutdown end private :<< private # Initialize the object. # # @param [Hash] opts the options to create the object with. # @!visibility private def ns_initialize(opts) @queue = Collection::NonConcurrentPriorityQueue.new(order: :min) @task_executor = Options.executor_from_options(opts) || Concurrent.global_io_executor @timer_executor = SingleThreadExecutor.new @condition = Event.new @ruby_pid = $$ # detects if Ruby has forked self.auto_terminate = opts.fetch(:auto_terminate, true) end # Post the task to the internal queue. # # @note This is intended as a callback method from ScheduledTask # only. It is not intended to be used directly. Post a task # by using the `SchedulesTask#execute` method. # # @!visibility private def post_task(task) synchronize{ ns_post_task(task) } end # @!visibility private def ns_post_task(task) return false unless ns_running? ns_reset_if_forked if (task.initial_delay) <= 0.01 task.executor.post{ task.process_task } else @queue.push(task) # only post the process method when the queue is empty @timer_executor.post(&method(:process_tasks)) if @queue.length == 1 @condition.set end true end # Remove the given task from the queue. # # @note This is intended as a callback method from `ScheduledTask` # only. It is not intended to be used directly. Cancel a task # by using the `ScheduledTask#cancel` method. # # @!visibility private def remove_task(task) synchronize{ @queue.delete(task) } end # `ExecutorService` callback called during shutdown. # # @!visibility private def ns_shutdown_execution ns_reset_if_forked @queue.clear @timer_executor.kill stopped_event.set end def ns_reset_if_forked if $$ != @ruby_pid @queue.clear @condition.reset @ruby_pid = $$ end end # Run a loop and execute tasks in the scheduled order and at the approximate # scheduled time. If no tasks remain the thread will exit gracefully so that # garbage collection can occur. If there are no ready tasks it will sleep # for up to 60 seconds waiting for the next scheduled task. # # @!visibility private def process_tasks loop do task = synchronize { @condition.reset; @queue.peek } break unless task now = Concurrent.monotonic_time diff = task.schedule_time - now if diff <= 0 # We need to remove the task from the queue before passing # it to the executor, to avoid race conditions where we pass # the peek'ed task to the executor and then pop a different # one that's been added in the meantime. # # Note that there's no race condition between the peek and # this pop - this pop could retrieve a different task from # the peek, but that task would be due to fire now anyway # (because @queue is a priority queue, and this thread is # the only reader, so whatever timer is at the head of the # queue now must have the same pop time, or a closer one, as # when we peeked). task = synchronize { @queue.pop } task.executor.post{ task.process_task } else @condition.wait([diff, 60].min) end end end end end concurrent-ruby-1.0.5/lib/concurrent/executors.rb000066400000000000000000000020271305460430400221540ustar00rootroot00000000000000require 'concurrent/executor/abstract_executor_service' require 'concurrent/executor/cached_thread_pool' require 'concurrent/executor/executor_service' require 'concurrent/executor/fixed_thread_pool' require 'concurrent/executor/immediate_executor' require 'concurrent/executor/indirect_immediate_executor' require 'concurrent/executor/java_executor_service' require 'concurrent/executor/java_single_thread_executor' require 'concurrent/executor/java_thread_pool_executor' require 'concurrent/executor/ruby_executor_service' require 'concurrent/executor/ruby_single_thread_executor' require 'concurrent/executor/ruby_thread_pool_executor' require 'concurrent/executor/cached_thread_pool' require 'concurrent/executor/safe_task_executor' require 'concurrent/executor/serial_executor_service' require 'concurrent/executor/serialized_execution' require 'concurrent/executor/serialized_execution_delegator' require 'concurrent/executor/single_thread_executor' require 'concurrent/executor/thread_pool_executor' require 'concurrent/executor/timer_set' concurrent-ruby-1.0.5/lib/concurrent/future.rb000066400000000000000000000101701305460430400214430ustar00rootroot00000000000000require 'thread' require 'concurrent/constants' require 'concurrent/errors' require 'concurrent/ivar' require 'concurrent/executor/safe_task_executor' require 'concurrent/options' module Concurrent # {include:file:doc/future.md} # # @!macro copy_options # # @see http://ruby-doc.org/stdlib-2.1.1/libdoc/observer/rdoc/Observable.html Ruby Observable module # @see http://clojuredocs.org/clojure_core/clojure.core/future Clojure's future function # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html java.util.concurrent.Future class Future < IVar # Create a new `Future` in the `:unscheduled` state. # # @yield the asynchronous operation to perform # # @!macro executor_and_deref_options # # @option opts [object, Array] :args zero or more arguments to be passed the task # block on execution # # @raise [ArgumentError] if no block is given def initialize(opts = {}, &block) raise ArgumentError.new('no block given') unless block_given? super(NULL, opts.merge(__task_from_block__: block), &nil) end # Execute an `:unscheduled` `Future`. Immediately sets the state to `:pending` and # passes the block to a new thread/thread pool for eventual execution. # Does nothing if the `Future` is in any state other than `:unscheduled`. # # @return [Future] a reference to `self` # # @example Instance and execute in separate steps # future = Concurrent::Future.new{ sleep(1); 42 } # future.state #=> :unscheduled # future.execute # future.state #=> :pending # # @example Instance and execute in one line # future = Concurrent::Future.new{ sleep(1); 42 }.execute # future.state #=> :pending def execute if compare_and_set_state(:pending, :unscheduled) @executor.post{ safe_execute(@task, @args) } self end end # Create a new `Future` object with the given block, execute it, and return the # `:pending` object. # # @yield the asynchronous operation to perform # # @!macro executor_and_deref_options # # @option opts [object, Array] :args zero or more arguments to be passed the task # block on execution # # @raise [ArgumentError] if no block is given # # @return [Future] the newly created `Future` in the `:pending` state # # @example # future = Concurrent::Future.execute{ sleep(1); 42 } # future.state #=> :pending def self.execute(opts = {}, &block) Future.new(opts, &block).execute end # @!macro ivar_set_method def set(value = NULL, &block) check_for_block_or_value!(block_given?, value) synchronize do if @state != :unscheduled raise MultipleAssignmentError else @task = block || Proc.new { value } end end execute end # Attempt to cancel the operation if it has not already processed. # The operation can only be cancelled while still `pending`. It cannot # be cancelled once it has begun processing or has completed. # # @return [Boolean] was the operation successfully cancelled. def cancel if compare_and_set_state(:cancelled, :pending) complete(false, nil, CancelledOperationError.new) true else false end end # Has the operation been successfully cancelled? # # @return [Boolean] def cancelled? state == :cancelled end # Wait the given number of seconds for the operation to complete. # On timeout attempt to cancel the operation. # # @param [Numeric] timeout the maximum time in seconds to wait. # @return [Boolean] true if the operation completed before the timeout # else false def wait_or_cancel(timeout) wait(timeout) if complete? true else cancel false end end protected def ns_initialize(value, opts) super @state = :unscheduled @task = opts[:__task_from_block__] @executor = Options.executor_from_options(opts) || Concurrent.global_io_executor @args = get_arguments_from(opts) end end end concurrent-ruby-1.0.5/lib/concurrent/hash.rb000066400000000000000000000017471305460430400210660ustar00rootroot00000000000000require 'concurrent/utility/engine' require 'concurrent/thread_safe/util' module Concurrent if Concurrent.on_cruby? # @!macro [attach] concurrent_hash # # A thread-safe subclass of Hash. This version locks against the object # itself for every method call, ensuring only one thread can be reading # or writing at a time. This includes iteration methods like `#each`, # which takes the lock repeatedly when reading an item. # # @see http://ruby-doc.org/core-2.2.0/Hash.html Ruby standard library `Hash` class Hash < ::Hash; end elsif Concurrent.on_jruby? require 'jruby/synchronized' # @!macro concurrent_hash class Hash < ::Hash include JRuby::Synchronized end elsif Concurrent.on_rbx? || Concurrent.on_truffle? require 'monitor' require 'concurrent/thread_safe/util/array_hash_rbx' # @!macro concurrent_hash class Hash < ::Hash end ThreadSafe::Util.make_synchronized_on_rbx Hash end end concurrent-ruby-1.0.5/lib/concurrent/immutable_struct.rb000066400000000000000000000040621305460430400235170ustar00rootroot00000000000000require 'concurrent/synchronization/abstract_struct' require 'concurrent/synchronization' module Concurrent # A thread-safe, immutable variation of Ruby's standard `Struct`. # # @see http://ruby-doc.org/core-2.2.0/Struct.html Ruby standard library `Struct` module ImmutableStruct include Synchronization::AbstractStruct def self.included(base) base.safe_initialization! end # @!macro struct_values def values ns_values end alias_method :to_a, :values # @!macro struct_values_at def values_at(*indexes) ns_values_at(indexes) end # @!macro struct_inspect def inspect ns_inspect end alias_method :to_s, :inspect # @!macro struct_merge def merge(other, &block) ns_merge(other, &block) end # @!macro struct_to_h def to_h ns_to_h end # @!macro struct_get def [](member) ns_get(member) end # @!macro struct_equality def ==(other) ns_equality(other) end # @!macro struct_each def each(&block) return enum_for(:each) unless block_given? ns_each(&block) end # @!macro struct_each_pair def each_pair(&block) return enum_for(:each_pair) unless block_given? ns_each_pair(&block) end # @!macro struct_select def select(&block) return enum_for(:select) unless block_given? ns_select(&block) end # @!macro struct_new def self.new(*args, &block) clazz_name = nil if args.length == 0 raise ArgumentError.new('wrong number of arguments (0 for 1+)') elsif args.length > 0 && args.first.is_a?(String) clazz_name = args.shift end FACTORY.define_struct(clazz_name, args, &block) end FACTORY = Class.new(Synchronization::LockableObject) do def define_struct(name, members, &block) synchronize do Synchronization::AbstractStruct.define_struct_class(ImmutableStruct, Synchronization::Object, name, members, &block) end end end.new private_constant :FACTORY end end concurrent-ruby-1.0.5/lib/concurrent/ivar.rb000066400000000000000000000163631305460430400211040ustar00rootroot00000000000000require 'concurrent/constants' require 'concurrent/errors' require 'concurrent/collection/copy_on_write_observer_set' require 'concurrent/concern/obligation' require 'concurrent/concern/observable' require 'concurrent/synchronization' module Concurrent # An `IVar` is like a future that you can assign. As a future is a value that # is being computed that you can wait on, an `IVar` is a value that is waiting # to be assigned, that you can wait on. `IVars` are single assignment and # deterministic. # # Then, express futures as an asynchronous computation that assigns an `IVar`. # The `IVar` becomes the primitive on which [futures](Future) and # [dataflow](Dataflow) are built. # # An `IVar` is a single-element container that is normally created empty, and # can only be set once. The I in `IVar` stands for immutable. Reading an # `IVar` normally blocks until it is set. It is safe to set and read an `IVar` # from different threads. # # If you want to have some parallel task set the value in an `IVar`, you want # a `Future`. If you want to create a graph of parallel tasks all executed # when the values they depend on are ready you want `dataflow`. `IVar` is # generally a low-level primitive. # # ## Examples # # Create, set and get an `IVar` # # ```ruby # ivar = Concurrent::IVar.new # ivar.set 14 # ivar.value #=> 14 # ivar.set 2 # would now be an error # ``` # # ## See Also # # 1. For the theory: Arvind, R. Nikhil, and K. Pingali. # [I-Structures: Data structures for parallel computing](http://dl.acm.org/citation.cfm?id=69562). # In Proceedings of Workshop on Graph Reduction, 1986. # 2. For recent application: # [DataDrivenFuture in Habanero Java from Rice](http://www.cs.rice.edu/~vs3/hjlib/doc/edu/rice/hj/api/HjDataDrivenFuture.html). class IVar < Synchronization::LockableObject include Concern::Obligation include Concern::Observable # Create a new `IVar` in the `:pending` state with the (optional) initial value. # # @param [Object] value the initial value # @param [Hash] opts the options to create a message with # @option opts [String] :dup_on_deref (false) call `#dup` before returning # the data # @option opts [String] :freeze_on_deref (false) call `#freeze` before # returning the data # @option opts [String] :copy_on_deref (nil) call the given `Proc` passing # the internal value and returning the value returned from the proc def initialize(value = NULL, opts = {}, &block) if value != NULL && block_given? raise ArgumentError.new('provide only a value or a block') end super(&nil) synchronize { ns_initialize(value, opts, &block) } end # Add an observer on this object that will receive notification on update. # # Upon completion the `IVar` will notify all observers in a thread-safe way. # The `func` method of the observer will be called with three arguments: the # `Time` at which the `Future` completed the asynchronous operation, the # final `value` (or `nil` on rejection), and the final `reason` (or `nil` on # fulfillment). # # @param [Object] observer the object that will be notified of changes # @param [Symbol] func symbol naming the method to call when this # `Observable` has changes` def add_observer(observer = nil, func = :update, &block) raise ArgumentError.new('cannot provide both an observer and a block') if observer && block direct_notification = false if block observer = block func = :call end synchronize do if event.set? direct_notification = true else observers.add_observer(observer, func) end end observer.send(func, Time.now, self.value, reason) if direct_notification observer end # @!macro [attach] ivar_set_method # Set the `IVar` to a value and wake or notify all threads waiting on it. # # @!macro [attach] ivar_set_parameters_and_exceptions # @param [Object] value the value to store in the `IVar` # @yield A block operation to use for setting the value # @raise [ArgumentError] if both a value and a block are given # @raise [Concurrent::MultipleAssignmentError] if the `IVar` has already # been set or otherwise completed # # @return [IVar] self def set(value = NULL) check_for_block_or_value!(block_given?, value) raise MultipleAssignmentError unless compare_and_set_state(:processing, :pending) begin value = yield if block_given? complete_without_notification(true, value, nil) rescue => ex complete_without_notification(false, nil, ex) end notify_observers(self.value, reason) self end # @!macro [attach] ivar_fail_method # Set the `IVar` to failed due to some error and wake or notify all threads waiting on it. # # @param [Object] reason for the failure # @raise [Concurrent::MultipleAssignmentError] if the `IVar` has already # been set or otherwise completed # @return [IVar] self def fail(reason = StandardError.new) complete(false, nil, reason) end # Attempt to set the `IVar` with the given value or block. Return a # boolean indicating the success or failure of the set operation. # # @!macro ivar_set_parameters_and_exceptions # # @return [Boolean] true if the value was set else false def try_set(value = NULL, &block) set(value, &block) true rescue MultipleAssignmentError false end protected # @!visibility private def ns_initialize(value, opts) value = yield if block_given? init_obligation self.observers = Collection::CopyOnWriteObserverSet.new set_deref_options(opts) if value == NULL @state = :pending else ns_complete_without_notification(true, value, nil) end end # @!visibility private def safe_execute(task, args = []) if compare_and_set_state(:processing, :pending) success, val, reason = SafeTaskExecutor.new(task, rescue_exception: true).execute(*@args) complete(success, val, reason) yield(success, val, reason) if block_given? end end # @!visibility private def complete(success, value, reason) complete_without_notification(success, value, reason) notify_observers(self.value, reason) self end # @!visibility private def complete_without_notification(success, value, reason) synchronize { ns_complete_without_notification(success, value, reason) } self end # @!visibility private def notify_observers(value, reason) observers.notify_and_delete_observers{ [Time.now, value, reason] } end # @!visibility private def ns_complete_without_notification(success, value, reason) raise MultipleAssignmentError if [:fulfilled, :rejected].include? @state set_state(success, value, reason) event.set end # @!visibility private def check_for_block_or_value!(block_given, value) # :nodoc: if (block_given && value != NULL) || (! block_given && value == NULL) raise ArgumentError.new('must set with either a value or a block') end end end end concurrent-ruby-1.0.5/lib/concurrent/lazy_register.rb000066400000000000000000000044431305460430400230220ustar00rootroot00000000000000require 'concurrent/atomic/atomic_reference' require 'concurrent/delay' module Concurrent # Hash-like collection that store lazys evaluated values. # # @example # register = Concurrent::LazyRegister.new # #=> #> # register[:key] # #=> nil # register.add(:key) { Concurrent::Actor.spawn!(Actor::AdHoc, :ping) { -> message { message } } } # #=> #> # register[:key] # #=> # # # @!macro edge_warning class LazyRegister < Synchronization::Object private(*attr_atomic(:data)) def initialize super self.data = {} end # Element reference. Retrieves the value object corresponding to the # key object. Returns nil if the key is not found. Raises an exception # if the stored item raised an exception when the block was evaluated. # # @param [Object] key # @return [Object] value stored for the key or nil if the key is not found # # @raise Exception when the initialization block fails def [](key) delay = data[key] delay ? delay.value! : nil end # Returns true if the given key is present. # # @param [Object] key # @return [true, false] if the key is registered def registered?(key) data.key?(key) end alias_method :key?, :registered? alias_method :has_key?, :registered? # Element assignment. Associates the value given by value with the # key given by key. # # @param [Object] key # @yield the object to store under the key # # @return [LazyRegister] self def register(key, &block) delay = Delay.new(executor: :immediate, &block) update_data { |h| h.merge(key => delay) } self end alias_method :add, :register alias_method :store, :register # Un-registers the object under key, realized or not. # # @param [Object] key # # @return [LazyRegister] self def unregister(key) update_data { |h| h.dup.tap { |j| j.delete(key) } } self end alias_method :remove, :unregister alias_method :delete, :unregister end end concurrent-ruby-1.0.5/lib/concurrent/map.rb000066400000000000000000000173401305460430400207140ustar00rootroot00000000000000require 'thread' require 'concurrent/constants' require 'concurrent/synchronization' module Concurrent # @!visibility private module Collection # @!visibility private MapImplementation = if Concurrent.java_extensions_loaded? # noinspection RubyResolve JRubyMapBackend elsif defined?(RUBY_ENGINE) case RUBY_ENGINE when 'ruby' require 'concurrent/collection/map/mri_map_backend' MriMapBackend when 'rbx' require 'concurrent/collection/map/atomic_reference_map_backend' AtomicReferenceMapBackend when 'jruby+truffle' require 'concurrent/collection/map/atomic_reference_map_backend' AtomicReferenceMapBackend else warn 'Concurrent::Map: unsupported Ruby engine, using a fully synchronized Concurrent::Map implementation' if $VERBOSE require 'concurrent/collection/map/synchronized_map_backend' SynchronizedMapBackend end else MriMapBackend end end # `Concurrent::Map` is a hash-like object and should have much better performance # characteristics, especially under high concurrency, than `Concurrent::Hash`. # However, `Concurrent::Map `is not strictly semantically equivalent to a ruby `Hash` # -- for instance, it does not necessarily retain ordering by insertion time as `Hash` # does. For most uses it should do fine though, and we recommend you consider # `Concurrent::Map` instead of `Concurrent::Hash` for your concurrency-safe hash needs. # # > require 'concurrent' # > # > map = Concurrent::Map.new class Map < Collection::MapImplementation # @!macro [new] map_method_is_atomic # This method is atomic. Atomic methods of `Map` which accept a block # do not allow the `self` instance to be used within the block. Doing # so will cause a deadlock. # @!method put_if_absent # @!macro map_method_is_atomic # @!method compute_if_absent # @!macro map_method_is_atomic # @!method compute_if_present # @!macro map_method_is_atomic # @!method compute # @!macro map_method_is_atomic # @!method merge_pair # @!macro map_method_is_atomic # @!method replace_pair # @!macro map_method_is_atomic # @!method replace_if_exists # @!macro map_method_is_atomic # @!method get_and_set # @!macro map_method_is_atomic # @!method delete # @!macro map_method_is_atomic # @!method delete_pair # @!macro map_method_is_atomic def initialize(options = nil, &block) if options.kind_of?(::Hash) validate_options_hash!(options) else options = nil end super(options) @default_proc = block end def [](key) if value = super # non-falsy value is an existing mapping, return it right away value # re-check is done with get_or_default(key, NULL) instead of a simple !key?(key) in order to avoid a race condition, whereby by the time the current thread gets to the key?(key) call # a key => value mapping might have already been created by a different thread (key?(key) would then return true, this elsif branch wouldn't be taken and an incorrent +nil+ value # would be returned) # note: nil == value check is not technically necessary elsif @default_proc && nil == value && NULL == (value = get_or_default(key, NULL)) @default_proc.call(self, key) else value end end alias_method :get, :[] alias_method :put, :[]= # @!macro [attach] map_method_not_atomic # The "fetch-then-act" methods of `Map` are not atomic. `Map` is intended # to be use as a concurrency primitive with strong happens-before # guarantees. It is not intended to be used as a high-level abstraction # supporting complex operations. All read and write operations are # thread safe, but no guarantees are made regarding race conditions # between the fetch operation and yielding to the block. Additionally, # this method does not support recursion. This is due to internal # constraints that are very unlikely to change in the near future. def fetch(key, default_value = NULL) if NULL != (value = get_or_default(key, NULL)) value elsif block_given? yield key elsif NULL != default_value default_value else raise_fetch_no_key end end # @!macro map_method_not_atomic def fetch_or_store(key, default_value = NULL) fetch(key) do put(key, block_given? ? yield(key) : (NULL == default_value ? raise_fetch_no_key : default_value)) end end # @!macro map_method_is_atomic def put_if_absent(key, value) computed = false result = compute_if_absent(key) do computed = true value end computed ? nil : result end unless method_defined?(:put_if_absent) def value?(value) each_value do |v| return true if value.equal?(v) end false end def keys arr = [] each_pair {|k, v| arr << k} arr end unless method_defined?(:keys) def values arr = [] each_pair {|k, v| arr << v} arr end unless method_defined?(:values) def each_key each_pair {|k, v| yield k} end unless method_defined?(:each_key) def each_value each_pair {|k, v| yield v} end unless method_defined?(:each_value) alias_method :each, :each_pair unless method_defined?(:each) def key(value) each_pair {|k, v| return k if v == value} nil end unless method_defined?(:key) alias_method :index, :key if RUBY_VERSION < '1.9' def empty? each_pair {|k, v| return false} true end unless method_defined?(:empty?) def size count = 0 each_pair {|k, v| count += 1} count end unless method_defined?(:size) def marshal_dump raise TypeError, "can't dump hash with default proc" if @default_proc h = {} each_pair {|k, v| h[k] = v} h end def marshal_load(hash) initialize populate_from(hash) end undef :freeze # @!visibility private DEFAULT_OBJ_ID_STR_WIDTH = 0.size == 4 ? 7 : 14 # we want to look "native", 7 for 32-bit, 14 for 64-bit # override default #inspect() method: firstly, we don't want to be spilling our guts (i-vars), secondly, MRI backend's # #inspect() call on its @backend i-var will bump @backend's iter level while possibly yielding GVL def inspect id_str = (object_id << 1).to_s(16).rjust(DEFAULT_OBJ_ID_STR_WIDTH, '0') "#<#{self.class.name}:0x#{id_str} entries=#{size} default_proc=#{@default_proc.inspect}>" end private def raise_fetch_no_key raise KeyError, 'key not found' end def initialize_copy(other) super populate_from(other) end def populate_from(hash) hash.each_pair {|k, v| self[k] = v} self end def validate_options_hash!(options) if (initial_capacity = options[:initial_capacity]) && (!initial_capacity.kind_of?(Integer) || initial_capacity < 0) raise ArgumentError, ":initial_capacity must be a positive Integer" end if (load_factor = options[:load_factor]) && (!load_factor.kind_of?(Numeric) || load_factor <= 0 || load_factor > 1) raise ArgumentError, ":load_factor must be a number between 0 and 1" end end end end concurrent-ruby-1.0.5/lib/concurrent/maybe.rb000066400000000000000000000200121305460430400212220ustar00rootroot00000000000000require 'concurrent/synchronization' module Concurrent # A `Maybe` encapsulates an optional value. A `Maybe` either contains a value # of (represented as `Just`), or it is empty (represented as `Nothing`). Using # `Maybe` is a good way to deal with errors or exceptional cases without # resorting to drastic measures such as exceptions. # # `Maybe` is a replacement for the use of `nil` with better type checking. # # For compatibility with {Concurrent::Concern::Obligation} the predicate and # accessor methods are aliased as `fulfilled?`, `rejected?`, `value`, and # `reason`. # # ## Motivation # # A common pattern in languages with pattern matching, such as Erlang and # Haskell, is to return *either* a value *or* an error from a function # Consider this Erlang code: # # ```erlang # case file:consult("data.dat") of # {ok, Terms} -> do_something_useful(Terms); # {error, Reason} -> lager:error(Reason) # end. # ``` # # In this example the standard library function `file:consult` returns a # [tuple](http://erlang.org/doc/reference_manual/data_types.html#id69044) # with two elements: an [atom](http://erlang.org/doc/reference_manual/data_types.html#id64134) # (similar to a ruby symbol) and a variable containing ancillary data. On # success it returns the atom `ok` and the data from the file. On failure it # returns `error` and a string with an explanation of the problem. With this # pattern there is no ambiguity regarding success or failure. If the file is # empty the return value cannot be misinterpreted as an error. And when an # error occurs the return value provides useful information. # # In Ruby we tend to return `nil` when an error occurs or else we raise an # exception. Both of these idioms are problematic. Returning `nil` is # ambiguous because `nil` may also be a valid value. It also lacks # information pertaining to the nature of the error. Raising an exception # is both expensive and usurps the normal flow of control. All of these # problems can be solved with the use of a `Maybe`. # # A `Maybe` is unambiguous with regard to whether or not it contains a value. # When `Just` it contains a value, when `Nothing` it does not. When `Just` # the value it contains may be `nil`, which is perfectly valid. When # `Nothing` the reason for the lack of a value is contained as well. The # previous Erlang example can be duplicated in Ruby in a principled way by # having functions return `Maybe` objects: # # ```ruby # result = MyFileUtils.consult("data.dat") # returns a Maybe # if result.just? # do_something_useful(result.value) # or result.just # else # logger.error(result.reason) # or result.nothing # end # ``` # # @example Returning a Maybe from a Function # module MyFileUtils # def self.consult(path) # file = File.open(path, 'r') # Concurrent::Maybe.just(file.read) # rescue => ex # return Concurrent::Maybe.nothing(ex) # ensure # file.close if file # end # end # # maybe = MyFileUtils.consult('bogus.file') # maybe.just? #=> false # maybe.nothing? #=> true # maybe.reason #=> # # # maybe = MyFileUtils.consult('README.md') # maybe.just? #=> true # maybe.nothing? #=> false # maybe.value #=> "# Concurrent Ruby\n[![Gem Version..." # # @example Using Maybe with a Block # result = Concurrent::Maybe.from do # Client.find(10) # Client is an ActiveRecord model # end # # # -- if the record was found # result.just? #=> true # result.value #=> # # # # -- if the record was not found # result.just? #=> false # result.reason #=> ActiveRecord::RecordNotFound # # @example Using Maybe with the Null Object Pattern # # In a Rails controller... # result = ClientService.new(10).find # returns a Maybe # render json: result.or(NullClient.new) # # @see https://hackage.haskell.org/package/base-4.2.0.1/docs/Data-Maybe.html Haskell Data.Maybe # @see https://github.com/purescript/purescript-maybe/blob/master/docs/Data.Maybe.md PureScript Data.Maybe class Maybe < Synchronization::Object include Comparable safe_initialization! # Indicates that the given attribute has not been set. # When `Just` the {#nothing} getter will return `NONE`. # When `Nothing` the {#just} getter will return `NONE`. NONE = Object.new.freeze # The value of a `Maybe` when `Just`. Will be `NONE` when `Nothing`. attr_reader :just # The reason for the `Maybe` when `Nothing`. Will be `NONE` when `Just`. attr_reader :nothing private_class_method :new # Create a new `Maybe` using the given block. # # Runs the given block passing all function arguments to the block as block # arguments. If the block runs to completion without raising an exception # a new `Just` is created with the value set to the return value of the # block. If the block raises an exception a new `Nothing` is created with # the reason being set to the raised exception. # # @param [Array] args Zero or more arguments to pass to the block. # @yield The block from which to create a new `Maybe`. # @yieldparam [Array] args Zero or more block arguments passed as # arguments to the function. # # @return [Maybe] The newly created object. # # @raise [ArgumentError] when no block given. def self.from(*args) raise ArgumentError.new('no block given') unless block_given? begin value = yield(*args) return new(value, NONE) rescue => ex return new(NONE, ex) end end # Create a new `Just` with the given value. # # @param [Object] value The value to set for the new `Maybe` object. # # @return [Maybe] The newly created object. def self.just(value) return new(value, NONE) end # Create a new `Nothing` with the given (optional) reason. # # @param [Exception] error The reason to set for the new `Maybe` object. # When given a string a new `StandardError` will be created with the # argument as the message. When no argument is given a new # `StandardError` with an empty message will be created. # # @return [Maybe] The newly created object. def self.nothing(error = '') if error.is_a?(Exception) nothing = error else nothing = StandardError.new(error.to_s) end return new(NONE, nothing) end # Is this `Maybe` a `Just` (successfully fulfilled with a value)? # # @return [Boolean] True if `Just` or false if `Nothing`. def just? ! nothing? end alias :fulfilled? :just? # Is this `Maybe` a `nothing` (rejected with an exception upon fulfillment)? # # @return [Boolean] True if `Nothing` or false if `Just`. def nothing? @nothing != NONE end alias :rejected? :nothing? alias :value :just alias :reason :nothing # Comparison operator. # # @return [Integer] 0 if self and other are both `Nothing`; # -1 if self is `Nothing` and other is `Just`; # 1 if self is `Just` and other is nothing; # `self.just <=> other.just` if both self and other are `Just`. def <=>(other) if nothing? other.nothing? ? 0 : -1 else other.nothing? ? 1 : just <=> other.just end end # Return either the value of self or the given default value. # # @return [Object] The value of self when `Just`; else the given default. def or(other) just? ? just : other end private # Create a new `Maybe` with the given attributes. # # @param [Object] just The value when `Just` else `NONE`. # @param [Exception, Object] nothing The exception when `Nothing` else `NONE`. # # @return [Maybe] The new `Maybe`. # # @!visibility private def initialize(just, nothing) @just = just @nothing = nothing end end end concurrent-ruby-1.0.5/lib/concurrent/mutable_struct.rb000066400000000000000000000206661305460430400232010ustar00rootroot00000000000000require 'concurrent/synchronization/abstract_struct' require 'concurrent/synchronization' module Concurrent # An thread-safe variation of Ruby's standard `Struct`. Values can be set at # construction or safely changed at any time during the object's lifecycle. # # @see http://ruby-doc.org/core-2.2.0/Struct.html Ruby standard library `Struct` module MutableStruct include Synchronization::AbstractStruct # @!macro [new] struct_new # # Factory for creating new struct classes. # # ``` # new([class_name] [, member_name]+>) -> StructClass click to toggle source # new([class_name] [, member_name]+>) {|StructClass| block } -> StructClass # new(value, ...) -> obj # StructClass[value, ...] -> obj # ``` # # The first two forms are used to create a new struct subclass `class_name` # that can contain a value for each member_name . This subclass can be # used to create instances of the structure like any other Class . # # If the `class_name` is omitted an anonymous struct class will be created. # Otherwise, the name of this struct will appear as a constant in the struct class, # so it must be unique for all structs under this base class and must start with a # capital letter. Assigning a struct class to a constant also gives the class # the name of the constant. # # If a block is given it will be evaluated in the context of `StructClass`, passing # the created class as a parameter. This is the recommended way to customize a struct. # Subclassing an anonymous struct creates an extra anonymous class that will never be used. # # The last two forms create a new instance of a struct subclass. The number of value # parameters must be less than or equal to the number of attributes defined for the # struct. Unset parameters default to nil. Passing more parameters than number of attributes # will raise an `ArgumentError`. # # @see http://ruby-doc.org/core-2.2.0/Struct.html#method-c-new Ruby standard library `Struct#new` # @!macro [attach] struct_values # # Returns the values for this struct as an Array. # # @return [Array] the values for this struct # def values synchronize { ns_values } end alias_method :to_a, :values # @!macro [attach] struct_values_at # # Returns the struct member values for each selector as an Array. # # A selector may be either an Integer offset or a Range of offsets (as in `Array#values_at`). # # @param [Fixnum, Range] indexes the index(es) from which to obatin the values (in order) def values_at(*indexes) synchronize { ns_values_at(indexes) } end # @!macro [attach] struct_inspect # # Describe the contents of this struct in a string. # # @return [String] the contents of this struct in a string def inspect synchronize { ns_inspect } end alias_method :to_s, :inspect # @!macro [attach] struct_merge # # Returns a new struct containing the contents of `other` and the contents # of `self`. If no block is specified, the value for entries with duplicate # keys will be that of `other`. Otherwise the value for each duplicate key # is determined by calling the block with the key, its value in `self` and # its value in `other`. # # @param [Hash] other the hash from which to set the new values # @yield an options block for resolving duplicate keys # @yieldparam [String, Symbol] member the name of the member which is duplicated # @yieldparam [Object] selfvalue the value of the member in `self` # @yieldparam [Object] othervalue the value of the member in `other` # # @return [Synchronization::AbstractStruct] a new struct with the new values # # @raise [ArgumentError] of given a member that is not defined in the struct def merge(other, &block) synchronize { ns_merge(other, &block) } end # @!macro [attach] struct_to_h # # Returns a hash containing the names and values for the struct’s members. # # @return [Hash] the names and values for the struct’s members def to_h synchronize { ns_to_h } end # @!macro [attach] struct_get # # Attribute Reference # # @param [Symbol, String, Integer] member the string or symbol name of the memeber # for which to obtain the value or the member's index # # @return [Object] the value of the given struct member or the member at the given index. # # @raise [NameError] if the member does not exist # @raise [IndexError] if the index is out of range. def [](member) synchronize { ns_get(member) } end # @!macro [attach] struct_equality # # Equality # # @return [Boolean] true if other has the same struct subclass and has # equal member values (according to `Object#==`) def ==(other) synchronize { ns_equality(other) } end # @!macro [attach] struct_each # # Yields the value of each struct member in order. If no block is given # an enumerator is returned. # # @yield the operation to be performed on each struct member # @yieldparam [Object] value each struct value (in order) def each(&block) return enum_for(:each) unless block_given? synchronize { ns_each(&block) } end # @!macro [attach] struct_each_pair # # Yields the name and value of each struct member in order. If no block is # given an enumerator is returned. # # @yield the operation to be performed on each struct member/value pair # @yieldparam [Object] member each struct member (in order) # @yieldparam [Object] value each struct value (in order) def each_pair(&block) return enum_for(:each_pair) unless block_given? synchronize { ns_each_pair(&block) } end # @!macro [attach] struct_select # # Yields each member value from the struct to the block and returns an Array # containing the member values from the struct for which the given block # returns a true value (equivalent to `Enumerable#select`). # # @yield the operation to be performed on each struct member # @yieldparam [Object] value each struct value (in order) # # @return [Array] an array containing each value for which the block returns true def select(&block) return enum_for(:select) unless block_given? synchronize { ns_select(&block) } end # @!macro [new] struct_set # # Attribute Assignment # # Sets the value of the given struct member or the member at the given index. # # @param [Symbol, String, Integer] member the string or symbol name of the memeber # for which to obtain the value or the member's index # # @return [Object] the value of the given struct member or the member at the given index. # # @raise [NameError] if the name does not exist # @raise [IndexError] if the index is out of range. def []=(member, value) if member.is_a? Integer length = synchronize { @values.length } if member >= length raise IndexError.new("offset #{member} too large for struct(size:#{length})") end synchronize { @values[member] = value } else send("#{member}=", value) end rescue NoMethodError raise NameError.new("no member '#{member}' in struct") end # @!macro struct_new def self.new(*args, &block) clazz_name = nil if args.length == 0 raise ArgumentError.new('wrong number of arguments (0 for 1+)') elsif args.length > 0 && args.first.is_a?(String) clazz_name = args.shift end FACTORY.define_struct(clazz_name, args, &block) end FACTORY = Class.new(Synchronization::LockableObject) do def define_struct(name, members, &block) synchronize do clazz = Synchronization::AbstractStruct.define_struct_class(MutableStruct, Synchronization::LockableObject, name, members, &block) members.each_with_index do |member, index| clazz.send(:define_method, member) do synchronize { @values[index] } end clazz.send(:define_method, "#{member}=") do |value| synchronize { @values[index] = value } end end clazz end end end.new private_constant :FACTORY end end concurrent-ruby-1.0.5/lib/concurrent/mvar.rb000066400000000000000000000163051305460430400211040ustar00rootroot00000000000000require 'concurrent/concern/dereferenceable' require 'concurrent/synchronization' module Concurrent # An `MVar` is a synchronized single element container. They are empty or # contain one item. Taking a value from an empty `MVar` blocks, as does # putting a value into a full one. You can either think of them as blocking # queue of length one, or a special kind of mutable variable. # # On top of the fundamental `#put` and `#take` operations, we also provide a # `#mutate` that is atomic with respect to operations on the same instance. # These operations all support timeouts. # # We also support non-blocking operations `#try_put!` and `#try_take!`, a # `#set!` that ignores existing values, a `#value` that returns the value # without removing it or returns `MVar::EMPTY`, and a `#modify!` that yields # `MVar::EMPTY` if the `MVar` is empty and can be used to set `MVar::EMPTY`. # You shouldn't use these operations in the first instance. # # `MVar` is a [Dereferenceable](Dereferenceable). # # `MVar` is related to M-structures in Id, `MVar` in Haskell and `SyncVar` in Scala. # # Note that unlike the original Haskell paper, our `#take` is blocking. This is how # Haskell and Scala do it today. # # @!macro copy_options # # ## See Also # # 1. P. Barth, R. Nikhil, and Arvind. [M-Structures: Extending a parallel, non- strict, functional language with state](http://dl.acm.org/citation.cfm?id=652538). In Proceedings of the 5th # ACM Conference on Functional Programming Languages and Computer Architecture (FPCA), 1991. # # 2. S. Peyton Jones, A. Gordon, and S. Finne. [Concurrent Haskell](http://dl.acm.org/citation.cfm?id=237794). # In Proceedings of the 23rd Symposium on Principles of Programming Languages # (PoPL), 1996. class MVar < Synchronization::Object include Concern::Dereferenceable safe_initialization! # Unique value that represents that an `MVar` was empty EMPTY = Object.new # Unique value that represents that an `MVar` timed out before it was able # to produce a value. TIMEOUT = Object.new # Create a new `MVar`, either empty or with an initial value. # # @param [Hash] opts the options controlling how the future will be processed # # @!macro deref_options def initialize(value = EMPTY, opts = {}) @value = value @mutex = Mutex.new @empty_condition = ConditionVariable.new @full_condition = ConditionVariable.new set_deref_options(opts) end # Remove the value from an `MVar`, leaving it empty, and blocking if there # isn't a value. A timeout can be set to limit the time spent blocked, in # which case it returns `TIMEOUT` if the time is exceeded. # @return [Object] the value that was taken, or `TIMEOUT` def take(timeout = nil) @mutex.synchronize do wait_for_full(timeout) # If we timed out we'll still be empty if unlocked_full? value = @value @value = EMPTY @empty_condition.signal apply_deref_options(value) else TIMEOUT end end end # acquires lock on the from an `MVAR`, yields the value to provided block, # and release lock. A timeout can be set to limit the time spent blocked, # in which case it returns `TIMEOUT` if the time is exceeded. # @return [Object] the value returned by the block, or `TIMEOUT` def borrow(timeout = nil) @mutex.synchronize do wait_for_full(timeout) # if we timeoud out we'll still be empty if unlocked_full? yield @value else TIMEOUT end end end # Put a value into an `MVar`, blocking if there is already a value until # it is empty. A timeout can be set to limit the time spent blocked, in # which case it returns `TIMEOUT` if the time is exceeded. # @return [Object] the value that was put, or `TIMEOUT` def put(value, timeout = nil) @mutex.synchronize do wait_for_empty(timeout) # If we timed out we won't be empty if unlocked_empty? @value = value @full_condition.signal apply_deref_options(value) else TIMEOUT end end end # Atomically `take`, yield the value to a block for transformation, and then # `put` the transformed value. Returns the transformed value. A timeout can # be set to limit the time spent blocked, in which case it returns `TIMEOUT` # if the time is exceeded. # @return [Object] the transformed value, or `TIMEOUT` def modify(timeout = nil) raise ArgumentError.new('no block given') unless block_given? @mutex.synchronize do wait_for_full(timeout) # If we timed out we'll still be empty if unlocked_full? value = @value @value = yield value @full_condition.signal apply_deref_options(value) else TIMEOUT end end end # Non-blocking version of `take`, that returns `EMPTY` instead of blocking. def try_take! @mutex.synchronize do if unlocked_full? value = @value @value = EMPTY @empty_condition.signal apply_deref_options(value) else EMPTY end end end # Non-blocking version of `put`, that returns whether or not it was successful. def try_put!(value) @mutex.synchronize do if unlocked_empty? @value = value @full_condition.signal true else false end end end # Non-blocking version of `put` that will overwrite an existing value. def set!(value) @mutex.synchronize do old_value = @value @value = value @full_condition.signal apply_deref_options(old_value) end end # Non-blocking version of `modify` that will yield with `EMPTY` if there is no value yet. def modify! raise ArgumentError.new('no block given') unless block_given? @mutex.synchronize do value = @value @value = yield value if unlocked_empty? @empty_condition.signal else @full_condition.signal end apply_deref_options(value) end end # Returns if the `MVar` is currently empty. def empty? @mutex.synchronize { @value == EMPTY } end # Returns if the `MVar` currently contains a value. def full? !empty? end protected def synchronize(&block) @mutex.synchronize(&block) end private def unlocked_empty? @value == EMPTY end def unlocked_full? ! unlocked_empty? end def wait_for_full(timeout) wait_while(@full_condition, timeout) { unlocked_empty? } end def wait_for_empty(timeout) wait_while(@empty_condition, timeout) { unlocked_full? } end def wait_while(condition, timeout) if timeout.nil? while yield condition.wait(@mutex) end else stop = Concurrent.monotonic_time + timeout while yield && timeout > 0.0 condition.wait(@mutex, timeout) timeout = stop - Concurrent.monotonic_time end end end end end concurrent-ruby-1.0.5/lib/concurrent/options.rb000066400000000000000000000024051305460430400216260ustar00rootroot00000000000000require 'concurrent/configuration' module Concurrent # @!visibility private module Options # Get the requested `Executor` based on the values set in the options hash. # # @param [Hash] opts the options defining the requested executor # @option opts [Executor] :executor when set use the given `Executor` instance. # Three special values are also supported: `:fast` returns the global fast executor, # `:io` returns the global io executor, and `:immediate` returns a new # `ImmediateExecutor` object. # # @return [Executor, nil] the requested thread pool, or nil when no option specified # # @!visibility private def self.executor_from_options(opts = {}) # :nodoc: if identifier = opts.fetch(:executor, nil) executor(identifier) else nil end end def self.executor(executor_identifier) case executor_identifier when :fast Concurrent.global_fast_executor when :io Concurrent.global_io_executor when :immediate Concurrent.global_immediate_executor when Concurrent::ExecutorService executor_identifier else raise ArgumentError, "executor not recognized by '#{executor_identifier}'" end end end end concurrent-ruby-1.0.5/lib/concurrent/promise.rb000066400000000000000000000450411305460430400216140ustar00rootroot00000000000000require 'thread' require 'concurrent/constants' require 'concurrent/errors' require 'concurrent/ivar' require 'concurrent/executor/safe_task_executor' require 'concurrent/options' module Concurrent PromiseExecutionError = Class.new(StandardError) # Promises are inspired by the JavaScript [Promises/A](http://wiki.commonjs.org/wiki/Promises/A) # and [Promises/A+](http://promises-aplus.github.io/promises-spec/) specifications. # # > A promise represents the eventual value returned from the single # > completion of an operation. # # Promises are similar to futures and share many of the same behaviours. # Promises are far more robust, however. Promises can be chained in a tree # structure where each promise may have zero or more children. Promises are # chained using the `then` method. The result of a call to `then` is always # another promise. Promises are resolved asynchronously (with respect to the # main thread) but in a strict order: parents are guaranteed to be resolved # before their children, children before their younger siblings. The `then` # method takes two parameters: an optional block to be executed upon parent # resolution and an optional callable to be executed upon parent failure. The # result of each promise is passed to each of its children upon resolution. # When a promise is rejected all its children will be summarily rejected and # will receive the reason. # # Promises have several possible states: *:unscheduled*, *:pending*, # *:processing*, *:rejected*, or *:fulfilled*. These are also aggregated as # `#incomplete?` and `#complete?`. When a Promise is created it is set to # *:unscheduled*. Once the `#execute` method is called the state becomes # *:pending*. Once a job is pulled from the thread pool's queue and is given # to a thread for processing (often immediately upon `#post`) the state # becomes *:processing*. The future will remain in this state until processing # is complete. A future that is in the *:unscheduled*, *:pending*, or # *:processing* is considered `#incomplete?`. A `#complete?` Promise is either # *:rejected*, indicating that an exception was thrown during processing, or # *:fulfilled*, indicating success. If a Promise is *:fulfilled* its `#value` # will be updated to reflect the result of the operation. If *:rejected* the # `reason` will be updated with a reference to the thrown exception. The # predicate methods `#unscheduled?`, `#pending?`, `#rejected?`, and # `#fulfilled?` can be called at any time to obtain the state of the Promise, # as can the `#state` method, which returns a symbol. # # Retrieving the value of a promise is done through the `value` (alias: # `deref`) method. Obtaining the value of a promise is a potentially blocking # operation. When a promise is *rejected* a call to `value` will return `nil` # immediately. When a promise is *fulfilled* a call to `value` will # immediately return the current value. When a promise is *pending* a call to # `value` will block until the promise is either *rejected* or *fulfilled*. A # *timeout* value can be passed to `value` to limit how long the call will # block. If `nil` the call will block indefinitely. If `0` the call will not # block. Any other integer or float value will indicate the maximum number of # seconds to block. # # Promises run on the global thread pool. # # @!macro copy_options # # ### Examples # # Start by requiring promises # # ```ruby # require 'concurrent' # ``` # # Then create one # # ```ruby # p = Concurrent::Promise.execute do # # do something # 42 # end # ``` # # Promises can be chained using the `then` method. The `then` method accepts a # block and an executor, to be executed on fulfillment, and a callable argument to be executed # on rejection. The result of the each promise is passed as the block argument # to chained promises. # # ```ruby # p = Concurrent::Promise.new{10}.then{|x| x * 2}.then{|result| result - 10 }.execute # ``` # # And so on, and so on, and so on... # # ```ruby # p = Concurrent::Promise.fulfill(20). # then{|result| result - 10 }. # then{|result| result * 3 }. # then(executor: different_executor){|result| result % 5 }.execute # ``` # # The initial state of a newly created Promise depends on the state of its parent: # - if parent is *unscheduled* the child will be *unscheduled* # - if parent is *pending* the child will be *pending* # - if parent is *fulfilled* the child will be *pending* # - if parent is *rejected* the child will be *pending* (but will ultimately be *rejected*) # # Promises are executed asynchronously from the main thread. By the time a # child Promise finishes intialization it may be in a different state than its # parent (by the time a child is created its parent may have completed # execution and changed state). Despite being asynchronous, however, the order # of execution of Promise objects in a chain (or tree) is strictly defined. # # There are multiple ways to create and execute a new `Promise`. Both ways # provide identical behavior: # # ```ruby # # create, operate, then execute # p1 = Concurrent::Promise.new{ "Hello World!" } # p1.state #=> :unscheduled # p1.execute # # # create and immediately execute # p2 = Concurrent::Promise.new{ "Hello World!" }.execute # # # execute during creation # p3 = Concurrent::Promise.execute{ "Hello World!" } # ``` # # Once the `execute` method is called a `Promise` becomes `pending`: # # ```ruby # p = Concurrent::Promise.execute{ "Hello, world!" } # p.state #=> :pending # p.pending? #=> true # ``` # # Wait a little bit, and the promise will resolve and provide a value: # # ```ruby # p = Concurrent::Promise.execute{ "Hello, world!" } # sleep(0.1) # # p.state #=> :fulfilled # p.fulfilled? #=> true # p.value #=> "Hello, world!" # ``` # # If an exception occurs, the promise will be rejected and will provide # a reason for the rejection: # # ```ruby # p = Concurrent::Promise.execute{ raise StandardError.new("Here comes the Boom!") } # sleep(0.1) # # p.state #=> :rejected # p.rejected? #=> true # p.reason #=> "#" # ``` # # #### Rejection # # When a promise is rejected all its children will be rejected and will # receive the rejection `reason` as the rejection callable parameter: # # ```ruby # p = [ Concurrent::Promise.execute{ Thread.pass; raise StandardError } ] # # c1 = p.then(Proc.new{ |reason| 42 }) # c2 = p.then(Proc.new{ |reason| raise 'Boom!' }) # # sleep(0.1) # # c1.state #=> :rejected # c2.state #=> :rejected # ``` # # Once a promise is rejected it will continue to accept children that will # receive immediately rejection (they will be executed asynchronously). # # #### Aliases # # The `then` method is the most generic alias: it accepts a block to be # executed upon parent fulfillment and a callable to be executed upon parent # rejection. At least one of them should be passed. The default block is `{ # |result| result }` that fulfills the child with the parent value. The # default callable is `{ |reason| raise reason }` that rejects the child with # the parent reason. # # - `on_success { |result| ... }` is the same as `then {|result| ... }` # - `rescue { |reason| ... }` is the same as `then(Proc.new { |reason| ... } )` # - `rescue` is aliased by `catch` and `on_error` class Promise < IVar # Initialize a new Promise with the provided options. # # @!macro executor_and_deref_options # # @!macro [attach] promise_init_options # # @option opts [Promise] :parent the parent `Promise` when building a chain/tree # @option opts [Proc] :on_fulfill fulfillment handler # @option opts [Proc] :on_reject rejection handler # @option opts [object, Array] :args zero or more arguments to be passed # the task block on execution # # @yield The block operation to be performed asynchronously. # # @raise [ArgumentError] if no block is given # # @see http://wiki.commonjs.org/wiki/Promises/A # @see http://promises-aplus.github.io/promises-spec/ def initialize(opts = {}, &block) opts.delete_if { |k, v| v.nil? } super(NULL, opts.merge(__promise_body_from_block__: block), &nil) end # Create a new `Promise` and fulfill it immediately. # # @!macro executor_and_deref_options # # @!macro promise_init_options # # @raise [ArgumentError] if no block is given # # @return [Promise] the newly created `Promise` def self.fulfill(value, opts = {}) Promise.new(opts).tap { |p| p.send(:synchronized_set_state!, true, value, nil) } end # Create a new `Promise` and reject it immediately. # # @!macro executor_and_deref_options # # @!macro promise_init_options # # @raise [ArgumentError] if no block is given # # @return [Promise] the newly created `Promise` def self.reject(reason, opts = {}) Promise.new(opts).tap { |p| p.send(:synchronized_set_state!, false, nil, reason) } end # Execute an `:unscheduled` `Promise`. Immediately sets the state to `:pending` and # passes the block to a new thread/thread pool for eventual execution. # Does nothing if the `Promise` is in any state other than `:unscheduled`. # # @return [Promise] a reference to `self` def execute if root? if compare_and_set_state(:pending, :unscheduled) set_pending realize(@promise_body) end else @parent.execute end self end # @!macro ivar_set_method # # @raise [Concurrent::PromiseExecutionError] if not the root promise def set(value = NULL, &block) raise PromiseExecutionError.new('supported only on root promise') unless root? check_for_block_or_value!(block_given?, value) synchronize do if @state != :unscheduled raise MultipleAssignmentError else @promise_body = block || Proc.new { |result| value } end end execute end # @!macro ivar_fail_method # # @raise [Concurrent::PromiseExecutionError] if not the root promise def fail(reason = StandardError.new) set { raise reason } end # Create a new `Promise` object with the given block, execute it, and return the # `:pending` object. # # @!macro executor_and_deref_options # # @!macro promise_init_options # # @return [Promise] the newly created `Promise` in the `:pending` state # # @raise [ArgumentError] if no block is given # # @example # promise = Concurrent::Promise.execute{ sleep(1); 42 } # promise.state #=> :pending def self.execute(opts = {}, &block) new(opts, &block).execute end # Chain a new promise off the current promise. # # @param [Proc] rescuer An optional rescue block to be executed if the # promise is rejected. # # @param [ThreadPool] executor An optional thread pool executor to be used # in the new Promise # # @yield The block operation to be performed asynchronously. # # @return [Promise] the new promise def then(rescuer = nil, executor = @executor, &block) raise ArgumentError.new('rescuers and block are both missing') if rescuer.nil? && !block_given? block = Proc.new { |result| result } unless block_given? child = Promise.new( parent: self, executor: executor, on_fulfill: block, on_reject: rescuer ) synchronize do child.state = :pending if @state == :pending child.on_fulfill(apply_deref_options(@value)) if @state == :fulfilled child.on_reject(@reason) if @state == :rejected @children << child end child end # Chain onto this promise an action to be undertaken on success # (fulfillment). # # @yield The block to execute # # @return [Promise] self def on_success(&block) raise ArgumentError.new('no block given') unless block_given? self.then(&block) end # Chain onto this promise an action to be undertaken on failure # (rejection). # # @yield The block to execute # # @return [Promise] self def rescue(&block) self.then(block) end alias_method :catch, :rescue alias_method :on_error, :rescue # Yield the successful result to the block that returns a promise. If that # promise is also successful the result is the result of the yielded promise. # If either part fails the whole also fails. # # @example # Promise.execute { 1 }.flat_map { |v| Promise.execute { v + 2 } }.value! #=> 3 # # @return [Promise] def flat_map(&block) child = Promise.new( parent: self, executor: ImmediateExecutor.new, ) on_error { |e| child.on_reject(e) } on_success do |result1| begin inner = block.call(result1) inner.execute inner.on_success { |result2| child.on_fulfill(result2) } inner.on_error { |e| child.on_reject(e) } rescue => e child.on_reject(e) end end child end # Builds a promise that produces the result of promises in an Array # and fails if any of them fails. # # @param [Array] promises # # @return [Promise] def self.zip(*promises) zero = fulfill([], executor: ImmediateExecutor.new) promises.reduce(zero) do |p1, p2| p1.flat_map do |results| p2.then do |next_result| results << next_result end end end end # Builds a promise that produces the result of self and others in an Array # and fails if any of them fails. # # @param [Array] others # # @return [Promise] def zip(*others) self.class.zip(self, *others) end # Aggregates a collection of promises and executes the `then` condition # if all aggregated promises succeed. Executes the `rescue` handler with # a `Concurrent::PromiseExecutionError` if any of the aggregated promises # fail. Upon execution will execute any of the aggregate promises that # were not already executed. # # @!macro [attach] promise_self_aggregate # # The returned promise will not yet have been executed. Additional `#then` # and `#rescue` handlers may still be provided. Once the returned promise # is execute the aggregate promises will be also be executed (if they have # not been executed already). The results of the aggregate promises will # be checked upon completion. The necessary `#then` and `#rescue` blocks # on the aggregating promise will then be executed as appropriate. If the # `#rescue` handlers are executed the raises exception will be # `Concurrent::PromiseExecutionError`. # # @param [Array] promises Zero or more promises to aggregate # @return [Promise] an unscheduled (not executed) promise that aggregates # the promises given as arguments def self.all?(*promises) aggregate(:all?, *promises) end # Aggregates a collection of promises and executes the `then` condition # if any aggregated promises succeed. Executes the `rescue` handler with # a `Concurrent::PromiseExecutionError` if any of the aggregated promises # fail. Upon execution will execute any of the aggregate promises that # were not already executed. # # @!macro promise_self_aggregate def self.any?(*promises) aggregate(:any?, *promises) end protected def ns_initialize(value, opts) super @executor = Options.executor_from_options(opts) || Concurrent.global_io_executor @args = get_arguments_from(opts) @parent = opts.fetch(:parent) { nil } @on_fulfill = opts.fetch(:on_fulfill) { Proc.new { |result| result } } @on_reject = opts.fetch(:on_reject) { Proc.new { |reason| raise reason } } @promise_body = opts[:__promise_body_from_block__] || Proc.new { |result| result } @state = :unscheduled @children = [] end # Aggregate a collection of zero or more promises under a composite promise, # execute the aggregated promises and collect them into a standard Ruby array, # call the given Ruby `Ennnumerable` predicate (such as `any?`, `all?`, `none?`, # or `one?`) on the collection checking for the success or failure of each, # then executing the composite's `#then` handlers if the predicate returns # `true` or executing the composite's `#rescue` handlers if the predicate # returns false. # # @!macro promise_self_aggregate def self.aggregate(method, *promises) composite = Promise.new do completed = promises.collect do |promise| promise.execute if promise.unscheduled? promise.wait promise end unless completed.empty? || completed.send(method){|promise| promise.fulfilled? } raise PromiseExecutionError end end composite end # @!visibility private def set_pending synchronize do @state = :pending @children.each { |c| c.set_pending } end end # @!visibility private def root? # :nodoc: @parent.nil? end # @!visibility private def on_fulfill(result) realize Proc.new { @on_fulfill.call(result) } nil end # @!visibility private def on_reject(reason) realize Proc.new { @on_reject.call(reason) } nil end # @!visibility private def notify_child(child) if_state(:fulfilled) { child.on_fulfill(apply_deref_options(@value)) } if_state(:rejected) { child.on_reject(@reason) } end # @!visibility private def complete(success, value, reason) children_to_notify = synchronize do set_state!(success, value, reason) @children.dup end children_to_notify.each { |child| notify_child(child) } observers.notify_and_delete_observers{ [Time.now, self.value, reason] } end # @!visibility private def realize(task) @executor.post do success, value, reason = SafeTaskExecutor.new(task, rescue_exception: true).execute(*@args) complete(success, value, reason) end end # @!visibility private def set_state!(success, value, reason) set_state(success, value, reason) event.set end # @!visibility private def synchronized_set_state!(success, value, reason) synchronize { set_state!(success, value, reason) } end end end concurrent-ruby-1.0.5/lib/concurrent/scheduled_task.rb000066400000000000000000000253501305460430400231210ustar00rootroot00000000000000require 'concurrent/constants' require 'concurrent/errors' require 'concurrent/configuration' require 'concurrent/ivar' require 'concurrent/collection/copy_on_notify_observer_set' require 'concurrent/utility/monotonic_time' require 'concurrent/options' module Concurrent # `ScheduledTask` is a close relative of `Concurrent::Future` but with one # important difference: A `Future` is set to execute as soon as possible # whereas a `ScheduledTask` is set to execute after a specified delay. This # implementation is loosely based on Java's # [ScheduledExecutorService](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledExecutorService.html). # It is a more feature-rich variant of {Concurrent.timer}. # # The *intended* schedule time of task execution is set on object construction # with the `delay` argument. The delay is a numeric (floating point or integer) # representing a number of seconds in the future. Any other value or a numeric # equal to or less than zero will result in an exception. The *actual* schedule # time of task execution is set when the `execute` method is called. # # The constructor can also be given zero or more processing options. Currently # the only supported options are those recognized by the # [Dereferenceable](Dereferenceable) module. # # The final constructor argument is a block representing the task to be performed. # If no block is given an `ArgumentError` will be raised. # # **States** # # `ScheduledTask` mixes in the [Obligation](Obligation) module thus giving it # "future" behavior. This includes the expected lifecycle states. `ScheduledTask` # has one additional state, however. While the task (block) is being executed the # state of the object will be `:processing`. This additional state is necessary # because it has implications for task cancellation. # # **Cancellation** # # A `:pending` task can be cancelled using the `#cancel` method. A task in any # other state, including `:processing`, cannot be cancelled. The `#cancel` # method returns a boolean indicating the success of the cancellation attempt. # A cancelled `ScheduledTask` cannot be restarted. It is immutable. # # **Obligation and Observation** # # The result of a `ScheduledTask` can be obtained either synchronously or # asynchronously. `ScheduledTask` mixes in both the [Obligation](Obligation) # module and the # [Observable](http://ruby-doc.org/stdlib-2.0/libdoc/observer/rdoc/Observable.html) # module from the Ruby standard library. With one exception `ScheduledTask` # behaves identically to [Future](Observable) with regard to these modules. # # @!macro copy_options # # @example Basic usage # # require 'concurrent' # require 'thread' # for Queue # require 'open-uri' # for open(uri) # # class Ticker # def get_year_end_closing(symbol, year) # uri = "http://ichart.finance.yahoo.com/table.csv?s=#{symbol}&a=11&b=01&c=#{year}&d=11&e=31&f=#{year}&g=m" # data = open(uri) {|f| f.collect{|line| line.strip } } # data[1].split(',')[4].to_f # end # end # # # Future # price = Concurrent::Future.execute{ Ticker.new.get_year_end_closing('TWTR', 2013) } # price.state #=> :pending # sleep(1) # do other stuff # price.value #=> 63.65 # price.state #=> :fulfilled # # # ScheduledTask # task = Concurrent::ScheduledTask.execute(2){ Ticker.new.get_year_end_closing('INTC', 2013) } # task.state #=> :pending # sleep(3) # do other stuff # task.value #=> 25.96 # # @example Successful task execution # # task = Concurrent::ScheduledTask.new(2){ 'What does the fox say?' } # task.state #=> :unscheduled # task.execute # task.state #=> pending # # # wait for it... # sleep(3) # # task.unscheduled? #=> false # task.pending? #=> false # task.fulfilled? #=> true # task.rejected? #=> false # task.value #=> 'What does the fox say?' # # @example One line creation and execution # # task = Concurrent::ScheduledTask.new(2){ 'What does the fox say?' }.execute # task.state #=> pending # # task = Concurrent::ScheduledTask.execute(2){ 'What do you get when you multiply 6 by 9?' } # task.state #=> pending # # @example Failed task execution # # task = Concurrent::ScheduledTask.execute(2){ raise StandardError.new('Call me maybe?') } # task.pending? #=> true # # # wait for it... # sleep(3) # # task.unscheduled? #=> false # task.pending? #=> false # task.fulfilled? #=> false # task.rejected? #=> true # task.value #=> nil # task.reason #=> # # # @example Task execution with observation # # observer = Class.new{ # def update(time, value, reason) # puts "The task completed at #{time} with value '#{value}'" # end # }.new # # task = Concurrent::ScheduledTask.new(2){ 'What does the fox say?' } # task.add_observer(observer) # task.execute # task.pending? #=> true # # # wait for it... # sleep(3) # # #>> The task completed at 2013-11-07 12:26:09 -0500 with value 'What does the fox say?' # # @!macro monotonic_clock_warning # # @see Concurrent.timer class ScheduledTask < IVar include Comparable # The executor on which to execute the task. # @!visibility private attr_reader :executor # Schedule a task for execution at a specified future time. # # @param [Float] delay the number of seconds to wait for before executing the task # # @yield the task to be performed # # @!macro executor_and_deref_options # # @option opts [object, Array] :args zero or more arguments to be passed the task # block on execution # # @raise [ArgumentError] When no block is given # @raise [ArgumentError] When given a time that is in the past def initialize(delay, opts = {}, &task) raise ArgumentError.new('no block given') unless block_given? raise ArgumentError.new('seconds must be greater than zero') if delay.to_f < 0.0 super(NULL, opts, &nil) synchronize do ns_set_state(:unscheduled) @parent = opts.fetch(:timer_set, Concurrent.global_timer_set) @args = get_arguments_from(opts) @delay = delay.to_f @task = task @time = nil @executor = Options.executor_from_options(opts) || Concurrent.global_io_executor self.observers = Collection::CopyOnNotifyObserverSet.new end end # The `delay` value given at instanciation. # # @return [Float] the initial delay. def initial_delay synchronize { @delay } end # The monotonic time at which the the task is scheduled to be executed. # # @return [Float] the schedule time or nil if `unscheduled` def schedule_time synchronize { @time } end # Comparator which orders by schedule time. # # @!visibility private def <=>(other) schedule_time <=> other.schedule_time end # Has the task been cancelled? # # @return [Boolean] true if the task is in the given state else false def cancelled? synchronize { ns_check_state?(:cancelled) } end # In the task execution in progress? # # @return [Boolean] true if the task is in the given state else false def processing? synchronize { ns_check_state?(:processing) } end # Cancel this task and prevent it from executing. A task can only be # cancelled if it is pending or unscheduled. # # @return [Boolean] true if successfully cancelled else false def cancel if compare_and_set_state(:cancelled, :pending, :unscheduled) complete(false, nil, CancelledOperationError.new) # To avoid deadlocks this call must occur outside of #synchronize # Changing the state above should prevent redundant calls @parent.send(:remove_task, self) else false end end # Reschedule the task using the original delay and the current time. # A task can only be reset while it is `:pending`. # # @return [Boolean] true if successfully rescheduled else false def reset synchronize{ ns_reschedule(@delay) } end # Reschedule the task using the given delay and the current time. # A task can only be reset while it is `:pending`. # # @param [Float] delay the number of seconds to wait for before executing the task # # @return [Boolean] true if successfully rescheduled else false # # @raise [ArgumentError] When given a time that is in the past def reschedule(delay) delay = delay.to_f raise ArgumentError.new('seconds must be greater than zero') if delay < 0.0 synchronize{ ns_reschedule(delay) } end # Execute an `:unscheduled` `ScheduledTask`. Immediately sets the state to `:pending` # and starts counting down toward execution. Does nothing if the `ScheduledTask` is # in any state other than `:unscheduled`. # # @return [ScheduledTask] a reference to `self` def execute if compare_and_set_state(:pending, :unscheduled) synchronize{ ns_schedule(@delay) } end self end # Create a new `ScheduledTask` object with the given block, execute it, and return the # `:pending` object. # # @param [Float] delay the number of seconds to wait for before executing the task # # @!macro executor_and_deref_options # # @return [ScheduledTask] the newly created `ScheduledTask` in the `:pending` state # # @raise [ArgumentError] if no block is given def self.execute(delay, opts = {}, &task) new(delay, opts, &task).execute end # Execute the task. # # @!visibility private def process_task safe_execute(@task, @args) end protected :set, :try_set, :fail, :complete protected # Schedule the task using the given delay and the current time. # # @param [Float] delay the number of seconds to wait for before executing the task # # @return [Boolean] true if successfully rescheduled else false # # @!visibility private def ns_schedule(delay) @delay = delay @time = Concurrent.monotonic_time + @delay @parent.send(:post_task, self) end # Reschedule the task using the given delay and the current time. # A task can only be reset while it is `:pending`. # # @param [Float] delay the number of seconds to wait for before executing the task # # @return [Boolean] true if successfully rescheduled else false # # @!visibility private def ns_reschedule(delay) return false unless ns_check_state?(:pending) @parent.send(:remove_task, self) && ns_schedule(delay) end end end concurrent-ruby-1.0.5/lib/concurrent/settable_struct.rb000066400000000000000000000072561305460430400233530ustar00rootroot00000000000000require 'concurrent/synchronization/abstract_struct' require 'concurrent/errors' require 'concurrent/synchronization' module Concurrent # An thread-safe, write-once variation of Ruby's standard `Struct`. # Each member can have its value set at most once, either at construction # or any time thereafter. Attempting to assign a value to a member # that has already been set will result in a `Concurrent::ImmutabilityError`. # # @see http://ruby-doc.org/core-2.2.0/Struct.html Ruby standard library `Struct` # @see http://en.wikipedia.org/wiki/Final_(Java) Java `final` keyword module SettableStruct include Synchronization::AbstractStruct # @!macro struct_values def values synchronize { ns_values } end alias_method :to_a, :values # @!macro struct_values_at def values_at(*indexes) synchronize { ns_values_at(indexes) } end # @!macro struct_inspect def inspect synchronize { ns_inspect } end alias_method :to_s, :inspect # @!macro struct_merge def merge(other, &block) synchronize { ns_merge(other, &block) } end # @!macro struct_to_h def to_h synchronize { ns_to_h } end # @!macro struct_get def [](member) synchronize { ns_get(member) } end # @!macro struct_equality def ==(other) synchronize { ns_equality(other) } end # @!macro struct_each def each(&block) return enum_for(:each) unless block_given? synchronize { ns_each(&block) } end # @!macro struct_each_pair def each_pair(&block) return enum_for(:each_pair) unless block_given? synchronize { ns_each_pair(&block) } end # @!macro struct_select def select(&block) return enum_for(:select) unless block_given? synchronize { ns_select(&block) } end # @!macro struct_set # # @raise [Concurrent::ImmutabilityError] if the given member has already been set def []=(member, value) if member.is_a? Integer length = synchronize { @values.length } if member >= length raise IndexError.new("offset #{member} too large for struct(size:#{length})") end synchronize do unless @values[member].nil? raise Concurrent::ImmutabilityError.new('struct member has already been set') end @values[member] = value end else send("#{member}=", value) end rescue NoMethodError raise NameError.new("no member '#{member}' in struct") end # @!macro struct_new def self.new(*args, &block) clazz_name = nil if args.length == 0 raise ArgumentError.new('wrong number of arguments (0 for 1+)') elsif args.length > 0 && args.first.is_a?(String) clazz_name = args.shift end FACTORY.define_struct(clazz_name, args, &block) end FACTORY = Class.new(Synchronization::LockableObject) do def define_struct(name, members, &block) synchronize do clazz = Synchronization::AbstractStruct.define_struct_class(SettableStruct, Synchronization::LockableObject, name, members, &block) members.each_with_index do |member, index| clazz.send(:define_method, member) do synchronize { @values[index] } end clazz.send(:define_method, "#{member}=") do |value| synchronize do unless @values[index].nil? raise Concurrent::ImmutabilityError.new('struct member has already been set') end @values[index] = value end end end clazz end end end.new private_constant :FACTORY end end concurrent-ruby-1.0.5/lib/concurrent/synchronization.rb000066400000000000000000000020661305460430400233770ustar00rootroot00000000000000require 'concurrent/utility/engine' require 'concurrent/synchronization/abstract_object' require 'concurrent/utility/native_extension_loader' # load native parts first Concurrent.load_native_extensions require 'concurrent/synchronization/mri_object' require 'concurrent/synchronization/jruby_object' require 'concurrent/synchronization/rbx_object' require 'concurrent/synchronization/truffle_object' require 'concurrent/synchronization/object' require 'concurrent/synchronization/volatile' require 'concurrent/synchronization/abstract_lockable_object' require 'concurrent/synchronization/mri_lockable_object' require 'concurrent/synchronization/jruby_lockable_object' require 'concurrent/synchronization/rbx_lockable_object' require 'concurrent/synchronization/truffle_lockable_object' require 'concurrent/synchronization/lockable_object' require 'concurrent/synchronization/condition' require 'concurrent/synchronization/lock' module Concurrent # {include:file:doc/synchronization.md} # {include:file:doc/synchronization-notes.md} module Synchronization end end concurrent-ruby-1.0.5/lib/concurrent/synchronization/000077500000000000000000000000001305460430400230465ustar00rootroot00000000000000concurrent-ruby-1.0.5/lib/concurrent/synchronization/abstract_lockable_object.rb000066400000000000000000000062441305460430400303660ustar00rootroot00000000000000module Concurrent module Synchronization # @!visibility private class AbstractLockableObject < Synchronization::Object protected # @!macro [attach] synchronization_object_method_synchronize # # @yield runs the block synchronized against this object, # equivalent of java's `synchronize(this) {}` # @note can by made public in descendants if required by `public :synchronize` def synchronize raise NotImplementedError end # @!macro [attach] synchronization_object_method_ns_wait_until # # Wait until condition is met or timeout passes, # protects against spurious wake-ups. # @param [Numeric, nil] timeout in seconds, `nil` means no timeout # @yield condition to be met # @yieldreturn [true, false] # @return [true, false] if condition met # @note only to be used inside synchronized block # @note to provide direct access to this method in a descendant add method # ``` # def wait_until(timeout = nil, &condition) # synchronize { ns_wait_until(timeout, &condition) } # end # ``` def ns_wait_until(timeout = nil, &condition) if timeout wait_until = Concurrent.monotonic_time + timeout loop do now = Concurrent.monotonic_time condition_result = condition.call return condition_result if now >= wait_until || condition_result ns_wait wait_until - now end else ns_wait timeout until condition.call true end end # @!macro [attach] synchronization_object_method_ns_wait # # Wait until another thread calls #signal or #broadcast, # spurious wake-ups can happen. # # @param [Numeric, nil] timeout in seconds, `nil` means no timeout # @return [self] # @note only to be used inside synchronized block # @note to provide direct access to this method in a descendant add method # ``` # def wait(timeout = nil) # synchronize { ns_wait(timeout) } # end # ``` def ns_wait(timeout = nil) raise NotImplementedError end # @!macro [attach] synchronization_object_method_ns_signal # # Signal one waiting thread. # @return [self] # @note only to be used inside synchronized block # @note to provide direct access to this method in a descendant add method # ``` # def signal # synchronize { ns_signal } # end # ``` def ns_signal raise NotImplementedError end # @!macro [attach] synchronization_object_method_ns_broadcast # # Broadcast to all waiting threads. # @return [self] # @note only to be used inside synchronized block # @note to provide direct access to this method in a descendant add method # ``` # def broadcast # synchronize { ns_broadcast } # end # ``` def ns_broadcast raise NotImplementedError end end end end concurrent-ruby-1.0.5/lib/concurrent/synchronization/abstract_object.rb000066400000000000000000000007511305460430400265270ustar00rootroot00000000000000module Concurrent module Synchronization # @!visibility private # @!macro internal_implementation_note class AbstractObject # @abstract has to be implemented based on Ruby runtime def initialize raise NotImplementedError end # @!visibility private # @abstract def full_memory_barrier raise NotImplementedError end def self.attr_volatile(*names) raise NotImplementedError end end end end concurrent-ruby-1.0.5/lib/concurrent/synchronization/abstract_struct.rb000066400000000000000000000077141305460430400266130ustar00rootroot00000000000000module Concurrent module Synchronization # @!visibility private # @!macro internal_implementation_note module AbstractStruct # @!visibility private def initialize(*values) super() ns_initialize(*values) end # @!macro [attach] struct_length # # Returns the number of struct members. # # @return [Fixnum] the number of struct members def length self.class::MEMBERS.length end alias_method :size, :length # @!macro [attach] struct_members # # Returns the struct members as an array of symbols. # # @return [Array] the struct members as an array of symbols def members self.class::MEMBERS.dup end protected # @!macro struct_values # # @!visibility private def ns_values @values.dup end # @!macro struct_values_at # # @!visibility private def ns_values_at(indexes) @values.values_at(*indexes) end # @!macro struct_to_h # # @!visibility private def ns_to_h length.times.reduce({}){|memo, i| memo[self.class::MEMBERS[i]] = @values[i]; memo} end # @!macro struct_get # # @!visibility private def ns_get(member) if member.is_a? Integer if member >= @values.length raise IndexError.new("offset #{member} too large for struct(size:#{@values.length})") end @values[member] else send(member) end rescue NoMethodError raise NameError.new("no member '#{member}' in struct") end # @!macro struct_equality # # @!visibility private def ns_equality(other) self.class == other.class && self.values == other.values end # @!macro struct_each # # @!visibility private def ns_each values.each{|value| yield value } end # @!macro struct_each_pair # # @!visibility private def ns_each_pair @values.length.times do |index| yield self.class::MEMBERS[index], @values[index] end end # @!macro struct_select # # @!visibility private def ns_select values.select{|value| yield value } end # @!macro struct_inspect # # @!visibility private def ns_inspect struct = pr_underscore(self.class.ancestors[1]) clazz = ((self.class.to_s =~ /^#" end # @!macro struct_merge # # @!visibility private def ns_merge(other, &block) self.class.new(*self.to_h.merge(other, &block).values) end # @!visibility private def pr_underscore(clazz) word = clazz.to_s word.gsub!(/::/, '/') word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2') word.gsub!(/([a-z\d])([A-Z])/,'\1_\2') word.tr!("-", "_") word.downcase! word end # @!visibility private def self.define_struct_class(parent, base, name, members, &block) clazz = Class.new(base || Object) do include parent self.const_set(:MEMBERS, members.collect{|member| member.to_s.to_sym}.freeze) def ns_initialize(*values) raise ArgumentError.new('struct size differs') if values.length > length @values = values.fill(nil, values.length..length-1) end end unless name.nil? begin parent.const_set(name, clazz) parent.const_get(name) rescue NameError raise NameError.new("identifier #{name} needs to be constant") end end members.each_with_index do |member, index| clazz.send(:define_method, member) do @values[index] end end clazz.class_exec(&block) unless block.nil? clazz end end end end concurrent-ruby-1.0.5/lib/concurrent/synchronization/condition.rb000066400000000000000000000026311305460430400253630ustar00rootroot00000000000000module Concurrent module Synchronization # TODO (pitr-ch 04-Dec-2016): should be in edge class Condition < LockableObject safe_initialization! # TODO (pitr 12-Sep-2015): locks two objects, improve # TODO (pitr 26-Sep-2015): study # http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/java/util/concurrent/locks/AbstractQueuedSynchronizer.java#AbstractQueuedSynchronizer.Node singleton_class.send :alias_method, :private_new, :new private_class_method :new def initialize(lock) super() @Lock = lock end def wait(timeout = nil) @Lock.synchronize { ns_wait(timeout) } end def ns_wait(timeout = nil) synchronize { super(timeout) } end def wait_until(timeout = nil, &condition) @Lock.synchronize { ns_wait_until(timeout, &condition) } end def ns_wait_until(timeout = nil, &condition) synchronize { super(timeout, &condition) } end def signal @Lock.synchronize { ns_signal } end def ns_signal synchronize { super } end def broadcast @Lock.synchronize { ns_broadcast } end def ns_broadcast synchronize { super } end end class LockableObject < LockableObjectImplementation def new_condition Condition.private_new(self) end end end end concurrent-ruby-1.0.5/lib/concurrent/synchronization/jruby_lockable_object.rb000066400000000000000000000004171305460430400277120ustar00rootroot00000000000000module Concurrent module Synchronization if Concurrent.on_jruby? && Concurrent.java_extensions_loaded? # @!visibility private # @!macro internal_implementation_note class JRubyLockableObject < AbstractLockableObject end end end end concurrent-ruby-1.0.5/lib/concurrent/synchronization/jruby_object.rb000066400000000000000000000017671305460430400260670ustar00rootroot00000000000000module Concurrent module Synchronization if Concurrent.on_jruby? && Concurrent.java_extensions_loaded? module JRubyAttrVolatile def self.included(base) base.extend(ClassMethods) end module ClassMethods def attr_volatile(*names) names.each do |name| ivar = :"@volatile_#{name}" class_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{name} instance_variable_get_volatile(:#{ivar}) end def #{name}=(value) instance_variable_set_volatile(:#{ivar}, value) end RUBY end names.map { |n| [n, :"#{n}="] }.flatten end end end # @!visibility private # @!macro internal_implementation_note class JRubyObject < AbstractObject include JRubyAttrVolatile def initialize # nothing to do end end end end end concurrent-ruby-1.0.5/lib/concurrent/synchronization/lock.rb000066400000000000000000000012131305460430400243200ustar00rootroot00000000000000module Concurrent module Synchronization # TODO (pitr-ch 04-Dec-2016): should be in edge class Lock < LockableObject # TODO use JavaReentrantLock on JRuby public :synchronize def wait(timeout = nil) synchronize { ns_wait(timeout) } end public :ns_wait def wait_until(timeout = nil, &condition) synchronize { ns_wait_until(timeout, &condition) } end public :ns_wait_until def signal synchronize { ns_signal } end public :ns_signal def broadcast synchronize { ns_broadcast } end public :ns_broadcast end end end concurrent-ruby-1.0.5/lib/concurrent/synchronization/lockable_object.rb000066400000000000000000000057541305460430400265100ustar00rootroot00000000000000module Concurrent module Synchronization # @!visibility private # @!macro internal_implementation_note LockableObjectImplementation = case when Concurrent.on_cruby? && Concurrent.ruby_version(:<=, 1, 9, 3) MriMonitorLockableObject when Concurrent.on_cruby? && Concurrent.ruby_version(:>, 1, 9, 3) MriMutexLockableObject when Concurrent.on_jruby? JRubyLockableObject when Concurrent.on_rbx? RbxLockableObject when Concurrent.on_truffle? MriMutexLockableObject else warn 'Possibly unsupported Ruby implementation' MriMonitorLockableObject end private_constant :LockableObjectImplementation # Safe synchronization under any Ruby implementation. # It provides methods like {#synchronize}, {#wait}, {#signal} and {#broadcast}. # Provides a single layer which can improve its implementation over time without changes needed to # the classes using it. Use {Synchronization::Object} not this abstract class. # # @note this object does not support usage together with # [`Thread#wakeup`](http://ruby-doc.org/core-2.2.0/Thread.html#method-i-wakeup) # and [`Thread#raise`](http://ruby-doc.org/core-2.2.0/Thread.html#method-i-raise). # `Thread#sleep` and `Thread#wakeup` will work as expected but mixing `Synchronization::Object#wait` and # `Thread#wakeup` will not work on all platforms. # # @see {Event} implementation as an example of this class use # # @example simple # class AnClass < Synchronization::Object # def initialize # super # synchronize { @value = 'asd' } # end # # def value # synchronize { @value } # end # end # # @!visibility private class LockableObject < LockableObjectImplementation # TODO (pitr 12-Sep-2015): make private for c-r, prohibit subclassing # TODO (pitr 12-Sep-2015): we inherit too much ourselves :/ # @!method initialize(*args, &block) # @!macro synchronization_object_method_initialize # @!method synchronize # @!macro synchronization_object_method_synchronize # @!method wait_until(timeout = nil, &condition) # @!macro synchronization_object_method_ns_wait_until # @!method wait(timeout = nil) # @!macro synchronization_object_method_ns_wait # @!method signal # @!macro synchronization_object_method_ns_signal # @!method broadcast # @!macro synchronization_object_method_ns_broadcast end end end concurrent-ruby-1.0.5/lib/concurrent/synchronization/mri_lockable_object.rb000066400000000000000000000027211305460430400273460ustar00rootroot00000000000000module Concurrent module Synchronization # @!visibility private # @!macro internal_implementation_note class MriLockableObject < AbstractLockableObject protected def ns_signal @__condition__.signal self end def ns_broadcast @__condition__.broadcast self end end # @!visibility private # @!macro internal_implementation_note class MriMutexLockableObject < MriLockableObject safe_initialization! def initialize(*defaults) super(*defaults) @__lock__ = ::Mutex.new @__condition__ = ::ConditionVariable.new end protected def synchronize if @__lock__.owned? yield else @__lock__.synchronize { yield } end end def ns_wait(timeout = nil) @__condition__.wait @__lock__, timeout self end end # @!visibility private # @!macro internal_implementation_note class MriMonitorLockableObject < MriLockableObject safe_initialization! def initialize(*defaults) super(*defaults) @__lock__ = ::Monitor.new @__condition__ = @__lock__.new_cond end protected def synchronize # TODO may be a problem with lock.synchronize { lock.wait } @__lock__.synchronize { yield } end def ns_wait(timeout = nil) @__condition__.wait timeout self end end end end concurrent-ruby-1.0.5/lib/concurrent/synchronization/mri_object.rb000066400000000000000000000020151305460430400255060ustar00rootroot00000000000000module Concurrent module Synchronization module MriAttrVolatile def self.included(base) base.extend(ClassMethods) end module ClassMethods def attr_volatile(*names) names.each do |name| ivar = :"@volatile_#{name}" class_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{name} #{ivar} end def #{name}=(value) #{ivar} = value end RUBY end names.map { |n| [n, :"#{n}="] }.flatten end end def full_memory_barrier # relying on undocumented behavior of CRuby, GVL acquire has lock which ensures visibility of ivars # https://github.com/ruby/ruby/blob/ruby_2_2/thread_pthread.c#L204-L211 end end # @!visibility private # @!macro internal_implementation_note class MriObject < AbstractObject include MriAttrVolatile def initialize # nothing to do end end end end concurrent-ruby-1.0.5/lib/concurrent/synchronization/object.rb000066400000000000000000000134561305460430400246520ustar00rootroot00000000000000module Concurrent module Synchronization # @!visibility private # @!macro internal_implementation_note ObjectImplementation = case when Concurrent.on_cruby? MriObject when Concurrent.on_jruby? JRubyObject when Concurrent.on_rbx? RbxObject when Concurrent.on_truffle? TruffleObject else MriObject end private_constant :ObjectImplementation # Abstract object providing final, volatile, ans CAS extensions to build other concurrent abstractions. # - final instance variables see {Object.safe_initialization!} # - volatile instance variables see {Object.attr_volatile} # - volatile instance variables see {Object.attr_atomic} class Object < ObjectImplementation # TODO make it a module if possible # @!method self.attr_volatile(*names) # Creates methods for reading and writing (as `attr_accessor` does) to a instance variable with # volatile (Java) semantic. The instance variable should be accessed oly through generated methods. # # @param [Array] names of the instance variables to be volatile # @return [Array] names of defined method names # Has to be called by children. def initialize super initialize_volatile_with_cas end # By calling this method on a class, it and all its children are marked to be constructed safely. Meaning that # all writes (ivar initializations) are made visible to all readers of newly constructed object. It ensures # same behaviour as Java's final fields. # @example # class AClass < Concurrent::Synchronization::Object # safe_initialization! # # def initialize # @AFinalValue = 'value' # published safely, does not have to be synchronized # end # end def self.safe_initialization! # define only once, and not again in children return if safe_initialization? def self.new(*args, &block) object = super(*args, &block) ensure object.full_memory_barrier if object end @safe_initialization = true end # @return [true, false] if this class is safely initialized. def self.safe_initialization? @safe_initialization = false unless defined? @safe_initialization @safe_initialization || (superclass.respond_to?(:safe_initialization?) && superclass.safe_initialization?) end # For testing purposes, quite slow. Injects assert code to new method which will raise if class instance contains # any instance variables with CamelCase names and isn't {.safe_initialization?}. def self.ensure_safe_initialization_when_final_fields_are_present Object.class_eval do def self.new(*args, &block) object = super(*args, &block) ensure has_final_field = object.instance_variables.any? { |v| v.to_s =~ /^@[A-Z]/ } if has_final_field && !safe_initialization? raise "there was an instance of #{object.class} with final field but not marked with safe_initialization!" end end end end # Creates methods for reading and writing to a instance variable with # volatile (Java) semantic as {.attr_volatile} does. # The instance variable should be accessed oly through generated methods. # This method generates following methods: `value`, `value=(new_value) #=> new_value`, # `swap_value(new_value) #=> old_value`, # `compare_and_set_value(expected, value) #=> true || false`, `update_value(&block)`. # @param [Array] names of the instance variables to be volatile with CAS. # @return [Array] names of defined method names. def self.attr_atomic(*names) @volatile_cas_fields ||= [] @volatile_cas_fields += names safe_initialization! define_initialize_volatile_with_cas names.each do |name| ivar = :"@Atomic#{name.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }}" class_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{name} #{ivar}.get end def #{name}=(value) #{ivar}.set value end def swap_#{name}(value) #{ivar}.swap value end def compare_and_set_#{name}(expected, value) #{ivar}.compare_and_set expected, value end def update_#{name}(&block) #{ivar}.update(&block) end RUBY end names.flat_map { |n| [n, :"#{n}=", :"swap_#{n}", :"compare_and_set_#{n}", :"update_#{n}"] } end # @param [true,false] inherited should inherited volatile with CAS fields be returned? # @return [Array] Returns defined volatile with CAS fields on this class. def self.volatile_cas_fields(inherited = true) @volatile_cas_fields ||= [] ((superclass.volatile_cas_fields if superclass.respond_to?(:volatile_cas_fields) && inherited) || []) + @volatile_cas_fields end private def self.define_initialize_volatile_with_cas assignments = @volatile_cas_fields.map { |name| "@Atomic#{name.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }} = AtomicReference.new(nil)" }.join("\n") class_eval <<-RUBY def initialize_volatile_with_cas super #{assignments} end RUBY end private_class_method :define_initialize_volatile_with_cas def initialize_volatile_with_cas end end end end concurrent-ruby-1.0.5/lib/concurrent/synchronization/rbx_lockable_object.rb000066400000000000000000000027001305460430400273470ustar00rootroot00000000000000module Concurrent module Synchronization # @!visibility private # @!macro internal_implementation_note class RbxLockableObject < AbstractLockableObject safe_initialization! def initialize(*defaults) super(*defaults) @__Waiters__ = [] @__owner__ = nil end protected def synchronize(&block) if @__owner__ == Thread.current yield else result = nil Rubinius.synchronize(self) do begin @__owner__ = Thread.current result = yield ensure @__owner__ = nil end end result end end def ns_wait(timeout = nil) wchan = Rubinius::Channel.new begin @__Waiters__.push wchan Rubinius.unlock(self) signaled = wchan.receive_timeout timeout ensure Rubinius.lock(self) if !signaled && !@__Waiters__.delete(wchan) # we timed out, but got signaled afterwards, # so pass that signal on to the next waiter @__Waiters__.shift << true unless @__Waiters__.empty? end end self end def ns_signal @__Waiters__.shift << true unless @__Waiters__.empty? self end def ns_broadcast @__Waiters__.shift << true until @__Waiters__.empty? self end end end end concurrent-ruby-1.0.5/lib/concurrent/synchronization/rbx_object.rb000066400000000000000000000021201305460430400255070ustar00rootroot00000000000000module Concurrent module Synchronization module RbxAttrVolatile def self.included(base) base.extend(ClassMethods) end module ClassMethods def attr_volatile(*names) names.each do |name| ivar = :"@volatile_#{name}" class_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{name} Rubinius.memory_barrier #{ivar} end def #{name}=(value) #{ivar} = value Rubinius.memory_barrier end RUBY end names.map { |n| [n, :"#{n}="] }.flatten end end def full_memory_barrier # Rubinius instance variables are not volatile so we need to insert barrier # TODO (pitr 26-Nov-2015): check comments like ^ Rubinius.memory_barrier end end # @!visibility private # @!macro internal_implementation_note class RbxObject < AbstractObject include RbxAttrVolatile def initialize # nothing to do end end end end concurrent-ruby-1.0.5/lib/concurrent/synchronization/truffle_lockable_object.rb000066400000000000000000000002631305460430400302250ustar00rootroot00000000000000module Concurrent module Synchronization class TruffleLockableObject < AbstractLockableObject def new(*) raise NotImplementedError end end end end concurrent-ruby-1.0.5/lib/concurrent/synchronization/truffle_object.rb000066400000000000000000000011541305460430400263710ustar00rootroot00000000000000module Concurrent module Synchronization module TruffleAttrVolatile def self.included(base) base.extend(ClassMethods) end module ClassMethods def attr_volatile(*names) # TODO may not always be available attr_atomic(*names) end end def full_memory_barrier Truffle::System.full_memory_barrier end end # @!visibility private # @!macro internal_implementation_note class TruffleObject < AbstractObject include TruffleAttrVolatile def initialize # nothing to do end end end end concurrent-ruby-1.0.5/lib/concurrent/synchronization/volatile.rb000066400000000000000000000012231305460430400252100ustar00rootroot00000000000000module Concurrent module Synchronization # Volatile adds the attr_volatile class method when included. # # @example # class Foo # include Concurrent::Synchronization::Volatile # # attr_volatile :bar # # def initialize # self.bar = 1 # end # end # # foo = Foo.new # foo.bar # => 1 # foo.bar = 2 # => 2 Volatile = case when Concurrent.on_cruby? MriAttrVolatile when Concurrent.on_jruby? JRubyAttrVolatile when Concurrent.on_rbx? || Concurrent.on_truffle? RbxAttrVolatile else MriAttrVolatile end end end concurrent-ruby-1.0.5/lib/concurrent/thread_safe/000077500000000000000000000000001305460430400220525ustar00rootroot00000000000000concurrent-ruby-1.0.5/lib/concurrent/thread_safe/readme.txt000066400000000000000000000001221305460430400240430ustar00rootroot00000000000000// TODO this directory should be removed over time - remnant of thread_safe merge concurrent-ruby-1.0.5/lib/concurrent/thread_safe/synchronized_delegator.rb000066400000000000000000000026161305460430400271510ustar00rootroot00000000000000require 'delegate' require 'monitor' module Concurrent unless defined?(SynchronizedDelegator) # This class provides a trivial way to synchronize all calls to a given object # by wrapping it with a `Delegator` that performs `Monitor#enter/exit` calls # around the delegated `#send`. Example: # # array = [] # not thread-safe on many impls # array = SynchronizedDelegator.new([]) # thread-safe # # A simple `Monitor` provides a very coarse-grained way to synchronize a given # object, in that it will cause synchronization for methods that have no need # for it, but this is a trivial way to get thread-safety where none may exist # currently on some implementations. # # This class is currently being considered for inclusion into stdlib, via # https://bugs.ruby-lang.org/issues/8556 # # @!visibility private class SynchronizedDelegator < SimpleDelegator def setup @old_abort = Thread.abort_on_exception Thread.abort_on_exception = true end def teardown Thread.abort_on_exception = @old_abort end def initialize(obj) __setobj__(obj) @monitor = Monitor.new end def method_missing(method, *args, &block) monitor = @monitor begin monitor.enter super ensure monitor.exit end end end end end concurrent-ruby-1.0.5/lib/concurrent/thread_safe/util.rb000066400000000000000000000006511305460430400233560ustar00rootroot00000000000000module Concurrent # @!visibility private module ThreadSafe # @!visibility private module Util # TODO (pitr-ch 15-Oct-2016): migrate to Utility::NativeInteger FIXNUM_BIT_SIZE = (0.size * 8) - 2 MAX_INT = (2 ** FIXNUM_BIT_SIZE) - 1 # TODO (pitr-ch 15-Oct-2016): migrate to Utility::ProcessorCounter CPU_COUNT = 16 # is there a way to determine this? end end end concurrent-ruby-1.0.5/lib/concurrent/thread_safe/util/000077500000000000000000000000001305460430400230275ustar00rootroot00000000000000concurrent-ruby-1.0.5/lib/concurrent/thread_safe/util/adder.rb000066400000000000000000000047541305460430400244450ustar00rootroot00000000000000require 'concurrent/thread_safe/util' require 'concurrent/thread_safe/util/striped64' module Concurrent # @!visibility private module ThreadSafe # @!visibility private module Util # A Ruby port of the Doug Lea's jsr166e.LondAdder class version 1.8 # available in public domain. # # Original source code available here: # http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/LongAdder.java?revision=1.8 # # One or more variables that together maintain an initially zero # sum. When updates (method +add+) are contended across threads, # the set of variables may grow dynamically to reduce contention. # Method +sum+ returns the current total combined across the # variables maintaining the sum. # # This class is usually preferable to single +Atomic+ reference when # multiple threads update a common sum that is used for purposes such # as collecting statistics, not for fine-grained synchronization # control. Under low update contention, the two classes have similar # characteristics. But under high contention, expected throughput of # this class is significantly higher, at the expense of higher space # consumption. # # @!visibility private class Adder < Striped64 # Adds the given value. def add(x) if (current_cells = cells) || !cas_base_computed {|current_base| current_base + x} was_uncontended = true hash = hash_code unless current_cells && (cell = current_cells.volatile_get_by_hash(hash)) && (was_uncontended = cell.cas_computed {|current_value| current_value + x}) retry_update(x, hash, was_uncontended) {|current_value| current_value + x} end end end def increment add(1) end def decrement add(-1) end # Returns the current sum. The returned value is _NOT_ an # atomic snapshot: Invocation in the absence of concurrent # updates returns an accurate result, but concurrent updates that # occur while the sum is being calculated might not be # incorporated. def sum x = base if current_cells = cells current_cells.each do |cell| x += cell.value if cell end end x end def reset internal_reset(0) end end end end end concurrent-ruby-1.0.5/lib/concurrent/thread_safe/util/array_hash_rbx.rb000066400000000000000000000013231305460430400263470ustar00rootroot00000000000000require 'concurrent/thread_safe/util' module Concurrent module ThreadSafe module Util def self.make_synchronized_on_rbx(klass) klass.class_eval do private def _mon_initialize @_monitor = Monitor.new unless @_monitor # avoid double initialisation end def self.allocate obj = super obj.send(:_mon_initialize) obj end end klass.superclass.instance_methods(false).each do |method| klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{method}(*args) @_monitor.synchronize { super } end RUBY end end end end end concurrent-ruby-1.0.5/lib/concurrent/thread_safe/util/cheap_lockable.rb000066400000000000000000000067151305460430400263010ustar00rootroot00000000000000require 'concurrent/thread_safe/util' require 'concurrent/thread_safe/util/volatile' module Concurrent # @!visibility private module ThreadSafe # @!visibility private module Util # Provides a cheapest possible (mainly in terms of memory usage) +Mutex+ # with the +ConditionVariable+ bundled in. # # Usage: # class A # include CheapLockable # # def do_exlusively # cheap_synchronize { yield } # end # # def wait_for_something # cheap_synchronize do # cheap_wait until resource_available? # do_something # cheap_broadcast # wake up others # end # end # end # # @!visibility private module CheapLockable private engine = defined?(RUBY_ENGINE) && RUBY_ENGINE if engine == 'rbx' # Making use of the Rubinius' ability to lock via object headers to avoid the overhead of the extra Mutex objects. def cheap_synchronize Rubinius.lock(self) begin yield ensure Rubinius.unlock(self) end end def cheap_wait wchan = Rubinius::Channel.new begin waiters = @waiters ||= [] waiters.push wchan Rubinius.unlock(self) signaled = wchan.receive_timeout nil ensure Rubinius.lock(self) unless signaled or waiters.delete(wchan) # we timed out, but got signaled afterwards (e.g. while waiting to # acquire @lock), so pass that signal on to the next waiter waiters.shift << true unless waiters.empty? end end self end def cheap_broadcast waiters = @waiters ||= [] waiters.shift << true until waiters.empty? self end elsif engine == 'jruby' # Use Java's native synchronized (this) { wait(); notifyAll(); } to avoid the overhead of the extra Mutex objects require 'jruby' def cheap_synchronize JRuby.reference0(self).synchronized { yield } end def cheap_wait JRuby.reference0(self).wait end def cheap_broadcast JRuby.reference0(self).notify_all end else require 'thread' extend Volatile attr_volatile :mutex # Non-reentrant Mutex#syncrhonize def cheap_synchronize true until (my_mutex = mutex) || cas_mutex(nil, my_mutex = Mutex.new) my_mutex.synchronize { yield } end # Releases this object's +cheap_synchronize+ lock and goes to sleep waiting for other threads to +cheap_broadcast+, reacquires the lock on wakeup. # Must only be called in +cheap_broadcast+'s block. def cheap_wait conditional_variable = @conditional_variable ||= ConditionVariable.new conditional_variable.wait(mutex) end # Wakes up all threads waiting for this object's +cheap_synchronize+ lock. # Must only be called in +cheap_broadcast+'s block. def cheap_broadcast if conditional_variable = @conditional_variable conditional_variable.broadcast end end end end end end end concurrent-ruby-1.0.5/lib/concurrent/thread_safe/util/power_of_two_tuple.rb000066400000000000000000000014771305460430400273070ustar00rootroot00000000000000require 'concurrent/thread_safe/util' require 'concurrent/tuple' module Concurrent # @!visibility private module ThreadSafe # @!visibility private module Util # @!visibility private class PowerOfTwoTuple < Concurrent::Tuple def initialize(size) raise ArgumentError, "size must be a power of 2 (#{size.inspect} provided)" unless size > 0 && size & (size - 1) == 0 super(size) end def hash_to_index(hash) (size - 1) & hash end def volatile_get_by_hash(hash) volatile_get(hash_to_index(hash)) end def volatile_set_by_hash(hash, value) volatile_set(hash_to_index(hash), value) end def next_in_size_table self.class.new(size << 1) end end end end end concurrent-ruby-1.0.5/lib/concurrent/thread_safe/util/striped64.rb000066400000000000000000000232011305460430400251760ustar00rootroot00000000000000require 'concurrent/thread_safe/util' require 'concurrent/thread_safe/util/power_of_two_tuple' require 'concurrent/thread_safe/util/volatile' require 'concurrent/thread_safe/util/xor_shift_random' module Concurrent # @!visibility private module ThreadSafe # @!visibility private module Util # A Ruby port of the Doug Lea's jsr166e.Striped64 class version 1.6 # available in public domain. # # Original source code available here: # http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/Striped64.java?revision=1.6 # # Class holding common representation and mechanics for classes supporting # dynamic striping on 64bit values. # # This class maintains a lazily-initialized table of atomically updated # variables, plus an extra +base+ field. The table size is a power of two. # Indexing uses masked per-thread hash codes. Nearly all methods on this # class are private, accessed directly by subclasses. # # Table entries are of class +Cell+; a variant of AtomicLong padded to # reduce cache contention on most processors. Padding is overkill for most # Atomics because they are usually irregularly scattered in memory and thus # don't interfere much with each other. But Atomic objects residing in # arrays will tend to be placed adjacent to each other, and so will most # often share cache lines (with a huge negative performance impact) without # this precaution. # # In part because +Cell+s are relatively large, we avoid creating them until # they are needed. When there is no contention, all updates are made to the # +base+ field. Upon first contention (a failed CAS on +base+ update), the # table is initialized to size 2. The table size is doubled upon further # contention until reaching the nearest power of two greater than or equal # to the number of CPUS. Table slots remain empty (+nil+) until they are # needed. # # A single spinlock (+busy+) is used for initializing and resizing the # table, as well as populating slots with new +Cell+s. There is no need for # a blocking lock: When the lock is not available, threads try other slots # (or the base). During these retries, there is increased contention and # reduced locality, which is still better than alternatives. # # Per-thread hash codes are initialized to random values. Contention and/or # table collisions are indicated by failed CASes when performing an update # operation (see method +retry_update+). Upon a collision, if the table size # is less than the capacity, it is doubled in size unless some other thread # holds the lock. If a hashed slot is empty, and lock is available, a new # +Cell+ is created. Otherwise, if the slot exists, a CAS is tried. Retries # proceed by "double hashing", using a secondary hash (XorShift) to try to # find a free slot. # # The table size is capped because, when there are more threads than CPUs, # supposing that each thread were bound to a CPU, there would exist a # perfect hash function mapping threads to slots that eliminates collisions. # When we reach capacity, we search for this mapping by randomly varying the # hash codes of colliding threads. Because search is random, and collisions # only become known via CAS failures, convergence can be slow, and because # threads are typically not bound to CPUS forever, may not occur at all. # However, despite these limitations, observed contention rates are # typically low in these cases. # # It is possible for a +Cell+ to become unused when threads that once hashed # to it terminate, as well as in the case where doubling the table causes no # thread to hash to it under expanded mask. We do not try to detect or # remove such cells, under the assumption that for long-running instances, # observed contention levels will recur, so the cells will eventually be # needed again; and for short-lived ones, it does not matter. # # @!visibility private class Striped64 # Padded variant of AtomicLong supporting only raw accesses plus CAS. # The +value+ field is placed between pads, hoping that the JVM doesn't # reorder them. # # Optimisation note: It would be possible to use a release-only # form of CAS here, if it were provided. # # @!visibility private class Cell < Concurrent::AtomicReference # TODO: this only adds padding after the :value slot, need to find a way to add padding before the slot # @!visibility private attr_reader *(12.times.collect{ |i| "padding_#{i}".to_sym }) alias_method :cas, :compare_and_set def cas_computed cas(current_value = value, yield(current_value)) end end extend Volatile attr_volatile :cells, # Table of cells. When non-null, size is a power of 2. :base, # Base value, used mainly when there is no contention, but also as a fallback during table initialization races. Updated via CAS. :busy # Spinlock (locked via CAS) used when resizing and/or creating Cells. alias_method :busy?, :busy def initialize super() self.busy = false self.base = 0 end # Handles cases of updates involving initialization, resizing, # creating new Cells, and/or contention. See above for # explanation. This method suffers the usual non-modularity # problems of optimistic retry code, relying on rechecked sets of # reads. # # Arguments: # [+x+] # the value # [+hash_code+] # hash code used # [+x+] # false if CAS failed before call def retry_update(x, hash_code, was_uncontended) # :yields: current_value hash = hash_code collided = false # True if last slot nonempty while true if current_cells = cells if !(cell = current_cells.volatile_get_by_hash(hash)) if busy? collided = false else # Try to attach new Cell if try_to_install_new_cell(Cell.new(x), hash) # Optimistically create and try to insert new cell break else redo # Slot is now non-empty end end elsif !was_uncontended # CAS already known to fail was_uncontended = true # Continue after rehash elsif cell.cas_computed {|current_value| yield current_value} break elsif current_cells.size >= CPU_COUNT || cells != current_cells # At max size or stale collided = false elsif collided && expand_table_unless_stale(current_cells) collided = false redo # Retry with expanded table else collided = true end hash = XorShiftRandom.xorshift(hash) elsif try_initialize_cells(x, hash) || cas_base_computed {|current_base| yield current_base} break end end self.hash_code = hash end private # Static per-thread hash code key. Shared across all instances to # reduce Thread locals pollution and because adjustments due to # collisions in one table are likely to be appropriate for # others. THREAD_LOCAL_KEY = "#{name}.hash_code".to_sym # A thread-local hash code accessor. The code is initially # random, but may be set to a different value upon collisions. def hash_code Thread.current[THREAD_LOCAL_KEY] ||= XorShiftRandom.get end def hash_code=(hash) Thread.current[THREAD_LOCAL_KEY] = hash end # Sets base and all +cells+ to the given value. def internal_reset(initial_value) current_cells = cells self.base = initial_value if current_cells current_cells.each do |cell| cell.value = initial_value if cell end end end def cas_base_computed cas_base(current_base = base, yield(current_base)) end def free? !busy? end def try_initialize_cells(x, hash) if free? && !cells try_in_busy do unless cells # Recheck under lock new_cells = PowerOfTwoTuple.new(2) new_cells.volatile_set_by_hash(hash, Cell.new(x)) self.cells = new_cells end end end end def expand_table_unless_stale(current_cells) try_in_busy do if current_cells == cells # Recheck under lock new_cells = current_cells.next_in_size_table current_cells.each_with_index {|x, i| new_cells.volatile_set(i, x)} self.cells = new_cells end end end def try_to_install_new_cell(new_cell, hash) try_in_busy do # Recheck under lock if (current_cells = cells) && !current_cells.volatile_get(i = current_cells.hash_to_index(hash)) current_cells.volatile_set(i, new_cell) end end end def try_in_busy if cas_busy(false, true) begin yield ensure self.busy = false end end end end end end end concurrent-ruby-1.0.5/lib/concurrent/thread_safe/util/volatile.rb000066400000000000000000000044321305460430400251760ustar00rootroot00000000000000require 'concurrent/thread_safe/util' module Concurrent # @!visibility private module ThreadSafe # @!visibility private module Util # @!visibility private module Volatile # Provides +volatile+ (in the JVM's sense) attribute accessors implemented # atop of +Concurrent::AtomicReference+. # # Usage: # class Foo # extend Concurrent::ThreadSafe::Util::Volatile # attr_volatile :foo, :bar # # def initialize(bar) # super() # must super() into parent initializers before using the volatile attribute accessors # self.bar = bar # end # # def hello # my_foo = foo # volatile read # self.foo = 1 # volatile write # cas_foo(1, 2) # => true | a strong CAS # end # end def attr_volatile(*attr_names) return if attr_names.empty? include(Module.new do atomic_ref_setup = attr_names.map {|attr_name| "@__#{attr_name} = Concurrent::AtomicReference.new"} initialize_copy_setup = attr_names.zip(atomic_ref_setup).map do |attr_name, ref_setup| "#{ref_setup}(other.instance_variable_get(:@__#{attr_name}).get)" end class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 def initialize(*) super #{atomic_ref_setup.join('; ')} end def initialize_copy(other) super #{initialize_copy_setup.join('; ')} end RUBY_EVAL attr_names.each do |attr_name| class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 def #{attr_name} @__#{attr_name}.get end def #{attr_name}=(value) @__#{attr_name}.set(value) end def compare_and_set_#{attr_name}(old_value, new_value) @__#{attr_name}.compare_and_set(old_value, new_value) end RUBY_EVAL alias_method :"cas_#{attr_name}", :"compare_and_set_#{attr_name}" alias_method :"lazy_set_#{attr_name}", :"#{attr_name}=" end end) end end end end end concurrent-ruby-1.0.5/lib/concurrent/thread_safe/util/xor_shift_random.rb000066400000000000000000000031331305460430400267210ustar00rootroot00000000000000require 'concurrent/thread_safe/util' module Concurrent # @!visibility private module ThreadSafe # @!visibility private module Util # A xorshift random number (positive +Fixnum+s) generator, provides # reasonably cheap way to generate thread local random numbers without # contending for the global +Kernel.rand+. # # Usage: # x = XorShiftRandom.get # uses Kernel.rand to generate an initial seed # while true # if (x = XorShiftRandom.xorshift).odd? # thread-localy generate a next random number # do_something_at_random # end # end module XorShiftRandom extend self MAX_XOR_SHIFTABLE_INT = MAX_INT - 1 # Generates an initial non-zero positive +Fixnum+ via +Kernel.rand+. def get Kernel.rand(MAX_XOR_SHIFTABLE_INT) + 1 # 0 can't be xorshifted end # xorshift based on: http://www.jstatsoft.org/v08/i14/paper if 0.size == 4 # using the "yˆ=y>>a; yˆ=y<>c;" transform with the (a,b,c) tuple with values (3,1,14) to minimise Bignum overflows def xorshift(x) x ^= x >> 3 x ^= (x << 1) & MAX_INT # cut-off Bignum overflow x ^= x >> 14 end else # using the "yˆ=y>>a; yˆ=y<>c;" transform with the (a,b,c) tuple with values (1,1,54) to minimise Bignum overflows def xorshift(x) x ^= x >> 1 x ^= (x << 1) & MAX_INT # cut-off Bignum overflow x ^= x >> 54 end end end end end end concurrent-ruby-1.0.5/lib/concurrent/timer_task.rb000066400000000000000000000273631305460430400223070ustar00rootroot00000000000000require 'concurrent/collection/copy_on_notify_observer_set' require 'concurrent/concern/dereferenceable' require 'concurrent/concern/observable' require 'concurrent/atomic/atomic_boolean' require 'concurrent/executor/executor_service' require 'concurrent/executor/ruby_executor_service' require 'concurrent/executor/safe_task_executor' require 'concurrent/scheduled_task' module Concurrent # A very common concurrency pattern is to run a thread that performs a task at # regular intervals. The thread that performs the task sleeps for the given # interval then wakes up and performs the task. Lather, rinse, repeat... This # pattern causes two problems. First, it is difficult to test the business # logic of the task because the task itself is tightly coupled with the # concurrency logic. Second, an exception raised while performing the task can # cause the entire thread to abend. In a long-running application where the # task thread is intended to run for days/weeks/years a crashed task thread # can pose a significant problem. `TimerTask` alleviates both problems. # # When a `TimerTask` is launched it starts a thread for monitoring the # execution interval. The `TimerTask` thread does not perform the task, # however. Instead, the TimerTask launches the task on a separate thread. # Should the task experience an unrecoverable crash only the task thread will # crash. This makes the `TimerTask` very fault tolerant. Additionally, the # `TimerTask` thread can respond to the success or failure of the task, # performing logging or ancillary operations. `TimerTask` can also be # configured with a timeout value allowing it to kill a task that runs too # long. # # One other advantage of `TimerTask` is that it forces the business logic to # be completely decoupled from the concurrency logic. The business logic can # be tested separately then passed to the `TimerTask` for scheduling and # running. # # In some cases it may be necessary for a `TimerTask` to affect its own # execution cycle. To facilitate this, a reference to the TimerTask instance # is passed as an argument to the provided block every time the task is # executed. # # The `TimerTask` class includes the `Dereferenceable` mixin module so the # result of the last execution is always available via the `#value` method. # Dereferencing options can be passed to the `TimerTask` during construction or # at any later time using the `#set_deref_options` method. # # `TimerTask` supports notification through the Ruby standard library # {http://ruby-doc.org/stdlib-2.0/libdoc/observer/rdoc/Observable.html # Observable} module. On execution the `TimerTask` will notify the observers # with three arguments: time of execution, the result of the block (or nil on # failure), and any raised exceptions (or nil on success). If the timeout # interval is exceeded the observer will receive a `Concurrent::TimeoutError` # object as the third argument. # # @!macro copy_options # # @example Basic usage # task = Concurrent::TimerTask.new{ puts 'Boom!' } # task.execute # # task.execution_interval #=> 60 (default) # task.timeout_interval #=> 30 (default) # # # wait 60 seconds... # #=> 'Boom!' # # task.shutdown #=> true # # @example Configuring `:execution_interval` and `:timeout_interval` # task = Concurrent::TimerTask.new(execution_interval: 5, timeout_interval: 5) do # puts 'Boom!' # end # # task.execution_interval #=> 5 # task.timeout_interval #=> 5 # # @example Immediate execution with `:run_now` # task = Concurrent::TimerTask.new(run_now: true){ puts 'Boom!' } # task.execute # # #=> 'Boom!' # # @example Last `#value` and `Dereferenceable` mixin # task = Concurrent::TimerTask.new( # dup_on_deref: true, # execution_interval: 5 # ){ Time.now } # # task.execute # Time.now #=> 2013-11-07 18:06:50 -0500 # sleep(10) # task.value #=> 2013-11-07 18:06:55 -0500 # # @example Controlling execution from within the block # timer_task = Concurrent::TimerTask.new(execution_interval: 1) do |task| # task.execution_interval.times{ print 'Boom! ' } # print "\n" # task.execution_interval += 1 # if task.execution_interval > 5 # puts 'Stopping...' # task.shutdown # end # end # # timer_task.execute # blocking call - this task will stop itself # #=> Boom! # #=> Boom! Boom! # #=> Boom! Boom! Boom! # #=> Boom! Boom! Boom! Boom! # #=> Boom! Boom! Boom! Boom! Boom! # #=> Stopping... # # @example Observation # class TaskObserver # def update(time, result, ex) # if result # print "(#{time}) Execution successfully returned #{result}\n" # elsif ex.is_a?(Concurrent::TimeoutError) # print "(#{time}) Execution timed out\n" # else # print "(#{time}) Execution failed with error #{ex}\n" # end # end # end # # task = Concurrent::TimerTask.new(execution_interval: 1, timeout_interval: 1){ 42 } # task.add_observer(TaskObserver.new) # task.execute # # #=> (2013-10-13 19:08:58 -0400) Execution successfully returned 42 # #=> (2013-10-13 19:08:59 -0400) Execution successfully returned 42 # #=> (2013-10-13 19:09:00 -0400) Execution successfully returned 42 # task.shutdown # # task = Concurrent::TimerTask.new(execution_interval: 1, timeout_interval: 1){ sleep } # task.add_observer(TaskObserver.new) # task.execute # # #=> (2013-10-13 19:07:25 -0400) Execution timed out # #=> (2013-10-13 19:07:27 -0400) Execution timed out # #=> (2013-10-13 19:07:29 -0400) Execution timed out # task.shutdown # # task = Concurrent::TimerTask.new(execution_interval: 1){ raise StandardError } # task.add_observer(TaskObserver.new) # task.execute # # #=> (2013-10-13 19:09:37 -0400) Execution failed with error StandardError # #=> (2013-10-13 19:09:38 -0400) Execution failed with error StandardError # #=> (2013-10-13 19:09:39 -0400) Execution failed with error StandardError # task.shutdown # # @see http://ruby-doc.org/stdlib-2.0/libdoc/observer/rdoc/Observable.html # @see http://docs.oracle.com/javase/7/docs/api/java/util/TimerTask.html class TimerTask < RubyExecutorService include Concern::Dereferenceable include Concern::Observable # Default `:execution_interval` in seconds. EXECUTION_INTERVAL = 60 # Default `:timeout_interval` in seconds. TIMEOUT_INTERVAL = 30 # Create a new TimerTask with the given task and configuration. # # @!macro [attach] timer_task_initialize # @param [Hash] opts the options defining task execution. # @option opts [Integer] :execution_interval number of seconds between # task executions (default: EXECUTION_INTERVAL) # @option opts [Integer] :timeout_interval number of seconds a task can # run before it is considered to have failed (default: TIMEOUT_INTERVAL) # @option opts [Boolean] :run_now Whether to run the task immediately # upon instantiation or to wait until the first # execution_interval # has passed (default: false) # # @!macro deref_options # # @raise ArgumentError when no block is given. # # @yield to the block after :execution_interval seconds have passed since # the last yield # @yieldparam task a reference to the `TimerTask` instance so that the # block can control its own lifecycle. Necessary since `self` will # refer to the execution context of the block rather than the running # `TimerTask`. # # @return [TimerTask] the new `TimerTask` def initialize(opts = {}, &task) raise ArgumentError.new('no block given') unless block_given? super end # Is the executor running? # # @return [Boolean] `true` when running, `false` when shutting down or shutdown def running? @running.true? end # Execute a previously created `TimerTask`. # # @return [TimerTask] a reference to `self` # # @example Instance and execute in separate steps # task = Concurrent::TimerTask.new(execution_interval: 10){ print "Hello World\n" } # task.running? #=> false # task.execute # task.running? #=> true # # @example Instance and execute in one line # task = Concurrent::TimerTask.new(execution_interval: 10){ print "Hello World\n" }.execute # task.running? #=> true def execute synchronize do if @running.false? @running.make_true schedule_next_task(@run_now ? 0 : @execution_interval) end end self end # Create and execute a new `TimerTask`. # # @!macro timer_task_initialize # # @example # task = Concurrent::TimerTask.execute(execution_interval: 10){ print "Hello World\n" } # task.running? #=> true def self.execute(opts = {}, &task) TimerTask.new(opts, &task).execute end # @!attribute [rw] execution_interval # @return [Fixnum] Number of seconds after the task completes before the # task is performed again. def execution_interval synchronize { @execution_interval } end # @!attribute [rw] execution_interval # @return [Fixnum] Number of seconds after the task completes before the # task is performed again. def execution_interval=(value) if (value = value.to_f) <= 0.0 raise ArgumentError.new('must be greater than zero') else synchronize { @execution_interval = value } end end # @!attribute [rw] timeout_interval # @return [Fixnum] Number of seconds the task can run before it is # considered to have failed. def timeout_interval synchronize { @timeout_interval } end # @!attribute [rw] timeout_interval # @return [Fixnum] Number of seconds the task can run before it is # considered to have failed. def timeout_interval=(value) if (value = value.to_f) <= 0.0 raise ArgumentError.new('must be greater than zero') else synchronize { @timeout_interval = value } end end private :post, :<< private def ns_initialize(opts, &task) set_deref_options(opts) self.execution_interval = opts[:execution] || opts[:execution_interval] || EXECUTION_INTERVAL self.timeout_interval = opts[:timeout] || opts[:timeout_interval] || TIMEOUT_INTERVAL @run_now = opts[:now] || opts[:run_now] @executor = Concurrent::SafeTaskExecutor.new(task) @running = Concurrent::AtomicBoolean.new(false) self.observers = Collection::CopyOnNotifyObserverSet.new end # @!visibility private def ns_shutdown_execution @running.make_false super end # @!visibility private def ns_kill_execution @running.make_false super end # @!visibility private def schedule_next_task(interval = execution_interval) ScheduledTask.execute(interval, args: [Concurrent::Event.new], &method(:execute_task)) nil end # @!visibility private def execute_task(completion) return nil unless @running.true? ScheduledTask.execute(execution_interval, args: [completion], &method(:timeout_task)) _success, value, reason = @executor.execute(self) if completion.try? self.value = value schedule_next_task time = Time.now observers.notify_observers do [time, self.value, reason] end end nil end # @!visibility private def timeout_task(completion) return unless @running.true? if completion.try? self.value = value schedule_next_task observers.notify_observers(Time.now, nil, Concurrent::TimeoutError.new) end end end end concurrent-ruby-1.0.5/lib/concurrent/tuple.rb000066400000000000000000000057541305460430400212760ustar00rootroot00000000000000require 'concurrent/atomic/atomic_reference' module Concurrent # A fixed size array with volatile (synchronized, thread safe) getters/setters. # Mixes in Ruby's `Enumerable` module for enhanced search, sort, and traversal. # # @example # tuple = Concurrent::Tuple.new(16) # # tuple.set(0, :foo) #=> :foo | volatile write # tuple.get(0) #=> :foo | volatile read # tuple.compare_and_set(0, :foo, :bar) #=> true | strong CAS # tuple.cas(0, :foo, :baz) #=> false | strong CAS # tuple.get(0) #=> :bar | volatile read # # @see https://en.wikipedia.org/wiki/Tuple Tuple entry at Wikipedia # @see http://www.erlang.org/doc/reference_manual/data_types.html#id70396 Erlang Tuple # @see http://ruby-doc.org/core-2.2.2/Enumerable.html Enumerable class Tuple include Enumerable # The (fixed) size of the tuple. attr_reader :size # @!visibility private Tuple = defined?(Rubinius::Tuple) ? Rubinius::Tuple : Array private_constant :Tuple # Create a new tuple of the given size. # # @param [Integer] size the number of elements in the tuple def initialize(size) @size = size @tuple = tuple = Tuple.new(size) i = 0 while i < size tuple[i] = Concurrent::AtomicReference.new i += 1 end end # Get the value of the element at the given index. # # @param [Integer] i the index from which to retrieve the value # @return [Object] the value at the given index or nil if the index is out of bounds def get(i) return nil if i >= @size || i < 0 @tuple[i].get end alias_method :volatile_get, :get # Set the element at the given index to the given value # # @param [Integer] i the index for the element to set # @param [Object] value the value to set at the given index # # @return [Object] the new value of the element at the given index or nil if the index is out of bounds def set(i, value) return nil if i >= @size || i < 0 @tuple[i].set(value) end alias_method :volatile_set, :set # Set the value at the given index to the new value if and only if the current # value matches the given old value. # # @param [Integer] i the index for the element to set # @param [Object] old_value the value to compare against the current value # @param [Object] new_value the value to set at the given index # # @return [Boolean] true if the value at the given element was set else false def compare_and_set(i, old_value, new_value) return false if i >= @size || i < 0 @tuple[i].compare_and_set(old_value, new_value) end alias_method :cas, :compare_and_set # Calls the given block once for each element in self, passing that element as a parameter. # # @yieldparam [Object] ref the `Concurrent::AtomicReference` object at the current index def each @tuple.each {|ref| yield ref.get} end end end concurrent-ruby-1.0.5/lib/concurrent/tvar.rb000066400000000000000000000136461305460430400211200ustar00rootroot00000000000000require 'set' require 'concurrent/synchronization' module Concurrent # A `TVar` is a transactional variable - a single-element container that # is used as part of a transaction - see `Concurrent::atomically`. # # @!macro thread_safe_variable_comparison # # {include:file:doc/tvar.md} class TVar < Synchronization::Object safe_initialization! # Create a new `TVar` with an initial value. def initialize(value) @value = value @version = 0 @lock = Mutex.new end # Get the value of a `TVar`. def value Concurrent::atomically do Transaction::current.read(self) end end # Set the value of a `TVar`. def value=(value) Concurrent::atomically do Transaction::current.write(self, value) end end # @!visibility private def unsafe_value # :nodoc: @value end # @!visibility private def unsafe_value=(value) # :nodoc: @value = value end # @!visibility private def unsafe_version # :nodoc: @version end # @!visibility private def unsafe_increment_version # :nodoc: @version += 1 end # @!visibility private def unsafe_lock # :nodoc: @lock end end # Run a block that reads and writes `TVar`s as a single atomic transaction. # With respect to the value of `TVar` objects, the transaction is atomic, in # that it either happens or it does not, consistent, in that the `TVar` # objects involved will never enter an illegal state, and isolated, in that # transactions never interfere with each other. You may recognise these # properties from database transactions. # # There are some very important and unusual semantics that you must be aware of: # # * Most importantly, the block that you pass to atomically may be executed # more than once. In most cases your code should be free of # side-effects, except for via TVar. # # * If an exception escapes an atomically block it will abort the transaction. # # * It is undefined behaviour to use callcc or Fiber with atomically. # # * If you create a new thread within an atomically, it will not be part of # the transaction. Creating a thread counts as a side-effect. # # Transactions within transactions are flattened to a single transaction. # # @example # a = new TVar(100_000) # b = new TVar(100) # # Concurrent::atomically do # a.value -= 10 # b.value += 10 # end def atomically raise ArgumentError.new('no block given') unless block_given? # Get the current transaction transaction = Transaction::current # Are we not already in a transaction (not nested)? if transaction.nil? # New transaction begin # Retry loop loop do # Create a new transaction transaction = Transaction.new Transaction::current = transaction # Run the block, aborting on exceptions begin result = yield rescue Transaction::AbortError => e transaction.abort result = Transaction::ABORTED rescue Transaction::LeaveError => e transaction.abort break result rescue => e transaction.abort raise e end # If we can commit, break out of the loop if result != Transaction::ABORTED if transaction.commit break result end end end ensure # Clear the current transaction Transaction::current = nil end else # Nested transaction - flatten it and just run the block yield end end # Abort a currently running transaction - see `Concurrent::atomically`. def abort_transaction raise Transaction::AbortError.new end # Leave a transaction without committing or aborting - see `Concurrent::atomically`. def leave_transaction raise Transaction::LeaveError.new end module_function :atomically, :abort_transaction, :leave_transaction private class Transaction ABORTED = Object.new ReadLogEntry = Struct.new(:tvar, :version) AbortError = Class.new(StandardError) LeaveError = Class.new(StandardError) def initialize @read_log = [] @write_log = {} end def read(tvar) Concurrent::abort_transaction unless valid? if @write_log.has_key? tvar @write_log[tvar] else @read_log.push(ReadLogEntry.new(tvar, tvar.unsafe_version)) tvar.unsafe_value end end def write(tvar, value) # Have we already written to this TVar? unless @write_log.has_key? tvar # Try to lock the TVar unless tvar.unsafe_lock.try_lock # Someone else is writing to this TVar - abort Concurrent::abort_transaction end # If we previously wrote to it, check the version hasn't changed @read_log.each do |log_entry| if log_entry.tvar == tvar and tvar.unsafe_version > log_entry.version Concurrent::abort_transaction end end end # Record the value written @write_log[tvar] = value end def abort unlock end def commit return false unless valid? @write_log.each_pair do |tvar, value| tvar.unsafe_value = value tvar.unsafe_increment_version end unlock true end def valid? @read_log.each do |log_entry| unless @write_log.has_key? log_entry.tvar if log_entry.tvar.unsafe_version > log_entry.version return false end end end true end def unlock @write_log.each_key do |tvar| tvar.unsafe_lock.unlock end end def self.current Thread.current[:current_tvar_transaction] end def self.current=(transaction) Thread.current[:current_tvar_transaction] = transaction end end end concurrent-ruby-1.0.5/lib/concurrent/utility/000077500000000000000000000000001305460430400213105ustar00rootroot00000000000000concurrent-ruby-1.0.5/lib/concurrent/utility/at_exit.rb000066400000000000000000000044571305460430400233040ustar00rootroot00000000000000require 'logger' require 'concurrent/synchronization' module Concurrent # Provides ability to add and remove handlers to be run at `Kernel#at_exit`, order is undefined. # Each handler is executed at most once. # # @!visibility private class AtExitImplementation < Synchronization::LockableObject include Logger::Severity def initialize(*args) super() synchronize { ns_initialize(*args) } end # Add a handler to be run at `Kernel#at_exit` # @param [Object] handler_id optionally provide an id, if allready present, handler is replaced # @yield the handler # @return id of the handler def add(handler_id = nil, &handler) id = handler_id || handler.object_id synchronize { @handlers[id] = handler } id end # Delete a handler by handler_id # @return [true, false] def delete(handler_id) !!synchronize { @handlers.delete handler_id } end # Is handler with handler_id rpesent? # @return [true, false] def handler?(handler_id) synchronize { @handlers.key? handler_id } end # @return copy of the handlers def handlers synchronize { @handlers }.clone end # install `Kernel#at_exit` callback to execute added handlers def install synchronize do @installed ||= begin at_exit { runner } true end self end end # Will it run during `Kernel#at_exit` def enabled? synchronize { @enabled } end # Configure if it runs during `Kernel#at_exit` def enabled=(value) synchronize { @enabled = value } end # run the handlers manually # @return ids of the handlers def run handlers, _ = synchronize { handlers, @handlers = @handlers, {} } handlers.each do |_, handler| begin handler.call rescue => error Concurrent.global_logger.call(ERROR, error) end end handlers.keys end private def ns_initialize(enabled = true) @handlers = {} @enabled = enabled end def runner run if synchronize { @enabled } end end private_constant :AtExitImplementation # @see AtExitImplementation # @!visibility private AtExit = AtExitImplementation.new.install end concurrent-ruby-1.0.5/lib/concurrent/utility/engine.rb000066400000000000000000000024211305460430400231010ustar00rootroot00000000000000module Concurrent module Utility # @!visibility private module EngineDetector def on_jruby? ruby_engine == 'jruby' end def on_jruby_9000? on_jruby? && ruby_version(:>=, 9, 0, 0, JRUBY_VERSION) end def on_cruby? ruby_engine == 'ruby' end def on_rbx? ruby_engine == 'rbx' end def on_truffle? ruby_engine == 'jruby+truffle' end def on_windows? !(RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/).nil? end def on_osx? !(RbConfig::CONFIG['host_os'] =~ /darwin|mac os/).nil? end def on_linux? !(RbConfig::CONFIG['host_os'] =~ /linux/).nil? end def ruby_engine defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby' end def ruby_version(comparison, major, minor, patch, version = RUBY_VERSION) result = (version.split('.').map(&:to_i) <=> [major, minor, patch]) comparisons = { :== => [0], :>= => [1, 0], :<= => [-1, 0], :> => [1], :< => [-1] } comparisons.fetch(comparison).include? result end end end # @!visibility private extend Utility::EngineDetector end concurrent-ruby-1.0.5/lib/concurrent/utility/monotonic_time.rb000066400000000000000000000026431305460430400246650ustar00rootroot00000000000000require 'concurrent/synchronization' module Concurrent class_definition = Class.new(Synchronization::LockableObject) do def initialize @last_time = Time.now.to_f super() end if defined?(Process::CLOCK_MONOTONIC) # @!visibility private def get_time Process.clock_gettime(Process::CLOCK_MONOTONIC) end elsif Concurrent.on_jruby? # @!visibility private def get_time java.lang.System.nanoTime() / 1_000_000_000.0 end else # @!visibility private def get_time synchronize do now = Time.now.to_f if @last_time < now @last_time = now else # clock has moved back in time @last_time += 0.000_001 end end end end end # Clock that cannot be set and represents monotonic time since # some unspecified starting point. # # @!visibility private GLOBAL_MONOTONIC_CLOCK = class_definition.new private_constant :GLOBAL_MONOTONIC_CLOCK # @!macro [attach] monotonic_get_time # # Returns the current time a tracked by the application monotonic clock. # # @return [Float] The current monotonic time when `since` not given else # the elapsed monotonic time between `since` and the current time # # @!macro monotonic_clock_warning def monotonic_time GLOBAL_MONOTONIC_CLOCK.get_time end module_function :monotonic_time end concurrent-ruby-1.0.5/lib/concurrent/utility/native_extension_loader.rb000066400000000000000000000033131305460430400265450ustar00rootroot00000000000000require 'concurrent/utility/engine' module Concurrent module Utility # @!visibility private module NativeExtensionLoader def allow_c_extensions? Concurrent.on_cruby? end def c_extensions_loaded? @c_extensions_loaded ||= false end def java_extensions_loaded? @java_extensions_loaded ||= false end def set_c_extensions_loaded @c_extensions_loaded = true end def set_java_extensions_loaded @java_extensions_loaded = true end def load_native_extensions unless defined? Synchronization::AbstractObject raise 'native_extension_loader loaded before Synchronization::AbstractObject' end if Concurrent.on_cruby? && !c_extensions_loaded? tries = [ lambda do require 'concurrent/extension' set_c_extensions_loaded end, lambda do # may be a Windows cross-compiled native gem require "concurrent/#{RUBY_VERSION[0..2]}/extension" set_c_extensions_loaded end] tries.each do |try| begin try.call break rescue LoadError next end end end if Concurrent.on_jruby? && !java_extensions_loaded? begin require 'concurrent_ruby_ext' set_java_extensions_loaded rescue LoadError # move on with pure-Ruby implementations raise 'On JRuby but Java extensions failed to load.' end end end end end # @!visibility private extend Utility::NativeExtensionLoader end concurrent-ruby-1.0.5/lib/concurrent/utility/native_integer.rb000066400000000000000000000024251305460430400246430ustar00rootroot00000000000000module Concurrent module Utility # @private module NativeInteger # http://stackoverflow.com/questions/535721/ruby-max-integer MIN_VALUE = -(2**(0.size * 8 - 2)) MAX_VALUE = (2**(0.size * 8 - 2) - 1) def ensure_upper_bound(value) if value > MAX_VALUE raise RangeError.new("#{value} is greater than the maximum value of #{MAX_VALUE}") end value end def ensure_lower_bound(value) if value < MIN_VALUE raise RangeError.new("#{value} is less than the maximum value of #{MIN_VALUE}") end value end def ensure_integer(value) unless value.is_a?(Integer) raise ArgumentError.new("#{value} is not an Integer") end value end def ensure_integer_and_bounds(value) ensure_integer value ensure_upper_bound value ensure_lower_bound value end def ensure_positive(value) if value < 0 raise ArgumentError.new("#{value} cannot be negative") end value end def ensure_positive_and_no_zero(value) if value < 1 raise ArgumentError.new("#{value} cannot be negative or zero") end value end extend self end end end concurrent-ruby-1.0.5/lib/concurrent/utility/processor_counter.rb000066400000000000000000000152171305460430400254210ustar00rootroot00000000000000require 'rbconfig' require 'concurrent/delay' module Concurrent module Utility # @!visibility private class ProcessorCounter def initialize @processor_count = Delay.new { compute_processor_count } @physical_processor_count = Delay.new { compute_physical_processor_count } end # Number of processors seen by the OS and used for process scheduling. For # performance reasons the calculated value will be memoized on the first # call. # # When running under JRuby the Java runtime call # `java.lang.Runtime.getRuntime.availableProcessors` will be used. According # to the Java documentation this "value may change during a particular # invocation of the virtual machine... [applications] should therefore # occasionally poll this property." Subsequently the result will NOT be # memoized under JRuby. # # On Windows the Win32 API will be queried for the # `NumberOfLogicalProcessors from Win32_Processor`. This will return the # total number "logical processors for the current instance of the # processor", which taked into account hyperthreading. # # * AIX: /usr/sbin/pmcycles (AIX 5+), /usr/sbin/lsdev # * Alpha: /usr/bin/nproc (/proc/cpuinfo exists but cannot be used) # * BSD: /sbin/sysctl # * Cygwin: /proc/cpuinfo # * Darwin: /usr/bin/hwprefs, /usr/sbin/sysctl # * HP-UX: /usr/sbin/ioscan # * IRIX: /usr/sbin/sysconf # * Linux: /proc/cpuinfo # * Minix 3+: /proc/cpuinfo # * Solaris: /usr/sbin/psrinfo # * Tru64 UNIX: /usr/sbin/psrinfo # * UnixWare: /usr/sbin/psrinfo # # @return [Integer] number of processors seen by the OS or Java runtime # # @see https://github.com/grosser/parallel/blob/4fc8b89d08c7091fe0419ca8fba1ec3ce5a8d185/lib/parallel.rb # # @see http://docs.oracle.com/javase/6/docs/api/java/lang/Runtime.html#availableProcessors() # @see http://msdn.microsoft.com/en-us/library/aa394373(v=vs.85).aspx def processor_count @processor_count.value end # Number of physical processor cores on the current system. For performance # reasons the calculated value will be memoized on the first call. # # On Windows the Win32 API will be queried for the `NumberOfCores from # Win32_Processor`. This will return the total number "of cores for the # current instance of the processor." On Unix-like operating systems either # the `hwprefs` or `sysctl` utility will be called in a subshell and the # returned value will be used. In the rare case where none of these methods # work or an exception is raised the function will simply return 1. # # @return [Integer] number physical processor cores on the current system # # @see https://github.com/grosser/parallel/blob/4fc8b89d08c7091fe0419ca8fba1ec3ce5a8d185/lib/parallel.rb # # @see http://msdn.microsoft.com/en-us/library/aa394373(v=vs.85).aspx # @see http://www.unix.com/man-page/osx/1/HWPREFS/ # @see http://linux.die.net/man/8/sysctl def physical_processor_count @physical_processor_count.value end private def compute_processor_count if Concurrent.on_jruby? java.lang.Runtime.getRuntime.availableProcessors elsif Concurrent.on_truffle? Truffle::Primitive.logical_processors else os_name = RbConfig::CONFIG["target_os"] if os_name =~ /mingw|mswin/ require 'win32ole' result = WIN32OLE.connect("winmgmts://").ExecQuery( "select NumberOfLogicalProcessors from Win32_Processor") result.to_enum.collect(&:NumberOfLogicalProcessors).reduce(:+) elsif File.readable?("/proc/cpuinfo") && (cpuinfo_count = IO.read("/proc/cpuinfo").scan(/^processor/).size) > 0 cpuinfo_count elsif File.executable?("/usr/bin/nproc") IO.popen("/usr/bin/nproc --all", &:read).to_i elsif File.executable?("/usr/bin/hwprefs") IO.popen("/usr/bin/hwprefs thread_count", &:read).to_i elsif File.executable?("/usr/sbin/psrinfo") IO.popen("/usr/sbin/psrinfo", &:read).scan(/^.*on-*line/).size elsif File.executable?("/usr/sbin/ioscan") IO.popen("/usr/sbin/ioscan -kC processor", &:read).scan(/^.*processor/).size elsif File.executable?("/usr/sbin/pmcycles") IO.popen("/usr/sbin/pmcycles -m", &:read).count("\n") elsif File.executable?("/usr/sbin/lsdev") IO.popen("/usr/sbin/lsdev -Cc processor -S 1", &:read).count("\n") elsif File.executable?("/usr/sbin/sysconf") and os_name =~ /irix/i IO.popen("/usr/sbin/sysconf NPROC_ONLN", &:read).to_i elsif File.executable?("/usr/sbin/sysctl") IO.popen("/usr/sbin/sysctl -n hw.ncpu", &:read).to_i elsif File.executable?("/sbin/sysctl") IO.popen("/sbin/sysctl -n hw.ncpu", &:read).to_i else # TODO (pitr-ch 05-Nov-2016): warn about failures 1 end end rescue return 1 end def compute_physical_processor_count ppc = case RbConfig::CONFIG["target_os"] when /darwin1/ IO.popen("/usr/sbin/sysctl -n hw.physicalcpu", &:read).to_i when /linux/ cores = {} # unique physical ID / core ID combinations phy = 0 IO.read("/proc/cpuinfo").scan(/^physical id.*|^core id.*/) do |ln| if ln.start_with?("physical") phy = ln[/\d+/] elsif ln.start_with?("core") cid = phy + ":" + ln[/\d+/] cores[cid] = true if not cores[cid] end end cores.count when /mswin|mingw/ require 'win32ole' result_set = WIN32OLE.connect("winmgmts://").ExecQuery( "select NumberOfCores from Win32_Processor") result_set.to_enum.collect(&:NumberOfCores).reduce(:+) else processor_count end # fall back to logical count if physical info is invalid ppc > 0 ? ppc : processor_count rescue return 1 end end end # create the default ProcessorCounter on load @processor_counter = Utility::ProcessorCounter.new singleton_class.send :attr_reader, :processor_counter def self.processor_count processor_counter.processor_count end def self.physical_processor_count processor_counter.physical_processor_count end end concurrent-ruby-1.0.5/lib/concurrent/version.rb000066400000000000000000000001101305460430400216070ustar00rootroot00000000000000module Concurrent VERSION = '1.0.5' EDGE_VERSION = '0.3.1' end concurrent-ruby-1.0.5/spec/000077500000000000000000000000001305460430400156075ustar00rootroot00000000000000concurrent-ruby-1.0.5/spec/.gitignore000066400000000000000000000000001305460430400175650ustar00rootroot00000000000000concurrent-ruby-1.0.5/spec/concurrent/000077500000000000000000000000001305460430400177715ustar00rootroot00000000000000concurrent-ruby-1.0.5/spec/concurrent/.gitignore000066400000000000000000000000001305460430400217470ustar00rootroot00000000000000concurrent-ruby-1.0.5/spec/concurrent/actor_spec.rb000066400000000000000000000247021305460430400224450ustar00rootroot00000000000000require 'concurrent/actor' module Concurrent module Actor AdHoc = Utils::AdHoc # FIXME better tests! describe 'Concurrent::Actor', edge: true do def terminate_actors(*actors) actors.each do |actor| unless actor.ask!(:terminated?) actor.ask!(:terminate!) end end end class Ping < Context def initialize(queue) @queue = queue end def on_message(message) case message when :child AdHoc.spawn!(:pong, @queue) { |queue| -> m { queue << m } } else @queue << message message end end end it 'forbids Immediate executor' do expect { Utils::AdHoc.spawn! name: 'test', executor: ImmediateExecutor.new }.to raise_error end describe 'spawning' do describe 'Actor#spawn!' do behaviour = -> v { -> _ { v } } subjects = { spawn: -> { Actor.spawn!(AdHoc, :ping, 'arg', &behaviour) }, context_spawn: -> { AdHoc.spawn!(:ping, 'arg', &behaviour) }, spawn_by_hash: -> { Actor.spawn!(class: AdHoc, name: :ping, args: ['arg'], &behaviour) }, context_spawn_by_hash: -> { AdHoc.spawn!(name: :ping, args: ['arg'], &behaviour) } } subjects.each do |desc, subject_definition| describe desc do subject(:actor, &subject_definition) after { terminate_actors actor } describe '#path' do subject { super().path } it { is_expected.to eq '/ping' } end describe '#parent' do subject { super().parent } it { is_expected.to eq Actor.root } end describe '#name' do subject { super().name } it { is_expected.to eq 'ping' } end it('executor should be global') { expect(subject.executor).to eq Concurrent.global_io_executor } describe '#reference' do subject { super().reference } it { is_expected.to eq subject } end it 'returns arg' do expect(subject.ask!(:anything)).to eq 'arg' end end end end it 'terminates on failed initialization' do a = AdHoc.spawn(name: :fail, logger: Concurrent::NULL_LOGGER) { raise } expect(a.ask(nil).wait.rejected?).to be_truthy expect(a.ask!(:terminated?)).to be_truthy end it 'terminates on failed initialization and raises with spawn!' do expect do AdHoc.spawn!(name: :fail, logger: Concurrent::NULL_LOGGER) { raise 'm' } end.to raise_error(StandardError, 'm') end it 'terminates on failed message processing' do a = AdHoc.spawn!(name: :fail, logger: Concurrent::NULL_LOGGER) { -> _ { raise } } expect(a.ask(nil).wait.rejected?).to be_truthy expect(a.ask!(:terminated?)).to be_truthy end end describe 'messaging' do subject { AdHoc.spawn!(:add) { c = 0; -> v { c = c + v } } } specify do subject.tell(1).tell(1) subject << 1 << 1 expect(subject.ask(0).value!).to eq 4 end after { terminate_actors subject } end describe 'children' do let(:parent) do AdHoc.spawn!(:parent) do -> message do if message == :child AdHoc.spawn!(:child) { -> _ { parent } } else children end end end end it 'has children set after a child is created' do child = parent.ask!(:child) expect(parent.ask!(nil)).to include(child) expect(child.ask!(nil)).to eq parent terminate_actors parent, child end end describe 'envelope' do subject { AdHoc.spawn!(:subject) { -> _ { envelope } } } specify do envelope = subject.ask!('a') expect(envelope).to be_a_kind_of Envelope expect(envelope.message).to eq 'a' expect(envelope.future).to be_resolved expect(envelope.future.value).to eq envelope expect(envelope.sender).to eq Thread.current terminate_actors subject end end describe 'termination' do subject do AdHoc.spawn!(:parent) do child = AdHoc.spawn!(:child) { -> v { v } } -> v { child } end end it 'terminates with all its children', buggy: true do child = subject.ask! :child expect(subject.ask!(:terminated?)).to be_falsey subject.ask(:terminate!).wait expect(subject.ask!(:terminated?)).to be_truthy expect(child.ask!(:terminated?)).to be_truthy terminate_actors subject, child end end describe 'dead letter routing' do it 'logs by deafault' do ping = Ping.spawn! :ping, [] ping << :terminate! ping << 'asd' sleep 0.1 # TODO end end describe 'message redirecting' do let(:parent) do AdHoc.spawn!(:parent) do child = AdHoc.spawn!(:child) { -> m { m+1 } } -> message do if message == :child child else redirect child end end end end it 'is evaluated by child' do expect(parent.ask!(1)).to eq 2 end end it 'links' do queue = Queue.new failure = nil # FIXME this leads to weird message processing ordering # failure = AdHoc.spawn!(:failure) { -> m { terminate! } } monitor = AdHoc.spawn!(:monitor) do failure = AdHoc.spawn!(:failure) { -> m { m } } failure << :link -> m { queue << [m, envelope.sender] } end failure << :hehe failure << :terminate! expect(queue.pop).to eq [[:terminated, nil], failure] terminate_actors monitor end it 'links atomically' do queue = Queue.new failure = nil monitor = AdHoc.spawn!(:monitor) do failure = AdHoc.spawn!(name: :failure, link: true) { -> m { m } } -> m { queue << [m, envelope.sender] } end failure << :hehe failure << :terminate! expect(queue.pop).to eq [[:terminated, nil], failure] terminate_actors monitor end describe 'pausing' do it 'pauses on error and resumes' do queue = Queue.new resuming_behaviour = Behaviour.restarting_behaviour_definition(:resume!) test = AdHoc.spawn! name: :tester, behaviour_definition: resuming_behaviour do actor = AdHoc.spawn! name: :pausing, behaviour_definition: Behaviour.restarting_behaviour_definition do queue << :init -> m { m == :add ? 1 : pass } end actor << :link queue << actor.ask!(:linked) actor << nil queue << actor.ask(:add) -> m { queue << m } end expect(queue.pop).to eq :init expect(queue.pop).to include(test) expect(queue.pop.value).to eq 1 expect(queue.pop).to eq :resumed terminate_actors test end it 'pauses on error and resets' do queue = Queue.new test = AdHoc.spawn! name: :tester, behaviour_definition: Behaviour.restarting_behaviour_definition do actor = AdHoc.spawn! name: :pausing, behaviour_definition: Behaviour.restarting_behaviour_definition do queue << :init -> m { m == :object_id ? self.object_id : pass } end queue << actor.ask!(:linked) queue << actor.ask!(:object_id) actor << nil queue << actor.ask(:object_id) -> m do queue << m end end expect(queue.pop).to eq :init expect(queue.pop).to include(test) first_id = queue.pop second_id = queue.pop.value expect(first_id).not_to eq second_id # context already reset expect(queue.pop).to eq :init # rebuilds context expect(queue.pop).to eq :reset terminate_actors test end it 'pauses on error and restarts' do queue = Queue.new resuming_behaviour = Behaviour.restarting_behaviour_definition.map do |c, *args| if Behaviour::Supervising == c [c, *[:restart!, :one_for_one]] else [c, *args] end end test = AdHoc.spawn! name: :tester, behaviour_definition: resuming_behaviour do actor = AdHoc.spawn! name: :pausing, behaviour_definition: Behaviour.restarting_behaviour_definition do queue << :init -> m { m == :add ? 1 : pass } end actor << :link queue << actor.ask!(:linked) actor << nil queue << actor.ask(:add) -> m do queue << m end end expect(queue.pop).to eq :init expect(queue.pop).to include(test) expect(queue.pop.wait.reason).to be_a_kind_of(ActorTerminated) expect(queue.pop).to eq :init expect(queue.pop).to eq :restarted terminate_actors test end end describe 'pool' do it 'supports asks', buggy: true do children = Queue.new pool = Concurrent::Actor::Utils::Pool.spawn! 'pool', 5 do |index| worker = Concurrent::Actor::Utils::AdHoc.spawn! name: "worker-#{index}", supervised: true do lambda do |message| fail if message == :fail 5 + message end end children.push worker worker end 10.times { expect(pool.ask!(5)).to eq 10 } expect(pool.ask(:fail).reason).to be_kind_of RuntimeError expect(pool.ask!(5)).to eq 10 expect(pool.ask!(:terminate!)).to be_truthy 5.times { expect(children.pop.ask!(:terminated?)).to be_truthy } terminate_actors pool end end end end end concurrent-ruby-1.0.5/spec/concurrent/agent_spec.rb000066400000000000000000001121541305460430400224320ustar00rootroot00000000000000require_relative 'concern/observable_shared' module Concurrent describe Agent do let!(:immediate) { Concurrent::ImmediateExecutor.new } let!(:executor) { Concurrent::SingleThreadExecutor.new } context 'initialization' do it 'sets the initial value' do subject = Agent.new(42) expect(subject.value).to eq 42 end it 'sets the initial error to nil' do subject = Agent.new(42) expect(subject.error).to be nil end it 'sets the error mode when given a valid value' do subject = Agent.new(42, error_mode: :fail) expect(subject.error_mode).to eq :fail end it 'defaults the error mode to :continue when an error handler is given' do subject = Agent.new(42, error_handler: ->(value){ true }) expect(subject.error_mode).to eq :continue end it 'defaults the error mode to :fail when no error handler is given' do subject = Agent.new(42) expect(subject.error_mode).to eq :fail end it 'raises an error when given an invalid error mode' do expect { Agent.new(42, error_mode: :bogus) }.to raise_error(ArgumentError) end it 'sets #failed? to false' do subject = Agent.new(42) expect(subject).to_not be_failed expect(subject).to_not be_stopped end end context 'action processing' do specify 'the given block will be passed the current value' do actual = nil expected = 0 subject = Agent.new(expected) subject.send_via(immediate){|value| actual = value } expect(actual).to eq expected end specify 'the given block will be passed any provided arguments' do actual = nil expected = [1, 2, 3, 4] subject = Agent.new(0) subject.send_via(immediate, *expected){|_, *args| actual = args } expect(actual).to eq expected end specify 'the return value will be passed to the validator function' do actual = nil expected = 42 validator = ->(new_value){ actual = new_value; true } subject = Agent.new(0, validator: validator) subject.send_via(immediate){ expected } expect(actual).to eq expected end specify 'upon validation the new value will be set to the block return value' do actual = nil expected = 42 validator = ->(new_value){ true } subject = Agent.new(0, validator: validator) subject.send_via(immediate){ expected } expect(subject.value).to eq expected end specify 'on success all observers will be notified' do observer_class = Class.new do def initialize(bucket) @bucket = bucket end def update(time, old_value, new_value) @bucket.concat([time, old_value, new_value]) end end bucket = [] subject = Agent.new(0) subject.add_observer(observer_class.new(bucket)) subject.send_via(immediate){ 42 } expect(bucket[0]).to be_a Time expect(bucket[1]).to eq 0 expect(bucket[2]).to eq 42 end specify 'any recursive action dispatches will run after the value has been updated' do subject = Agent.new(0) subject.send_via(executor, subject) do |v1, a1| expect(v1).to eq 0 a1.send_via(executor, a1) do |v2, a2| expect(v2).to eq 1 a1.send_via(executor, a2) do |v3, a3| expect(v3).to eq 2 3 end 2 end 1 end end specify 'when the action raises an error the value will not change' do expected = 0 subject = Agent.new(expected) subject.send_via(immediate){ raise StandardError } expect(subject.value).to eq expected end specify 'when the action raises an error the validator will not be called' do validator_called = false validator = ->(new_value){ validator_called = true } subject = Agent.new(0, validator: validator) subject.send_via(immediate){ raise StandareError } expect(validator_called).to be false end specify 'when validation returns false the value will not change' do expected = 0 validator = ->(new_value){ false } subject = Agent.new(0, validator: validator) subject.send_via(immediate){ 42 } expect(subject.value).to eq expected end specify 'when validation raises an error the value will not change' do expected = 0 validator = ->(new_value){ raise StandareError } subject = Agent.new(0, validator: validator) subject.send_via(immediate){ 42 } expect(subject.value).to eq expected end specify 'when the action raises an error the handler will be called' do error_handler_called = false error_handler = ->(agent, exception){ error_handler_called = true } subject = Agent.new(0, error_handler: error_handler) subject.send_via(immediate){ raise StandardError } expect(error_handler_called).to be true end specify 'when validation fails the handler will be called' do error_handler_called = false error_handler = ->(agent, exception){ error_handler_called = true } validator = ->(new_value){ false } subject = Agent.new(0, error_handler: error_handler, validator: validator) subject.send_via(immediate){ 42 } expect(error_handler_called).to be true end specify 'when validation raises an error the handler will be called' do error_handler_called = false error_handler = ->(agent, exception){ error_handler_called = true } validator = ->(new_value){ raise StandardError } subject = Agent.new(0, error_handler: error_handler, validator: validator) subject.send_via(immediate){ 42 } expect(error_handler_called).to be true end end context 'validation' do it 'sets the new value when the validator returns true' do expected = 42 validator = ->(new_value){ true } subject = Agent.new(0, validator: validator) subject.send_via(immediate){ expected } expect(subject.value).to eq expected end it 'rejects the new value when the validator returns false' do expected = 0 validator = ->(new_value){ false } subject = Agent.new(expected, validator: validator) subject.send_via(immediate){ 42 } expect(subject.value).to eq expected end it 'rejects the new value when the validator raises an error' do expected = 0 validator = ->(new_value){ raise StandardError } subject = Agent.new(expected, validator: validator) subject.send_via(immediate){ 42 } expect(subject.value).to eq expected end it 'sets the error when the error mode is :fail and the validator returns false' do validator = ->(new_value){ false } subject = Agent.new(0, error_mode: :fail, validator: validator) subject.send_via(immediate){ 42 } expect(subject.error).to be_a Agent::ValidationError end it 'sets the error when the error mode is :fail and the validator raises an error' do validator = ->(new_value){ raise expected } subject = Agent.new(0, error_mode: :fail, validator: validator) subject.send_via(immediate){ 42 } expect(subject.error).to be_a Agent::ValidationError end it 'does not set an error when the error mode is :continue and the validator returns false' do validator = ->(new_value){ false } subject = Agent.new(0, error_mode: :continue, validator: validator) subject.send_via(immediate){ 42 } expect(subject.error).to be nil end it 'does not set an error when the error mode is :continue and the validator raises an error' do validator = ->(new_value){ raise StandardError } subject = Agent.new(0, error_mode: :continue, validator: validator) subject.send_via(immediate){ 42 } expect(subject.error).to be nil end it 'does not trigger observation when validation fails' do observer_class = Class.new do attr_reader :count def initialize @count = 0 end def update(time, old_value, new_value) @count += 1 end end observer = observer_class.new subject = Agent.new(0, validator: ->(new_value){ false }) subject.add_observer(observer) subject.send_via(immediate){ 42 } expect(observer.count).to eq 0 end end context 'error handling' do specify 'the agent will be passed to the handler' do actual = nil error_handler = ->(agent, error){ actual = agent } subject = Agent.new(0, error_handler: error_handler) subject.send_via(immediate){ raise StandardError} expect(actual).to eq subject end specify 'the exception will be passed to the handler' do expected = StandardError.new actual = nil error_handler = ->(agent, error){ actual = error } subject = Agent.new(0, error_handler: error_handler) subject.send_via(immediate){ raise expected} expect(actual).to eq expected end specify 'does not trigger observation' do observer_class = Class.new do attr_reader :count def initialize @count = 0 end def update(time, old_value, new_value) @count += 1 end end observer = observer_class.new subject = Agent.new(0) subject.add_observer(observer) subject.send_via(immediate){ raise StandardError } expect(observer.count).to eq 0 end end context 'error mode' do context ':continue' do it 'does not set an error when the validator returns false' do validator = ->(new_value){ false } subject = Agent.new(0, error_mode: :continue, validator: validator) subject.send_via(immediate){ 42 } expect(subject.error).to be nil end it 'does not set an error when the validator raises an error' do validator = ->(new_value){ raise StandardError } subject = Agent.new(0, error_mode: :continue, validator: validator) subject.send_via(immediate){ 42 } expect(subject.error).to be nil end it 'does not set an error when the action raises an error' do subject = Agent.new(0, error_mode: :continue) subject.send_via(immediate){ raise StandardError } expect(subject.error).to be nil end it 'does not block further action processing' do expected = 42 actual = nil subject = Agent.new(0, error_mode: :continue) subject.send_via(immediate){ raise StandardError } subject.send_via(immediate){ 42 } expect(subject.value).to eq 42 end it 'sets #failed? to false' do subject = Agent.new(0, error_mode: :continue) subject.send_via(immediate){ raise StandardError } expect(subject).to_not be_failed end end context ':fail' do it 'sets the error when the validator returns false' do validator = ->(new_value){ false } subject = Agent.new(0, error_mode: :fail, validator: validator) subject.send_via(immediate){ 42 } expect(subject.error).to be_a Agent::ValidationError end it 'sets the error when the validator raises an error' do validator = ->(new_value){ raise expected } subject = Agent.new(0, error_mode: :fail, validator: validator) subject.send_via(immediate){ 42 } expect(subject.error).to be_a Agent::ValidationError end it 'sets the error when the action raises an error' do expected = StandardError.new subject = Agent.new(0, error_mode: :fail) subject.send_via(immediate){ raise expected } expect(subject.error).to eq expected end it 'blocks all further action processing until a restart' do latch = Concurrent::CountDownLatch.new expected = 42 subject = Agent.new(0, error_mode: :fail) subject.send_via(immediate){ raise StandardError } subject.send_via(executor){ latch.count_down; expected } latch.wait(0.1) expect(subject.value).to eq 0 subject.restart(42) latch.wait(0.1) sleep(0.1) expect(subject.value).to eq expected end it 'sets #failed? to true' do subject = Agent.new(0, error_mode: :fail) subject.send_via(immediate){ raise StandardError } expect(subject).to be_failed end end end context 'nested actions' do specify 'occur in the order they ar post' do actual = [] expected = [0, 1, 2, 3, 4] latch = Concurrent::CountDownLatch.new subject = Agent.new(0) subject.send_via(executor, subject) do |v1, a1| a1.send_via(executor, a1) do |v2, a2| a1.send_via(executor, a2) do |v3, a3| a1.send_via(executor, a3) do |v4, a4| a1.send_via(executor, a4) do |v5, a5| actual << v5; latch.count_down end actual << v4; v4 + 1 end actual << v3; v3 + 1 end actual << v2; v2 + 1 end actual << v1; v1 + 1 end latch.wait(2) expect(actual).to eq expected end specify 'work with immediate execution' do actual = [] expected = [0, 1, 2] subject = Agent.new(0) subject.send_via(immediate) do |v1| subject.send_via(immediate) do |v2| subject.send_via(immediate) do |v3| actual << v3 end actual << v2; v2 + 1 end actual << v1; v1 + 1 end expect(actual).to eq expected end end context 'posting' do context 'with #send' do it 'returns true when the job is post' do subject = Agent.new(0) expect(subject.send{ nil }).to be true end it 'returns false when #failed?' do subject = Agent.new(0) allow(subject).to receive(:failed?).and_return(true) expect(subject.send{ nil }).to be false end it 'posts to the global fast executor' do expect(Concurrent.global_fast_executor).to receive(:post).with(any_args).and_call_original subject = Agent.new(0) subject.send{ nil } end it 'does not wait for the action to process' do job_done = false subject = Agent.new(0) subject.send{ sleep(5); job_done = true } expect(job_done).to be false end end context 'with #send!' do it 'returns true when the job is post' do subject = Agent.new(0) expect(subject.send!{ nil }).to be true end it 'raises an error when #failed?' do subject = Agent.new(0) allow(subject).to receive(:failed?).and_return(true) expect { subject.send!{ nil } }.to raise_error(Agent::Error) end it 'posts to the global fast executor' do expect(Concurrent.global_fast_executor).to receive(:post).with(any_args).and_call_original subject = Agent.new(0) subject.send!{ nil } end it 'does not wait for the action to process' do job_done = false subject = Agent.new(0) subject.send!{ sleep(5); job_done = true } expect(job_done).to be false end end context 'with #send_off' do it 'returns true when the job is post' do subject = Agent.new(0) expect(subject.send_off{ nil }).to be true end it 'returns false when #failed?' do subject = Agent.new(0) allow(subject).to receive(:failed?).and_return(true) expect(subject.send_off{ nil }).to be false end it 'posts to the global io executor' do expect(Concurrent.global_io_executor).to receive(:post).with(any_args).and_call_original subject = Agent.new(0) subject.send_off{ nil } end it 'does not wait for the action to process' do job_done = false subject = Agent.new(0) subject.send_off{ sleep(5); job_done = true } expect(job_done).to be false end end context 'with #send_off!' do it 'returns true when the job is post' do subject = Agent.new(0) expect(subject.send_off!{ nil }).to be true end it 'raises an error when #failed?' do subject = Agent.new(0) allow(subject).to receive(:failed?).and_return(true) expect { subject.send_off!{ nil } }.to raise_error(Agent::Error) end it 'posts to the global io executor' do expect(Concurrent.global_io_executor).to receive(:post).with(any_args).and_call_original subject = Agent.new(0) subject.send_off!{ nil } end it 'does not wait for the action to process' do job_done = false subject = Agent.new(0) subject.send_off!{ sleep(5); job_done = true } expect(job_done).to be false end end context 'with #send_via' do it 'returns true when the job is post' do subject = Agent.new(0) expect(subject.send_via(immediate){ nil }).to be true end it 'returns false when #failed?' do subject = Agent.new(0) allow(subject).to receive(:failed?).and_return(true) expect(subject.send_via(immediate){ nil }).to be false end it 'posts to the given executor' do expect(immediate).to receive(:post).with(any_args).and_call_original subject = Agent.new(0) subject.send_via(immediate){ nil } end it 'does not wait for the action to process' do job_done = false subject = Agent.new(0) subject.send_via(executor){ sleep(5); job_done = true } expect(job_done).to be false end end context 'with #send_via!' do it 'returns true when the job is post' do subject = Agent.new(0) expect(subject.send_via!(immediate){ nil }).to be true end it 'raises an error when #failed?' do subject = Agent.new(0) allow(subject).to receive(:failed?).and_return(true) expect { subject.send_via!(immediate){ nil } }.to raise_error(Agent::Error) end it 'posts to the given executor' do expect(immediate).to receive(:post).with(any_args).and_call_original subject = Agent.new(0) subject.send_via!(immediate){ nil } end it 'does not wait for the action to process' do job_done = false subject = Agent.new(0) subject.send_via!(executor){ sleep(5); job_done = true } expect(job_done).to be false end end context 'with #post' do it 'returns true when the job is post' do subject = Agent.new(0) expect(subject.post{ nil }).to be true end it 'returns false when #failed?' do subject = Agent.new(0) allow(subject).to receive(:failed?).and_return(true) expect(subject.post{ nil }).to be false end it 'posts to the global io executor' do expect(Concurrent.global_io_executor).to receive(:post).with(any_args).and_call_original subject = Agent.new(0) subject.post{ nil } end it 'does not wait for the action to process' do job_done = false subject = Agent.new(0) subject.post{ sleep(5); job_done = true } expect(job_done).to be false end end context 'with #<<' do it 'returns self when the job is post' do subject = Agent.new(0) expect(subject << proc { nil }).to be subject end it 'returns self when #failed?' do subject = Agent.new(0) allow(subject).to receive(:failed?).and_return(true) expect(subject << proc { nil }).to be subject end it 'posts to the global io executor' do expect(Concurrent.global_io_executor).to receive(:post).with(any_args).and_call_original subject = Agent.new(0) subject << proc { nil } end it 'does not wait for the action to process' do job_done = false subject = Agent.new(0) subject << proc { sleep(5); job_done = true } expect(job_done).to be false end end end context '#restart' do context 'when #failed?' do it 'raises an error if the new value is not valid' do subject = Agent.new(0, error_mode: :fail, validator: ->(new_value){ false }) subject.send_via(immediate){ raise StandardError } expect { subject.restart(0) }.to raise_error(Agent::Error) end it 'sets the new value' do subject = Agent.new(0, error_mode: :fail) subject.send_via(immediate){ raise StandardError } subject.restart(42) expect(subject.value).to eq 42 end it 'clears the error' do subject = Agent.new(0, error_mode: :fail) subject.send_via(immediate){ raise StandardError } subject.restart(42) expect(subject.error).to be nil end it 'sets #failed? to true' do subject = Agent.new(0, error_mode: :fail) subject.send_via(immediate){ raise StandardError } subject.restart(42) expect(subject).to_not be_failed end it 'removes all actions from the queue when :clear_actions is true' do latch = Concurrent::CountDownLatch.new end_latch = Concurrent::CountDownLatch.new subject = Agent.new(0, error_mode: :fail) subject.send_via(executor){ latch.wait; raise StandardError } subject.send_via(executor){ end_latch.count_down } latch.count_down 10.times{ break if subject.failed?; sleep(0.1) } subject.restart(42, clear_actions: true) result = end_latch.wait(0.1) expect(result).to be false end it 'does not clear the action queue when :clear_actions is false' do latch = Concurrent::CountDownLatch.new end_latch = Concurrent::CountDownLatch.new subject = Agent.new(0, error_mode: :fail) subject.send_via(executor){ latch.wait; raise StandardError } subject.send_via(executor){ end_latch.count_down } latch.count_down 10.times{ break if subject.failed?; sleep(0.1) } subject.restart(42, clear_actions: false) result = end_latch.wait(3) expect(result).to be true end it 'does not clear the action queue when :clear_actions is not given' do latch = Concurrent::CountDownLatch.new end_latch = Concurrent::CountDownLatch.new subject = Agent.new(0, error_mode: :fail) subject.send_via(executor){ latch.wait; raise StandardError } subject.send_via(executor){ end_latch.count_down } latch.count_down 10.times{ break if subject.failed?; sleep(0.1) } subject.restart(42) result = end_latch.wait(3) expect(result).to be true end it 'resumes action processing if actions are enqueued' do count = 5 latch = Concurrent::CountDownLatch.new finish_latch = Concurrent::CountDownLatch.new(5) subject = Agent.new(0, error_mode: :fail) subject.send_via(executor){ latch.wait; raise StandardError } count.times{ subject.send_via(executor){ finish_latch.count_down } } queue = subject.instance_variable_get(:@queue) size = queue.size expect(size).to be > 0 latch.count_down 10.times{ break if subject.failed?; sleep(0.1) } subject.restart(42, clear_actions: false) expect(finish_latch.wait(5)).to be true end it 'does not trigger observation' do observer_class = Class.new do attr_reader :count def initialize @count = 0 end def update(time, old_value, new_value) @count += 1 end end observer = observer_class.new subject = Agent.new(0, error_mode: :fail) subject.add_observer(observer) subject.send_via(immediate){ raise StandardError } subject.restart(42) expect(observer.count).to eq 0 end end context 'when not #failed?' do it 'raises an error' do subject = Agent.new(0) expect { subject.restart(0) }.to raise_error(Agent::Error) end end end context 'waiting' do context 'the await job' do it 'does not change the value' do expected = 42 subject = Agent.new(0) subject.send_via(executor){ sleep(0.1); expected } subject.await_for(1) expect(subject.value).to eq expected end it 'does not trigger the error mode' do subject = Agent.new(10) subject.send{ |x| sleep(0.1); x + 1 } subject.await_for(1) expect(subject.value).to eq 11 expect(subject).to_not be_failed expect(subject.error).to be nil end it 'does not trigger observers' do observer_class = Class.new do attr_reader :count def initialize @count = 0 end def update(time, old_value, new_value) @count += 1 end end observer = observer_class.new subject = Agent.new(0) subject.add_observer(observer) subject.send_via(executor){ sleep(0.1); 42 } subject.await_for(1) expect(observer.count).to eq 1 end it 'waits for nested actions' do bucket = [] latch = Concurrent::CountDownLatch.new executor = Concurrent::FixedThreadPool.new(3) subject = Agent.new(0) subject.send_via(executor) do subject.send_via(executor) do subject.send_via(executor) do bucket << 3 end latch.count_down sleep(0.2) bucket << 2 end bucket << 1 end latch.wait subject.await_for(5) expect(bucket).to eq [1, 2, 3] end end context 'with #await' do it 'returns self when there are no pending actions' do subject = Agent.new(0) expect(subject.await).to eq subject expect(subject.await.value).to eq 0 end it 'does not block on actions from other threads' do latch = Concurrent::CountDownLatch.new subject = Agent.new(0) t = Thread.new do subject.send_via(executor){ sleep } latch.count_down end latch.wait(0.1) ok = subject.await t.kill expect(ok).to be_truthy end it 'blocks indefinitely' do start = Concurrent.monotonic_time subject = Agent.new(0) subject.send_via(executor){ sleep(1) } expect(subject.await).to be_truthy expect(Concurrent.monotonic_time - start).to be > 0.5 end it 'returns true when all prior actions have processed' do count = 0 expected = 5 subject = Agent.new(0) subject.send_via(executor){ sleep(1) } expected.times{ subject.send_via(executor){ count += 1 } } subject.await expect(count).to eq expected end it 'blocks forever if restarted with :clear_actions true', notravis: true do pending('the timing is nearly impossible'); fail subject = Agent.new(0, error_mode: :fail) t = Thread.new do subject.send_via(executor){ sleep(0.1) } subject.send_via(executor){ raise StandardError } subject.send_via(executor){ nil } Thread.new{ subject.restart(42, clear_actions: true) } subject.await end thread_status = t.join(0.3) t.kill expect(thread_status).to be nil end end context 'with #await_for' do it 'returns true when there are no pending actions' do subject = Agent.new(0) expect(subject.await_for(1)).to be true end it 'does not block on actions from other threads' do latch = Concurrent::CountDownLatch.new subject = Agent.new(0) t = Thread.new do subject.send_via(executor){ sleep } latch.count_down end latch.wait(0.1) ok = subject.await_for(0.1) t.kill expect(ok).to be true end it 'returns true when all prior actions have processed', buggy: true do subject = Agent.new(0) subject.send_via(executor){ sleep(1) } 5.times{ subject.send_via(executor){ nil } } expect(subject.await_for(10)).to be true end it 'returns false on timeout' do subject = Agent.new(0) subject.send_via(executor){ sleep(1) } 5.times{ subject.send_via(executor){ nil } } expect(subject.await_for(0.1)).to be false end it 'returns false if restarted with :clear_actions true', notravis: true do pending('the timing is nearly impossible'); fail subject = Agent.new(0, error_mode: :fail) subject.send_via(executor){ sleep(0.1) } subject.send_via(executor){ raise StandardError } subject.send_via(executor){ nil } t = Thread.new{ subject.restart(42, clear_actions: true) } ok = subject.await_for(0.2) expect(ok).to be false end end context 'with #await_for!' do it 'returns true when there are no pending actions' do subject = Agent.new(0) expect(subject.await_for!(1)).to be true end it 'does not block on actions from other threads' do latch = Concurrent::CountDownLatch.new subject = Agent.new(0) t = Thread.new do subject.send_via(executor){ sleep } latch.count_down end latch.wait(0.1) ok = subject.await_for!(0.1) t.kill expect(ok).to be true end it 'returns true when all prior actions have processed' do subject = Agent.new(0) subject.send_via(executor){ sleep(1) } 5.times{ subject.send_via(executor){ nil } } expect(subject.await_for!(10)).to be true end it 'raises an error on timeout' do subject = Agent.new(0) subject.send_via(executor){ sleep(1) } 5.times{ subject.send_via(executor){ nil } } expect { subject.await_for!(0.1) }.to raise_error(Concurrent::TimeoutError) end it 'raises an error if restarted with :clear_actions true', notravis: true do pending('the timing is nearly impossible'); fail subject = Agent.new(0, error_mode: :fail) subject.send_via(executor){ sleep(0.1) } subject.send_via(executor){ raise StandardError } subject.send_via(executor){ nil } t = Thread.new{ subject.restart(42, clear_actions: true) } expect { subject.await_for!(0.2) }.to raise_error(Concurrent::TimeoutError) end end context 'with #wait' do it 'returns true when there are no pending actions and timeout is nil' do subject = Agent.new(0) expect(subject.wait(nil)).to be true end it 'returns true when there are no pending actions and a timeout is given' do subject = Agent.new(0) expect(subject.wait(1)).to be true end it 'does not block on actions from other threads' do latch = Concurrent::CountDownLatch.new subject = Agent.new(0) t = Thread.new do subject.send_via(executor){ sleep } latch.count_down end latch.wait(0.1) ok = subject.wait(0.1) t.kill expect(ok).to be true end it 'blocks indefinitely when timeout is nil' do start = Concurrent.monotonic_time subject = Agent.new(0) subject.send_via(executor){ sleep(1) } expect(subject.wait(nil)).to be true expect(Concurrent.monotonic_time - start).to be > 0.5 end it 'blocks forever when timeout is nil and restarted with :clear_actions true', notravis: true do pending('the timing is nearly impossible'); fail subject = Agent.new(0, error_mode: :fail) t = Thread.new do subject.send_via(executor){ sleep(0.1) } subject.send_via(executor){ raise StandardError } subject.send_via(executor){ nil } Thread.new{ subject.restart(42, clear_actions: true) } subject.wait(nil) end thread_status = t.join(0.3) t.kill expect(thread_status).to be nil end it 'returns true when all prior actions have processed' do count = 0 expected = 5 subject = Agent.new(0) subject.send_via(executor){ sleep(1) } expected.times{ subject.send_via(executor){ count += 1 } } subject.wait(nil) expect(count).to eq expected end it 'returns false on timeout' do subject = Agent.new(0) subject.send_via(executor){ sleep(1) } 5.times{ subject.send_via(executor){ nil } } expect(subject.wait(0.1)).to be false end it 'returns false when timeout is given and restarted with :clear_actions true', notravis: true do pending('the timing is nearly impossible'); fail subject = Agent.new(0, error_mode: :fail) subject.send_via(executor){ sleep(0.1) } subject.send_via(executor){ raise StandardError } subject.send_via(executor){ nil } t = Thread.new{ subject.restart(42, clear_actions: true) } ok = subject.wait(0.2) expect(ok).to be false end end context 'with .await' do it 'returns true when all prior actions on all agents have processed' do latch = Concurrent::CountDownLatch.new agents = 3.times.collect{ Agent.new(0) } agents.each{|agent| agent.send_via(executor, latch){|_, l| l.wait(1) } } Thread.new{ latch.count_down } ok = Agent.await(*agents) expect(ok).to be true end end context 'with .await_for' do it 'returns true when there are no pending actions' do agents = 3.times.collect{ Agent.new(0) } ok = Agent.await_for(1, *agents) expect(ok).to be true end it 'returns true when all prior actions for all agents have processed' do latch = Concurrent::CountDownLatch.new agents = 3.times.collect{ Agent.new(0) } agents.each{|agent| agent.send_via(executor, latch){|_, l| l.wait(1) } } Thread.new{ latch.count_down } ok = Agent.await_for(1, *agents) expect(ok).to be true end it 'returns false on timeout' do agents = 3.times.collect{ Agent.new(0) } agents.each{|agent| agent.send_via(executor){ sleep(0.3) } } ok = Agent.await_for(0.1, *agents) expect(ok).to be false end end context 'with await_for!' do it 'returns true when there are no pending actions' do agents = 3.times.collect{ Agent.new(0) } ok = Agent.await_for!(1, *agents) expect(ok).to be true end it 'returns true when all prior actions for all agents have processed' do latch = Concurrent::CountDownLatch.new agents = 3.times.collect{ Agent.new(0) } agents.each{|agent| agent.send_via(executor, latch){|_, l| l.wait(1) } } Thread.new{ latch.count_down } ok = Agent.await_for!(1, *agents) expect(ok).to be true end it 'raises an exception on timeout' do agents = 3.times.collect{ Agent.new(0) } agents.each{|agent| agent.send_via(executor){ sleep(0.3) } } expect { Agent.await_for!(0.1, *agents) }.to raise_error(Concurrent::TimeoutError) end end end context :observable do subject { Agent.new(0) } def trigger_observable(observable) observable.send_via(immediate){ 42 } end it_behaves_like :observable end end end concurrent-ruby-1.0.5/spec/concurrent/array_spec.rb000066400000000000000000000005271305460430400224520ustar00rootroot00000000000000module Concurrent describe Array do let!(:ary) { described_class.new } it 'concurrency' do (1..THREADS).map do |i| Thread.new do 1000.times do ary << i ary.each { |x| x * 2 } ary.shift ary.last end end end.map(&:join) end end end concurrent-ruby-1.0.5/spec/concurrent/async_spec.rb000066400000000000000000000176641305460430400224630ustar00rootroot00000000000000module Concurrent describe Async do let(:async_class) do Class.new do include Concurrent::Async attr_accessor :accessor def initialize(*args) end def echo(msg) msg end def gather(first, second = nil) return first, second end def boom(ex = StandardError.new) raise ex end def wait(seconds) sleep(seconds) end def with_block yield end end end subject do async_class.new end context 'object creation' do it 'delegates to the original constructor' do args = [:foo, 'bar', 42] expect(async_class).to receive(:original_new).once.with(*args).and_call_original async_class.new(*args) end specify 'passes all args to the original constructor' do clazz = Class.new do include Concurrent::Async attr_reader :args def initialize(*args) @args = args end end object = clazz.new(:foo, :bar) expect(object.args).to eq [:foo, :bar] end specify 'passes a given block to the original constructor' do clazz = Class.new do include Concurrent::Async attr_reader :block def initialize(&block) @block = yield end end object = clazz.new{ 42 } expect(object.block).to eq 42 end specify 'initializes synchronization' do mock = async_class.new allow(async_class).to receive(:original_new).and_return(mock) expect(mock).to receive(:init_synchronization).once.with(no_args) async_class.new end end context '#validate_argc' do subject do Class.new { def zero() nil; end def three(a, b, c, &block) nil; end def two_plus_two(a, b, c=nil, d=nil, &block) nil; end def many(*args, &block) nil; end }.new end it 'raises an exception when the method is not defined' do expect { Async::validate_argc(subject, :bogus) }.to raise_error(StandardError) end it 'raises an exception for too many args on a zero arity method' do expect { Async::validate_argc(subject, :zero, 1, 2, 3) }.to raise_error(ArgumentError) end it 'does not raise an exception for correct zero arity' do expect { Async::validate_argc(subject, :zero) }.not_to raise_error end it 'raises an exception for too many args on a method with positive arity' do expect { Async::validate_argc(subject, :three, 1, 2, 3, 4) }.to raise_error(ArgumentError) end it 'raises an exception for too few args on a method with positive arity' do expect { Async::validate_argc(subject, :three, 1, 2) }.to raise_error(ArgumentError) end it 'does not raise an exception for correct positive arity' do expect { Async::validate_argc(subject, :three, 1, 2, 3) }.not_to raise_error end it 'raises an exception for too few args on a method with negative arity' do expect { Async::validate_argc(subject, :two_plus_two, 1) }.to raise_error(ArgumentError) end it 'does not raise an exception for correct negative arity' do expect { Async::validate_argc(subject, :two_plus_two, 1, 2) Async::validate_argc(subject, :two_plus_two, 1, 2, 3, 4) Async::validate_argc(subject, :two_plus_two, 1, 2, 3, 4, 5, 6) Async::validate_argc(subject, :many) Async::validate_argc(subject, :many, 1, 2) Async::validate_argc(subject, :many, 1, 2, 3, 4) }.not_to raise_error end end context '#async' do it 'raises an error when calling a method that does not exist' do expect { subject.async.bogus }.to raise_error(StandardError) end it 'raises an error when passing too few arguments' do expect { subject.async.gather }.to raise_error(ArgumentError) end it 'raises an error when pasing too many arguments (arity >= 0)' do expect { subject.async.echo(1, 2, 3, 4, 5) }.to raise_error(StandardError) end it 'returns a :pending IVar' do val = subject.async.wait(1) expect(val).to be_a Concurrent::IVar expect(val).to be_pending end it 'runs the future on the global executor' do expect(Concurrent.global_io_executor).to receive(:post).with(any_args). and_call_original subject.async.echo(:foo) end it 'sets the value on success' do val = subject.async.echo(:foo) expect(val.value).to eq :foo expect(val).to be_fulfilled end it 'sets the reason on failure' do ex = ArgumentError.new val = subject.async.boom(ex) val.wait expect(val.reason).to eq ex expect(val).to be_rejected end it 'sets the reason when giving too many optional arguments' do val = subject.async.gather(1, 2, 3, 4, 5) val.wait expect(val.reason).to be_a StandardError expect(val).to be_rejected end it 'supports attribute accessors' do subject.async.accessor = :foo val = subject.async.accessor expect(val.value).to eq :foo expect(subject.accessor).to eq :foo end it 'supports methods with blocks' do val = subject.async.with_block{ :foo } expect(val.value).to eq :foo end end context '#await' do it 'raises an error when calling a method that does not exist' do expect { subject.await.bogus }.to raise_error(StandardError) end it 'raises an error when passing too few arguments' do expect { subject.await.gather }.to raise_error(ArgumentError) end it 'raises an error when pasing too many arguments (arity >= 0)' do expect { subject.await.echo(1, 2, 3, 4, 5) }.to raise_error(StandardError) end it 'returns a :fulfilled IVar' do val = subject.await.echo(5) expect(val).to be_a Concurrent::IVar expect(val).to be_fulfilled end it 'runs the future on the global executor' do expect(Concurrent.global_io_executor).to receive(:post).with(any_args). and_call_original subject.await.echo(:foo) end it 'sets the value on success' do val = subject.await.echo(:foo) expect(val.value).to eq :foo expect(val).to be_fulfilled end it 'sets the reason on failure' do ex = ArgumentError.new val = subject.await.boom(ex) expect(val.reason).to eq ex expect(val).to be_rejected end it 'sets the reason when giving too many optional arguments' do val = subject.await.gather(1, 2, 3, 4, 5) expect(val.reason).to be_a StandardError expect(val).to be_rejected end it 'supports attribute accessors' do subject.await.accessor = :foo val = subject.await.accessor expect(val.value).to eq :foo expect(subject.accessor).to eq :foo end it 'supports methods with blocks' do val = subject.await.with_block{ :foo } expect(val.value).to eq :foo end end context 'locking' do it 'uses the same lock for both #async and #await' do object = Class.new { include Concurrent::Async attr_reader :bucket def gather(seconds, first, *rest) sleep(seconds) (@bucket ||= []).concat([first]) @bucket.concat(rest) end }.new object.async.gather(0.5, :a, :b) object.await.gather(0, :c, :d) expect(object.bucket).to eq [:a, :b, :c, :d] end end end end concurrent-ruby-1.0.5/spec/concurrent/atom_spec.rb000066400000000000000000000131501305460430400222700ustar00rootroot00000000000000require_relative 'concern/observable_shared' module Concurrent describe Atom do context 'construction' do it 'sets the initial value to the given value' do atom = Atom.new(42) expect(atom.value).to eq 42 end end context '#compare_and_set' do it 'sets the new value if the current value matches' do atom = Atom.new(42) atom.compare_and_set(42, :foo) expect(atom.value).to eq :foo end it 'returns true if the current value matches' do atom = Atom.new(42) expect(atom.compare_and_set(42, :foo)).to be true end it 'rejects the new value if the current value does not match' do atom = Atom.new(42) atom.compare_and_set(:foo, 'bar') expect(atom.value).to eq 42 end it 'returns false if the current value does not match' do atom = Atom.new(42) expect(atom.compare_and_set(:foo, 'bar')).to be false end it 'rejects the new value if the validator returns false' do validator = ->(value){ false } atom = Atom.new(42, validator: validator) atom.compare_and_set(42, :foo) expect(atom.value).to eq 42 end it 'rejects the new value if the validator raises an exception' do validator = ->(value){ raise StandardError } atom = Atom.new(42, validator: validator) atom.compare_and_set(42, :foo) expect(atom.value).to eq 42 end it 'returns false if the validator returns false' do validator = ->(value){ false } atom = Atom.new(42, validator: validator) expect(atom.compare_and_set(42, :foo)).to be false end it 'returns false if the validator raises an exception' do validator = ->(value){ raise StandardError } atom = Atom.new(42, validator: validator) expect(atom.compare_and_set(42, :foo)).to be false end end context '#swap' do it 'raises an exception when no block is given' do atom = Atom.new(42) expect { atom.swap }.to raise_error(ArgumentError) end it 'passes the current value to the block' do actual = nil expected = 42 atom = Atom.new(expected) atom.swap do |value| actual = value end expect(actual).to eq expected end it 'passes all arguments to the block' do actual = nil expected = [1, 2, 3] atom = Atom.new(42) atom.swap(*expected) do |value, *args| actual = args end expect(actual).to eq expected end it 'sets the new value to the result of the block' do atom = Atom.new(42) atom.swap{ :foo } expect(atom.value).to eq :foo end it 'rejects the new value if the validator returns false' do validator = ->(value){ false } atom = Atom.new(42, validator: validator) atom.swap{ 100 } expect(atom.value).to eq 42 end it 'rejects the new value if the validator raises an exception' do validator = ->(value){ raise StandardError } atom = Atom.new(42, validator: validator) atom.swap{ 100 } expect(atom.value).to eq 42 end it 'returns the new value on success' do atom = Atom.new(42) expect(atom.swap{ :foo }).to eq :foo end it 'returns the old value if the validator returns false' do validator = ->(value){ false } atom = Atom.new(42, validator: validator) expect(atom.swap{ 100 }).to eq 42 end it 'returns the old value if the validator raises an exception' do validator = ->(value){ raise StandardError } atom = Atom.new(42, validator: validator) expect(atom.swap{ 100 }).to eq 42 end it 'calls the block more than once if the value changes underneath' do latch1 = Concurrent::CountDownLatch.new latch2 = Concurrent::CountDownLatch.new counter = Concurrent::AtomicFixnum.new(0) atom = Atom.new(0) t = Thread.new do atom.swap do |value| latch1.count_down latch2.wait(1) counter.increment 42 end end latch1.wait(1) atom.swap{ 100 } latch2.count_down t.join(1) expect(counter.value).to be > 1 end it 'reraises the exception from block' do atom = Atom.new(0) expect do atom.swap do |value| fail 'something went wrong' end end.to raise_error 'something went wrong' end end context '#reset' do it 'sets the new value' do atom = Atom.new(42) atom.reset(:foo) expect(atom.value).to eq :foo end it 'returns the new value on success' do atom = Atom.new(42) expect(atom.reset(:foo)).to eq :foo end it 'returns the new value on success' do atom = Atom.new(42) expect(atom.reset(:foo)).to eq :foo end it 'returns the old value if the validator returns false' do validator = ->(value){ false } atom = Atom.new(42, validator: validator) expect(atom.reset(:foo)).to eq 42 end it 'returns the old value if the validator raises an exception' do validator = ->(value){ raise StandardError } atom = Atom.new(42, validator: validator) expect(atom.reset(:foo)).to eq 42 end end context :observable do subject { Atom.new(0) } def trigger_observable(observable) observable.reset(42) end it_behaves_like :observable end end end concurrent-ruby-1.0.5/spec/concurrent/atomic/000077500000000000000000000000001305460430400212455ustar00rootroot00000000000000concurrent-ruby-1.0.5/spec/concurrent/atomic/atomic_boolean_spec.rb000066400000000000000000000106651305460430400255670ustar00rootroot00000000000000shared_examples :atomic_boolean do describe 'construction' do it 'sets the initial value' do expect(described_class.new(true).value).to be true end it 'defaults the initial value to false' do expect(described_class.new.value).to be false end it 'evaluates the truthiness of a true value' do expect(described_class.new(10).value).to be true end it 'evaluates the truthiness of a false value' do expect(described_class.new(nil).value).to be false end end describe '#value' do it 'returns the current value' do counter = described_class.new(true) expect(counter.value).to be true counter.make_false expect(counter.value).to be false counter.make_true expect(counter.value).to be true end end describe '#value=' do it 'sets the #value to the given `Boolean`' do atomic = described_class.new(true) atomic.value = false expect(atomic.value).to be false end it 'returns the new value' do atomic = described_class.new(false) expect(atomic.value = true).to be true end it 'evaluates the truthiness of a true value' do atomic = described_class.new(false) atomic.value = 10 expect(atomic.value).to be true end it 'evaluates the truthiness of a false value' do atomic = described_class.new(true) atomic.value = nil expect(atomic.value).to be false end end describe '#true?' do specify { expect(described_class.new(true).true?).to be true } specify { expect(described_class.new(false).true?).to be false } end describe '#false?' do specify { expect(described_class.new(true).false?).to be false } specify { expect(described_class.new(false).false?).to be true } end describe '#make_true' do it 'makes a false value true and returns true' do subject = described_class.new(false) expect(subject.make_true).to be true expect(subject.value).to be true end it 'keeps a true value true and returns false' do subject = described_class.new(true) expect(subject.make_true).to be false expect(subject.value).to be true end end describe '#make_false' do it 'makes a true value false and returns true' do subject = described_class.new(true) expect(subject.make_false).to be true expect(subject.value).to be false end it 'keeps a false value false and returns false' do subject = described_class.new(false) expect(subject.make_false).to be false expect(subject.value).to be false end end end module Concurrent describe MutexAtomicBoolean do it_should_behave_like :atomic_boolean context 'instance methods' do before(:each) do expect(subject).to receive(:synchronize).with(no_args).and_return(true) end specify 'value is synchronized' do subject.value end specify 'value= is synchronized' do subject.value = 10 end specify 'true? is synchronized' do subject.true? end specify 'false? is synchronized' do subject.false? end specify 'make_true is synchronized' do subject.make_true end specify 'make_false is synchronized' do subject.make_false end end end if defined? Concurrent::CAtomicBoolean describe CAtomicBoolean, ext: true do it_should_behave_like :atomic_boolean end end if Concurrent.on_jruby? describe JavaAtomicBoolean do it_should_behave_like :atomic_boolean end end describe AtomicBoolean do if RUBY_ENGINE != 'ruby' it 'does not load the C extension' do expect(defined?(Concurrent::CAtomicBoolean)).to be_falsey end end if Concurrent.on_jruby? it 'inherits from JavaAtomicBoolean' do expect(AtomicBoolean.ancestors).to include(JavaAtomicBoolean) end elsif defined? Concurrent::CAtomicBoolean it 'inherits from CAtomicBoolean', ext: true do expect(AtomicBoolean.ancestors).to include(CAtomicBoolean) end else it 'inherits from MutexAtomicBoolean' do expect(AtomicBoolean.ancestors).to include(MutexAtomicBoolean) end end describe '#to_s and #inspect' do it 'includes the value' do subject = described_class.new(true) expect(subject.to_s).to include('true') expect(subject.inspect).to include('true') end end end end concurrent-ruby-1.0.5/spec/concurrent/atomic/atomic_fixnum_spec.rb000066400000000000000000000136661305460430400254620ustar00rootroot00000000000000shared_examples :atomic_fixnum do context 'construction' do it 'sets the initial value' do expect(described_class.new(10).value).to eq 10 end it 'defaults the initial value to zero' do expect(described_class.new.value).to eq 0 end it 'raises an exception if the initial value is not a Fixnum' do expect { described_class.new(10.01) }.to raise_error end end context '#value' do it 'returns the current value' do counter = described_class.new(10) expect(counter.value).to eq 10 counter.increment expect(counter.value).to eq 11 counter.decrement expect(counter.value).to eq 10 end end context '#value=' do it 'sets the #value to the given `Fixnum`' do atomic = described_class.new(0) atomic.value = 10 expect(atomic.value).to eq 10 end it 'returns the new value' do atomic = described_class.new(0) expect(atomic.value = 10).to eq 10 end it 'raises and exception if the value is not a `Fixnum`' do atomic = described_class.new(0) expect { atomic.value = 'foo' }.to raise_error end end context '#increment' do it 'increases the value by one when no argument is given' do counter = described_class.new(10) 3.times{ counter.increment } expect(counter.value).to eq 13 end it 'returns the new value when no argument is given' do counter = described_class.new(10) expect(counter.increment).to eq 11 end it 'increases the value by the given argument' do counter = described_class.new(10) counter.increment(5) expect(counter.value).to eq 15 end it 'returns the new value the given argument' do counter = described_class.new(10) expect(counter.increment(5)).to eq 15 end it 'is aliased as #up' do expect(described_class.new(10).up).to eq 11 end end context '#decrement' do it 'decreases the value by one when no argument is given' do counter = described_class.new(10) 3.times{ counter.decrement } expect(counter.value).to eq 7 end it 'returns the new value when no argument is given' do counter = described_class.new(10) expect(counter.decrement).to eq 9 end it 'decreases the value by the given argument' do counter = described_class.new(10) counter.decrement(5) expect(counter.value).to eq 5 end it 'returns the new value the given argument' do counter = described_class.new(10) expect(counter.decrement(5)).to eq 5 end it 'is aliased as #down' do expect(described_class.new(10).down).to eq 9 end end context '#compare_and_set' do it 'returns false if the value is not found' do expect(described_class.new(14).compare_and_set(2, 14)).to eq false end it 'returns true if the value is found' do expect(described_class.new(14).compare_and_set(14, 2)).to eq true end it 'sets if the value is found' do f = described_class.new(14) f.compare_and_set(14, 2) expect(f.value).to eq 2 end it 'does not set if the value is not found' do f = described_class.new(14) f.compare_and_set(2, 12) expect(f.value).to eq 14 end end context '#update' do it 'passes the current value to the block' do atomic = described_class.new(1000) atomic.update { |v| (expect(v).to eq 1000); 1 } end it 'atomically sets the value to the return value from the block' do atomic = described_class.new(1000) atomic.update { |v| v + 1 } expect(atomic.value).to eq 1001 end it 'returns the new value' do atomic = described_class.new(1000) expect(atomic.update { |v| v + 1 }).to eq 1001 end end end module Concurrent describe MutexAtomicFixnum do it_should_behave_like :atomic_fixnum context 'construction' do it 'raises an exception if the initial value is too big' do expect { described_class.new(described_class::MAX_VALUE + 1) }.to raise_error end it 'raises an exception if the initial value is too small' do expect { described_class.new(described_class::MIN_VALUE - 1) }.to raise_error end end context 'instance methods' do before(:each) do expect(subject).to receive(:synchronize).with(no_args).and_call_original end specify 'value is synchronized' do subject.value end specify 'value= is synchronized' do subject.value = 10 end specify 'increment is synchronized' do subject.increment end specify 'decrement is synchronized' do subject.decrement end specify 'compare_and_set is synchronized' do subject.compare_and_set(14, 2) end end end if defined? Concurrent::CAtomicFixnum describe CAtomicFixnum, ext: true do it_should_behave_like :atomic_fixnum end end if Concurrent.on_jruby? describe JavaAtomicFixnum do it_should_behave_like :atomic_fixnum end end describe AtomicFixnum do if RUBY_ENGINE != 'ruby' it 'does not load the C extension' do expect(defined?(Concurrent::CAtomicFixnum)).to be_falsey end end if Concurrent.on_jruby? it 'inherits from JavaAtomicFixnum' do expect(AtomicFixnum.ancestors).to include(JavaAtomicFixnum) end elsif defined? Concurrent::CAtomicFixnum it 'inherits from CAtomicFixnum', ext: true do expect(AtomicFixnum.ancestors).to include(CAtomicFixnum) end else it 'inherits from MutexAtomicFixnum' do expect(AtomicFixnum.ancestors).to include(MutexAtomicFixnum) end end describe '#to_s and #inspect' do it 'includes the value' do subject = described_class.new(42) expect(subject.to_s).to include('42') expect(subject.inspect).to include('42') end end end end concurrent-ruby-1.0.5/spec/concurrent/atomic/atomic_markable_reference_spec.rb000066400000000000000000000100221305460430400277270ustar00rootroot00000000000000describe Concurrent::Edge::AtomicMarkableReference do subject { described_class.new 1000, true } describe '.initialize' do it 'constructs the object' do expect(subject.value).to eq 1000 expect(subject.marked?).to eq true end it 'has sane defaults' do amr = described_class.new expect(amr.value).to eq nil expect(amr.marked?).to eq false end end describe '#set' do it 'sets the value and mark' do val, mark = subject.set 1001, true expect(subject.value).to eq 1001 expect(subject.marked?).to eq true expect(val).to eq 1001 expect(mark).to eq true end end describe '#try_update!' do it 'updates the value and mark' do val, mark = subject.try_update! { |v, m| [v + 1, !m] } expect(subject.value).to eq 1001 expect(val).to eq 1001 expect(mark).to eq false end it 'raises ConcurrentUpdateError when attempting to set inside of block' do expect do subject.try_update! do |v, m| subject.set(1001, false) [v + 1, !m] end end.to raise_error Concurrent::ConcurrentUpdateError end end describe '#try_update' do it 'updates the value and mark' do val, mark = subject.try_update { |v, m| [v + 1, !m] } expect(subject.value).to eq 1001 expect(val).to eq 1001 expect(mark).to eq false end it 'returns nil when attempting to set inside of block' do expect do subject.try_update do |v, m| subject.set(1001, false) [v + 1, !m] end.to eq nil end end end describe '#update' do it 'updates the value and mark' do val, mark = subject.update { |v, m| [v + 1, !m] } expect(subject.value).to eq 1001 expect(subject.marked?).to eq false expect(val).to eq 1001 expect(mark).to eq false end it 'retries until update succeeds' do tries = 0 subject.update do |v, m| tries += 1 subject.set(1001, false) [v + 1, !m] end expect(tries).to eq 2 end end describe '#compare_and_set' do context 'when objects have the same identity' do it 'sets the value and mark' do arr = [1, 2, 3] subject.set(arr, true) expect(subject.compare_and_set(arr, 1.2, true, false)).to be_truthy end end context 'when objects have the different identity' do it 'it does not set the value or mark' do subject.set([1, 2, 3], true) expect(subject.compare_and_set([1, 2, 3], 1.2, true, false)) .to be_falsey end context 'when comparing Numeric objects' do context 'Non-idepotent Float' do it 'sets the value and mark' do subject.set(1.0 + 0.1, true) expect(subject.compare_and_set(1.0 + 0.1, 1.2, true, false)) .to be_truthy end end context 'BigNum' do it 'sets the value and mark' do subject.set(2**100, false) expect(subject.compare_and_set(2**100, 2**99, false, true)) .to be_truthy end end context 'Rational' do it 'sets the value and mark' do require 'rational' unless ''.respond_to? :to_r subject.set(Rational(1, 3), true) comp = subject.compare_and_set(Rational(1, 3), Rational(3, 1), true, false) expect(comp).to be_truthy end end end context 'Rational' do it 'is successful' do # Complex require 'complex' unless ''.respond_to? :to_c subject.set(Complex(1, 2), false) comp = subject.compare_and_set(Complex(1, 2), Complex(1, 3), false, true) expect(comp) .to be_truthy end end end end end concurrent-ruby-1.0.5/spec/concurrent/atomic/atomic_reference_spec.rb000066400000000000000000000161111305460430400260760ustar00rootroot00000000000000shared_examples :atomic_reference do specify :test_construct do atomic = described_class.new expect(atomic.value).to be_nil atomic = described_class.new(0) expect(atomic.value).to eq 0 end specify :test_value do atomic = described_class.new(0) atomic.value = 1 expect(atomic.value).to eq 1 end specify :test_update do # use a number outside JRuby's fixnum cache range, to ensure identity is preserved atomic = described_class.new(1000) res = atomic.update {|v| v + 1} expect(atomic.value).to eq 1001 expect(res).to eq 1001 end specify :test_try_update do # use a number outside JRuby's fixnum cache range, to ensure identity is preserved atomic = described_class.new(1000) res = atomic.try_update {|v| v + 1} expect(atomic.value).to eq 1001 expect(res).to eq 1001 end specify :test_try_update_bang do # use a number outside JRuby's fixnum cache range, to ensure identity is preserved atomic = described_class.new(1000) res = atomic.try_update! {|v| v + 1} expect(atomic.value).to eq 1001 expect(res).to eq 1001 end specify :test_swap do atomic = described_class.new(1000) res = atomic.swap(1001) expect(atomic.value).to eq 1001 expect(res).to eq 1000 end specify :test_try_update_fails do # use a number outside JRuby's fixnum cache range, to ensure identity is preserved atomic = described_class.new(1000) expect( # assigning within block exploits implementation detail for test atomic.try_update {|v| atomic.value = 1001 ; v + 1} ).to be_falsey end specify :test_try_update_bang_fails do # use a number outside JRuby's fixnum cache range, to ensure identity is preserved atomic = described_class.new(1000) expect { # assigning within block exploits implementation detail for test atomic.try_update! {|v| atomic.value = 1001 ; v + 1} }.to raise_error Concurrent::ConcurrentUpdateError end specify :test_update_retries do tries = 0 # use a number outside JRuby's fixnum cache range, to ensure identity is preserved atomic = described_class.new(1000) # assigning within block exploits implementation detail for test atomic.update{|v| tries += 1 ; atomic.value = 1001 ; v + 1} expect(tries).to eq 2 end specify :test_numeric_cas do atomic = described_class.new(0) # 9-bit idempotent Fixnum (JRuby) max_8 = 2**256 - 1 min_8 = -(2**256) atomic.set(max_8) max_8.upto(max_8 + 2) do |i| expect(atomic.compare_and_swap(i, i+1)).to be_truthy, "CAS failed for numeric #{i} => #{i + 1}" end atomic.set(min_8) min_8.downto(min_8 - 2) do |i| expect(atomic.compare_and_swap(i, i-1)).to be_truthy, "CAS failed for numeric #{i} => #{i - 1}" end # 64-bit idempotent Fixnum (MRI, Rubinius) max_64 = 2**62 - 1 min_64 = -(2**62) atomic.set(max_64) max_64.upto(max_64 + 2) do |i| expect(atomic.compare_and_swap(i, i+1)).to be_truthy, "CAS failed for numeric #{i} => #{i + 1}" end atomic.set(min_64) min_64.downto(min_64 - 2) do |i| expect(atomic.compare_and_swap(i, i-1)).to be_truthy, "CAS failed for numeric #{i} => #{i - 1}" end ## 64-bit overflow into Bignum (JRuby) max_64 = 2**63 - 1 min_64 = (-2**63) atomic.set(max_64) max_64.upto(max_64 + 2) do |i| expect(atomic.compare_and_swap(i, i+1)).to be_truthy, "CAS failed for numeric #{i} => #{i + 1}" end atomic.set(min_64) min_64.downto(min_64 - 2) do |i| expect(atomic.compare_and_swap(i, i-1)).to be_truthy, "CAS failed for numeric #{i} => #{i - 1}" end # non-idempotent Float (JRuby, Rubinius, MRI < 2.0.0 or 32-bit) atomic.set(1.0 + 0.1) expect(atomic.compare_and_set(1.0 + 0.1, 1.2)).to be_truthy, "CAS failed for #{1.0 + 0.1} => 1.2" # Bignum atomic.set(2**100) expect(atomic.compare_and_set(2**100, 0)).to be_truthy, "CAS failed for #{2**100} => 0" # Rational require 'rational' unless ''.respond_to? :to_r atomic.set(Rational(1,3)) expect(atomic.compare_and_set(Rational(1,3), 0)).to be_truthy, "CAS failed for #{Rational(1,3)} => 0" # Complex require 'complex' unless ''.respond_to? :to_c atomic.set(Complex(1,2)) expect(atomic.compare_and_set(Complex(1,2), 0)).to be_truthy, "CAS failed for #{Complex(1,2)} => 0" end end module Concurrent describe AtomicReference do it_should_behave_like :atomic_reference describe '#to_s and #inspect' do it 'includes the value' do subject = described_class.new('kajhsd') expect(subject.to_s).to include('kajhsd') expect(subject.inspect).to include('kajhsd') end end end describe MutexAtomicReference do it_should_behave_like :atomic_reference end if defined? Concurrent::CAtomicReference describe CAtomicReference, ext: true do it_should_behave_like :atomic_reference end elsif defined? Concurrent::JavaAtomicReference describe JavaAtomicReference do it_should_behave_like :atomic_reference end elsif defined? Concurrent::RbxAtomicReference describe RbxAtomicReference do it_should_behave_like :atomic_reference end end describe AtomicReference do if Concurrent.on_jruby? it 'inherits from JavaAtomicReference' do expect(AtomicReference.ancestors).to include(Concurrent::JavaAtomicReference) end elsif Concurrent.allow_c_extensions? it 'inherits from CAtomicReference' do expect(AtomicReference.ancestors).to include(Concurrent::CAtomicReference) end elsif Concurrent.on_rbx? it 'inherits from RbxAtomicReference' do expect(AtomicReference.ancestors).to include(Concurrent::RbxAtomicReference) end else it 'inherits from MutexAtomicReference' do expect(AtomicReference.ancestors).to include(Concurrent::MutexAtomicReference) end end end describe MutexAtomicReference do it_should_behave_like :atomic_reference end if defined? Concurrent::CAtomicReference describe CAtomicReference, ext: true do it_should_behave_like :atomic_reference end elsif defined? Concurrent::JavaAtomicReference describe JavaAtomicReference do it_should_behave_like :atomic_reference end elsif defined? Concurrent::RbxAtomicReference describe RbxAtomicReference do it_should_behave_like :atomic_reference end end describe AtomicReference do if Concurrent.on_jruby? it 'inherits from JavaAtomicReference' do expect(AtomicReference.ancestors).to include(Concurrent::JavaAtomicReference) end elsif Concurrent.allow_c_extensions? it 'inherits from CAtomicReference', ext: true do expect(AtomicReference.ancestors).to include(Concurrent::CAtomicReference) end elsif Concurrent.on_rbx? it 'inherits from RbxAtomicReference' do expect(AtomicReference.ancestors).to include(Concurrent::RbxAtomicReference) end else it 'inherits from MutexAtomicReference' do expect(AtomicReference.ancestors).to include(Concurrent::MutexAtomicReference) end end end end concurrent-ruby-1.0.5/spec/concurrent/atomic/count_down_latch_spec.rb000066400000000000000000000075521305460430400261470ustar00rootroot00000000000000shared_examples :count_down_latch do let(:latch) { described_class.new(3) } let(:zero_count_latch) { described_class.new(0) } context '#initialize' do it 'raises an exception if the initial count is less than zero' do expect { described_class.new(-1) }.to raise_error(ArgumentError) end it 'raises an exception if the initial count is not an integer' do expect { described_class.new('foo') }.to raise_error(ArgumentError) end it 'defaults the count to 1' do latch = described_class.new expect(latch.count).to eq 1 end end describe '#count' do it 'should be the value passed to the constructor' do expect(latch.count).to eq 3 end it 'should be decreased after every count down' do latch.count_down expect(latch.count).to eq 2 end it 'should not go below zero' do 5.times { latch.count_down } expect(latch.count).to eq 0 end end describe '#wait' do context 'count set to zero' do it 'should return true immediately' do result = zero_count_latch.wait expect(result).to be_truthy end it 'should return true immediately with timeout' do result = zero_count_latch.wait(5) expect(result).to be_truthy end end context 'non zero count' do it 'should block thread until counter is set to zero' do 3.times do Thread.new { sleep(0.1); latch.count_down } end result = latch.wait expect(result).to be_truthy expect(latch.count).to eq 0 end it 'should block until counter is set to zero with timeout' do 3.times do Thread.new { sleep(0.1); latch.count_down } end result = latch.wait(1) expect(result).to be_truthy expect(latch.count).to eq 0 end it 'should block until timeout and return false when counter is not set to zero' do result = latch.wait(0.1) expect(result).to be_falsey expect(latch.count).to eq 3 end end end end module Concurrent describe MutexCountDownLatch do it_should_behave_like :count_down_latch context 'spurious wake ups' do subject { described_class.new(3) } before(:each) do def subject.simulate_spurious_wake_up synchronize do ns_signal ns_broadcast end end end it 'should resist to spurious wake ups without timeout' do latch = Concurrent::CountDownLatch.new(1) expected = false t = Thread.new do latch.wait(1) subject.wait expected = true end latch.count_down t.join(0.1) subject.simulate_spurious_wake_up t.join(0.1) expect(expected).to be_falsey end it 'should resist to spurious wake ups with timeout' do start_latch = Concurrent::CountDownLatch.new(1) finish_latch = Concurrent::CountDownLatch.new(1) expected = false t = Thread.new do start_latch.wait(1) subject.wait(0.5) expected = true finish_latch.count_down end start_latch.count_down t.join(0.1) subject.simulate_spurious_wake_up t.join(0.1) expect(expected).to be_falsey finish_latch.wait(1) expect(expected).to be_truthy end end end if Concurrent.on_jruby? describe JavaCountDownLatch do it_should_behave_like :count_down_latch end end describe CountDownLatch do if Concurrent.on_jruby? it 'inherits from JavaCountDownLatch' do expect(CountDownLatch.ancestors).to include(JavaCountDownLatch) end else it 'inherits from MutexCountDownLatch' do expect(CountDownLatch.ancestors).to include(MutexCountDownLatch) end end end end concurrent-ruby-1.0.5/spec/concurrent/atomic/cyclic_barrier_spec.rb000066400000000000000000000155471305460430400255740ustar00rootroot00000000000000module Concurrent describe CyclicBarrier do let(:parties) { 3 } let!(:barrier) { described_class.new(3) } context '#initialize' do it 'raises an exception if the initial count is less than 1' do expect { described_class.new(0) }.to raise_error(ArgumentError) end it 'raises an exception if the initial count is not an integer' do expect { described_class.new('foo') }.to raise_error(ArgumentError) end end describe '#parties' do it 'should be the value passed to the constructor' do expect(barrier.parties).to eq 3 end end describe '#number_waiting' do context 'without any waiting thread' do it 'should be equal to zero' do expect(barrier.number_waiting).to eq 0 end end context 'with waiting threads' do it 'should be equal to the waiting threads count' do threads = [Thread.new { barrier.wait }, Thread.new { barrier.wait }] Thread.pass until threads.all? { |t| t.status == 'sleep' } expect(barrier.number_waiting).to eq 2 end end end describe '#broken?' do it 'should not be broken when created' do expect(barrier.broken?).to eq false end it 'should not be broken when reset is called without waiting thread' do barrier.reset expect(barrier.broken?).to eq false end end describe 'reset' do it 'should release all waiting threads', buggy: true do start_latch = CountDownLatch.new(1) continue_latch = CountDownLatch.new(1) Thread.new do start_latch.count_down barrier.wait continue_latch.count_down end start_latch.wait(1) barrier.reset expect(barrier).not_to be_broken expect(barrier.number_waiting).to eq 0 end end describe '#wait' do context 'without timeout' do it 'should block the thread' do t = Thread.new { barrier.wait } t.join(0.1) expect(t.status).to eq 'sleep' end it 'should release all threads when their number matches the desired one' do latch = CountDownLatch.new(parties) parties.times { Thread.new { barrier.wait; latch.count_down } } expect(latch.wait(1)).to be_truthy expect(barrier.number_waiting).to eq 0 expect(barrier).not_to be_broken end it 'returns true when released' do latch = CountDownLatch.new(parties) parties.times { Thread.new { latch.count_down if barrier.wait == true } } expect(latch.wait(1)).to be_truthy end it 'executes the block once' do counter = AtomicFixnum.new barrier = described_class.new(parties) { counter.increment } latch = CountDownLatch.new(parties) parties.times { Thread.new { latch.count_down if barrier.wait == true } } expect(latch.wait(1)).to be_truthy expect(counter.value).to eq 1 end it 'can be reused' do first_latch = CountDownLatch.new(parties) parties.times { Thread.new { barrier.wait; first_latch.count_down } } latch = CountDownLatch.new(parties) parties.times { Thread.new { barrier.wait; latch.count_down } } expect(latch.wait(1)).to be_truthy end it 'return false if barrier has been reset', buggy: true do latch = CountDownLatch.new(1) t = Thread.new { latch.count_down if barrier.wait == false } t.join(0.1) barrier.reset expect(latch.wait(1)).to be_truthy end end context 'with timeout' do context 'timeout not expiring' do it 'should block the thread' do t = Thread.new { barrier.wait(1) } t.join(0.1) expect(t.status).to eq 'sleep' end it 'should release all threads when their number matches the desired one' do latch = CountDownLatch.new(parties) parties.times { Thread.new { barrier.wait(1); latch.count_down } } expect(latch.wait(0.2)).to be_truthy expect(barrier.number_waiting).to eq 0 end it 'returns true when released' do latch = CountDownLatch.new(parties) parties.times { Thread.new { latch.count_down if barrier.wait(1) == true } } expect(latch.wait(1)).to be_truthy end end context 'timeout expiring' do it 'returns false' do latch = CountDownLatch.new(1) Thread.new { latch.count_down if barrier.wait(0.1) == false } expect(latch.wait(1)).to be_truthy end it 'breaks the barrier and release all other threads' do latch = CountDownLatch.new(2) Thread.new { barrier.wait(0.1); latch.count_down } Thread.new { barrier.wait; latch.count_down } expect(latch.wait(1)).to be_truthy expect(barrier).to be_broken end it 'breaks the barrier and release all other threads 2' do t1 = Thread.new { barrier.wait(0.1) } t2 = Thread.new { barrier.wait(0.1) } [t1, t2].each(&:join) expect(barrier).to be_broken end it 'does not execute the block on timeout' do counter = AtomicFixnum.new barrier = described_class.new(parties) { counter.increment } barrier.wait(0.1) expect(counter.value).to eq 0 end end end context '#broken barrier' do it 'should not accept new threads' do t = Thread.new { barrier.wait(0.1) } t.join(0.2) expect(barrier).to be_broken expect(barrier.wait).to be_falsey end it 'can be reset' do t = Thread.new { barrier.wait(0.1) } t.join(0.2) expect(barrier).to be_broken barrier.reset expect(barrier).not_to be_broken end end end context 'spurious wake ups' do before(:each) do def barrier.simulate_spurious_wake_up synchronize do ns_signal ns_broadcast end end end it 'should resist to spurious wake ups without timeout' do @expected = false t = Thread.new { barrier.wait; @expected = true } t.join(0.1) barrier.simulate_spurious_wake_up t.join(0.1) expect(@expected).to be_falsey end it 'should resist to spurious wake ups with timeout' do @expected = false t = Thread.new { barrier.wait(0.5); @expected = true } t.join(0.1) barrier.simulate_spurious_wake_up t.join(0.1) expect(@expected).to be_falsey end end end end concurrent-ruby-1.0.5/spec/concurrent/atomic/event_spec.rb000066400000000000000000000106261305460430400237320ustar00rootroot00000000000000module Concurrent describe Event do subject{ Event.new } context '#initialize' do it 'sets the state to unset' do expect(subject).not_to be_set end end context '#set?' do it 'returns true when the event has been set' do subject.set expect(subject).to be_set end it 'returns false if the event is unset' do expect(subject).not_to be_set end end context '#set' do it 'triggers the event' do latch = CountDownLatch.new(1) t = Thread.new{ subject.wait.tap{ latch.count_down } } t.join(0.1) subject.set expect(latch.wait(1)).to be true end it 'sets the state to set' do subject.set expect(subject).to be_set end end context '#try?' do it 'triggers the event if not already set' do subject.try? expect(subject).to be_set end it 'returns true if not previously set' do expect(subject.try?).to be true end it 'returns false if previously set' do subject.set expect(subject.try?).to be false end end context '#reset' do it 'does not change the state of an unset event' do subject.reset expect(subject).not_to be_set end it 'does not trigger an unset event' do latch = CountDownLatch.new(1) Thread.new{ subject.wait.tap{ latch.count_down } } subject.reset expect(latch.wait(0.1)).to be false end it 'returns true when called on an unset event' do expect(subject.reset).to be true end it 'sets the state of a set event to unset' do subject.set expect(subject).to be_set subject.reset expect(subject).not_to be_set end it 'returns true when called on a set event' do subject.set expect(subject).to be_set expect(subject.reset).to be true end end context '#wait' do it 'returns immediately when the event has been set' do subject.reset latch = CountDownLatch.new(1) subject.set Thread.new{ subject.wait(1000); latch.count_down } expect(latch.wait(0.1)).to be true end it 'returns true once the event is set' do subject.set expect(subject.wait).to be true end it 'blocks indefinitely when the timer is nil' do subject.reset latch = CountDownLatch.new(1) Thread.new{ subject.wait.tap{ latch.count_down } } expect(latch.wait(0.1)).to be false subject.set expect(latch.wait(0.1)).to be true end it 'stops waiting when the timer expires' do subject.reset latch = CountDownLatch.new(1) Thread.new{ subject.wait(0.2); latch.count_down } expect(latch.wait(0.1)).to be false expect(latch.wait).to be true end it 'returns false when the timer expires' do subject.reset expect(subject.wait(1)).to be false end it 'triggers multiple waiting threads' do latch = CountDownLatch.new(5) subject.reset 5.times{ Thread.new{ subject.wait; latch.count_down } } subject.set expect(latch.wait(0.2)).to be true end it 'behaves appropriately if wait begins while #set is processing' do subject.reset latch = CountDownLatch.new(5) 5.times{ Thread.new{ subject.wait(5) } } subject.set 5.times{ Thread.new{ subject.wait; latch.count_down } } expect(latch.wait(0.2)).to be true end end context 'spurious wake ups' do before(:each) do def subject.simulate_spurious_wake_up synchronize do ns_signal ns_broadcast end end end it 'should resist to spurious wake ups without timeout' do latch = CountDownLatch.new(1) t = Thread.new{ subject.wait.tap{ latch.count_down } } t.join(0.1) subject.simulate_spurious_wake_up expect(latch.wait(0.1)).to be false end it 'should resist spurious wake ups with timeout', buggy: true do latch = CountDownLatch.new(1) t = Thread.new{ subject.wait(0.5); latch.count_down } t.join(0.1) subject.simulate_spurious_wake_up expect(latch.wait(0.1)).to be false expect(latch.wait(1)).to be true end end end end concurrent-ruby-1.0.5/spec/concurrent/atomic/read_write_lock_spec.rb000066400000000000000000000346101305460430400257450ustar00rootroot00000000000000module Concurrent describe ReadWriteLock do context '#write_locked?' do it 'returns true when the write lock is held' do latch_1 = Concurrent::CountDownLatch.new(1) latch_2 = Concurrent::CountDownLatch.new(1) thread = Thread.new do subject.with_write_lock do latch_1.count_down latch_2.wait(1) end end latch_1.wait(1) expect(subject).to be_write_locked latch_2.count_down thread.join end it 'returns false when the write lock is not held' do expect(subject).to_not be_write_locked end it 'returns false when the write lock is not held but there are readers' do latch = Concurrent::CountDownLatch.new(1) thread = Thread.new do subject.with_read_lock do latch.wait(1) end end expect(subject).to_not be_write_locked latch.count_down thread.join end end context '#has_waiters?' do it 'returns false when no locks are held' do expect(subject).to_not have_waiters end it 'returns false when there are readers but no writers' do latch = Concurrent::CountDownLatch.new(1) thread = Thread.new do subject.with_read_lock do latch.wait(1) end end expect(subject).to_not have_waiters latch.count_down thread.join end it 'returns true when the write lock is held and there are waiting readers' do latch_1 = Concurrent::CountDownLatch.new(1) latch_2 = Concurrent::CountDownLatch.new(1) latch_3 = Concurrent::CountDownLatch.new(1) thread_1 = Thread.new do latch_1.wait(1) subject.acquire_write_lock latch_2.count_down latch_3.wait(1) subject.release_write_lock end thread_2 = Thread.new do latch_2.wait(1) subject.acquire_read_lock subject.release_read_lock end latch_1.count_down latch_2.wait(1) expect(subject).to have_waiters latch_3.count_down [thread_1, thread_2].each(&:join) end it 'returns true when the write lock is held and there are waiting writers' do latch_1 = Concurrent::CountDownLatch.new(1) latch_2 = Concurrent::CountDownLatch.new(1) latch_3 = Concurrent::CountDownLatch.new(1) thread_1 = Thread.new do latch_1.wait(1) subject.acquire_write_lock latch_2.count_down latch_3.wait(1) subject.release_write_lock end thread_2 = Thread.new do latch_2.wait(1) subject.acquire_write_lock subject.release_write_lock end latch_1.count_down latch_2.wait(1) expect(subject).to have_waiters latch_3.count_down [thread_1, thread_2].each(&:join) end end context '#with_read_lock' do it 'acquires the lock' do expect(subject).to receive(:acquire_read_lock).with(no_args) subject.with_read_lock { nil } end it 'returns the value of the block operation' do expected = 100 actual = subject.with_read_lock { expected } expect(actual).to eq expected end it 'releases the lock' do expect(subject).to receive(:release_read_lock).with(no_args) subject.with_read_lock { nil } end it 'raises an exception if no block is given' do expect { subject.with_read_lock }.to raise_error(ArgumentError) end it 'raises an exception if maximum lock limit is exceeded' do counter = Concurrent::AtomicFixnum.new(ReadWriteLock::MAX_READERS) allow(Concurrent::AtomicFixnum).to receive(:new).with(anything).and_return(counter) expect { subject.with_read_lock { nil } }.to raise_error(Concurrent::ResourceLimitError) end it 'releases the lock when an exception is raised' do expect(subject).to receive(:release_read_lock).with(any_args) begin subject.release_read_lock { raise StandardError } rescue end end end context '#with_write_lock' do it 'acquires the lock' do expect(subject).to receive(:acquire_write_lock).with(no_args) subject.with_write_lock { nil } end it 'returns the value of the block operation' do expected = 100 actual = subject.with_write_lock { expected } expect(actual).to eq expected end it 'releases the lock' do expect(subject).to receive(:release_write_lock).with(no_args) subject.with_write_lock { nil } end it 'raises an exception if no block is given' do expect { subject.with_write_lock }.to raise_error(ArgumentError) end it 'raises an exception if maximum lock limit is exceeded' do counter = Concurrent::AtomicFixnum.new(ReadWriteLock::MAX_WRITERS) allow(Concurrent::AtomicFixnum).to receive(:new).with(anything).and_return(counter) expect { subject.with_write_lock { nil } }.to raise_error(Concurrent::ResourceLimitError) end it 'releases the lock when an exception is raised' do expect(subject).to receive(:release_write_lock).with(any_args) begin subject.with_write_lock { raise StandardError } rescue end end end context '#acquire_read_lock' do it 'increments the lock count' do counter = Concurrent::AtomicFixnum.new(0) allow(Concurrent::AtomicFixnum).to receive(:new).with(anything).and_return(counter) subject.acquire_read_lock expect(counter.value).to eq 1 end it 'waits for a running writer to finish' do latch_1 = Concurrent::CountDownLatch.new(1) latch_2 = Concurrent::CountDownLatch.new(1) latch_3 = Concurrent::CountDownLatch.new(1) write_flag = Concurrent::AtomicBoolean.new(false) read_flag = Concurrent::AtomicBoolean.new(false) thread_1 = Thread.new do latch_1.wait(1) subject.acquire_write_lock latch_2.count_down latch_3.wait(1) write_flag.make_true subject.release_write_lock end thread_2 = Thread.new do latch_2.wait(1) expect(write_flag.value).to be false latch_3.count_down subject.acquire_read_lock expect(write_flag.value).to be true read_flag.make_true subject.release_read_lock end latch_1.count_down [thread_1, thread_2].each(&:join) expect(write_flag.value).to be true expect(read_flag.value).to be true end it 'does not wait for any running readers' do counter = Concurrent::AtomicFixnum.new(0) allow(Concurrent::AtomicFixnum).to receive(:new).with(anything).and_return(counter) latch_1 = Concurrent::CountDownLatch.new(1) latch_2 = Concurrent::CountDownLatch.new(1) latch_3 = Concurrent::CountDownLatch.new(1) read_flag_1 = Concurrent::AtomicBoolean.new(false) read_flag_2 = Concurrent::AtomicBoolean.new(false) thread_1 = Thread.new do latch_1.wait(1) subject.acquire_read_lock expect(counter.value).to eq 1 latch_2.count_down latch_3.wait(1) read_flag_1.make_true subject.release_read_lock end thread_2 = Thread.new do latch_2.wait(1) expect(read_flag_1.value).to be false subject.acquire_read_lock expect(counter.value).to eq 2 latch_3.count_down read_flag_2.make_true subject.release_read_lock end latch_1.count_down [thread_1, thread_2].each(&:join) expect(read_flag_1.value).to be true expect(read_flag_2.value).to be true expect(counter.value).to eq 0 end it 'raises an exception if maximum lock limit is exceeded' do counter = Concurrent::AtomicFixnum.new(ReadWriteLock::MAX_WRITERS) allow(Concurrent::AtomicFixnum).to receive(:new).with(anything).and_return(counter) expect { subject.acquire_write_lock { nil } }.to raise_error(Concurrent::ResourceLimitError) end it 'returns true if the lock is acquired' do expect(subject.acquire_read_lock).to be true end end context '#release_read_lock' do it 'decrements the counter' do counter = Concurrent::AtomicFixnum.new(0) allow(Concurrent::AtomicFixnum).to receive(:new).with(anything).and_return(counter) subject.acquire_read_lock expect(counter.value).to eq 1 subject.release_read_lock expect(counter.value).to eq 0 end it 'unblocks waiting writers' do latch_1 = Concurrent::CountDownLatch.new(1) latch_2 = Concurrent::CountDownLatch.new(1) write_flag = Concurrent::AtomicBoolean.new(false) thread = Thread.new do latch_1.wait(1) latch_2.count_down subject.acquire_write_lock write_flag.make_true subject.release_write_lock end subject.acquire_read_lock latch_1.count_down latch_2.wait(1) expect(write_flag.value).to be false subject.release_read_lock thread.join expect(write_flag.value).to be true end it 'returns true if the lock is released' do subject.acquire_read_lock expect(subject.release_read_lock).to be true end it 'returns true if the lock was never set' do expect(subject.release_read_lock).to be true end end context '#acquire_write_lock' do it 'increments the lock count' do counter = Concurrent::AtomicFixnum.new(0) allow(Concurrent::AtomicFixnum).to receive(:new).with(anything).and_return(counter) subject.acquire_write_lock expect(counter.value).to be > 1 end it 'waits for a running writer to finish' do latch_1 = Concurrent::CountDownLatch.new(1) latch_2 = Concurrent::CountDownLatch.new(1) latch_3 = Concurrent::CountDownLatch.new(1) write_flag_1 = Concurrent::AtomicBoolean.new(false) write_flag_2 = Concurrent::AtomicBoolean.new(false) thread_1 = Thread.new do latch_1.wait(1) subject.acquire_write_lock latch_2.count_down latch_3.wait(1) write_flag_1.make_true subject.release_write_lock end thread_2 = Thread.new do latch_2.wait(1) expect(write_flag_1.value).to be false latch_3.count_down subject.acquire_write_lock expect(write_flag_1.value).to be true write_flag_2.make_true subject.release_write_lock end latch_1.count_down [thread_1, thread_2].each(&:join) expect(write_flag_1.value).to be true expect(write_flag_2.value).to be true end it 'waits for a running reader to finish' do latch_1 = Concurrent::CountDownLatch.new(1) latch_2 = Concurrent::CountDownLatch.new(1) latch_3 = Concurrent::CountDownLatch.new(1) read_flag = Concurrent::AtomicBoolean.new(false) write_flag = Concurrent::AtomicBoolean.new(false) thread_1 = Thread.new do latch_1.wait(1) subject.acquire_read_lock latch_2.count_down latch_3.wait(1) read_flag.make_true subject.release_read_lock end thread_2 = Thread.new do latch_2.wait(1) expect(read_flag.value).to be false latch_3.count_down subject.acquire_write_lock expect(read_flag.value).to be true write_flag.make_true subject.release_write_lock end latch_1.count_down [thread_1, thread_2].each(&:join) expect(read_flag.value).to be true expect(write_flag.value).to be true end it 'raises an exception if maximum lock limit is exceeded' do counter = Concurrent::AtomicFixnum.new(ReadWriteLock::MAX_WRITERS) allow(Concurrent::AtomicFixnum).to receive(:new).with(anything).and_return(counter) expect { subject.acquire_write_lock { nil } }.to raise_error(Concurrent::ResourceLimitError) end it 'returns true if the lock is acquired' do expect(subject.acquire_write_lock).to be true end end context '#release_write_lock' do it 'decrements the counter' do counter = Concurrent::AtomicFixnum.new(0) allow(Concurrent::AtomicFixnum).to receive(:new).with(anything).and_return(counter) subject.acquire_write_lock expect(counter.value).to be > 1 subject.release_write_lock expect(counter.value).to eq 0 end it 'unblocks waiting readers' do latch_1 = Concurrent::CountDownLatch.new(1) latch_2 = Concurrent::CountDownLatch.new(1) read_flag = Concurrent::AtomicBoolean.new(false) thread = Thread.new do latch_1.wait(1) latch_2.count_down subject.acquire_read_lock read_flag.make_true subject.release_read_lock end subject.acquire_write_lock latch_1.count_down latch_2.wait(1) expect(read_flag.value).to be false subject.release_write_lock thread.join expect(read_flag.value).to be true end it 'unblocks waiting writers' do latch_1 = Concurrent::CountDownLatch.new(1) latch_2 = Concurrent::CountDownLatch.new(1) write_flag = Concurrent::AtomicBoolean.new(false) thread = Thread.new do latch_1.wait(1) latch_2.count_down subject.acquire_write_lock write_flag.make_true subject.release_write_lock end subject.acquire_write_lock latch_1.count_down latch_2.wait(1) expect(write_flag.value).to be false subject.release_write_lock thread.join expect(write_flag.value).to be true end it 'returns true if the lock is released' do subject.acquire_write_lock expect(subject.release_write_lock).to be true end it 'returns true if the lock was never set' do expect(subject.release_write_lock).to be true end end end end concurrent-ruby-1.0.5/spec/concurrent/atomic/reentrant_read_write_lock_spec.rb000066400000000000000000000423071305460430400300310ustar00rootroot00000000000000unless Concurrent.on_jruby? # NOTE: These tests depend heavily on the private/undocumented # `ThreadLocalVar#value_for` method. This method does not, and cannot work # on JRuby at this time. Therefore, these tests cannot be run successfully on # JRuby. The initial implementation used a variation of `ThreadLocalVar` # which was pure-Ruby on all platforms and exhibited behavior that allowed # these tests to work. Functionality on JRuby was verified at that time. So # long as `ReentrantReadWriteLock` is not changed (with respect to # `ThreadLocalVar`) we can safely assume proper functionality on JRuby. require 'timeout' module Concurrent BaseMatcher = RSpec::Matchers::BuiltIn::BaseMatcher RRWL = ReentrantReadWriteLock # no way I'm typing that 50 times # **************************************************************** # First some custom matchers to make our tests all nice and pretty # **************************************************************** class HoldLock def initialize(lock) @lock = lock end def for_read HoldReadLock.new(@lock) end def for_write HoldWriteLock.new(@lock) end def for_both HoldBoth.new(@lock) end end class HoldReadLock < BaseMatcher def match(lock, thread) ((lock.instance_eval { @Counter.value } & RRWL::MAX_READERS) != 0) && ((lock.instance_eval { @HeldCount.send(:value_for, thread) } & RRWL::READ_LOCK_MASK) > 0) end end class HoldWriteLock < BaseMatcher def match(lock, thread) ((lock.instance_eval { @Counter.value } & RRWL::RUNNING_WRITER) != 0) && ((lock.instance_eval { @HeldCount.send(:value_for, thread) } & RRWL::WRITE_LOCK_MASK) > 0) end end class HoldBoth < BaseMatcher def match(lock, thread) HoldReadLock.new(lock).matches?(thread) && HoldWriteLock.new(lock).matches?(thread) end end class BeFree < BaseMatcher MASK = RRWL::MAX_READERS + RRWL::RUNNING_WRITER def matches?(lock) (lock.instance_eval { @Counter.value } & MASK) == 0 end def failure_message "expected lock to be free" end end # ******************************************************* describe ReentrantReadWriteLock do let(:lock) { RRWL.new } def hold(lock) HoldLock.new(lock) end def be_free BeFree.new end def wait_up_to(secs, &condition) _end = Time.now + secs while !condition.call && Time.now < _end sleep(0.001) end end context "read lock" do it "allows other read locks to be acquired at the same time" do lock # stupid RSpec 'let' is not thread-safe! Timeout.timeout(3) do got_lock = 10.times.collect { CountDownLatch.new } threads = 10.times.collect do |n| Thread.new do # Each thread takes the read lock and then waits for another one # They will only finish if ALL of them get their read lock expect(lock.acquire_read_lock).to be true expect(Thread.current).to hold(lock).for_read got_lock[n].count_down got_lock[(n+1) % 10].wait end end threads.each(&:join) end end it "can be acquired more than once" do Timeout.timeout(3) do 10.times { expect(lock.acquire_read_lock).to be true } expect(Thread.current).to hold(lock).for_read 10.times { expect(lock.release_read_lock).to be true } expect(Thread.current).not_to hold(lock).for_read expect(lock).to be_free end end it "can be acquired while holding a write lock" do Timeout.timeout(3) do expect(lock.acquire_write_lock).to be true expect(Thread.current).to hold(lock).for_write expect(lock.acquire_read_lock).to be true expect(Thread.current).to hold(lock).for_both expect(lock.release_read_lock).to be true expect(Thread.current).to hold(lock).for_write expect(Thread.current).not_to hold(lock).for_read expect(lock.release_write_lock).to be true expect(lock).to be_free end end it "can be upgraded to a write lock" do Timeout.timeout(3) do expect(lock.acquire_read_lock).to be true expect(Thread.current).to hold(lock).for_read # now we want to upgrade... expect(lock.acquire_write_lock).to be true expect(lock.release_read_lock).to be true expect(Thread.current).to hold(lock).for_write expect(lock.release_write_lock).to be true expect(lock).to be_free end end it "cannot be released when not held" do expect { lock.release_read_lock }.to raise_error(IllegalOperationError) end it "cannot be released more times than it was taken" do Timeout.timeout(3) do 2.times { lock.acquire_read_lock } 2.times { lock.release_read_lock } expect { lock.release_read_lock }.to raise_error(IllegalOperationError) end end it "wakes up waiting writers when the last read lock is released" do latch1,latch2 = CountDownLatch.new(3),CountDownLatch.new good = AtomicBoolean.new(false) threads = [ Thread.new { lock.acquire_read_lock; latch1.count_down; latch2.wait; lock.release_read_lock }, Thread.new { lock.acquire_read_lock; latch1.count_down; latch2.wait; lock.release_read_lock }, Thread.new { lock.acquire_read_lock; latch1.count_down; latch2.wait; lock.release_read_lock }, Thread.new { latch1.wait; lock.acquire_write_lock; good.value = true } ] wait_up_to(0.2) { threads[3].status == 'sleep' } # The last thread should be waiting to acquire a write lock now... expect(threads[3].status).to eql "sleep" expect(threads[3]).not_to hold(lock).for_write expect(good.value).to be false # Throw latch2 and the 3 readers will wake up and all release their read locks... latch2.count_down wait_up_to(0.2) { good.value } expect(threads[3]).to hold(lock).for_write expect(good.value).to be true end end context "write lock" do it "cannot be acquired when another thread holds a write lock" do latch = CountDownLatch.new threads = [ Thread.new { lock.acquire_write_lock; latch.count_down }, Thread.new { latch.wait; lock.acquire_write_lock } ] expect { Timeout.timeout(1) { threads[0].join }}.not_to raise_error expect(threads[0]).to hold(lock).for_write expect(threads[1]).not_to hold(lock).for_write wait_up_to(0.2) { threads[1].status == 'sleep' } expect(threads[1].status).to eql "sleep" end it "cannot be acquired when another thread holds a read lock" do latch = CountDownLatch.new threads = [ Thread.new { lock.acquire_read_lock; latch.count_down }, Thread.new { latch.wait; lock.acquire_write_lock } ] expect { Timeout.timeout(1) { threads[0].join }}.not_to raise_error expect(threads[0]).to hold(lock).for_read expect(threads[1]).not_to hold(lock).for_write wait_up_to(0.2) { threads[1].status == 'sleep' } expect(threads[1].status).to eql "sleep" end it "can be acquired more than once" do Timeout.timeout(3) do 10.times { expect(lock.acquire_write_lock).to be true } expect(Thread.current).to hold(lock).for_write 10.times { expect(lock.release_write_lock).to be true } expect(Thread.current).not_to hold(lock).for_write expect(lock).to be_free end end it "can be acquired while holding a read lock" do Timeout.timeout(3) do expect(lock.acquire_read_lock).to be true expect(Thread.current).to hold(lock).for_read expect(lock.acquire_write_lock).to be true expect(Thread.current).to hold(lock).for_both expect(lock.release_write_lock).to be true expect(Thread.current).to hold(lock).for_read expect(Thread.current).not_to hold(lock).for_write expect(lock.release_read_lock).to be true expect(lock).to be_free end end it "can be downgraded to a read lock" do Timeout.timeout(3) do expect(lock.acquire_write_lock).to be true expect(Thread.current).to hold(lock).for_write # now we want to downgrade... expect(lock.acquire_read_lock).to be true expect(lock.release_write_lock).to be true expect(Thread.current).to hold(lock).for_read expect(lock.release_read_lock).to be true expect(lock).to be_free end end it "cannot be released when not held" do expect { lock.release_write_lock }.to raise_error(IllegalOperationError) end it "cannot be released more times than it was taken" do Timeout.timeout(3) do 2.times { lock.acquire_write_lock } 2.times { lock.release_write_lock } expect { lock.release_write_lock }.to raise_error(IllegalOperationError) end end it "wakes up waiting readers when the write lock is released", buggy: true do latch1,latch2 = CountDownLatch.new,CountDownLatch.new good = AtomicFixnum.new(0) threads = [ Thread.new { lock.acquire_write_lock; latch1.count_down; latch2.wait; lock.release_write_lock }, Thread.new { latch1.wait; lock.acquire_read_lock; good.update { |n| n+1 }}, Thread.new { latch1.wait; lock.acquire_read_lock; good.update { |n| n+1 }}, Thread.new { latch1.wait; lock.acquire_read_lock; good.update { |n| n+1 }} ] wait_up_to(0.2) { threads[3].status == 'sleep' } # The last 3 threads should be waiting to acquire read locks now... # TODO (pitr-ch 15-Oct-2016): https://travis-ci.org/ruby-concurrency/concurrent-ruby/jobs/166777543 (1..3).each { |n| expect(threads[n].status).to eql "sleep" } (1..3).each { |n| expect(threads[n]).not_to hold(lock).for_read } # Throw latch2 and the writer will wake up and release its write lock... latch2.count_down wait_up_to(0.2) { good.value == 3 } (1..3).each { |n| expect(threads[n]).to hold(lock).for_read } end it "wakes up waiting writers when the write lock is released" do latch1,latch2 = CountDownLatch.new,CountDownLatch.new good = AtomicBoolean.new(false) threads = [ Thread.new { lock.acquire_write_lock; latch1.count_down; latch2.wait; lock.release_write_lock }, Thread.new { latch1.wait; lock.acquire_write_lock; good.value = true }, ] wait_up_to(0.2) { threads[1].status == 'sleep' } # The last thread should be waiting to acquire a write lock now... expect(threads[1].status).to eql "sleep" expect(threads[1]).not_to hold(lock).for_write # Throw latch2 and the writer will wake up and release its write lock... latch2.count_down wait_up_to(0.2) { good.value } expect(threads[1]).to hold(lock).for_write end end context "#with_read_lock" do it "acquires read block before yielding, then releases it" do expect(lock).to be_free lock.with_read_lock { expect(Thread.current).to hold(lock).for_read } expect(lock).to be_free end it "releases read lock if an exception is raised in block" do expect { lock.with_read_lock { raise "Bad" } }.to raise_error expect(lock).to be_free expect(Thread.current).not_to hold(lock).for_read end end context "#with_write_lock" do it "acquires write block before yielding, then releases it" do expect(lock).to be_free lock.with_write_lock { expect(Thread.current).to hold(lock).for_write } expect(lock).to be_free end it "releases write lock if an exception is raised in block" do expect { lock.with_write_lock { raise "Bad" } }.to raise_error expect(lock).to be_free expect(Thread.current).not_to hold(lock).for_write end end context "#try_read_lock" do it "returns false immediately if read lock cannot be obtained" do Timeout.timeout(3) do latch = CountDownLatch.new thread = Thread.new { lock.acquire_write_lock; latch.count_down } latch.wait expect { Timeout.timeout(0.01) { expect(lock.try_read_lock).to be false } }.not_to raise_error expect(Thread.current).not_to hold(lock).for_read end end it "acquires read lock and returns true if it can do so without blocking" do Timeout.timeout(3) do latch = CountDownLatch.new thread = Thread.new { lock.acquire_read_lock; latch.count_down } latch.wait expect { Timeout.timeout(0.01) { expect(lock.try_read_lock).to be true } }.not_to raise_error expect(lock).not_to be_free expect(Thread.current).to hold(lock).for_read end end it "can acquire a read lock if a read lock is already held" do Timeout.timeout(3) do expect(lock.acquire_read_lock).to be true expect(lock.try_read_lock).to be true expect(Thread.current).to hold(lock).for_read expect(lock.release_read_lock).to be true expect(lock.release_read_lock).to be true expect(Thread.current).not_to hold(lock).for_read expect(lock).to be_free end end it "can acquire a read lock if a write lock is already held" do Timeout.timeout(3) do expect(lock.acquire_write_lock).to be true expect(lock.try_read_lock).to be true expect(Thread.current).to hold(lock).for_read expect(lock.release_read_lock).to be true expect(lock.release_write_lock).to be true expect(Thread.current).not_to hold(lock).for_read expect(lock).to be_free end end end context "#try_write_lock" do it "returns false immediately if write lock cannot be obtained" do Timeout.timeout(3) do latch = CountDownLatch.new thread = Thread.new { lock.acquire_write_lock; latch.count_down } latch.wait expect { Timeout.timeout(0.02) { expect(lock.try_write_lock).to be false } }.not_to raise_error expect(Thread.current).not_to hold(lock).for_write end end it "acquires write lock and returns true if it can do so without blocking" do Timeout.timeout(3) do expect { Timeout.timeout(0.02) { expect(lock.try_write_lock).to be true } }.not_to raise_error expect(lock).not_to be_free expect(Thread.current).to hold(lock).for_write end end it "can acquire a write lock if a read lock is already held" do Timeout.timeout(3) do expect(lock.acquire_read_lock).to be true expect(lock.try_write_lock).to be true expect(Thread.current).to hold(lock).for_write expect(lock.release_write_lock).to be true expect(lock.release_read_lock).to be true expect(Thread.current).not_to hold(lock).for_write expect(lock).to be_free end end it "can acquire a write lock if a write lock is already held" do Timeout.timeout(3) do expect(lock.acquire_write_lock).to be true expect(lock.try_write_lock).to be true expect(Thread.current).to hold(lock).for_write expect(lock.release_write_lock).to be true expect(lock.release_write_lock).to be true expect(Thread.current).not_to hold(lock).for_write expect(lock).to be_free end end end it "can survive a torture test" do latch = CountDownLatch.new count = 0 writers = 5.times.collect do Thread.new do 500.times do lock.with_write_lock do value = (count += 1) sleep(0.0001) count = value+1 end end end end readers = 15.times.collect do Thread.new do 500.times do lock.with_read_lock { expect(count % 2).to eq 0 } end end end writers.each(&:join) readers.each(&:join) expect(count).to eq 5000 end end end end concurrent-ruby-1.0.5/spec/concurrent/atomic/semaphore_spec.rb000066400000000000000000000111011305460430400245610ustar00rootroot00000000000000shared_examples :semaphore do let(:semaphore) { described_class.new(3) } describe '#initialize' do it 'raises an exception if the initial count is not an integer' do expect { described_class.new('foo') }.to raise_error(ArgumentError) end context 'when initializing with 0' do let(:semaphore) { described_class.new(0) } it do expect(semaphore).to_not be nil end end context 'when initializing with -1' do let(:semaphore) { described_class.new(-1) } it do semaphore.release expect(semaphore.available_permits).to eq 0 end end end describe '#acquire' do context 'permits available' do it 'should return true immediately' do result = semaphore.acquire expect(result).to be_nil end end context 'not enough permits available' do it 'should block thread until permits are available' do semaphore.drain_permits Thread.new { sleep(0.2); semaphore.release } result = semaphore.acquire expect(result).to be_nil expect(semaphore.available_permits).to eq 0 end end context 'when acquiring negative permits' do it do expect { semaphore.acquire(-1) }.to raise_error(ArgumentError) end end end describe '#drain_permits' do it 'drains all available permits' do drained = semaphore.drain_permits expect(drained).to eq 3 expect(semaphore.available_permits).to eq 0 end it 'drains nothing in no permits are available' do semaphore.reduce_permits 3 drained = semaphore.drain_permits expect(drained).to eq 0 end end describe '#try_acquire' do context 'without timeout' do it 'acquires immediately if permits are available' do result = semaphore.try_acquire(1) expect(result).to be_truthy end it 'returns false immediately in no permits are available' do result = semaphore.try_acquire(20) expect(result).to be_falsey end context 'when trying to acquire negative permits' do it do expect { semaphore.try_acquire(-1) }.to raise_error(ArgumentError) end end end context 'with timeout' do it 'acquires immediately if permits are available' do result = semaphore.try_acquire(1, 5) expect(result).to be_truthy end it 'acquires when permits are available within timeout' do semaphore.drain_permits Thread.new { sleep 0.1; semaphore.release } result = semaphore.try_acquire(1, 1) expect(result).to be_truthy end it 'returns false on timeout' do semaphore.drain_permits result = semaphore.try_acquire(1, 0.1) expect(result).to be_falsey end end end describe '#reduce_permits' do it 'raises ArgumentError if reducing by negative number' do expect { semaphore.reduce_permits(-1) }.to raise_error(ArgumentError) end it 'reduces permits below zero' do semaphore.reduce_permits 1003 expect(semaphore.available_permits).to eq(-1000) end it 'reduces permits' do semaphore.reduce_permits 1 expect(semaphore.available_permits).to eq 2 semaphore.reduce_permits 2 expect(semaphore.available_permits).to eq 0 end it 'reduces zero permits' do semaphore.reduce_permits 0 expect(semaphore.available_permits).to eq 3 end end describe '#release' do it 'increases the number of available permits by one' do semaphore.release expect(semaphore.available_permits).to eq 4 end context 'when a number of permits is specified' do it 'increases the number of available permits by the specified value' do semaphore.release(2) expect(semaphore.available_permits).to eq 5 end context 'when permits is set to negative number' do it do expect { semaphore.release(-1) }.to raise_error(ArgumentError) end end end end end module Concurrent describe MutexSemaphore do it_should_behave_like :semaphore end if Concurrent.on_jruby? describe JavaSemaphore do it_should_behave_like :semaphore end end describe Semaphore do if Concurrent.on_jruby? it 'inherits from JavaSemaphore' do expect(Semaphore.ancestors).to include(JavaSemaphore) end else it 'inherits from MutexSemaphore' do expect(Semaphore.ancestors).to include(MutexSemaphore) end end end end concurrent-ruby-1.0.5/spec/concurrent/atomic/thread_local_var_spec.rb000066400000000000000000000064131305460430400261010ustar00rootroot00000000000000require 'rbconfig' module Concurrent require 'concurrent/atomic/thread_local_var' describe ThreadLocalVar do context '#initialize' do it 'can set an initial value' do v = described_class.new(14) expect(v.value).to eq 14 end it 'sets nil as a default initial value' do v = described_class.new expect(v.value).to be_nil end it 'sets the same initial value for all threads' do v = described_class.new(14) t1 = Thread.new { v.value } t2 = Thread.new { v.value } expect(t1.value).to eq 14 expect(t2.value).to eq 14 end if Concurrent.on_jruby? it 'extends JavaThreadLocalVar' do expect(described_class.ancestors).to include(Concurrent::JavaThreadLocalVar) end else it 'extends RubyThreadLocalVar' do expect(described_class.ancestors).to include(Concurrent::RubyThreadLocalVar) end end it 'can set a block to be called to get the initial value' do v = described_class.new { 14 } expect(v.value).to eq 14 end context 'when attempting to set both an initial value and a block' do it do expect { described_class.new(14) { 14 } }.to raise_error(ArgumentError) end end end context '#value' do let(:v) { described_class.new(14) } it 'returns the current value' do expect(v.value).to eq 14 end it 'returns the value after modification' do v.value = 2 expect(v.value).to eq 2 end context 'when using a block to initialize the value' do it 'calls the block to initialize the value' do block = proc { } expect(block).to receive(:call) v = described_class.new(&block) v.value end it 'sets the block return value as the current value' do value = 13 v = described_class.new { value += 1 } v.value expect(v.value).to be 14 end it 'calls the block to initialize the value for each thread' do block = proc { } expect(block).to receive(:call).twice v = described_class.new(&block) Thread.new { v.value }.join Thread.new { v.value }.join end end end context '#value=' do let(:v) { described_class.new(14) } it 'sets a new value' do v.value = 2 expect(v.value).to eq 2 end it 'returns the new value' do expect(v.value = 2).to eq 2 end it 'does not modify the initial value for other threads' do v.value = 2 t = Thread.new { v.value } expect(t.value).to eq 14 end it 'does not modify the value for other threads' do v.value = 2 b1 = CountDownLatch.new(2) b2 = CountDownLatch.new(2) t1 = Thread.new do b1.count_down b1.wait v.value = 1 b2.count_down b2.wait v.value end t2 = Thread.new do b1.count_down b1.wait v.value = 2 b2.count_down b2.wait v.value end expect(t1.value).to eq 1 expect(t2.value).to eq 2 end end end end concurrent-ruby-1.0.5/spec/concurrent/channel/000077500000000000000000000000001305460430400214015ustar00rootroot00000000000000concurrent-ruby-1.0.5/spec/concurrent/channel/buffer/000077500000000000000000000000001305460430400226525ustar00rootroot00000000000000concurrent-ruby-1.0.5/spec/concurrent/channel/buffer/base_shared.rb000066400000000000000000000054471305460430400254510ustar00rootroot00000000000000shared_examples :channel_buffer do specify do expect(subject).to respond_to(:blocking?) end context '#capacity' do specify { expect(subject.capacity).to be >= 0 } end context '#size' do it 'returns zero upon initialization' do expect(subject.size).to eq 0 end end context '#empty?' do it 'returns true when empty' do expect(subject).to be_empty end end context '#full?' do it 'returns false when not full' do expect(subject).to_not be_full end end context '#put' do it 'does not enqueue the item when closed' do subject.close subject.put(:foo) expect(subject).to be_empty end it 'returns false when closed' do subject.close expect(subject.put(:foo)).to be false end end context '#offer' do it 'returns true on success' do subject # initialize on this thread t = Thread.new do subject.take end t.join(0.1) expect(subject.offer(:foo)).to be true end it 'does not enqueue the item when closed' do subject.close subject.offer(:foo) expect(subject).to be_empty end it 'returns false immediately when closed' do subject.close expect(subject.offer(:foo)).to be false end end context '#take' do it 'returns Concurrent::NULL when closed' do subject.close expect(subject.take).to eq Concurrent::NULL end end context '#next' do it 'returns Concurrent::NULL, false when closed' do subject.close item, more = subject.next expect(item).to eq Concurrent::NULL expect(more).to be false end end context '#poll' do it 'returns the next item immediately if available' do subject # initialize on this thread t = Thread.new do subject.put(42) end t.join(0.1) # TODO (pitr-ch 15-Oct-2016): fails on JRuby https://travis-ci.org/pitr-ch/concurrent-ruby/jobs/167937038 expect(subject.poll).to eq 42 end it 'returns Concurrent::NULL immediately if no item is available' do expect(subject.poll).to eq Concurrent::NULL end it 'returns Concurrent::NULL when closed' do subject.close expect(subject.poll).to eq Concurrent::NULL end end context '#close' do it 'sets #closed? to false' do subject.close expect(subject).to be_closed end it 'returns true when not previously closed' do expect(subject.close).to be true end it 'returns false when already closed' do subject.close expect(subject.close).to be false end end context '#closed?' do it 'returns true when new' do expect(subject).to_not be_closed end it 'returns false after #close' do subject.close expect(subject).to be_closed end end end concurrent-ruby-1.0.5/spec/concurrent/channel/buffer/base_spec.rb000066400000000000000000000023531305460430400251260ustar00rootroot00000000000000require_relative 'buffered_shared' module Concurrent::Channel::Buffer describe Base, edge: true do subject { described_class.new } specify do expect(subject.capacity).to eq 0 end specify do expect(subject).to be_blocking end specify do expect { subject.size }.to raise_error(NotImplementedError) end specify do expect { subject.empty? }.to raise_error(NotImplementedError) end specify do expect { subject.full? }.to raise_error(NotImplementedError) end specify do expect { subject.put(42) }.to raise_error(NotImplementedError) end specify do expect { subject.offer(42) }.to raise_error(NotImplementedError) end specify do expect { subject.take }.to raise_error(NotImplementedError) end specify do expect { subject.poll }.to raise_error(NotImplementedError) end specify do expect { subject.next }.to raise_error(NotImplementedError) end specify do expect(subject).to_not be_closed end specify do subject.close expect(subject).to be_closed end end end concurrent-ruby-1.0.5/spec/concurrent/channel/buffer/buffered_shared.rb000066400000000000000000000077221305460430400263170ustar00rootroot00000000000000require_relative 'base_shared' shared_examples :channel_buffered_buffer do it_behaves_like :channel_buffer context '#initialize' do it 'raises an exception if size <= 0' do expect { described_class.new(0) }.to raise_error(ArgumentError) end end context '#capacity' do it 'returns the maximum capacity of the buffer' do subject = described_class.new(10) expect(subject.capacity).to eq 10 end end context '#size' do it 'is 0 when first created' do expect(subject.size).to eq 0 end it 'returns the number of items in the buffer' do fill = subject.capacity / 2 fill.times { subject.put(:foo) } expect(subject.size).to eq fill end it 'is 0 when there are taking threads but no putting threads' do t = Thread.new { subject.take } t.join(0.1) expect(subject.size).to eq 0 t.kill # cleanup end end context '#empty?' do it 'returns true when empty' do subject = described_class.new(10) expect(subject).to be_empty end end context '#put' do it 'enqueues the item when size > 0, not full, and not closed' do subject.put(:foo) expect(subject).to_not be_empty end it 'returns true when the item is put' do expect(subject.put(:foo)).to be true end end context '#offer' do it 'enqueues the item immediately when not full and not closed' do subject.offer(:foo) expect(subject.take).to eq :foo end end context '#take' do it 'returns the first item when not empty' do subject.put(:foo) expect(subject.take).to eq :foo end it 'blocks until not empty' do subject # initialize on this thread bucket = Concurrent::AtomicReference.new(nil) t = Thread.new do bucket.value = subject.take end t.join(0.1) before = bucket.value subject.put(42) t.join(0.1) after = bucket.value expect(before).to be nil expect(after).to eq 42 expect(t.status).to be false end it 'returns Concurrent::NULL when closed and empty' do subject.close expect(subject.take).to eq Concurrent::NULL end end context '#next' do it 'blocks until not empty' do subject # initialize on this thread bucket = Concurrent::AtomicReference.new([]) t = Thread.new do bucket.value = subject.next end t.join(0.1) before = bucket.value subject.put(42) t.join(0.1) after = bucket.value expect(before).to eq [] expect(after.first).to eq 42 expect(after.last).to be true expect(t.status).to be false end it 'returns , true when there is only one item and not closed' do subject.offer(42) item, more = subject.next expect(item).to eq 42 expect(more).to be true end it 'returns , true when there are multiple items' do subject.offer(:foo) subject.offer(:bar) subject.offer(:baz) item1, more1 = subject.next item2, more2 = subject.next item3, more3 = subject.next expect(item1).to eq :foo expect(more1).to be true expect(item2).to eq :bar expect(more2).to be true expect(item3).to eq :baz expect(more3).to be true end it 'returns , true when closed and last item' do capacity = subject.capacity expect(capacity).to be >= 1 capacity.times { subject.put(:foo) } subject.close capacity.times do item, more = subject.next expect(item).to eq :foo expect(more).to be true end end it 'returns Concurrent::NULL, false when closed and no items remain' do capacity = subject.capacity expect(capacity).to be >= 1 capacity.times { subject.put(:foo) } subject.close capacity.times { subject.next } item, more = subject.next expect(item).to eq Concurrent::NULL expect(more).to be false end end end concurrent-ruby-1.0.5/spec/concurrent/channel/buffer/buffered_spec.rb000066400000000000000000000023341305460430400257750ustar00rootroot00000000000000require_relative 'buffered_shared' module Concurrent::Channel::Buffer describe Buffered, edge: true do let(:capacity) { 10 } subject { described_class.new(capacity) } it_behaves_like :channel_buffered_buffer specify do expect(subject).to be_blocking end context '#full?' do it 'returns true when at max capacity' do subject = described_class.new(1) subject.put(:foo) expect(subject).to be_full end end context '#put' do it 'blocks when at capacity until a thread is ready to take' do subject = described_class.new(1) subject.put(13) bucket = Concurrent::AtomicReference.new(nil) t = Thread.new do subject.put(42) bucket.value = 42 end t.join(0.1) before = bucket.value subject.take t.join(0.1) after = bucket.value expect(before).to be nil expect(after).to eq 42 expect(t.status).to be false end end context '#offer' do it 'returns false immediately when full' do subject = described_class.new(1) subject.put(:foo) expect(subject.offer(:bar)).to be false end end end end concurrent-ruby-1.0.5/spec/concurrent/channel/buffer/dropping_spec.rb000066400000000000000000000023251305460430400260350ustar00rootroot00000000000000require_relative 'buffered_shared' module Concurrent::Channel::Buffer describe Dropping, edge: true do subject { described_class.new(10) } it_behaves_like :channel_buffered_buffer specify do expect(subject).to_not be_blocking end context '#put' do it 'does not block when full' do subject = described_class.new(1) 3.times {|i| expect(subject.put(i)).to be true } end it 'drops the last value when full' do subject = described_class.new(1) 3.times{|i| subject.put(i)} internal_buffer = subject.instance_variable_get(:@buffer) expect(internal_buffer.size).to eq 1 expect(internal_buffer.first).to eq 0 end end context '#offer' do it 'returns true immediately when full' do subject = described_class.new(1) subject.put(:foo) expect(subject.offer(:bar)).to be true end it 'drops the last value when full' do subject = described_class.new(1) 3.times{|i| subject.offer(i)} internal_buffer = subject.instance_variable_get(:@buffer) expect(internal_buffer.size).to eq 1 expect(internal_buffer.first).to eq 0 end end end end concurrent-ruby-1.0.5/spec/concurrent/channel/buffer/sliding_spec.rb000066400000000000000000000023261305460430400256450ustar00rootroot00000000000000require_relative 'buffered_shared' module Concurrent::Channel::Buffer describe Sliding, edge: true do subject { described_class.new(10) } it_behaves_like :channel_buffered_buffer specify do expect(subject).to_not be_blocking end context '#put' do it 'does not block when full' do subject = described_class.new(1) 3.times {|i| expect(subject.put(i)).to be true } end it 'drops the first value when full' do subject = described_class.new(1) 3.times{|i| subject.put(i)} internal_buffer = subject.instance_variable_get(:@buffer) expect(internal_buffer.size).to eq 1 expect(internal_buffer.first).to eq 2 end end context '#offer' do it 'returns true immediately when full' do subject = described_class.new(1) subject.put(:foo) expect(subject.offer(:bar)).to be true end it 'drops the first value when full' do subject = described_class.new(1) 3.times{|i| subject.offer(i)} internal_buffer = subject.instance_variable_get(:@buffer) expect(internal_buffer.size).to eq 1 expect(internal_buffer.first).to eq 2 end end end end concurrent-ruby-1.0.5/spec/concurrent/channel/buffer/ticker_spec.rb000066400000000000000000000026571305460430400255040ustar00rootroot00000000000000require_relative 'timing_buffer_shared' module Concurrent::Channel::Buffer describe Ticker, edge: true do let(:delay) { 0.1 } subject { described_class.new(delay) } it_behaves_like :channel_timing_buffer context '#take' do it 'triggers until closed' do expected = 3 actual = 0 expected.times { actual += 1 if subject.take.is_a? Concurrent::Channel::Tick } expect(actual).to eq expected end it 'returns Concurrent::NULL when closed after trigger' do subject.take subject.close expect(subject).to be_closed expect(subject.take).to eq Concurrent::NULL end end context '#poll' do it 'triggers until closed' do expected = 3 actual = 0 expected.times do until subject.poll.is_a?(Concurrent::Channel::Tick) actual += 1 end end end end context '#next' do it 'triggers until closed' do expected = 3 actual = 0 expected.times { actual += 1 if subject.next.first.is_a? Concurrent::Channel::Tick } expect(actual).to eq expected end it 'returns true for more while open' do _, more = subject.next expect(more).to be true end it 'returns false for more once closed' do subject.close _, more = subject.next expect(more).to be false end end end end concurrent-ruby-1.0.5/spec/concurrent/channel/buffer/timer_spec.rb000066400000000000000000000016621305460430400253360ustar00rootroot00000000000000require_relative 'timing_buffer_shared' module Concurrent::Channel::Buffer describe Timer, edge: true do let(:delay) { 0.1 } subject { described_class.new(0.1) } it_behaves_like :channel_timing_buffer context '#take' do it 'closes automatically on first take' do expect(subject.take).to be_truthy expect(subject).to be_closed end end context '#poll' do it 'closes automatically on first take' do loop do break if subject.poll != Concurrent::NULL end expect(subject).to be_closed end end context '#next' do it 'closes automatically on first take' do loop do value, _ = subject.next break if value != Concurrent::NULL end expect(subject).to be_closed end it 'returns false for more' do _, more = subject.next expect(more).to be false end end end end concurrent-ruby-1.0.5/spec/concurrent/channel/buffer/timing_buffer_shared.rb000066400000000000000000000072371305460430400273560ustar00rootroot00000000000000require_relative 'base_shared' shared_examples :channel_timing_buffer do specify do expect(subject).to be_blocking end context '#capacity' do specify do expect(subject.capacity).to eq 1 end end context '#size' do specify do expect(subject.size).to eq 0 end end context '#empty?' do specify do expect(subject).to_not be_empty end end context '#full?' do specify do expect(subject).to be_full end end context '#put' do specify do expect(subject.put(:foo)).to be false end end context '#offer' do specify do expect(subject.offer(:foo)).to be false end end context '#take' do it 'blocks when the timer is not ready' do actual = Concurrent::AtomicBoolean.new(false) subject = described_class.new(10) t = Thread.new do subject.take actual.make_true end t.join(0.1) actual = actual.value t.kill # clean up expect(actual).to be false end it 'returns a Tick' do subject = described_class.new(0.1) expect(subject.take).to be_a Concurrent::Channel::Tick end it 'triggers after the specified time interval' do start = Concurrent::Channel::Tick.new.monotonic subject = described_class.new(0.1) actual = subject.take.monotonic expect(actual - start).to be >= 0.1 end it 'returns Concurrent::NULL when closed' do subject.close expect(subject.take).to eq Concurrent::NULL end end context '#poll' do it 'returns Concurrent::NULL when the timer is not ready' do subject = described_class.new(0.1) expect(subject.poll).to eq Concurrent::NULL end it 'returns a Tick' do subject = described_class.new(0.1) sleep(0.2) expect(subject.poll).to be_a Concurrent::Channel::Tick end it 'returns Concurrent::NULL when closed' do subject.close expect(subject.poll).to eq Concurrent::NULL end it 'triggers after the specified time interval' do start = Concurrent::Channel::Tick.new.monotonic subject = described_class.new(0.1) sleep(0.2) actual = subject.poll.monotonic expect(actual - start).to be >= 0.1 end end context '#next' do it 'blocks when the timer is not ready' do actual = Concurrent::AtomicBoolean.new(false) subject = described_class.new(10) t = Thread.new do subject.next actual.make_true end t.join(0.1) actual = actual.value t.kill # clean up expect(actual).to be false end it 'returns a Tick when open' do subject = described_class.new(0.1) value, _ = subject.next expect(value).to be_a Concurrent::Channel::Tick end it 'returns Concurrent::NULL, false when closed' do subject.close expect(subject.take).to eq Concurrent::NULL end it 'triggers after the specified time interval' do start = Concurrent::Channel::Tick.new.monotonic subject = described_class.new(0.1) actual, _ = subject.next expect(actual.monotonic - start).to be >= 0.1 end end context '#close' do it 'sets #closed? to false' do subject.close expect(subject).to be_closed end it 'returns true when not previously closed' do expect(subject.close).to be true end it 'returns false when already closed' do subject.close expect(subject.close).to be false end end context '#closed?' do it 'returns true when new' do expect(subject).to_not be_closed end it 'returns false after #close' do subject.close expect(subject).to be_closed end end end concurrent-ruby-1.0.5/spec/concurrent/channel/buffer/unbuffered_spec.rb000066400000000000000000000133421305460430400263410ustar00rootroot00000000000000require_relative 'base_shared' module Concurrent::Channel::Buffer describe Unbuffered, edge: true do subject { described_class.new } it_behaves_like :channel_buffer specify do expect(subject).to be_blocking end specify do expect(subject.capacity).to eq 1 end context '#size' do it 'is 0 when first created' do expect(subject.size).to eq 0 end it 'is 1 when a putting thread is waiting' do t = Thread.new { subject.put(:foo) } t.join(0.1) expect(subject.size).to eq 1 t.kill # cleanup end it 'is 0 when there are taking threads but no putting threads' do t = Thread.new { subject.take } t.join(0.1) expect(subject.size).to eq 0 t.kill # cleanup end end context '#empty?' do it 'is true when there are no putting threads' do expect(subject).to be_empty end it 'is false when there are waiting putting threads' do t = Thread.new { subject.put(:foo) } t.join(0.1) expect(subject).to_not be_empty t.kill # cleanup end end context '#full?' do it 'is false when there are no putting threads' do expect(subject).to_not be_full end it 'is false when there are waiting putting threads' do t = Thread.new { subject.put(:foo) } t.join(0.1) expect(subject).to be_full t.kill # cleanup end end context '#put' do it 'does not enqueue the item when closed' do subject.close subject.put(:foo) expect(subject).to be_empty end it 'returns false when closed' do subject.close expect(subject.put(:foo)).to be false end it 'blocks until a thread is ready to take' do subject # initialize on this thread bucket = Concurrent::AtomicReference.new(nil) t = Thread.new do subject.put(42) bucket.value = 42 end t.join(0.1) before = bucket.value subject.take t.join(0.1) after = bucket.value expect(before).to be nil expect(after).to eq 42 expect(t.status).to be false end it 'delivers when closed after put starts' do t = Thread.new do subject.put(:foo) end t.join(0.1) subject.close item = subject.take t.kill #clean up expect(item).to eq :foo end end context '#offer' do it 'returns false immediately when a put in in progress' do subject # initialize on this thread t = Thread.new do subject.put(:foo) # block the thread end t.join(0.1) ok = subject.offer(:bar) subject.poll # release the blocked thread expect(ok).to be false end it 'gives the item to a waiting taker and returns true' do subject # initialize on this thread bucket = Concurrent::AtomicReference.new(nil) t = Thread.new do bucket.value = subject.take end t.join(0.1) before = bucket.value ok = subject.offer(42) t.join(0.1) after = bucket.value expect(ok).to be true expect(before).to be nil expect(after).to eq 42 end end context '#take' do it 'returns false immediately when a put in in progress' do subject # initialize on this thread t = Thread.new do subject.put(:foo) # block the thread end t.join(0.1) ok = subject.offer(:bar) subject.poll # release the blocked thread expect(ok).to be false end it 'gives the item to a waiting taker and returns true' do subject # initialize on this thread bucket = Concurrent::AtomicReference.new(nil) t = Thread.new do bucket.value = subject.take end t.join(0.1) before = bucket.value ok = subject.offer(42) t.join(0.1) after = bucket.value expect(ok).to be true expect(before).to be nil expect(after).to eq 42 end end context '#next' do it 'blocks when no putting and returns , true when one arrives' do subject # initialize on this thread bucket = Concurrent::AtomicReference.new([]) t = Thread.new do bucket.value = subject.next end t.join(0.1) before = bucket.value subject.put(42) t.join(0.1) after = bucket.value expect(before).to eq [] expect(after.first).to eq 42 expect(after.last).to be true expect(t.status).to be false end it 'returns , true when there are multiple putting' do subject # initialize on this thread threads = 2.times.collect do Thread.new do subject.put(42) end end threads.each {|t| t.join(0.1)} item, more = subject.next subject.poll # clear the channel expect(item).to eq 42 expect(more).to be true end it 'returns , true when closed and last item' do t = Thread.new do subject.put(:foo) end t.join(0.1) subject.close item, more = subject.next t.kill #clean up expect(item).to eq :foo expect(more).to be true end it 'returns Concurrent::NULL, false when closed and no items remain' do t = Thread.new do subject.put(:foo) end subject.close subject.next item, more = subject.next t.kill #clean up expect(item).to eq Concurrent::NULL expect(more).to be false end end end end concurrent-ruby-1.0.5/spec/concurrent/channel/integration_spec.rb000066400000000000000000000127171305460430400252730ustar00rootroot00000000000000describe 'channel integration tests', edge: true, notravis: true do let!(:examples_root) { File.expand_path(File.join(File.dirname(__FILE__), '../../../examples')) } context 'A Tour of Go' do let!(:script_root) { File.join(examples_root, 'a-tour-of-go-channels') } specify 'channels.rb' do expected = [-5, 17, 12] result = `ruby #{File.join(script_root, 'channels.rb')}` results = result.split(' ').map(&:chomp).collect{|i| i.to_i} expect($?.to_i).to eq 0 expect(results.length).to eq 3 expected.each do |n| expect(results).to include(n) end end specify 'buffered-channels.rb' do expected = <<-STDOUT 1 2 STDOUT result = `ruby #{File.join(script_root, 'buffered-channels.rb')}` expect($?.to_i).to eq 0 expect(result).to eq expected end specify 'range-and-close.rb' do expected = <<-STDOUT 0 1 1 2 3 5 8 13 21 34 STDOUT result = `ruby #{File.join(script_root, 'range-and-close.rb')}` expect($?.to_i).to eq 0 expect(result).to eq expected end specify 'select.rb' do expected = <<-STDOUT 0 1 1 2 3 5 8 13 21 34 quit STDOUT result = `ruby #{File.join(script_root, 'select.rb')}` expect($?.to_i).to eq 0 expect(result).to eq expected end specify 'default-selection.rb', notravis: true do expected = <<-STDOUT . . tick. . . tick. . . tick. . . tick. . . tick. BOOM! STDOUT result = `ruby #{File.join(script_root, 'default-selection.rb')}` expect($?.to_i).to eq 0 expect(result).to eq expected end end context 'Go By Example' do let!(:script_root) { File.join(examples_root, 'go-by-example-channels') } specify 'channels.rb' do expected = <<-STDOUT ping STDOUT result = `ruby #{File.join(script_root, 'channels.rb')}` expect($?.to_i).to eq 0 expect(result).to eq expected end specify 'channel-buffering.rb' do expected = <<-STDOUT buffered channel STDOUT result = `ruby #{File.join(script_root, 'channel-buffering.rb')}` expect($?.to_i).to eq 0 expect(result).to eq expected end specify 'channel-synchronization.rb' do expected = <<-STDOUT working... done STDOUT result = `ruby #{File.join(script_root, 'channel-synchronization.rb')}` expect($?.to_i).to eq 0 expect(result).to eq expected end specify 'channel-directions.rb' do expected = <<-STDOUT passed message STDOUT result = `ruby #{File.join(script_root, 'channel-directions.rb')}` expect($?.to_i).to eq 0 expect(result).to eq expected end specify 'select.rb' do expected = <<-STDOUT received one received two STDOUT result = `ruby #{File.join(script_root, 'select.rb')}` expect($?.to_i).to eq 0 expect(result).to eq expected end specify 'timeouts.rb' do expected = <<-STDOUT timeout 1 result 2 STDOUT result = `ruby #{File.join(script_root, 'timeouts.rb')}` expect($?.to_i).to eq 0 expect(result).to eq expected end specify 'non-blocking-channel-operations.rb' do expected = <<-STDOUT no message received no message sent no activity STDOUT result = `ruby #{File.join(script_root, 'non-blocking-channel-operations.rb')}` expect($?.to_i).to eq 0 expect(result).to eq expected end specify 'closing-channels.rb' do expected = [ 'sent job 1', 'received job 1', 'sent job 2', 'received job 2', 'sent job 3', 'received job 3', 'sent all jobs', 'received all jobs', ] result = `ruby #{File.join(script_root, 'closing-channels.rb')}` expect($?.to_i).to eq 0 expected.each do |line| expect(result).to match(/^#{line}$/) end end specify 'range-over-channels.rb' do expected = <<-STDOUT one two STDOUT result = `ruby #{File.join(script_root, 'range-over-channels.rb')}` expect($?.to_i).to eq 0 expect(result).to eq expected end specify 'timers.rb' do expected = <<-STDOUT Timer 1 expired Timer 2 stopped STDOUT result = `ruby #{File.join(script_root, 'timers.rb')}` expect($?.to_i).to eq 0 expect(result).to eq expected end specify 'ticker.rb' do result = `ruby #{File.join(script_root, 'ticker.rb')}` results = result.lines.map(&:chomp) expect($?.to_i).to eq 0 expect(results.length).to eq 4 (0..2).each do |i| expect(results[i]).to match(/^Tick at /) end expect(results.last).to match('Ticker stopped') end specify 'worker-pools.rb' do expected = [ /^worker \d processing job 1$/, /^worker \d processing job 2$/, /^worker \d processing job 3$/, /^worker \d processing job 4$/, /^worker \d processing job 5$/, /^worker \d processing job 6$/, /^worker \d processing job 7$/, /^worker \d processing job 8$/, /^worker \d processing job 9$/, ] result = `ruby #{File.join(script_root, 'worker-pools.rb')}` expect($?.to_i).to eq 0 expected.each do |regex| expect(result).to match(regex) end end specify 'rate-limiting.rb' do result = `ruby #{File.join(script_root, 'rate-limiting.rb')}` results = result.lines.map(&:chomp) expect($?.to_i).to eq 0 expect(results.length).to eq 11 (0..4).each do |i| expect(results[i]).to match(/^request #{i+1}/) expect(results[i+6]).to match(/^request #{i+1}/) end end end end concurrent-ruby-1.0.5/spec/concurrent/channel/tick_spec.rb000066400000000000000000000036671305460430400237060ustar00rootroot00000000000000module Concurrent class Channel describe Tick, edge: true do it 'initializes to current time when no argument given' do allow(Concurrent).to receive(:monotonic_time).and_return(42) subject = Tick.new expect(subject.monotonic).to eq 42 end it 'initializes to the given monotonic time' do m = Concurrent.monotonic_time subject = Tick.new(m) expect(subject.monotonic).to eq m end specify '#utc returns a Time object in UTC' do t = subject.utc expect(subject.utc).to be_a Time expect(subject.utc.zone).to eq 'UTC' end specify '#epoch returns the UTC time as epoch seconds' do expect(subject.utc.to_f).to eq subject.epoch end specify '#to_s formats as a time', :truffle_bug => true do expect(subject.to_s).to match /\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{6} \+\d{4} UTC/ end context 'comparison' do it 'correctly compares to a Numeric (monotonic)' do present = Concurrent.monotonic_time past = present - 42 future = present + 42 subject = Tick.new(present) expect(subject).to be < future expect(subject).to be == present expect(subject).to be > past end it 'correctly compares to a Time' do present = Time.now past = Time.now - 42*60*60 future = Time.now + 42*60*60 subject = Tick.new expect(subject).to be < future expect(subject).to be > past end it 'correctly compares to a Tick' do now = Concurrent.monotonic_time present = Tick.new(now) past = Tick.new(now - 42) future = Tick.new(now + 42) subject = Tick.new(now) expect(subject).to be < future expect(subject).to eq present expect(subject).to be > past end end end end end concurrent-ruby-1.0.5/spec/concurrent/channel_spec.rb000066400000000000000000000440741305460430400227510ustar00rootroot00000000000000module Concurrent describe Channel, edge: true, buggy: true do context 'initialization' do it 'raises an exception when the :buffer is invalid' do expect { Channel.new(buffer: :bogus) }.to raise_error(ArgumentError) end it 'is :unbuffered when neither :buffer nore :capacity is given' do expect(Channel::Buffer::Unbuffered).to receive(:new).with(no_args).and_call_original Channel.new end it 'is :unbuffered when :unbuffered is given' do expect(Channel::Buffer::Unbuffered).to receive(:new).with(no_args).and_call_original Channel.new(buffer: :unbuffered) end it 'is :unbuffered when :buffered and capacity: 0' do expect(Channel::Buffer::Unbuffered).to receive(:new).with(no_args).and_call_original Channel.new(buffer: :buffered, capacity: 0) end it 'raises an exception when both :unbuffered and :capacity are given' do expect { Channel.new(buffer: :unbuffered, capacity: 0) }.to raise_error(ArgumentError) end it 'is :buffered when :capacity > 0 and no :buffer given' do expect(Channel::Buffer::Buffered).to receive(:new).with(5).and_call_original Channel.new(capacity: 5) end it 'is :buffered when :buffered given' do expect(Channel::Buffer::Buffered).to receive(:new).with(5).and_call_original Channel.new(buffer: :buffered, capacity: 5) end it 'raises an exception when :buffered given without :capacity' do expect { Channel.new(buffer: :buffered) }.to raise_error(ArgumentError) end it 'raises an exception when :buffered and :capacity < 0' do expect { Channel.new(buffer: :buffered, capacity: -1) }.to raise_error(ArgumentError) end it 'is :dropping when :dropping and :capacity > 0' do expect(Channel::Buffer::Dropping).to receive(:new).with(5).and_call_original Channel.new(buffer: :dropping, capacity: 5) end it 'raises an exception when :dropping given without :capacity' do expect { Channel.new(buffer: :dropping) }.to raise_error(ArgumentError) end it 'raises an exception when :dropping and :capacity < 1' do expect { Channel.new(buffer: :dropping, capacity: 0) }.to raise_error(ArgumentError) end it 'is :sliding when :sliding and :capacity > 0' do expect(Channel::Buffer::Sliding).to receive(:new).with(5).and_call_original Channel.new(buffer: :sliding, capacity: 5) end it 'raises an exception when :sliding given without :capacity' do expect { Channel.new(buffer: :sliding) }.to raise_error(ArgumentError) end it 'raises an exception when :sliding and :capacity < 1' do expect { Channel.new(buffer: :sliding, capacity: 0) }.to raise_error(ArgumentError) end it 'uses the given buffer' do buffer = Channel::Buffer::Buffered.new(10) subject = Channel.new(buffer) expect(subject).to receive(:put).with(42) subject.put(42) end end context 'factories' do specify do expect(Channel::Buffer::Ticker).to receive(:new).with(10).and_call_original Channel.ticker(10) end specify do expect(Channel::Buffer::Timer).to receive(:new).with(10).and_call_original Channel.timer(10) end end context '#put' do it 'returns true on success' do subject = Channel.new(buffer: :buffered, capacity: 2) expect(subject.put(:foo)).to be true end it 'returns false on failure' do subject = Channel.new(buffer: :buffered, capacity: 2) subject.close expect(subject.put(:foo)).to be false end it 'rejects when the validator returns false' do validator = ->(value) { false } subject = Channel.new(capacity: 10, validator: validator) expect(subject.put(42)).to be false end it 'rejects when the validator raises an exception' do validator = ->(value) { raise StandardError } subject = Channel.new(capacity: 10, validator: validator) expect(subject.put(42)).to be false end it 'rejects nil' do expect(subject.put(nil)).to be false end end context 'put!' do it 'returns true on success' do subject = Channel.new(buffer: :buffered, capacity: 2) expect(subject.put!(:foo)).to be true end it 'raises an exception on failure' do subject = Channel.new(buffer: :buffered, capacity: 2) subject.close expect { subject.put!(:foo) }.to raise_error(Channel::Error) end it 'rejects when the validator returns false' do validator = ->(value) { false } subject = Channel.new(capacity: 10, validator: validator) expect{ subject.put!(42) }.to raise_error(Channel::ValidationError) end it 'rejects when the validator raises an exception' do validator = ->(value) { raise StandardError } subject = Channel.new(capacity: 10, validator: validator) expect{ subject.put!(42) }.to raise_error(StandardError) end it 'rejects nil' do expect { subject.put!(nil) }.to raise_error(Channel::ValidationError) end end context 'put?' do it 'returns a just Maybe on success' do subject = Channel.new(buffer: :buffered, capacity: 2) result = subject.put?(:foo) expect(result).to be_a Concurrent::Maybe expect(result).to be_just end it 'returns a nothing Maybe on failure' do subject = Channel.new(buffer: :buffered, capacity: 2) subject.close result = subject.put?(:foo) expect(result).to be_a Concurrent::Maybe expect(result).to be_nothing end it 'rejects when the validator returns false' do validator = ->(value) { false } subject = Channel.new(capacity: 10, validator: validator) expect(subject.put?(42)).to be_nothing end it 'rejects when the validator raises an exception' do validator = ->(value) { false } subject = Channel.new(capacity: 10, validator: validator) expect(subject.put?(42)).to be_nothing end it 'accepts nil' do result = subject.put?(nil) expect(result).to be_a Concurrent::Maybe expect(result).to be_just end end context '#offer' do it 'returns true on success' do subject = Channel.new(buffer: :buffered, capacity: 2) expect(subject.offer(:foo)).to be true end it 'returns false on failure' do subject = Channel.new(buffer: :buffered, capacity: 2) subject.close expect(subject.offer(:foo)).to be false end it 'rejects when the validator returns false' do validator = ->(value) { false } subject = Channel.new(capacity: 10, validator: validator) expect(subject.offer(42)).to be false end it 'rejects when the validator raises an exception' do validator = ->(value) { raise StandardError } subject = Channel.new(capacity: 10, validator: validator) expect(subject.offer(42)).to be false end it 'rejects nil' do expect(subject.offer(nil)).to be false end end context 'offer!' do it 'returns true on success' do subject = Channel.new(buffer: :buffered, capacity: 2) expect(subject.offer!(:foo)).to be true end it 'raises an exception on failure' do subject = Channel.new(buffer: :buffered, capacity: 2) subject.close expect { subject.offer!(:foo) }.to raise_error(Channel::Error) end it 'rejects when the validator returns false' do validator = ->(value) { false } subject = Channel.new(capacity: 10, validator: validator) expect{ subject.offer!(42) }.to raise_error(Channel::ValidationError) end it 'rejects when the validator raises an exception' do validator = ->(value) { raise StandardError } subject = Channel.new(capacity: 10, validator: validator) expect{ subject.offer!(42) }.to raise_error(StandardError) end it 'rejects nil' do expect { subject.offer!(nil) }.to raise_error(Channel::ValidationError) end end context 'offer?' do it 'returns a just Maybe on success' do subject = Channel.new(buffer: :buffered, capacity: 2) result = subject.offer?(:foo) expect(result).to be_a Concurrent::Maybe expect(result).to be_just end it 'returns a nothing Maybe on failure' do subject = Channel.new(buffer: :buffered, capacity: 2) subject.close result = subject.offer?(:foo) expect(result).to be_a Concurrent::Maybe expect(result).to be_nothing end it 'rejects when the validator returns false' do validator = ->(value) { false } subject = Channel.new(capacity: 10, validator: validator) expect(subject.offer?(42)).to be_nothing end it 'rejects when the validator raises an exception' do validator = ->(value) { false } subject = Channel.new(capacity: 10, validator: validator) expect(subject.offer?(42)).to be_nothing end it 'accepts nil' do subject = Channel.new(buffer: :buffered, capacity: 2) result = subject.offer?(nil) expect(result).to be_a Concurrent::Maybe expect(result).to be_just end end context '#take' do subject { Channel.new(buffer: :buffered, capacity: 2) } it 'takes the next item when not empty' do subject.put(:foo) expect(subject.take).to eq :foo end it 'returns nil on failure' do subject.close expect(subject.take).to be nil end end context '#take!' do subject { Channel.new(buffer: :buffered, capacity: 2) } it 'takes the next item when not empty' do subject.put(:foo) expect(subject.take!).to eq :foo end it 'raises an exception on failure' do subject.close expect { subject.take! }.to raise_error(Channel::Error) end end context '#take?' do subject { Channel.new(buffer: :buffered, capacity: 2) } it 'returns a just Maybe on success' do subject.put(:foo) result = subject.take? expect(result).to be_a Concurrent::Maybe expect(result).to be_just expect(result.value).to eq :foo end it 'returns a nothing Maybe on failure' do subject.close result = subject.take? expect(result).to be_a Concurrent::Maybe expect(result).to be_nothing end end context '#next' do subject { Channel.new(buffer: :buffered, capacity: 3) } it 'returns , true when there is one item' do subject.put(:foo) item, more = subject.next expect(item).to eq :foo expect(more).to be true end it 'returns , true when there are multiple items' do subject.put(:foo) subject.put(:bar) item, more = subject.next subject.poll # clear the buffer expect(item).to eq :foo expect(more).to be true end it 'returns nil, false when empty and closed' do subject.close item, more = subject.next expect(item).to be nil expect(more).to be false end it 'returns , true when closed and last item' do capacity = subject.capacity expect(capacity).to be >= 1 capacity.times { subject.put(:foo) } subject.close capacity.times do item, more = subject.next expect(item).to eq :foo expect(more).to be true end end it 'returns nil, false when closed and no items remain' do capacity = subject.capacity expect(capacity).to be >= 1 capacity.times { subject.put(:foo) } subject.close capacity.times { subject.next } item, more = subject.next expect(item).to be_nil expect(more).to be false end end context '#next?' do subject { Channel.new(buffer: :buffered, capacity: 2) } it 'returns a just Maybe and true when there is one item' do subject.put(:foo) item, more = subject.next? expect(item).to be_a Concurrent::Maybe expect(item).to be_just expect(item.value).to eq :foo expect(more).to be true end it 'returns a just Maybe, true when there are multiple items' do subject.put(:foo) subject.put(:bar) item, more = subject.next? subject.poll # clear the buffer expect(item).to be_a Concurrent::Maybe expect(item).to be_just expect(item.value).to eq :foo expect(more).to be true end it 'returns a nothing Maybe and false on failure' do subject.close item, more = subject.next? expect(item).to be_a Concurrent::Maybe expect(item).to be_nothing expect(more).to be false end end context '#poll' do it 'returns the next item immediately if available' do subject # initialize on this thread t = Thread.new do subject.put(42) end t.join(0.1) expect(subject.poll).to eq 42 end it 'returns nil immediately if no item is available' do expect(subject.poll).to be nil end it 'returns nil on failure' do subject.close expect(subject.poll).to be nil end end context '#poll!' do it 'returns the next item immediately if available' do subject # initialize on this thread t = Thread.new do subject.put(42) end t.join(0.1) expect(subject.poll!).to eq 42 end it 'raises an exception immediately if no item is available' do expect { subject.poll! }.to raise_error(Channel::Error) end it 'raises an exception on failure' do subject.close expect { subject.poll! }.to raise_error(Channel::Error) end end context '#poll?' do it 'returns a just Maybe immediately if available', buggy: true do subject # initialize on this thread t = Thread.new do subject.put(42) end t.join(0.1) result = subject.poll? expect(result).to be_a Concurrent::Maybe expect(result).to be_just expect(result.value).to eq 42 end it 'returns a nothing Maybe immediately if no item is available' do result = subject.poll? expect(result).to be_a Concurrent::Maybe expect(result).to be_nothing end it 'returns a nothing Maybe on failure' do subject.close result = subject.poll? expect(result).to be_a Concurrent::Maybe expect(result).to be_nothing end end context '.each' do it 'raises and exception when no block is given' do expect { subject.each }.to raise_error(ArgumentError) end it 'iterates until the channel is closed' do expected = [13, 42, 2001] subject = Channel.new(capacity: expected.length) expected.each { |value| subject.put(value) } subject.close actual = [] subject.each { |value| actual << value } expect(actual).to eq expected end end context 'goroutines', notravis: true do let(:default_executor) { Channel.const_get(:GOROUTINES) } context '.go' do it 'raises an exception when no block is given' do expect { Channel.go }.to raise_error(ArgumentError) end specify do expect(default_executor).to receive(:post).with(1, 2, 3) Channel.go(1, 2, 3) { nil } end end context '.go_via' do it 'raises an exception when no block is given' do expect { Channel.go_via }.to raise_error(ArgumentError) end specify do executor = ImmediateExecutor.new expect(executor).to receive(:post).with(1, 2, 3) Channel.go_via(executor, 1, 2, 3) { nil } end end context '.go_loop' do it 'raises an exception when no block is given' do expect { Channel.go_loop }.to raise_error(ArgumentError) end it 'loops until the block returns false' do actual = 0 expected = 3 latch = Concurrent::CountDownLatch.new(expected) Channel.go_loop do actual += 1 latch.count_down actual < expected end latch.wait(10) expect(actual).to eq expected end end context '.go_loop_via' do it 'raises an exception when no block is given' do expect { Channel.go_loop_via }.to raise_error(ArgumentError) end it 'loops until the block returns false' do actual = 0 expected = 3 executor = ImmediateExecutor.new latch = Concurrent::CountDownLatch.new(expected) Channel.go_loop_via(executor) do actual += 1 latch.count_down actual < expected end latch.wait(3) expect(actual).to eq expected end end end context 'select' do it 'raises an exception when no block is given' do expect { Channel.select }.to raise_error(ArgumentError) end it 'passes a selector to the block' do actual = nil Channel.select { |s| actual = s; s.error { } } expect(actual).to be_a Channel::Selector end specify do expect_any_instance_of(Channel::Selector).to receive(:execute) Channel.select { |s| s.error { } } end end end end concurrent-ruby-1.0.5/spec/concurrent/collection/000077500000000000000000000000001305460430400221245ustar00rootroot00000000000000concurrent-ruby-1.0.5/spec/concurrent/collection/copy_on_notify_observer_set_spec.rb000066400000000000000000000002611305460430400313020ustar00rootroot00000000000000require_relative 'observer_set_shared' module Concurrent module Collection describe CopyOnNotifyObserverSet do it_behaves_like 'an observer set' end end end concurrent-ruby-1.0.5/spec/concurrent/collection/copy_on_write_observer_set_spec.rb000066400000000000000000000002601305460430400311230ustar00rootroot00000000000000require_relative 'observer_set_shared' module Concurrent module Collection describe CopyOnWriteObserverSet do it_behaves_like 'an observer set' end end end concurrent-ruby-1.0.5/spec/concurrent/collection/non_concurrent_priority_queue_spec.rb000066400000000000000000000204711305460430400316700ustar00rootroot00000000000000shared_examples :priority_queue do subject{ described_class.new } context '#initialize' do it 'sorts from high to low when :order is :max' do subject = described_class.from_list([2, 1, 4, 5, 3, 0], order: :max) expect(subject.pop).to eq 5 expect(subject.pop).to eq 4 expect(subject.pop).to eq 3 end it 'sorts from high to low when :order is :high' do subject = described_class.new(order: :high) [2, 1, 4, 5, 3, 0].each{|item| subject << item } expect(subject.pop).to eq 5 expect(subject.pop).to eq 4 expect(subject.pop).to eq 3 end it 'sorts from low to high when :order is :min' do subject = described_class.from_list([2, 1, 4, 5, 3, 0], order: :min) expect(subject.pop).to eq 0 expect(subject.pop).to eq 1 expect(subject.pop).to eq 2 end it 'sorts from low to high when :order is :low' do subject = described_class.new(order: :low) [2, 1, 4, 5, 3, 0].each{|item| subject << item } expect(subject.pop).to eq 0 expect(subject.pop).to eq 1 expect(subject.pop).to eq 2 end it 'sorts from high to low by default' do subject = described_class.new subject = described_class.from_list([2, 1, 4, 5, 3, 0]) expect(subject.pop).to eq 5 expect(subject.pop).to eq 4 expect(subject.pop).to eq 3 end end context '#clear' do it 'removes all items from a populated queue' do 10.times{|i| subject << i} subject.clear expect(subject).to be_empty end it 'has no effect on an empty queue' do subject.clear expect(subject).to be_empty end specify { expect(subject.clear).to be_truthy } end context '#delete' do it 'deletes the requested item when found' do 10.times{|item| subject << item } subject.delete(5) expect(subject.pop).to eq 9 expect(subject.pop).to eq 8 expect(subject.pop).to eq 7 expect(subject.pop).to eq 6 expect(subject.pop).to eq 4 expect(subject.pop).to eq 3 expect(subject.pop).to eq 2 expect(subject.pop).to eq 1 expect(subject.pop).to eq 0 end it 'deletes the requested item when it is the first element' do 10.times{|item| subject << item } subject.delete(9) expect(subject.length).to eq 9 expect(subject.pop).to eq 8 expect(subject.pop).to eq 7 expect(subject.pop).to eq 6 expect(subject.pop).to eq 5 expect(subject.pop).to eq 4 expect(subject.pop).to eq 3 expect(subject.pop).to eq 2 expect(subject.pop).to eq 1 expect(subject.pop).to eq 0 end it 'deletes the requested item when it is the last element' do 10.times{|item| subject << item } subject.delete(2) expect(subject.length).to eq 9 expect(subject.pop).to eq 9 expect(subject.pop).to eq 8 expect(subject.pop).to eq 7 expect(subject.pop).to eq 6 expect(subject.pop).to eq 5 expect(subject.pop).to eq 4 expect(subject.pop).to eq 3 expect(subject.pop).to eq 1 expect(subject.pop).to eq 0 end it 'deletes multiple matching items when present' do [2, 1, 2, 2, 2, 3, 2].each{|item| subject << item } subject.delete(2) expect(subject.pop).to eq 3 expect(subject.pop).to eq 1 end it 'returns true when found' do 10.times{|i| subject << i} expect(subject.delete(2)).to be_truthy end it 'returns false when not found' do 10.times{|i| subject << i} expect(subject.delete(100)).to be_falsey end it 'returns false when called on an empty queue' do expect(subject.delete(:foo)).to be_falsey end end context '#empty?' do it 'returns true for an empty queue' do expect(subject).to be_empty end it 'returns false for a populated queue' do 10.times{|i| subject << i} expect(subject).not_to be_empty end end context '#include?' do it 'returns true if the item is found' do 10.times{|i| subject << i} expect(subject).to include(5) end it 'returns false if the item is not found' do 10.times{|i| subject << i} expect(subject).not_to include(50) end it 'returns false when the queue is empty' do expect(subject).not_to include(1) end it 'is aliased as #has_priority?' do 10.times{|i| subject << i} expect(subject).to have_priority(5) end end context '#length' do it 'returns the length of a populated queue' do 10.times{|i| subject << i} expect(subject.length).to eq 10 end it 'returns zero when the queue is empty' do expect(subject.length).to eq 0 end it 'is aliased as #size' do 10.times{|i| subject << i} expect(subject.size).to eq 10 end end context '#peek' do it 'returns the item at the head of the queue' do 10.times{|i| subject << i} expect(subject.peek).to eq 9 end it 'does not remove the item from the queue' do 10.times{|i| subject << i} subject.peek expect(subject.length).to eq 10 expect(subject).to include(9) end it 'returns nil when the queue is empty' do expect(subject.peek).to be_nil end end context '#pop' do it 'returns the item at the head of the queue' do 10.times{|i| subject << i} expect(subject.pop).to eq 9 end it 'removes the item from the queue' do 10.times{|i| subject << i} subject.pop expect(subject.length).to eq 9 expect(subject).not_to include(9) end it 'returns nil when the queue is empty' do expect(subject.pop).to be_nil end it 'returns nil when called multiple times while empty' do 10.times do expect(subject.pop).to be nil end end it 'is aliased as #deq' do 10.times{|i| subject << i} expect(subject.deq).to eq 9 end it 'is aliased as #shift' do 10.times{|i| subject << i} expect(subject.shift).to eq 9 end end context '#push' do it 'raises an exception when attempting to enqueue nil' do expect { subject.push(nil) }.to raise_error(ArgumentError) end it 'adds the item to the queue' do subject.push(1) expect(subject).to include(1) end it 'sorts the new item in priority order' do 3.times{|i| subject << i} expect(subject.pop).to eq 2 expect(subject.pop).to eq 1 expect(subject.pop).to eq 0 end it 'arbitrarily orders equal items with respect to each other' do 3.times{|i| subject << i} subject.push(1) expect(subject.pop).to eq 2 expect(subject.pop).to eq 1 expect(subject.pop).to eq 1 expect(subject.pop).to eq 0 end specify { expect(subject.push(10)).to be_truthy } it 'is aliased as <<' do subject << 1 expect(subject).to include(1) end it 'is aliased as enq' do subject.enq(1) expect(subject).to include(1) end end context '.from_list' do it 'creates an empty queue from an empty list' do subject = described_class.from_list([]) expect(subject).to be_empty end it 'creates a sorted, populated queue from an Array' do subject = described_class.from_list([2, 1, 4, 5, 3, 0]) expect(subject.pop).to eq 5 expect(subject.pop).to eq 4 expect(subject.pop).to eq 3 expect(subject.pop).to eq 2 expect(subject.pop).to eq 1 expect(subject.pop).to eq 0 end it 'creates a sorted, populated queue from a Hash' do subject = described_class.from_list(two: 2, one: 1, three: 3, zero: 0) expect(subject.length).to eq 4 end end end module Concurrent module Collection describe RubyNonConcurrentPriorityQueue do it_should_behave_like :priority_queue end if Concurrent.on_jruby? describe JavaNonConcurrentPriorityQueue do it_should_behave_like :priority_queue end end describe NonConcurrentPriorityQueue do if Concurrent.on_jruby? it 'inherits from JavaNonConcurrentPriorityQueue' do expect(NonConcurrentPriorityQueue.ancestors).to include(JavaNonConcurrentPriorityQueue) end else it 'inherits from RubyNonConcurrentPriorityQueue' do expect(NonConcurrentPriorityQueue.ancestors).to include(RubyNonConcurrentPriorityQueue) end end end end end concurrent-ruby-1.0.5/spec/concurrent/collection/observer_set_shared.rb000066400000000000000000000161221305460430400265030ustar00rootroot00000000000000shared_examples "an observer set" do let (:observer_set) { described_class.new } let (:observer) { double('observer') } let (:another_observer) { double('another observer') } describe '#add_observer' do context 'with arguments' do it 'should return the observer' do expect(observer_set.add_observer(observer, :a_method)).to eq(observer) end end context 'with a block' do it 'should return the observer based on a block' do observer = observer_set.add_observer { :block } expect(observer.call).to eq(:block) end end end describe '#notify_observers' do it 'should return the observer set' do expect(observer_set.notify_observers).to be(observer_set) end context 'with a single observer' do it 'should update a registered observer without arguments' do expect(observer).to receive(:update).with(no_args) observer_set.add_observer(observer) observer_set.notify_observers end it 'should update a registered observer with arguments' do expect(observer).to receive(:update).with(1, 2, 3) observer_set.add_observer(observer) observer_set.notify_observers(1, 2, 3) end it 'should notify an observer using the chosen method' do expect(observer).to receive(:another_method).with('a string arg') observer_set.add_observer(observer, :another_method) observer_set.notify_observers('a string arg') end it 'should notify an observer once using the last added method' do expect(observer).to receive(:another_method).with(any_args).never expect(observer).to receive(:yet_another_method).with('a string arg') observer_set.add_observer(observer, :another_method) observer_set.add_observer(observer, :yet_another_method) observer_set.notify_observers('a string arg') end it 'should notify an observer from a block' do notification = double expect(notification).to receive(:catch) observer_set.add_observer {|arg| arg.catch } observer_set.notify_observers notification end it 'can be called many times' do expect(observer).to receive(:update).with(:an_arg).twice expect(observer).to receive(:update).with(no_args).once observer_set.add_observer(observer) observer_set.notify_observers(:an_arg) observer_set.notify_observers observer_set.notify_observers(:an_arg) end end context 'with many observers' do it 'should notify all observer using the chosen method' do expect(observer).to receive(:a_method).with(4, 'a') expect(another_observer).to receive(:update).with(4, 'a') observer_set.add_observer(observer, :a_method) observer_set.add_observer(another_observer) observer_set.notify_observers(4, 'a') end end context 'with a block' do before(:each) do allow(observer).to receive(:update).with(any_args) allow(another_observer).to receive(:update).with(any_args) end it 'calls the block once for every observer' do counter = double('block call counter') expect(counter).to receive(:called).with(no_args).exactly(2).times observer_set.add_observer(observer) observer_set.add_observer(another_observer) observer_set.notify_observers{ counter.called } end it 'passes the block return value to the update method' do expect(observer).to receive(:update).with(1, 2, 3, 4) observer_set.add_observer(observer) observer_set.notify_observers{ [1, 2, 3, 4] } end it 'accepts blocks returning a single value' do expect(observer).to receive(:update).with(:foo) observer_set.add_observer(observer) observer_set.notify_observers{ :foo } end it 'accepts block return values that include arrays' do expect(observer).to receive(:update).with(1, [2, 3], 4) observer_set.add_observer(observer) observer_set.notify_observers{ [1, [2, 3], 4] } end it 'raises an exception if given both arguments and a block' do observer_set.add_observer(observer) expect { observer_set.notify_observers(1, 2, 3, 4){ nil } }.to raise_error(ArgumentError) end end end context '#count_observers' do it 'should be zero after initialization' do expect(observer_set.count_observers).to eq 0 end it 'should be 1 after the first observer is added' do observer_set.add_observer(observer) expect(observer_set.count_observers).to eq 1 end it 'should be 1 if the same observer is added many times' do observer_set.add_observer(observer) observer_set.add_observer(observer, :another_method) observer_set.add_observer(observer, :yet_another_method) expect(observer_set.count_observers).to eq 1 end it 'should be equal to the number of unique observers' do observer_set.add_observer(observer) observer_set.add_observer(another_observer) observer_set.add_observer(double('observer 3')) observer_set.add_observer(double('observer 4')) expect(observer_set.count_observers).to eq 4 end end describe '#delete_observer' do it 'should not notify a deleted observer' do expect(observer).to receive(:update).never observer_set.add_observer(observer) observer_set.delete_observer(observer) observer_set.notify_observers end it 'can delete a non added observer' do observer_set.delete_observer(observer) end it 'should return the observer' do expect(observer_set.delete_observer(observer)).to be(observer) end end describe '#delete_observers' do it 'should remove all observers' do expect(observer).to receive(:update).never expect(another_observer).to receive(:update).never observer_set.add_observer(observer) observer_set.add_observer(another_observer) observer_set.delete_observers observer_set.notify_observers end it 'should return the observer set' do expect(observer_set.delete_observers).to be(observer_set) end end describe '#notify_and_delete_observers' do before(:each) do observer_set.add_observer(observer, :a_method) observer_set.add_observer(another_observer) expect(observer).to receive(:a_method).with('args').once expect(another_observer).to receive(:update).with('args').once end it 'should notify all observers' do observer_set.notify_and_delete_observers('args') end it 'should clear observers' do observer_set.notify_and_delete_observers('args') expect(observer_set.count_observers).to eq(0) end it 'can be called many times without any other notification' do observer_set.notify_and_delete_observers('args') observer_set.notify_and_delete_observers('args') observer_set.notify_and_delete_observers('args') end it 'should return the observer set' do expect(observer_set.notify_and_delete_observers('args')).to be(observer_set) end end end concurrent-ruby-1.0.5/spec/concurrent/collection_each_shared.rb000066400000000000000000000015041305460430400247570ustar00rootroot00000000000000shared_examples :collection_each do it 'common' do @cache.send(method) { |k, v| fail } expect(@cache).to eq @cache.send(method) {} @cache[:a] = 1 h = {} @cache.send(method) { |k, v| h[k] = v } expect({:a => 1}).to eq h @cache[:b] = 2 h = {} @cache.send(method) { |k, v| h[k] = v } expect({:a => 1, :b => 2}).to eq h end it 'pair iterator' do @cache[:a] = 1 @cache[:b] = 2 i = 0 r = @cache.send(method) do |k, v| if i == 0 i += 1 next fail elsif i == 1 break :breaked end end expect(:breaked).to eq r end it 'allows modification' do @cache[:a] = 1 @cache[:b] = 1 @cache[:c] = 1 expect_size_change(1) do @cache.send(method) do |k, v| @cache[:z] = 1 end end end end concurrent-ruby-1.0.5/spec/concurrent/concern/000077500000000000000000000000001305460430400214205ustar00rootroot00000000000000concurrent-ruby-1.0.5/spec/concurrent/concern/dereferenceable_shared.rb000066400000000000000000000103171305460430400263700ustar00rootroot00000000000000shared_examples :dereferenceable do it 'defaults :dup_on_deref to false' do value = 'value' expect(value).not_to receive(:dup).with(any_args) subject = dereferenceable_subject(value) subject.value subject = dereferenceable_subject(value, dup_on_deref: false) subject.value subject = dereferenceable_subject(value, dup: false) subject.value end it 'calls #dup when the :dup_on_deref option is true' do value = 'value' subject = dereferenceable_subject(value, dup_on_deref: true) expect(subject.value.object_id).not_to eq value.object_id subject = dereferenceable_subject(value, dup: true) expect(subject.value.object_id).not_to eq value.object_id end it 'defaults :freeze_on_deref to false' do value = 'value' expect(value).not_to receive(:freeze).with(any_args) subject = dereferenceable_subject(value) subject.value subject = dereferenceable_subject(value, freeze_on_deref: false) subject.value subject = dereferenceable_subject(value, freeze: false) subject.value end it 'calls #freeze when the :freeze_on_deref option is true' do value = 'value' subject = dereferenceable_subject(value, freeze_on_deref: true) expect(subject.value).to be_frozen subject = dereferenceable_subject(value, freeze: true) expect(subject.value).to be_frozen end it 'defaults :copy_on_deref to nil' do value = 'value' subject = dereferenceable_subject(value) expect(subject.value.object_id).to eq(value.object_id) subject = dereferenceable_subject(value, copy_on_deref: nil) expect(subject.value.object_id).to eq(value.object_id) subject = dereferenceable_subject(value, copy: nil) expect(subject.value.object_id).to eq(value.object_id) end it 'calls the block when the :copy_on_deref option is passed a proc' do value = 'value' copy = proc{|val| 'copy' } subject = dereferenceable_subject(value, copy_on_deref: copy) expect(subject.value.object_id).not_to eq(value.object_id) subject = dereferenceable_subject(value, copy: copy) expect(subject.value.object_id).not_to eq(value.object_id) end it 'calls the :copy block first followed by #dup followed by #freeze' do value = 'value' copied = 'copied' dup = 'dup' frozen = 'frozen' copy = proc{|val| copied } expect(copied).to receive(:dup).at_least(:once).with(no_args).and_return(dup) expect(dup).to receive(:freeze).at_least(:once).with(no_args).and_return(frozen) subject = dereferenceable_subject(value, dup_on_deref: true, freeze_on_deref: true, copy_on_deref: copy) expect(subject.value).to eq frozen end it 'does not call #dup when #dup_on_deref is set and the value is nil' do allow_message_expectations_on_nil result = nil expect(result).not_to receive(:dup).with(any_args) subject = dereferenceable_subject(result, dup_on_deref: true) subject.value end it 'does not call #freeze when #freeze_on_deref is set and the value is nil' do allow_message_expectations_on_nil result = nil expect(result).not_to receive(:freeze).with(any_args) subject = dereferenceable_subject(result, freeze_on_deref: true) subject.value end it 'does not call the #copy_on_deref block when the value is nil' do copier = proc { 42 } subject = dereferenceable_subject(nil, copy_on_deref: copier) expect(subject.value).to be_nil end it 'supports dereference flags with observers' do if dereferenceable_subject(0).respond_to?(:add_observer) latch = Concurrent::CountDownLatch.new observer = Class.new do def initialize(latch) @latch = latch end def update(*args) @latch.count_down end end.new(latch) result = 'result' copier = proc { result } expect(result).to receive(:dup).at_least(:once).and_return(result) expect(result).to receive(:freeze).at_least(:once).and_return(result) expect(copier).to receive(:call).at_least(:once).and_return(result) subject = dereferenceable_observable(dup_on_deref: true, freeze_on_deref: true, copy_on_deref: copier) subject.add_observer(observer) execute_dereferenceable(subject) latch.wait(1) end end end concurrent-ruby-1.0.5/spec/concurrent/concern/obligation_shared.rb000066400000000000000000000047461305460430400254350ustar00rootroot00000000000000shared_examples :obligation do context '#state' do it 'is :pending when first created' do f = pending_subject expect(f.state).to eq(:pending) expect(f).to be_pending end it 'is :fulfilled when the handler completes' do f = fulfilled_subject expect(f.state).to eq(:fulfilled) expect(f).to be_fulfilled end it 'is :rejected when the handler raises an exception' do f = rejected_subject expect(f.state).to eq(:rejected) expect(f).to be_rejected end end context '#value' do let!(:supports_timeout) { pending_subject.method(:value).arity != 0 } it 'returns nil when reaching the optional timeout value' do if supports_timeout f = pending_subject expect(f.value(0)).to be_nil expect(f).to be_pending end end it 'returns immediately when timeout is zero' do if supports_timeout expect(Concurrent).not_to receive(:timeout).with(any_args()) f = pending_subject expect(f.value(0)).to be_nil expect(f).to be_pending end end it 'returns the value when fulfilled before timeout' do if supports_timeout f = pending_subject expect(f.value(10)).to be_truthy expect(f).to be_fulfilled end end it 'returns nil when timeout reached' do if supports_timeout f = pending_subject expect(f.value(0.001)).to be_nil expect(f).to be_pending end end it 'is nil when :pending' do if supports_timeout expected = pending_subject.value(0) expect(expected).to be_nil end end it 'blocks the caller when :pending and timeout is nil' do f = pending_subject expect(f.value).to be_truthy expect(f).to be_fulfilled end it 'is nil when :rejected' do expected = rejected_subject.value expect(expected).to be_nil end it 'is set to the return value of the block when :fulfilled' do expected = fulfilled_subject.value expect(expected).to eq fulfilled_value end end context '#reason' do it 'is nil when :pending' do expect(pending_subject.reason).to be_nil end it 'is nil when :fulfilled' do expect(fulfilled_subject.reason).to be_nil end it 'is set to error object of the exception when :rejected' do expect(rejected_subject.reason).to be_a(Exception) expect(rejected_subject.reason.to_s).to match(/#{rejected_reason}/) end end end concurrent-ruby-1.0.5/spec/concurrent/concern/obligation_spec.rb000066400000000000000000000223111305460430400251050ustar00rootroot00000000000000module Concurrent module Concern describe Obligation do let (:obligation_class) do Class.new(Synchronization::LockableObject) do include Obligation public :state=, :compare_and_set_state, :if_state attr_writer :value, :reason end end let (:obligation) { obligation_class.new } let (:event) { double 'event' } shared_examples :incomplete do it 'should be not completed' do expect(obligation).not_to be_complete end it 'should be incomplete' do expect(obligation).to be_incomplete end methods = [:value, :value!, :no_error!] methods.each do |method| describe "##{method}" do it 'should return immediately if timeout is zero' do result = obligation.send(method, 0) if method == :no_error! expect(result).to eq obligation else expect(result).to be_nil end end it 'should block on the event if timeout is not set' do allow(obligation).to receive(:event).and_return(event) expect(event).to receive(:wait).with(nil) obligation.send method end it 'should block on the event if timeout is not zero' do allow(obligation).to receive(:event).and_return(event) expect(event).to receive(:wait).with(5) obligation.send(method, 5) end end end end context 'unscheduled' do before(:each) { obligation.state = :unscheduled } it_should_behave_like :incomplete end context 'pending' do before(:each) { obligation.state = :pending } it_should_behave_like :incomplete end context 'fulfilled' do before(:each) do obligation.state = :fulfilled obligation.send(:value=, 42) allow(obligation).to receive(:event).and_return(event) end it 'should be completed' do expect(obligation).to be_complete end it 'should be not incomplete' do expect(obligation).not_to be_incomplete end describe '#value' do it 'should return immediately if timeout is zero' do expect(obligation.value(0)).to eq 42 end it 'should return immediately if timeout is not set' do expect(event).not_to receive(:wait) expect(obligation.value).to eq 42 end it 'should return immediately if timeout is not zero' do expect(event).not_to receive(:wait) expect(obligation.value(5)).to eq 42 end end describe '#value!' do it 'should return immediately if timeout is zero' do expect(obligation.value!(0)).to eq 42 end it 'should return immediately if timeout is not set' do expect(event).not_to receive(:wait) expect(obligation.value!).to eq 42 end it 'should return immediately if timeout is not zero' do expect(event).not_to receive(:wait) expect(obligation.value!(5)).to eq 42 end end describe '#no_error!' do it 'should return immediately if timeout is zero' do expect(obligation.no_error!(0)).to eq obligation end it 'should return immediately if timeout is not set' do expect(event).not_to receive(:wait) expect(obligation.no_error!).to eq obligation end it 'should return immediately if timeout is not zero' do expect(event).not_to receive(:wait) expect(obligation.no_error!(5)).to eq obligation end end end context 'rejected' do before(:each) do obligation.state = :rejected allow(obligation).to receive(:event).and_return(event) end it 'should be completed' do expect(obligation).to be_complete end it 'should be not incomplete' do expect(obligation).not_to be_incomplete end describe '#value' do it 'should return immediately if timeout is zero' do expect(event).not_to receive(:wait) expect(obligation.value(0)).to be_nil end it 'should return immediately if timeout is not set' do expect(event).not_to receive(:wait) expect(obligation.value).to be_nil end it 'should return immediately if timeout is not zero' do expect(event).not_to receive(:wait) expect(obligation.value(5)).to be_nil end end describe '#value!' do it 'should return immediately if timeout is zero' do expect(event).not_to receive(:wait) expect { obligation.value!(0) }.to raise_error end it 'should return immediately if timeout is not set' do expect(event).not_to receive(:wait) expect { obligation.value! }.to raise_error end it 'should return immediately if timeout is not zero' do expect(event).not_to receive(:wait) expect { obligation.value!(5) }.to raise_error end end describe '#no_error!' do it 'should return immediately if timeout is zero' do expect(event).not_to receive(:wait) expect { obligation.no_error!(0) }.to raise_error end it 'should return immediately if timeout is not set' do expect(event).not_to receive(:wait) expect { obligation.no_error! }.to raise_error end it 'should return immediately if timeout is not zero' do expect(event).not_to receive(:wait) expect { obligation.no_error!(5) }.to raise_error end end end describe '#compare_and_set_state' do before(:each) { obligation.state = :unscheduled } context 'unexpected state' do it 'should return false if state is not the expected one' do expect(obligation.compare_and_set_state(:pending, :rejected)).to be_falsey end it 'should not change the state if current is not the expected one' do obligation.compare_and_set_state(:pending, :rejected) expect(obligation.state).to eq :unscheduled end end context 'expected state' do it 'should return true if state is the expected one' do expect(obligation.compare_and_set_state(:pending, :unscheduled)).to be_truthy end it 'should not change the state if current is not the expected one' do obligation.compare_and_set_state(:pending, :unscheduled) expect(obligation.state).to eq :pending end end end describe '#if_state' do before(:each) { obligation.state = :unscheduled } it 'should raise without block' do expect { obligation.if_state(:pending) }.to raise_error(ArgumentError) end it 'should return false if state is not expected' do expect(obligation.if_state(:pending, :rejected) { 42 }).to be_falsey end it 'should the block value if state is expected' do expect(obligation.if_state(:rejected, :unscheduled) { 42 }).to eq 42 end it 'should execute the block within the mutex' do expect(obligation).to receive(:synchronize) obligation.if_state(:unscheduled) { nil } end end context '#get_arguments_from' do it 'returns an empty array when opts is not given' do args = obligation.send(:get_arguments_from) expect(args).to be_a ::Array expect(args).to be_empty end it 'returns an empty array when opts is an empty hash' do args = obligation.send(:get_arguments_from, {}) expect(args).to be_a ::Array expect(args).to be_empty end it 'returns an empty array when there is no :args key' do args = obligation.send(:get_arguments_from, foo: 'bar') expect(args).to be_a ::Array expect(args).to be_empty end it 'returns an empty array when the :args key has a nil value' do args = obligation.send(:get_arguments_from, args: nil) expect(args).to be_a ::Array expect(args).to be_empty end it 'returns a one-element array when the :args key has a non-array value' do args = obligation.send(:get_arguments_from, args: 'foo') expect(args).to eq ['foo'] end it 'returns an array when when the :args key has an array value' do expected = [1, 2, 3, 4] args = obligation.send(:get_arguments_from, args: expected) expect(args).to eq expected end it 'returns the given array when the :args key has a complex array value' do expected = [(1..10).to_a, (20..30).to_a, (100..110).to_a] args = obligation.send(:get_arguments_from, args: expected) expect(args).to eq expected end end end end end concurrent-ruby-1.0.5/spec/concurrent/concern/observable_shared.rb000066400000000000000000000115361305460430400254250ustar00rootroot00000000000000shared_examples :observable do let(:observer_set) do subject.instance_variable_get(:@observers) end let(:observer_class) do Class.new do def initialize(&block) @block = block end def update(*args) @block.call(*args) if @block end end end let(:observer){ observer_class.new } let!(:observer_func){ :notify } let(:observer_with_func_class) do Class.new do def initialize(&block) @block = block end def notify(*args) @block.call(*args) if @block end end end let(:observer_with_func){ observer_with_func_class.new } context '#add_observer' do it 'adds an observer if called before first notification' do expect(observer_set).to receive(:add_observer).with(any_args) subject.add_observer(observer) end it 'adds an observer with :func if called before first notification' do expect(observer_set).to receive(:add_observer).with(observer_with_func, :notify) subject.add_observer(observer_with_func, observer_func) end it 'creates an observer from a block if called before first notification' do block = proc{ nil } expect(observer_set).to receive(:add_observer).with(any_args) subject.add_observer(&block) end it 'raises an exception if not given an observer or a block' do expect { subject.add_observer }.to raise_error(ArgumentError) end it 'raises an exception when given both an observer and a block' do expect { subject.add_observer(observer){ nil } }.to raise_error(ArgumentError) end end context '#delete_observer' do it 'deletes the given observer if called before first notification' do expect(subject.count_observers).to eq 0 subject.add_observer(observer) expect(subject.count_observers).to eq 1 subject.delete_observer(observer) expect(subject.count_observers).to eq 0 end it 'returns the removed observer if found in the observer set' do subject.add_observer(observer) expect(subject.delete_observer(observer)).to eq observer end it 'returns the given observer even when not found in the observer set' do expect(subject.delete_observer(observer)).to eq observer end end context '#delete_observers' do it 'deletes all observers when called before first notification' do 5.times{ subject.add_observer(observer_class.new) } expect(subject.count_observers).to eq 5 subject.delete_observers expect(subject.count_observers).to eq 0 end it 'returns self' do expect(subject.delete_observers).to eq subject end end context '#count_observers' do it 'returns zero for a new observable object' do expect(subject.count_observers).to eq 0 end it 'returns a count of registered observers if called before first notification' do 5.times{ subject.add_observer(observer_class.new) } expect(subject.count_observers).to eq 5 end it 'returns zero after #delete_observers has been called' do 5.times{ subject.add_observer(observer_class.new) } subject.delete_observers expect(subject.count_observers).to eq 0 end end context 'first notification' do it 'calls the #update method on all observers without a specified :func' do latch = Concurrent::CountDownLatch.new(5) 5.times do subject.add_observer(observer_class.new{ latch.count_down }) end trigger_observable(subject) latch.wait(1) expect(latch.count).to eq 0 end it 'calls the appropriate function on all observers which specified a :func' do latch = Concurrent::CountDownLatch.new(5) 5.times do obs = observer_with_func_class.new{ latch.count_down } subject.add_observer(obs, observer_func) end trigger_observable(subject) latch.wait(1) expect(latch.count).to eq 0 end it 'calls the proc for all observers added as a block' do latch = Concurrent::CountDownLatch.new(5) 5.times do subject.add_observer{ latch.count_down } end trigger_observable(subject) latch.wait(1) expect(latch.count).to eq 0 end it 'does not notify any observers removed with #delete_observer' do latch = Concurrent::CountDownLatch.new(5) obs = observer_class.new{ latch.count_down } subject.add_observer(obs) subject.delete_observer(obs) trigger_observable(subject) latch.wait(1) expect(latch.count).to eq 5 end it 'does not notify any observers after #delete_observers called' do latch = Concurrent::CountDownLatch.new(5) 5.times do subject.add_observer(observer_class.new{ latch.count_down }) end subject.delete_observers trigger_observable(subject) latch.wait(1) expect(latch.count).to eq 5 end end end concurrent-ruby-1.0.5/spec/concurrent/concern/observable_spec.rb000066400000000000000000000031101305460430400250760ustar00rootroot00000000000000module Concurrent module Concern describe Observable do let (:described_class) do Class.new do include Observable public :observers, :observers= end end let(:observer_set) { double(:observer_set) } subject { described_class.new } before(:each) do subject.observers = observer_set end it 'does not initialize set by by default' do expect(described_class.new.observers).to be_nil end it 'uses the given observer set' do expected = Collection::CopyOnWriteObserverSet.new subject.observers = expected expect(subject.observers).to eql expected end it 'delegates #add_observer' do expect(observer_set).to receive(:add_observer).with(:observer, :update) { |v| v } expect(subject.add_observer(:observer)).to eq :observer end it 'delegates #with_observer' do expect(observer_set).to receive(:add_observer).with(:observer, :update) { |v| v } expect(subject.with_observer(:observer)).to eq subject end it 'delegates #delete_observer' do expect(observer_set).to receive(:delete_observer).with(:observer) subject.delete_observer(:observer) end it 'delegates #delete_observers' do expect(observer_set).to receive(:delete_observers).with(no_args) subject.delete_observers end it 'delegates #count_observers' do expect(observer_set).to receive(:count_observers).with(no_args) subject.count_observers end end end end concurrent-ruby-1.0.5/spec/concurrent/configuration_spec.rb000066400000000000000000000024471305460430400242060ustar00rootroot00000000000000module Concurrent describe 'configuration', notravis: true do before(:all) do reset_gem_configuration end after(:each) do reset_gem_configuration end context 'global executors' do it 'creates a global timer set' do expect(Concurrent.global_timer_set).not_to be_nil expect(Concurrent.global_timer_set).to respond_to(:post) end it 'creates a global fast executor' do expect(Concurrent.global_fast_executor).not_to be_nil expect(Concurrent.global_fast_executor).to respond_to(:post) end it 'creates a global io executor' do expect(Concurrent.global_io_executor).not_to be_nil expect(Concurrent.global_io_executor).to respond_to(:post) end specify 'Concurrent::AtExit.run acts on all executors with auto_terminate: true' do # The 'at_least(:once)' clauses account for global config reset expect(Concurrent.global_fast_executor).to receive(:kill).at_least(:once).with(no_args).and_call_original expect(Concurrent.global_io_executor).to receive(:kill).at_least(:once).with(no_args).and_call_original expect(Concurrent.global_timer_set).to receive(:kill).at_least(:once).with(no_args).and_call_original Concurrent::AtExit.run end end end end concurrent-ruby-1.0.5/spec/concurrent/dataflow_spec.rb000066400000000000000000000164511305460430400231400ustar00rootroot00000000000000module Concurrent describe 'dataflow' do let(:executor) { ImmediateExecutor.new } let(:root_executor) { SimpleExecutorService.new } it 'raises an exception when no block given' do expect { Concurrent::dataflow }.to raise_error(ArgumentError) expect { Concurrent::dataflow_with(root_executor) }.to raise_error(ArgumentError) end specify '#dataflow uses the global fast executor' do input = Future.execute{0} expect(Concurrent).to receive(:dataflow_with).once. with(Concurrent.global_io_executor, input) Concurrent::dataflow(input){0} end specify '#dataflow_with uses the given executor' do input = Future.execute{0} result = Future.new{0} expect(Future).to receive(:new).with(executor: root_executor).and_return(result) Concurrent::dataflow_with(root_executor, input){0} end specify '#dataflow_with raises an exception when no executor given' do expect { Concurrent::dataflow_with(nil){ nil } }.to raise_error(ArgumentError) end it 'accepts zero or more dependencies' do Concurrent::dataflow(){0} Concurrent::dataflow(Future.execute{0}){0} Concurrent::dataflow(Future.execute{0}, Future.execute{0}){0} Concurrent::dataflow_with(root_executor, ){0} Concurrent::dataflow_with(root_executor, Future.execute{0}){0} Concurrent::dataflow_with(root_executor, Future.execute{0}, Future.execute{0}){0} end it 'accepts uncompleted dependencies' do d = Future.new(executor: executor){0} Concurrent::dataflow(d){0} d.execute d = Future.new(executor: executor){0} Concurrent::dataflow_with(root_executor, d){0} d.execute end it 'accepts completed dependencies' do d = Future.new(executor: executor){0} d.execute Concurrent::dataflow(d){0} d = Future.new(executor: executor){0} d.execute Concurrent::dataflow_with(root_executor, d){0} end it 'raises an exception if any dependencies are not IVars' do expect { Concurrent::dataflow(nil) }.to raise_error(ArgumentError) expect { Concurrent::dataflow(Future.execute{0}, nil) }.to raise_error(ArgumentError) expect { Concurrent::dataflow(nil, Future.execute{0}) }.to raise_error(ArgumentError) expect { Concurrent::dataflow_with(root_executor, nil) }.to raise_error(ArgumentError) expect { Concurrent::dataflow_with(root_executor, Future.execute{0}, nil) }.to raise_error(ArgumentError) expect { Concurrent::dataflow_with(root_executor, nil, Future.execute{0}) }.to raise_error(ArgumentError) end it 'doesn\'t raises exceptions from dependencies, unless called with !' do d1 = Concurrent::dataflow(){raise} d2 = Concurrent::dataflow(){raise} f = Concurrent::dataflow!(d1, d2){|d1v, d2v| [d1v,d2v]} expect{f.value!}.to raise_error d1 = Concurrent::dataflow(){raise} d2 = Concurrent::dataflow(){raise} f = Concurrent::dataflow(d1, d2){|d1v, d2v| [d1v,d2v]} expect{f.value!}.to_not raise_error end it 'returns a Future' do expect(Concurrent::dataflow{0}).to be_a(Future) expect(Concurrent::dataflow{0}).to be_a(Future) end context 'does not schedule the Future' do specify 'if no dependencies are completed' do d = Future.new(executor: executor){0} f = Concurrent::dataflow(d){0} expect(f).to be_unscheduled d.execute d = Future.new(executor: executor){0} f = Concurrent::dataflow_with(root_executor, d){0} expect(f).to be_unscheduled d.execute end specify 'if one dependency of two is completed' do d1 = Future.new(executor: executor){0} d2 = Future.new(executor: executor){0} f = Concurrent::dataflow(d1, d2){0} d1.execute expect(f).to be_unscheduled d2.execute d1 = Future.new(executor: executor){0} d2 = Future.new(executor: executor){0} f = Concurrent::dataflow_with(root_executor, d1, d2){0} d1.execute expect(f).to be_unscheduled d2.execute end end context 'schedules the Future when all dependencies are available' do specify 'if there is just one' do d = Future.new(executor: executor){0} f = Concurrent::dataflow(d){0} d.execute expect(f.value).to eq 0 d = Future.new(executor: executor){0} f = Concurrent::dataflow_with(root_executor, d){0} d.execute expect(f.value).to eq 0 end specify 'if there is more than one' do d1 = Future.new(executor: executor){0} d2 = Future.new(executor: executor){0} f = Concurrent::dataflow(d1, d2){0} d1.execute d2.execute expect(f.value).to eq 0 d1 = Future.new(executor: executor){0} d2 = Future.new(executor: executor){0} f = Concurrent::dataflow_with(root_executor, d1, d2){0} d1.execute d2.execute expect(f.value).to eq 0 end end context 'counts already executed dependencies' do specify 'if there is just one' do d = Future.new(executor: executor){0} d.execute f = Concurrent::dataflow(d){0} expect(f.value).to eq 0 d = Future.new(executor: executor){0} d.execute f = Concurrent::dataflow_with(root_executor, d){0} expect(f.value).to eq 0 end specify 'if there is more than one' do d1 = Future.new(executor: executor){0} d2 = Future.new(executor: executor){0} d1.execute d2.execute f = Concurrent::dataflow(d1, d2){0} expect(f.value).to eq 0 d1 = Future.new(executor: executor){0} d2 = Future.new(executor: executor){0} d1.execute d2.execute f = Concurrent::dataflow_with(root_executor, d1, d2){0} expect(f.value).to eq 0 end end context 'passes the values of dependencies into the block' do specify 'if there is just one' do d = Future.new(executor: executor){14} f = Concurrent::dataflow(d){|v| v } d.execute expect(f.value).to eq 14 d = Future.new(executor: executor){14} f = Concurrent::dataflow_with(root_executor, d){|v| v } d.execute expect(f.value).to eq 14 end specify 'if there is more than one' do d1 = Future.new(executor: executor){14} d2 = Future.new(executor: executor){2} f = Concurrent::dataflow(d1, d2) {|v1, v2| v1 + v2} d1.execute d2.execute expect(f.value).to eq 16 d1 = Future.new(executor: executor){14} d2 = Future.new(executor: executor){2} f = Concurrent::dataflow_with(root_executor, d1, d2) {|v1, v2| v1 + v2} d1.execute d2.execute expect(f.value).to eq 16 end end context 'module function' do it 'can be called as Concurrent.dataflow and Concurrent.dataflow_with' do def fib_with_dot(n) if n < 2 Concurrent.dataflow { n } else n1 = fib_with_dot(n - 1) n2 = fib_with_dot(n - 2) Concurrent.dataflow_with(ImmediateExecutor.new, n1, n2) { n1.value + n2.value } end end expected = fib_with_dot(7) expect(expected.value).to eq 13 end end end end concurrent-ruby-1.0.5/spec/concurrent/delay_spec.rb000066400000000000000000000043461305460430400224350ustar00rootroot00000000000000require_relative 'concern/dereferenceable_shared' require_relative 'concern/obligation_shared' module Concurrent describe Delay do context 'behavior' do # dereferenceable def dereferenceable_subject(value, opts = {}) delay = Delay.new(opts){ value } delay.tap{ delay.value } end it_should_behave_like :dereferenceable # obligation let!(:fulfilled_value) { 10 } let!(:rejected_reason) { StandardError.new('mojo jojo') } let(:pending_subject) do Delay.new(executor: :fast){ sleep 0.05; fulfilled_value } end let(:fulfilled_subject) do delay = Delay.new{ fulfilled_value } delay.tap{ delay.value } end let(:rejected_subject) do delay = Delay.new{ raise rejected_reason } delay.tap{ delay.value } end it_should_behave_like :obligation end context '#initialize' do it 'sets the state to :pending' do expect(Delay.new{ nil }.state).to eq :pending expect(Delay.new{ nil }).to be_pending end it 'raises an exception when no block given' do expect { Delay.new }.to raise_error(ArgumentError) end end context '#reconfigure' do it 'returns value of block used in reconfiguration' do expect(Delay.new { nil }.tap { |d| d.reconfigure { true } }.value).to be_truthy end it 'returns false when process completed?' do d = Delay.new { 1 } expect(d.reconfigure { 2 }).to be_truthy expect(d.value).to be 2 expect(d.reconfigure { 3 }).to be_falsey end end context '#value' do let(:task){ proc{ nil } } it 'does not call the block before #value is called' do expect(task).not_to receive(:call).with(any_args) Delay.new(&task) end it 'calls the block when #value is called' do expect(task).to receive(:call).once.with(any_args).and_return(nil) Delay.new(&task).value end it 'only calls the block once no matter how often #value is called' do expect(task).to receive(:call).once.with(any_args).and_return(nil) delay = Delay.new(&task) 5.times{ delay.value } end end end end concurrent-ruby-1.0.5/spec/concurrent/edge/000077500000000000000000000000001305460430400206755ustar00rootroot00000000000000concurrent-ruby-1.0.5/spec/concurrent/edge/lock_free_linked_set_spec.rb000066400000000000000000000130511305460430400263660ustar00rootroot00000000000000require 'concurrent' require 'concurrent/edge' require 'securerandom' describe Concurrent::Edge::LockFreeLinkedSet, edge: true do subject { described_class.new } describe '.new' do context 'when passed default val' do it 'uses the val arg as data for each node' do set = described_class.new 3, true expect(set.all? { |val| val == true }).to be_truthy end end end describe '#add' do it 'appends to the linked set' do expect(subject.add 'test string1').to be true end context 'in a multi-threaded environment', buggy: true do it 'adds the items to the set' do to_insert = %w(one two three four five six) threads = ::Array.new(16) do Thread.new do to_insert.each do |item| subject.add item end end end threads.each(&:join) to_insert.each do |item| expect(subject.contains? item).to be true end end end end describe '#<<' do it 'appends to the linked set and returns self' do expect(subject << 'test string1').to be_a described_class end it 'returns self regardless of whether it was logically added' do subject << 'test string' expect(subject << 'test string').to be_a described_class end end describe '#contains?' do context 'when checking if set includes a value' do it 'returns true if a value exists' do subject << 'Concurrency... ooh! ahh!' expect(subject.contains? 'Concurrency... ooh! ahh!').to eq true end it 'compares object using Object#hash' do val = 'Hash me.' subject << val expect(subject.contains? 'Hash me.').to eq true end it 'returns false for values not in the set' do subject << 'Concurrency... ooh! ahh!' expect(subject.contains? 'Sequential... booh! nah!').to eq false end context 'when set is empty' do it 'does not break' do expect(subject.contains? 'Nothing to see here.').to eq false end end context 'when set is long' do it 'does not break' do arr = ::Array.new(1000) { SecureRandom.hex } arr.each { |n| subject << n } ret = arr.all? { |n| subject.contains? n } expect(ret).to be true end end context 'in a multi-threaded environment', buggy: true do it 'correctly check that the set contains the item' do to_insert = %w(one two three four five six) to_insert.each { |item| subject << item } threads = ::Array.new(16) do Thread.new do 100.times { subject << SecureRandom.hex } to_insert.each do |item| expect(subject.contains? item).to be true end end end threads.each(&:join) to_insert.each do |item| expect(subject.contains? item).to be true end end end end end describe '#remove' do context 'when item is inside of set' do before { subject << 'one' << 'two' << 'three' } it 'the item is no longer visible to the user' do subject.remove 'three' expect(subject.contains? 'three').to be false end it 'allows for the item to be added despite being physically present' do subject.remove 'three' expect(subject.add 'three').to be true end end context 'in a multi-threaded environment', buggy: true do it 'adds the items to the set' do to_insert = %w(one two three four five six) to_insert.each { |item| subject << item } threads = ::Array.new(8) do Thread.new { subject.remove 'one' } Thread.new { subject.remove 'two' } Thread.new { subject.remove 'three' } end threads.each(&:join) expect(subject.contains? 'one').to be false expect(subject.contains? 'two').to be false expect(subject.contains? 'three').to be false expect(subject.contains? 'four').to be true expect(subject.contains? 'five').to be true expect(subject.contains? 'six').to be true end it 'does not recognize the existence of the item when removed' do to_insert = %w(one two three four five six) to_insert.each { |item| subject << item } threads = ::Array.new(16) do Thread.new do 100.times { subject << SecureRandom.hex } to_insert.each do |item| subject.remove item expect(subject.contains? item).to be false end end end threads.map(&:join) end end context 'when item is not inside of set' do before { subject << 'one' << 'two' << 'three' } it 'does not remove to value' do expect(subject.remove 'four').to be false end it 'the set remains intact' do expect(subject).to receive :remove subject.remove 'four' present = %w(one two three).map { |n| subject.contains? n }.all? expect(present).to be true end context 'when the set is empty' do subject { described_class.new } it 'remove does not break' do expect(subject.remove 'test').to be false end end context 'when the set is large' do subject { described_class.new(1000) { SecureRandom.hex } } it 'remove successfully removes the node' do subject << 'Testing' expect(subject.remove 'Testing').to be true end end end end end concurrent-ruby-1.0.5/spec/concurrent/edge/promises_spec.rb000066400000000000000000000552021305460430400241010ustar00rootroot00000000000000require 'concurrent/edge/promises' require 'thread' describe 'Concurrent::Promises' do include Concurrent::Promises::FactoryMethods describe 'chain_resolvable' do it 'event' do b = resolvable_event a = resolvable_event.chain_resolvable(b) a.resolve expect(b).to be_resolved end it 'future' do b = resolvable_future a = resolvable_future.chain_resolvable(b) a.fulfill :val expect(b).to be_resolved expect(b.value).to eq :val end end describe '.future' do it 'executes' do future = future { 1 + 1 } expect(future.value!).to eq 2 future = fulfilled_future(1).then { |v| v + 1 } expect(future.value!).to eq 2 end it 'executes with args' do future = future(1, 2, &:+) expect(future.value!).to eq 3 future = fulfilled_future(1).then(1) { |v, a| v + 1 } expect(future.value!).to eq 2 end end describe '.delay' do def behaves_as_delay(delay, value) expect(delay.resolved?).to eq false expect(delay.value!).to eq value end specify do behaves_as_delay delay { 1 + 1 }, 2 behaves_as_delay fulfilled_future(1).delay.then { |v| v + 1 }, 2 behaves_as_delay delay(1) { |a| a + 1 }, 2 behaves_as_delay fulfilled_future(1).delay.then { |v| v + 1 }, 2 end end describe '.schedule' do it 'scheduled execution' do start = Time.now.to_f queue = Queue.new future = schedule(0.1) { 1 + 1 }.then { |v| queue.push(v); queue.push(Time.now.to_f - start); queue } expect(future.value!).to eq queue expect(queue.pop).to eq 2 expect(queue.pop).to be >= 0.09 start = Time.now.to_f queue = Queue.new future = resolved_event. schedule(0.1). then { 1 }. then { |v| queue.push(v); queue.push(Time.now.to_f - start); queue } expect(future.value!).to eq queue expect(queue.pop).to eq 1 expect(queue.pop).to be >= 0.09 end it 'scheduled execution in graph' do start = Time.now.to_f queue = Queue.new future = future { sleep 0.1; 1 }. schedule(0.1). then { |v| v + 1 }. then { |v| queue.push(v); queue.push(Time.now.to_f - start); queue } future.wait! expect(future.value!).to eq queue expect(queue.pop).to eq 2 expect(queue.pop).to be >= 0.09 scheduled = resolved_event.schedule(0.1) expect(scheduled.resolved?).to be_falsey scheduled.wait expect(scheduled.resolved?).to be_truthy end end describe '.event' do specify do resolvable_event = resolvable_event() one = resolvable_event.chain(1) { |arg| arg } join = zip(resolvable_event).chain { 1 } expect(one.resolved?).to be false resolvable_event.resolve expect(one.value!).to eq 1 expect(join.wait.resolved?).to be true end end describe '.future without block' do specify do resolvable_future = resolvable_future() one = resolvable_future.then(&:succ) join = zip_futures(resolvable_future).then { |v| v } expect(one.resolved?).to be false resolvable_future.fulfill 0 expect(one.value!).to eq 1 expect(join.wait!.resolved?).to be true expect(join.value!).to eq 0 end end describe '.any_resolved' do it 'continues on first result' do f1 = resolvable_future f2 = resolvable_future f3 = resolvable_future any1 = any_resolved_future(f1, f2) any2 = f2 | f3 f1.fulfill 1 f2.reject StandardError.new expect(any1.value!).to eq 1 expect(any2.reason).to be_a_kind_of StandardError end end describe '.any_fulfilled' do it 'continues on first result' do f1 = resolvable_future f2 = resolvable_future any = any_fulfilled_future(f1, f2) f1.reject StandardError.new f2.fulfill :value expect(any.value!).to eq :value end end describe '.zip' do it 'waits for all results' do a = future { 1 } b = future { 2 } c = future { 3 } z1 = a & b z2 = zip a, b, c z3 = zip a z4 = zip expect(z1.value!).to eq [1, 2] expect(z2.value!).to eq [1, 2, 3] expect(z3.value!).to eq [1] expect(z4.value!).to eq [] q = Queue.new z1.then { |*args| q << args } expect(q.pop).to eq [1, 2] z1.then { |a, b, c| q << [a, b, c] } expect(q.pop).to eq [1, 2, nil] z2.then { |a, b, c| q << [a, b, c] } expect(q.pop).to eq [1, 2, 3] z3.then { |a| q << a } expect(q.pop).to eq 1 z3.then { |*a| q << a } expect(q.pop).to eq [1] z4.then { |a| q << a } expect(q.pop).to eq nil z4.then { |*a| q << a } expect(q.pop).to eq [] expect(z1.then { |a, b| a+b }.value!).to eq 3 expect(z1.then { |a, b| a+b }.value!).to eq 3 expect(z1.then(&:+).value!).to eq 3 expect(z2.then { |a, b, c| a+b+c }.value!).to eq 6 expect(future { 1 }.delay).to be_a_kind_of Concurrent::Promises::Future expect(future { 1 }.delay.wait!).to be_resolved expect(resolvable_event.resolve.delay).to be_a_kind_of Concurrent::Promises::Event expect(resolvable_event.resolve.delay.wait).to be_resolved a = future { 1 } b = future { raise 'b' } c = future { raise 'c' } zip(a, b, c).chain { |*args| q << args } expect(q.pop.flatten.map(&:class)).to eq [FalseClass, 0.class, NilClass, NilClass, NilClass, RuntimeError, RuntimeError] zip(a, b, c).rescue { |*args| q << args } expect(q.pop.map(&:class)).to eq [NilClass, RuntimeError, RuntimeError] expect(zip.wait(0.1)).to eq true end context 'when a future raises an error' do let(:a_future) { future { raise 'error' } } it 'raises a concurrent error' do expect { zip(a_future).value! }.to raise_error(StandardError) end end end describe '.zip_events' do it 'waits for all and returns event' do a = fulfilled_future 1 b = rejected_future :any c = resolvable_event.resolve z2 = zip_events a, b, c z3 = zip_events a z4 = zip_events expect(z2.resolved?).to be_truthy expect(z3.resolved?).to be_truthy expect(z4.resolved?).to be_truthy end end describe 'Future' do it 'has sync and async callbacks' do callbacks_tester = ->(event_or_future) do queue = Queue.new push_args = -> *args { queue.push args } event_or_future.on_resolution! &push_args event_or_future.on_resolution!(1, &push_args) if event_or_future.is_a? Concurrent::Promises::Future event_or_future.on_fulfillment! &push_args event_or_future.on_fulfillment!(2, &push_args) event_or_future.on_rejection! &push_args event_or_future.on_rejection!(3, &push_args) end event_or_future.on_resolution &push_args event_or_future.on_resolution(4, &push_args) if event_or_future.is_a? Concurrent::Promises::Future event_or_future.on_fulfillment &push_args event_or_future.on_fulfillment(5, &push_args) event_or_future.on_rejection &push_args event_or_future.on_rejection(6, &push_args) end event_or_future.on_resolution_using(:io, &push_args) event_or_future.on_resolution_using(:io, 7, &push_args) if event_or_future.is_a? Concurrent::Promises::Future event_or_future.on_fulfillment_using(:io, &push_args) event_or_future.on_fulfillment_using(:io, 8, &push_args) event_or_future.on_rejection_using(:io, &push_args) event_or_future.on_rejection_using(:io, 9, &push_args) end event_or_future.wait Array.new(event_or_future.is_a?(Concurrent::Promises::Future) ? 12 : 6) { queue.pop } end callback_results = callbacks_tester.call(fulfilled_future(:v)) expect(callback_results).to contain_exactly([true, :v, nil], [true, :v, nil, 1], [:v], [:v, 2], [true, :v, nil], [true, :v, nil, 4], [:v], [:v, 5], [true, :v, nil], [true, :v, nil, 7], [:v], [:v, 8]) err = StandardError.new 'boo' callback_results = callbacks_tester.call(rejected_future(err)) expect(callback_results).to contain_exactly([false, nil, err], [false, nil, err, 1], [err], [err, 3], [false, nil, err], [false, nil, err, 4], [err], [err, 6], [false, nil, err], [false, nil, err, 7], [err], [err, 9]) callback_results = callbacks_tester.call(resolved_event) expect(callback_results).to contain_exactly([], [1], [], [4], [], [7]) end [:wait, :wait!, :value, :value!, :reason, :result].each do |method_with_timeout| it "#{ method_with_timeout } supports setting timeout" do start_latch = Concurrent::CountDownLatch.new end_latch = Concurrent::CountDownLatch.new future = future do start_latch.count_down end_latch.wait(1) end start_latch.wait(1) future.send(method_with_timeout, 0.1) expect(future).not_to be_resolved end_latch.count_down future.wait end end it 'chains' do future0 = future { 1 }.then { |v| v + 2 } # both executed on default FAST_EXECUTOR future1 = future0.then_on(:fast) { raise 'boo' } # executed on IO_EXECUTOR future2 = future1.then { |v| v + 1 } # will reject with 'boo' error, executed on default FAST_EXECUTOR future3 = future1.rescue { |err| err.message } # executed on default FAST_EXECUTOR future4 = future0.chain { |success, value, reason| success } # executed on default FAST_EXECUTOR future5 = future3.with_default_executor(:fast) # connects new future with different executor, the new future is resolved when future3 is future6 = future5.then(&:capitalize) # executes on IO_EXECUTOR because default was set to :io on future5 future7 = future0 & future3 future8 = future0.rescue { raise 'never happens' } # future0 fulfills so future8'll have same value as future 0 futures = [future0, future1, future2, future3, future4, future5, future6, future7, future8] futures.each &:wait table = futures.each_with_index.map do |f, i| '%5i %7s %10s %6s %4s %6s' % [i, f.fulfilled?, f.value, f.reason, (f.promise.executor if f.promise.respond_to?(:executor)), f.default_executor] end.unshift('index success value reason pool d.pool') expect(table.join("\n")).to eq <<-TABLE.gsub(/^\s+\|/, '').strip |index success value reason pool d.pool | 0 true 3 io io | 1 false boo fast io | 2 false boo io io | 3 true boo io io | 4 true true io io | 5 true boo fast | 6 true Boo fast fast | 7 true [3, "boo"] io | 8 true 3 io io TABLE end it 'constructs promise like tree' do # if head of the tree is not constructed with #future but with #delay it does not start execute, # it's triggered later by calling wait or value on any of the dependent futures or the delay itself three = (head = delay { 1 }).then { |v| v.succ }.then(&:succ) four = three.delay.then(&:succ) # meaningful to_s and inspect defined for Future and Promise expect(head.to_s).to match /<#Concurrent::Promises::Future:0x[\da-f]+ pending>/ expect(head.inspect).to( match(/<#Concurrent::Promises::Future:0x[\da-f]+ pending>/)) # evaluates only up to three, four is left unevaluated expect(three.value!).to eq 3 expect(four).not_to be_resolved expect(four.value!).to eq 4 # futures hidden behind two delays trigger evaluation of both double_delay = delay { 1 }.delay.then(&:succ) expect(double_delay.value!).to eq 2 end it 'allows graphs' do head = future { 1 } branch1 = head.then(&:succ) branch2 = head.then(&:succ).delay.then(&:succ) results = [ zip(branch1, branch2).then { |b1, b2| b1 + b2 }, branch1.zip(branch2).then { |b1, b2| b1 + b2 }, (branch1 & branch2).then { |b1, b2| b1 + b2 }] Thread.pass until branch1.resolved? expect(branch1).to be_resolved expect(branch2).not_to be_resolved expect(results.map(&:value)).to eq [5, 5, 5] expect(zip(branch1, branch2).value!).to eq [2, 3] end describe '#flat' do it 'returns value of inner future' do f = future { future { 1 } }.flat.then(&:succ) expect(f.value!).to eq 2 end it 'propagates rejection of inner future' do err = StandardError.new('boo') f = future { rejected_future(err) }.flat expect(f.reason).to eq err end it 'it propagates rejection of the future which was suppose to provide inner future' do f = future { raise 'boo' }.flat expect(f.reason.message).to eq 'boo' end it 'rejects if inner value is not a future' do f = future { 'boo' }.flat expect(f.reason).to be_an_instance_of TypeError f = future { resolved_event }.flat expect(f.reason).to be_an_instance_of TypeError end it 'propagates requests for values to delayed futures' do expect(future { delay { 1 } }.flat.value!(0.1)).to eq 1 expect(Array.new(3) { |i| Concurrent::Promises.delay { i } }. inject { |a, b| a.then { b }.flat }.value!(0.2)).to eq 2 end end it 'resolves future when Exception raised' do f = future { raise Exception, 'reject' } f.wait 1 expect(f).to be_resolved expect(f).to be_rejected expect { f.value! }.to raise_error(Exception, 'reject') end it 'runs' do body = lambda do |v| v += 1 v < 5 ? future(v, &body) : v end expect(future(0, &body).run.value!).to eq 5 body = lambda do |v| v += 1 v < 5 ? future(v, &body) : raise(v.to_s) end expect(future(0, &body).run.reason.message).to eq '5' end end describe 'interoperability' do it 'with actor' do actor = Concurrent::Actor::Utils::AdHoc.spawn :doubler do -> v { v * 2 } end expect(future { 2 }. then_ask(actor). then { |v| v + 2 }. value!).to eq 6 end it 'with channel' do ch1 = Concurrent::Promises::Channel.new ch2 = Concurrent::Promises::Channel.new result = Concurrent::Promises.select_channel(ch1, ch2) ch1.push 1 expect(result.value!).to eq [ch1, 1] future { 1+1 }.then_push_channel(ch1) result = (Concurrent::Promises.future { '%02d' } & Concurrent::Promises.select_channel(ch1, ch2)). then { |format, (channel, value)| format format, value } expect(result.value!).to eq '02' end end describe 'Cancellation', edge: true do specify do source, token = Concurrent::Cancellation.create futures = Array.new(2) { future(token) { |t| t.loop_until_canceled { Thread.pass }; :done } } source.cancel futures.each do |future| expect(future.value!).to eq :done end end specify do source, token = Concurrent::Cancellation.create source.cancel expect(token.canceled?).to be_truthy cancellable_branch = Concurrent::Promises.delay { 1 } expect((cancellable_branch | token.to_event).value).to be_nil expect(cancellable_branch.resolved?).to be_falsey end specify do source, token = Concurrent::Cancellation.create cancellable_branch = Concurrent::Promises.delay { 1 } expect(any_resolved_future(cancellable_branch, token.to_event).value).to eq 1 expect(cancellable_branch.resolved?).to be_truthy end specify do source, token = Concurrent::Cancellation.create( Concurrent::Promises.resolvable_future, false, nil, err = StandardError.new('Cancelled')) source.cancel expect(token.canceled?).to be_truthy cancellable_branch = Concurrent::Promises.delay { 1 } expect((cancellable_branch | token.to_future).reason).to eq err expect(cancellable_branch.resolved?).to be_falsey end end describe 'Throttling' do specify do limit = 4 throttle = Concurrent::Throttle.new limit counter = Concurrent::AtomicFixnum.new testing = -> *args do counter.increment sleep rand * 0.02 + 0.02 # returns less then 3 since it's throttled v = counter.decrement + 1 v end expect(Concurrent::Promises.zip( *20.times.map do |i| throttle.throttled_future_chain { |trigger| trigger.then(throttle, &testing) } end).value!.all? { |v| v <= limit }).to be_truthy expect(Concurrent::Promises.zip( *20.times.map do |i| throttle.throttled_future(throttle, &testing) end).value!.all? { |v| v <= limit }).to be_truthy expect(Concurrent::Promises.zip( *20.times.map do |i| Concurrent::Promises. fulfilled_future(i). throttled_by(throttle) { |trigger| trigger.then(throttle, &testing) } end).value!.all? { |v| v <= limit }).to be_truthy expect(Concurrent::Promises.zip( *20.times.map do |i| Concurrent::Promises. fulfilled_future(i). then_throttled_by(throttle, throttle, &testing) end).value!.all? { |v| v <= limit }).to be_truthy end end describe 'Promises::Channel' do specify do channel = Concurrent::Promises::Channel.new 1 pushed1 = channel.push 1 expect(pushed1.resolved?).to be_truthy expect(pushed1.value!).to eq 1 pushed2 = channel.push 2 expect(pushed2.resolved?).to be_falsey popped = channel.pop expect(pushed1.value!).to eq 1 expect(pushed2.resolved?).to be_truthy expect(pushed2.value!).to eq 2 expect(popped.value!).to eq 1 popped = channel.pop expect(popped.value!).to eq 2 popped = channel.pop expect(popped.resolved?).to be_falsey pushed3 = channel.push 3 expect(popped.value!).to eq 3 expect(pushed3.resolved?).to be_truthy expect(pushed3.value!).to eq 3 end specify do ch1 = Concurrent::Promises::Channel.new ch2 = Concurrent::Promises::Channel.new ch3 = Concurrent::Promises::Channel.new add = -> do (ch1.pop & ch2.pop).then do |a, b| if a == :done && b == :done :done else ch3.push a + b add.call end end end ch1.push 1 ch2.push 2 ch1.push 'a' ch2.push 'b' ch1.push nil ch2.push true result = Concurrent::Promises.future(&add).run.result expect(result[0..1]).to eq [false, nil] expect(result[2]).to be_a_kind_of(NoMethodError) expect(ch3.pop.value!).to eq 3 expect(ch3.pop.value!).to eq 'ab' ch1.push 1 ch2.push 2 ch1.push 'a' ch2.push 'b' ch1.push :done ch2.push :done expect(Concurrent::Promises.future(&add).run.result).to eq [true, :done, nil] expect(ch3.pop.value!).to eq 3 expect(ch3.pop.value!).to eq 'ab' end end end describe Concurrent::ProcessingActor do specify do actor = Concurrent::ProcessingActor.act do |actor| actor.receive.then do |message| # the actor ends with message message end end # actor.tell! :a_message expect(actor.termination.value!).to eq :a_message def count(actor, count) # the block passed to receive is called when the actor receives the message actor.receive.then do |number_or_command, answer| # code which is evaluated after the number is received case number_or_command when :done # this will become the result (final value) of the actor count when :count # reply the current count answer.fulfill count # continue running count(actor, count) when Integer # this will call count again to set up what to do on next message, based on new state `count + numer` count(actor, count + number_or_command) end end # evaluation of count ends immediately # code which is evaluated before the number is received, should be empty end counter = Concurrent::ProcessingActor.act { |a| count a, 0 } expect(counter.tell!(2).ask(:count).value!).to eq 2 expect(counter.tell!(3).tell!(:done).termination.value!).to eq 5 add_once_actor = Concurrent::ProcessingActor.act do |actor| actor.receive.then do |(a, b), answer| result = a + b answer.fulfill result # terminate with result value result end end expect(add_once_actor.ask([1, 2]).value!).to eq 3 expect(add_once_actor.ask(%w(ab cd)).reason).to be_a_kind_of RuntimeError expect(add_once_actor.termination.value!).to eq 3 def pair_adder(actor) (actor.receive & actor.receive).then do |(value1, answer1), (value2, answer2)| result = value1 + value2 answer1.fulfill result if answer1 answer2.fulfill result if answer2 pair_adder actor end end pair_adder = Concurrent::ProcessingActor.act { |a| pair_adder a } expect(pair_adder.tell!(3).ask(2).value!).to eq 5 expect((pair_adder.ask('a') & pair_adder.ask('b')).value!).to eq %w[ab ab] expect((pair_adder.ask('a') | pair_adder.ask('b')).value!).to eq 'ab' end end concurrent-ruby-1.0.5/spec/concurrent/exchanger_spec.rb000066400000000000000000000156741305460430400233110ustar00rootroot00000000000000shared_examples 'exchanger method with indefinite timeout' do before(:each) do subject # ensure proper initialization end it 'blocks indefinitely' do latch_1 = Concurrent::CountDownLatch.new latch_2 = Concurrent::CountDownLatch.new t = Thread.new do latch_1.count_down subject.send(method, 1) latch_2.count_down end latch_1.wait(1) latch_2.wait(0.1) expect(latch_2.count).to eq 1 t.kill end it 'receives the other value' do first_value = nil second_value = nil latch = Concurrent::CountDownLatch.new(2) threads = [ Thread.new { first_value = subject.send(method, 2); latch.count_down }, Thread.new { second_value = subject.send(method, 4); latch.count_down } ] latch.wait(1) expect(get_value(first_value)).to eq 4 expect(get_value(second_value)).to eq 2 threads.each {|t| t.kill } end it 'can be reused' do first_value = nil second_value = nil latch_1 = Concurrent::CountDownLatch.new(2) latch_2 = Concurrent::CountDownLatch.new(2) threads = [ Thread.new { first_value = subject.send(method, 1); latch_1.count_down }, Thread.new { second_value = subject.send(method, 0); latch_1.count_down } ] latch_1.wait(1) threads.each {|t| t.kill } threads = [ Thread.new { first_value = subject.send(method, 10); latch_2.count_down }, Thread.new { second_value = subject.send(method, 12); latch_2.count_down } ] latch_2.wait(1) expect(get_value(first_value)).to eq 12 expect(get_value(second_value)).to eq 10 threads.each {|t| t.kill } end end shared_examples 'exchanger method with finite timeout' do it 'blocks until timeout' do duration = Concurrent::TestHelpers.monotonic_interval do begin subject.send(method, 2, 0.1) rescue Concurrent::TimeoutError # do nothing end end expect(duration).to be_within(0.05).of(0.1) end it 'receives the other value' do first_value = nil second_value = nil latch = Concurrent::CountDownLatch.new(2) threads = [ Thread.new { first_value = subject.send(method, 2, 1); latch.count_down }, Thread.new { second_value = subject.send(method, 4, 1); latch.count_down } ] latch.wait(1) expect(get_value(first_value)).to eq 4 expect(get_value(second_value)).to eq 2 threads.each {|t| t.kill } end it 'can be reused' do first_value = nil second_value = nil latch_1 = Concurrent::CountDownLatch.new(2) latch_2 = Concurrent::CountDownLatch.new(2) threads = [ Thread.new { first_value = subject.send(method, 1, 1); latch_1.count_down }, Thread.new { second_value = subject.send(method, 0, 1); latch_1.count_down } ] latch_1.wait(1) threads.each {|t| t.kill } threads = [ Thread.new { first_value = subject.send(method, 10, 1); latch_2.count_down }, Thread.new { second_value = subject.send(method, 12, 1); latch_2.count_down } ] latch_2.wait(1) expect(get_value(first_value)).to eq 12 expect(get_value(second_value)).to eq 10 threads.each {|t| t.kill } end end shared_examples 'exchanger method cross-thread interactions' do it 'when first, waits for a second' do first_value = nil second_value = nil latch = Concurrent::CountDownLatch.new(1) t1 = Thread.new do first_value = subject.send(method, :foo, 1) latch.count_down end t1.join(0.1) second_value = subject.send(method, :bar, 0) latch.wait(1) expect(get_value(first_value)).to eq :bar expect(get_value(second_value)).to eq :foo t1.kill end it 'allows multiple firsts to cancel if necessary', buggy: true do first_value = nil second_value = nil cancels = 3 cancel_latch = Concurrent::CountDownLatch.new(cancels) success_latch = Concurrent::CountDownLatch.new(1) threads = cancels.times.collect do Thread.new do begin first_value = subject.send(method, :foo, 0.1) rescue Concurrent::TimeoutError # suppress ensure cancel_latch.count_down end end end threads.each {|t| t.join(1) } cancel_latch.wait(1) t1 = Thread.new do first_value = subject.send(method, :bar, 1) success_latch.count_down end t1.join(0.1) second_value = subject.send(method, :baz, 0) success_latch.wait(1) expect(get_value(first_value)).to eq :baz expect(get_value(second_value)).to eq :bar t1.kill threads.each {|t| t.kill } end end shared_examples :exchanger do context '#exchange' do let!(:method) { :exchange } def get_value(result) result end it_behaves_like 'exchanger method with indefinite timeout' it_behaves_like 'exchanger method with finite timeout' it_behaves_like 'exchanger method cross-thread interactions' end context '#exchange!' do let!(:method) { :exchange! } def get_value(result) result end it_behaves_like 'exchanger method with indefinite timeout' it_behaves_like 'exchanger method with finite timeout' it_behaves_like 'exchanger method cross-thread interactions' end context '#try_exchange' do let!(:method) { :try_exchange } def get_value(result) result.value end it_behaves_like 'exchanger method with indefinite timeout' it_behaves_like 'exchanger method with finite timeout' it_behaves_like 'exchanger method cross-thread interactions' end end module Concurrent describe RubyExchanger do it_behaves_like :exchanger if Concurrent.on_cruby? specify 'stress test', notravis: true do thread_count = 100 exchange_count = 100 latch = Concurrent::CountDownLatch.new(thread_count) good = Concurrent::AtomicFixnum.new(0) bad = Concurrent::AtomicFixnum.new(0) ugly = Concurrent::AtomicFixnum.new(0) threads = thread_count.times.collect do |i| Thread.new do exchange_count.times do |j| begin result = subject.exchange!(i, 1) result == i ? ugly.up : good.up rescue Concurrent::TimeoutError bad.up end end latch.count_down end end latch.wait puts "Good: #{good.value}, Bad (timeout): #{bad.value}, Ugly: #{ugly.value}" expect(good.value + bad.value + ugly.value).to eq thread_count * exchange_count expect(ugly.value).to eq 0 threads.each {|t| t.kill } end end end if defined? JavaExchanger describe JavaExchanger do it_behaves_like :exchanger end end describe Exchanger do context 'class hierarchy' do if Concurrent.on_jruby? it 'inherits from JavaExchanger' do expect(Exchanger.ancestors).to include(JavaExchanger) end else it 'inherits from RubyExchanger' do expect(Exchanger.ancestors).to include(RubyExchanger) end end end end end concurrent-ruby-1.0.5/spec/concurrent/executor/000077500000000000000000000000001305460430400216275ustar00rootroot00000000000000concurrent-ruby-1.0.5/spec/concurrent/executor/cached_thread_pool_spec.rb000066400000000000000000000165071305460430400267660ustar00rootroot00000000000000require_relative 'thread_pool_shared' module Concurrent describe CachedThreadPool do subject do described_class.new(fallback_policy: :discard) end after(:each) do subject.kill subject.wait_for_termination(1) end it_should_behave_like :thread_pool let(:latch) { Concurrent::CountDownLatch.new } context '#initialize' do it 'sets :max_length to DEFAULT_MAX_POOL_SIZE' do expect(described_class.new.max_length).to eq described_class::DEFAULT_MAX_POOL_SIZE end it 'sets :min_length to DEFAULT_MIN_POOL_SIZE' do subject = expect(described_class.new.min_length).to eq described_class::DEFAULT_MIN_POOL_SIZE end it 'sets :idletime to DEFAULT_THREAD_IDLETIMEOUT' do subject = expect(described_class.new.idletime).to eq described_class::DEFAULT_THREAD_IDLETIMEOUT end it 'sets :max_queue to DEFAULT_MAX_QUEUE_SIZE' do subject = expect(described_class.new.max_queue).to eq described_class::DEFAULT_MAX_QUEUE_SIZE end end context '#min_length' do it 'returns zero on creation' do expect(subject.min_length).to eq 0 end it 'returns zero while running' do 10.times{ subject.post{ nil } } subject.post { latch.count_down } latch.wait(0.1) expect(subject.min_length).to eq 0 end it 'returns zero once shutdown' do 10.times{ subject.post{ nil } } subject.post { latch.count_down } latch.wait(0.1) subject.shutdown subject.wait_for_termination(1) expect(subject.min_length).to eq 0 end end context '#max_length' do it 'returns :max_length on creation' do expect(subject.max_length).to eq described_class::DEFAULT_MAX_POOL_SIZE end it 'returns :max_length while running' do 10.times{ subject.post{ nil } } subject.post { latch.count_down } latch.wait(0.1) expect(subject.max_length).to eq described_class::DEFAULT_MAX_POOL_SIZE end it 'returns :max_length once shutdown' do 10.times{ subject.post{ nil } } subject.post { latch.count_down } latch.wait(0.1) subject.shutdown subject.wait_for_termination(1) expect(subject.max_length).to eq described_class::DEFAULT_MAX_POOL_SIZE end end context '#largest_length' do it 'returns zero on creation' do expect(subject.largest_length).to eq 0 end it 'returns a non-zero number once tasks have been received' do 10.times{ subject.post{ sleep(0.1) } } subject.post { latch.count_down } latch.wait(0.1) expect(subject.largest_length).to be > 0 end it 'returns a non-zero number after shutdown if tasks have been received' do 10.times{ subject.post{ sleep(0.1) } } subject.post { latch.count_down } latch.wait(0.1) subject.shutdown subject.wait_for_termination(1) expect(subject.largest_length).to be > 0 end end context '#idletime' do subject{ described_class.new(idletime: 42) } it 'returns the thread idletime' do expect(subject.idletime).to eq 42 end end context 'runtime-specific implementation' do if Concurrent.on_jruby? context '#initialize' do it 'sets :fallback_policy correctly' do clazz = java.util.concurrent.ThreadPoolExecutor::DiscardPolicy policy = clazz.new expect(clazz).to receive(:new).at_least(:once).with(any_args).and_return(policy) subject = CachedThreadPool.new(fallback_policy: :discard) expect(subject.fallback_policy).to eq :discard end it 'defaults :fallback_policy to :abort' do subject = CachedThreadPool.new expect(subject.fallback_policy).to eq :abort end it 'raises an exception if given an invalid :fallback_policy' do expect { CachedThreadPool.new(fallback_policy: :bogus) }.to raise_error(ArgumentError) end end else context 'garbage collection' do subject { described_class.new(idletime: 0.1, max_threads: 2, gc_interval: 0) } it 'removes from pool any thread that has been idle too long' do latch = Concurrent::CountDownLatch.new(4) 4.times { subject.post { sleep 0.1; latch.count_down } } expect(latch.wait(1)).to be true sleep 0.2 subject.post {} sleep 0.2 expect(subject.length).to be < 4 end it 'deals with dead threads' do expect(subject).to receive(:ns_worker_died).exactly(5).times.and_call_original dead_threads_queue = Queue.new 5.times { subject.post { sleep 0.1; dead_threads_queue.push Thread.current; raise Exception } } sleep(0.2) latch = Concurrent::CountDownLatch.new(5) 5.times { subject.post { sleep 0.1; latch.count_down } } expect(latch.wait(1)).to be true dead_threads = [] dead_threads << dead_threads_queue.pop until dead_threads_queue.empty? expect(dead_threads.all? { |t| !t.alive? }).to be true end end context 'worker creation and caching' do subject { described_class.new(idletime: 1, max_threads: 5) } it 'creates new workers when there are none available' do expect(subject.length).to eq 0 5.times { sleep(0.1); subject << proc { sleep(1) } } sleep(1) expect(subject.length).to eq 5 end it 'uses existing idle threads' do 5.times { subject << proc { sleep(0.1) } } sleep(1) expect(subject.length).to be >= 5 3.times { subject << proc { sleep(1) } } sleep(0.1) expect(subject.length).to be >= 5 end end end context 'stress', notravis: true do configurations = [ { min_threads: 2, max_threads: ThreadPoolExecutor::DEFAULT_MAX_POOL_SIZE, auto_terminate: false, idletime: 0.1, # 1 minute max_queue: 0, # unlimited fallback_policy: :caller_runs, # shouldn't matter -- 0 max queue gc_interval: 0.1 }, { min_threads: 2, max_threads: 4, auto_terminate: false, idletime: 0.1, # 1 minute max_queue: 0, # unlimited fallback_policy: :caller_runs, # shouldn't matter -- 0 max queue gc_interval: 0.1 } ] configurations.each do |config| specify do pool = RubyThreadPoolExecutor.new(config) 10.times do count = Concurrent::CountDownLatch.new(100) 100.times do pool.post { count.count_down } end count.wait sleep 0.01 # let the tasks end after count_down expect(pool.length).to be <= [200, config[:max_threads]].min if pool.length > [110, config[:max_threads]].min puts "ERRORSIZE #{pool.length} max #{config[:max_threads]}" end end end end end end end end concurrent-ruby-1.0.5/spec/concurrent/executor/executor_service_shared.rb000066400000000000000000000121531305460430400270620ustar00rootroot00000000000000require_relative 'global_thread_pool_shared' shared_examples :executor_service do after(:each) do subject.kill subject.wait_for_termination(0.1) end it_should_behave_like :global_thread_pool context '#post' do it 'rejects the block while shutting down' do latch = Concurrent::CountDownLatch.new(1) subject.post{ sleep(1) } subject.shutdown begin subject.post{ latch.count_down } rescue Concurrent::RejectedExecutionError end expect(latch.wait(0.1)).to be_falsey end it 'rejects the block once shutdown' do subject.shutdown latch = Concurrent::CountDownLatch.new(1) begin subject.post{ latch.count_down } rescue Concurrent::RejectedExecutionError end expect(latch.wait(0.1)).to be_falsey end end context '#running?' do it 'returns true when the thread pool is running' do expect(subject).to be_running end it 'returns false when the thread pool is shutting down' do subject.post{ sleep(1) } subject.shutdown subject.wait_for_termination(1) expect(subject).not_to be_running end it 'returns false when the thread pool is shutdown' do subject.shutdown subject.wait_for_termination(1) expect(subject).not_to be_running end it 'returns false when the thread pool is killed' do subject.kill subject.wait_for_termination(1) expect(subject).not_to be_running end end context '#shutdown' do it 'stops accepting new tasks' do latch1 = Concurrent::CountDownLatch.new(1) latch2 = Concurrent::CountDownLatch.new(1) subject.post{ sleep(0.1); latch1.count_down } latch1.wait(1) subject.shutdown subject.wait_for_termination begin subject.post{ latch2.count_down } rescue Concurrent::RejectedExecutionError end expect(latch2.wait(0.2)).to be_falsey end it 'allows in-progress tasks to complete' do latch = Concurrent::CountDownLatch.new(1) subject.post{ sleep(0.1); latch.count_down } subject.shutdown expect(latch.wait(1)).to be_truthy end it 'allows pending tasks to complete' do latch = Concurrent::CountDownLatch.new(2) subject.post{ sleep(0.2); latch.count_down } subject.post{ sleep(0.2); latch.count_down } subject.shutdown expect(latch.wait(1)).to be_truthy end end context '#shutdown followed by #wait_for_termination' do it 'allows in-progress tasks to complete' do latch = Concurrent::CountDownLatch.new(1) subject.post{ sleep(0.1); latch.count_down } subject.shutdown subject.wait_for_termination(1) expect(latch.wait(1)).to be_truthy end it 'allows pending tasks to complete' do q = Queue.new 5.times do |i| subject.post { sleep 0.1; q << i } end subject.shutdown subject.wait_for_termination(1) expect(q.length).to eq 5 end it 'stops accepting/running new tasks' do expected = Concurrent::AtomicFixnum.new(0) subject.post{ sleep(0.1); expected.increment } subject.post{ sleep(0.1); expected.increment } subject.shutdown begin subject.post{ expected.increment } rescue Concurrent::RejectedExecutionError end subject.wait_for_termination(1) expect(expected.value).to eq(2) end end context '#kill' do it 'stops accepting new tasks' do expected = Concurrent::AtomicBoolean.new(false) latch = Concurrent::CountDownLatch.new(1) subject.post{ sleep(0.1); latch.count_down } latch.wait(1) subject.kill begin subject.post{ expected.make_true } rescue Concurrent::RejectedExecutionError end sleep(0.1) expect(expected.value).to be_falsey end it 'rejects all pending tasks' do subject.post{ sleep(1) } sleep(0.1) subject.kill sleep(0.1) begin expect(subject.post{ nil }).to be_falsey rescue Concurrent::RejectedExecutionError end end end context '#wait_for_termination' do it 'immediately returns true when no operations are pending' do subject.shutdown expect(subject.wait_for_termination(0)).to be_truthy end it 'returns true after shutdown has complete' do 10.times { subject << proc{ nil } } sleep(0.1) subject.shutdown expect(subject.wait_for_termination(1)).to be_truthy end it 'returns true when shutdown sucessfully completes before timeout' do subject.post{ sleep(0.5) } sleep(0.1) subject.shutdown expect(subject.wait_for_termination(1)).to be_truthy end it 'returns false when shutdown fails to complete before timeout' do unless subject.serialized? 100.times{ subject.post{ sleep(1) } } sleep(0.1) subject.shutdown expect(subject.wait_for_termination(0)).to be_falsey end end it 'waits forever when no timeout value is given' do subject.post{ sleep(0.5) } sleep(0.1) subject.shutdown expect(subject.wait_for_termination).to be_truthy end end end concurrent-ruby-1.0.5/spec/concurrent/executor/fixed_thread_pool_spec.rb000066400000000000000000000200201305460430400266370ustar00rootroot00000000000000require_relative 'thread_pool_shared' module Concurrent describe FixedThreadPool do let!(:num_threads){ 5 } subject { described_class.new(num_threads) } after(:each) do subject.kill subject.wait_for_termination(0.1) end it_should_behave_like :thread_pool let(:latch) { Concurrent::CountDownLatch.new } context '#initialize default values' do subject { described_class.new(5) } it 'defaults :min_length correctly' do expect(subject.min_length).to eq 5 end it 'defaults :max_length correctly' do expect(subject.max_length).to eq 5 end it 'defaults :fallback_policy to :abort' do expect(subject.fallback_policy).to eq :abort end it 'defaults :idletime correctly' do expect(subject.idletime).to eq subject.class.const_get(:DEFAULT_THREAD_IDLETIMEOUT) end it 'defaults default :max_queue to zero' do expect(subject.max_queue).to eq 0 end end context '#initialize explicit values' do it 'raises an exception when the pool length is less than one' do expect { described_class.new(0) }.to raise_error(ArgumentError) end it 'sets explicit :max_queue correctly' do subject = described_class.new(5, :max_queue => 10) expect(subject.max_queue).to eq 10 end it 'correctly sets valid :fallback_policy' do subject = described_class.new(5, :fallback_policy => :caller_runs) expect(subject.fallback_policy).to eq :caller_runs end it "correctly sets valid :idletime" do subject = described_class.new(5, :idletime => 10) expect(subject.idletime).to eq 10 end it 'raises an exception if given an invalid :fallback_policy' do expect { described_class.new(5, fallback_policy: :bogus) }.to raise_error(ArgumentError) end end context '#min_length' do it 'returns :num_threads on creation' do expect(subject.min_length).to eq num_threads end it 'returns :num_threads while running' do 10.times{ subject.post{ nil } } subject.post { latch.count_down } latch.wait(0.1) expect(subject.min_length).to eq num_threads end it 'returns :num_threads once shutdown' do 10.times{ subject.post{ nil } } subject.post { latch.count_down } latch.wait(0.1) subject.shutdown subject.wait_for_termination(1) expect(subject.min_length).to eq num_threads end end context '#max_length' do it 'returns :num_threads on creation' do expect(subject.max_length).to eq num_threads end it 'returns :num_threads while running' do 10.times{ subject.post{ nil } } subject.post { latch.count_down } latch.wait(0.1) expect(subject.max_length).to eq num_threads end it 'returns :num_threads once shutdown' do 10.times{ subject.post{ nil } } subject.post { latch.count_down } latch.wait(0.1) subject.shutdown subject.wait_for_termination(1) expect(subject.max_length).to eq num_threads end end context '#length' do it 'returns :num_threads while running' do 10.times{ subject.post{ nil } } subject.post { latch.count_down } latch.wait(0.1) expect(subject.length).to eq num_threads end end context '#largest_length' do it 'returns zero on creation' do expect(subject.largest_length).to eq 0 end it 'returns :num_threads while running' do 10.times{ subject.post{ nil } } subject.post { latch.count_down } latch.wait(0.1) expect(subject.largest_length).to eq num_threads end it 'returns :num_threads once shutdown' do 10.times{ subject.post{ nil } } subject.post { latch.count_down } latch.wait(0.1) subject.shutdown subject.wait_for_termination(1) expect(subject.largest_length).to eq num_threads end end context '#kill' do it 'attempts to kill all in-progress tasks' do thread_count = [subject.length, 5].max @expected = false thread_count.times do # kill tries to shutdown first with 1sec timeout, so wait 2sec here subject.post { sleep(2) } end subject.post{ @expected = true } sleep(0.1) subject.kill sleep(0.1) expect(@expected).to be_falsey end end context 'worker creation and caching' do it 'never creates more than :num_threads threads' do pool = described_class.new(5) 100.times{ pool << proc{ sleep(1) } } sleep(0.1) expect(pool.length).to eq 5 pool.kill end end context 'fallback policy' do before(:each) do @queue = Queue.new end after(:each) do subject.kill end # On abort, it should raise an error it "raises an error when overflow on abort" do latch = Concurrent::CountDownLatch.new(5) mutex = Mutex.new subject = described_class.new(2, :max_queue => 2, :fallback_policy => :abort) expect { 5.times do |i| subject.post do sleep 0.1 mutex.synchronize{ @queue << i } latch.count_down end end latch.wait(1) }.to raise_error end # On discard, we'd expect no error, but also not all five results it 'discards when fallback_policy is :discard' do latch = Concurrent::CountDownLatch.new(5) mutex = Mutex.new subject = described_class.new(2, :max_queue => 2, :fallback_policy => :discard) 5.times do |i| subject.post do sleep 0.1 mutex.synchronize{ @queue << i } latch.count_down end end latch.wait(1) expect(@queue.length).to be < 5 end # To check for caller_runs, we'll check how many unique threads # actually ran the block it 'uses the calling thread for overflow under caller_runs' do latch = Concurrent::CountDownLatch.new(5) mutex = Mutex.new subject = described_class.new(2, :max_queue => 2, :fallback_policy => :caller_runs) 5.times do |i| subject.post do sleep 0.1 mutex.synchronize{ @queue << Thread.current } latch.count_down end end latch.wait(1) # Turn the queue into an array a = [] a << @queue.shift until @queue.empty? #NOTE: This test is very, very difficult to setup properly. Hence the 'be_within' matcher expect(a.size).to be_within(1).of(5) # one for each run of the block expect(a.uniq.size).to be_within(1).of(3) # one for each of the two threads, plus the caller end end context 'runtime-specific implementation' do if Concurrent.on_jruby? it 'sets :fallback_policy correctly' do clazz = java.util.concurrent.ThreadPoolExecutor::DiscardPolicy policy = clazz.new expect(clazz).to receive(:new).at_least(:once).with(any_args).and_return(policy) subject = FixedThreadPool.new(5, fallback_policy: :discard) expect(subject.fallback_policy).to eq :discard end else context 'exception handling' do it 'restarts threads that experience exception' do count = subject.length count.times{ subject << proc{ raise StandardError } } sleep(1) expect(subject.length).to eq count end end context 'worker creation and caching' do it 'creates new workers when there are none available' do pool = described_class.new(5) expect(pool.length).to eq 0 5.times{ pool << proc{ sleep(1) } } sleep(0.1) expect(pool.length).to eq 5 pool.kill end end end end end end concurrent-ruby-1.0.5/spec/concurrent/executor/global_thread_pool_shared.rb000066400000000000000000000014231305460430400273220ustar00rootroot00000000000000shared_examples :global_thread_pool do context '#post' do it 'raises an exception if no block is given' do expect { subject.post }.to raise_error(ArgumentError) end it 'returns true when the block is added to the queue' do expect(subject.post{ nil }).to be_truthy end it 'calls the block with the given arguments' do latch = Concurrent::CountDownLatch.new(1) expected = nil subject.post(1, 2, 3) do |a, b, c| expected = [a, b, c] latch.count_down end latch.wait(0.2) expect(expected).to eq [1, 2, 3] end it 'aliases #<<' do latch = Concurrent::CountDownLatch.new(1) subject << proc { latch.count_down } expect(latch.wait(0.2)).to eq true end end end concurrent-ruby-1.0.5/spec/concurrent/executor/immediate_executor_spec.rb000066400000000000000000000002751305460430400270460ustar00rootroot00000000000000require_relative 'executor_service_shared' module Concurrent describe ImmediateExecutor do subject { ImmediateExecutor.new } it_should_behave_like :executor_service end end concurrent-ruby-1.0.5/spec/concurrent/executor/indirect_immediate_executor_spec.rb000066400000000000000000000010351305460430400307220ustar00rootroot00000000000000require_relative 'executor_service_shared' module Concurrent describe IndirectImmediateExecutor do subject { IndirectImmediateExecutor.new } it_should_behave_like :executor_service it "runs its tasks synchronously" do start = Time.now subject.post { sleep 0.1 } expect(Time.now - start).to be >= 0.1 end it "runs the task on a separate thread" do used_thread = nil subject.post { used_thread = Thread.current } expect(used_thread).not_to be(Thread.current) end end end concurrent-ruby-1.0.5/spec/concurrent/executor/java_single_thread_executor_spec.rb000066400000000000000000000005451305460430400307210ustar00rootroot00000000000000if Concurrent.on_jruby? require_relative 'executor_service_shared' module Concurrent describe JavaSingleThreadExecutor, :type=>:jruby do after(:each) do subject.kill subject.wait_for_termination(0.1) end subject { JavaSingleThreadExecutor.new } it_should_behave_like :executor_service end end end concurrent-ruby-1.0.5/spec/concurrent/executor/java_thread_pool_executor_spec.rb000066400000000000000000000037041305460430400304110ustar00rootroot00000000000000if Concurrent.on_jruby? require_relative 'thread_pool_executor_shared' module Concurrent describe JavaThreadPoolExecutor, :type => :jruby do after(:each) do subject.kill subject.wait_for_termination(0.1) end subject do JavaThreadPoolExecutor.new( min_threads: 2, max_threads: 5, idletime: 60, max_queue: 10, fallback_policy: :discard ) end it_should_behave_like :thread_pool it_should_behave_like :thread_pool_executor context '#overload_policy' do specify ':abort maps to AbortPolicy' do clazz = java.util.concurrent.ThreadPoolExecutor::AbortPolicy policy = clazz.new expect(clazz).to receive(:new).at_least(:once).with(any_args).and_return(policy) JavaThreadPoolExecutor.new( min_threads: 2, max_threads: 5, idletime: 60, max_queue: 10, fallback_policy: :abort ) end specify ':discard maps to DiscardPolicy' do clazz = java.util.concurrent.ThreadPoolExecutor::DiscardPolicy policy = clazz.new expect(clazz).to receive(:new).at_least(:once).with(any_args).and_return(policy) JavaThreadPoolExecutor.new( min_threads: 2, max_threads: 5, idletime: 60, max_queue: 10, fallback_policy: :discard ) end specify ':caller_runs maps to CallerRunsPolicy' do clazz = java.util.concurrent.ThreadPoolExecutor::CallerRunsPolicy policy = clazz.new expect(clazz).to receive(:new).at_least(:once).with(any_args).and_return(policy) JavaThreadPoolExecutor.new( min_threads: 2, max_threads: 5, idletime: 60, max_queue: 10, fallback_policy: :caller_runs ) end end end end end concurrent-ruby-1.0.5/spec/concurrent/executor/ruby_single_thread_executor_spec.rb000066400000000000000000000004631305460430400307600ustar00rootroot00000000000000require_relative 'executor_service_shared' module Concurrent describe RubySingleThreadExecutor, :type=>:mrirbx do after(:each) do subject.kill subject.wait_for_termination(0.1) end subject { RubySingleThreadExecutor.new } it_should_behave_like :executor_service end end concurrent-ruby-1.0.5/spec/concurrent/executor/ruby_thread_pool_executor_spec.rb000066400000000000000000000025111305460430400304440ustar00rootroot00000000000000require_relative 'thread_pool_executor_shared' module Concurrent describe RubyThreadPoolExecutor, :type=>:mrirbx do after(:each) do subject.kill subject.wait_for_termination(0.1) end subject do RubyThreadPoolExecutor.new( min_threads: 2, max_threads: 5, idletime: 60, max_queue: 10, fallback_policy: :discard ) end it_should_behave_like :thread_pool it_should_behave_like :thread_pool_executor context '#remaining_capacity' do let!(:expected_max){ 100 } let(:latch) { Concurrent::CountDownLatch.new } subject do RubyThreadPoolExecutor.new( min_threads: 10, max_threads: 20, idletime: 60, max_queue: expected_max, fallback_policy: :discard ) end it 'returns :max_length when no tasks are enqueued' do 5.times{ subject.post{ nil } } subject.post { latch.count_down } latch.wait(0.1) expect(subject.remaining_capacity).to eq expected_max end it 'returns the remaining capacity when tasks are enqueued' do 100.times{ subject.post{ sleep(0.5) } } subject.post { latch.count_down } latch.wait(0.1) expect(subject.remaining_capacity).to be < expected_max end end end end concurrent-ruby-1.0.5/spec/concurrent/executor/safe_task_executor_spec.rb000066400000000000000000000054551305460430400270550ustar00rootroot00000000000000module Concurrent describe SafeTaskExecutor do describe '#execute' do context 'happy execution' do let(:task) { Proc.new { 42 } } subject { SafeTaskExecutor.new(task) } it 'should return success' do success, value, reason = subject.execute expect(success).to be_truthy end it 'should return task value' do success, value, reason = subject.execute expect(value).to eq 42 end it 'should return a nil reason' do success, value, reason = subject.execute expect(reason).to be_nil end it 'passes all arguments to #execute to the task' do expected = nil task = proc {|*args| expected = args } SafeTaskExecutor.new(task).execute(1, 2, 3) expect(expected).to eq [1, 2, 3] end it 'protectes #execute with a mutex' do expect(subject).to receive(:synchronize).with(no_args) subject.execute end end context 'failing execution' do let(:task) { Proc.new { raise StandardError.new('an error') } } subject { SafeTaskExecutor.new(task) } it 'should return false success' do success, value, reason = subject.execute expect(success).to be_falsey end it 'should return a nil value' do success, value, reason = subject.execute expect(value).to be_nil end it 'should return the reason' do success, value, reason = subject.execute expect(reason).to be_a(StandardError) expect(reason.message).to eq 'an error' end it 'rescues Exception when :rescue_exception is true' do task = proc { raise Exception } subject = SafeTaskExecutor.new(task, rescue_exception: true) expect { subject.execute }.to_not raise_error end it 'rescues StandardError when :rescue_exception is false' do task = proc { raise StandardError } subject = SafeTaskExecutor.new(task, rescue_exception: false) expect { subject.execute }.to_not raise_error task = proc { raise Exception } subject = SafeTaskExecutor.new(task, rescue_exception: false) expect { subject.execute }.to raise_error(Exception) end it 'rescues StandardError by default' do task = proc { raise StandardError } subject = SafeTaskExecutor.new(task) expect { subject.execute }.to_not raise_error task = proc { raise Exception } subject = SafeTaskExecutor.new(task) expect { subject.execute }.to raise_error(Exception) end end end end end concurrent-ruby-1.0.5/spec/concurrent/executor/serialized_execution_spec.rb000066400000000000000000000003521305460430400274040ustar00rootroot00000000000000require_relative 'executor_service_shared' module Concurrent describe SerializedExecutionDelegator do subject { SerializedExecutionDelegator.new(ImmediateExecutor.new) } it_should_behave_like :executor_service end end concurrent-ruby-1.0.5/spec/concurrent/executor/simple_executor_service_spec.rb000066400000000000000000000064061305460430400301230ustar00rootroot00000000000000require_relative 'executor_service_shared' module Concurrent describe SimpleExecutorService do subject { SimpleExecutorService.new } it_should_behave_like :executor_service context '#post' do subject { SimpleExecutorService.new } it 'creates a new thread for a call without arguments' do thread = Thread.new{ nil } expect(Thread).to receive(:new).with(no_args()).and_return(thread) expect(Concurrent.global_fast_executor).not_to receive(:post).with(any_args()) subject.post{ nil } end it 'executes a call without arguments' do latch = CountDownLatch.new(1) subject.post{ latch.count_down } expect(latch.wait(1)).to be_truthy end it 'creates a new thread for a call with arguments' do thread = Thread.new{ nil } expect(Thread).to receive(:new).with(1,2,3).and_return(thread) expect(Concurrent.global_fast_executor).not_to receive(:post).with(any_args()) subject.post(1,2,3){ nil } end it 'executes a call with one argument' do latch = CountDownLatch.new(3) subject.post(3){|count| count.times{ latch.count_down } } expect(latch.wait(1)).to be_truthy end it 'executes a call with multiple arguments' do latch = CountDownLatch.new(10) subject.post(1,2,3,4){|*count| count.reduce(:+).times{ latch.count_down } } expect(latch.wait(1)).to be_truthy end it 'aliases #<<' do thread = Thread.new{ nil } expect(Thread).to receive(:new).with(no_args()).and_return(thread) expect(Concurrent.global_fast_executor).not_to receive(:post).with(any_args()) subject << proc{ nil } end end context 'SimpleExecutorService.post' do subject { SimpleExecutorService } it 'creates a new thread for a call without arguments' do thread = Thread.new{ nil } expect(Thread).to receive(:new).with(no_args()).and_return(thread) expect(Concurrent.global_fast_executor).not_to receive(:post).with(any_args()) subject.post{ nil } end it 'executes a call without arguments' do latch = CountDownLatch.new(1) subject.post{ latch.count_down } expect(latch.wait(1)).to be_truthy end it 'creates a new thread for a call with arguments' do thread = Thread.new{ nil } expect(Thread).to receive(:new).with(1,2,3).and_return(thread) expect(Concurrent.global_fast_executor).not_to receive(:post).with(any_args()) subject.post(1,2,3){ nil } end it 'executes a call with one argument' do latch = CountDownLatch.new(3) subject.post(3){|count| count.times{ latch.count_down } } expect(latch.wait(1)).to be_truthy end it 'executes a call with multiple arguments' do latch = CountDownLatch.new(10) subject.post(1,2,3,4){|*count| count.reduce(:+).times{ latch.count_down } } expect(latch.wait(1)).to be_truthy end it 'aliases #<<' do thread = Thread.new{ nil } expect(Thread).to receive(:new).with(no_args()).and_return(thread) expect(Concurrent.global_fast_executor).not_to receive(:post).with(any_args()) subject << proc{ nil } end end end end concurrent-ruby-1.0.5/spec/concurrent/executor/thread_pool_class_cast_spec.rb000066400000000000000000000014021305460430400276620ustar00rootroot00000000000000module Concurrent describe SingleThreadExecutor do if Concurrent.on_jruby? it 'inherits from JavaSingleThreadExecutor' do expect(SingleThreadExecutor.ancestors).to include(JavaSingleThreadExecutor) end else it 'inherits from RubySingleThreadExecutor' do expect(SingleThreadExecutor.ancestors).to include(RubySingleThreadExecutor) end end end describe ThreadPoolExecutor do if Concurrent.on_jruby? it 'inherits from JavaThreadPoolExecutor' do expect(ThreadPoolExecutor.ancestors).to include(JavaThreadPoolExecutor) end else it 'inherits from RubyThreadPoolExecutor' do expect(ThreadPoolExecutor.ancestors).to include(RubyThreadPoolExecutor) end end end end concurrent-ruby-1.0.5/spec/concurrent/executor/thread_pool_executor_shared.rb000066400000000000000000000406561305460430400277330ustar00rootroot00000000000000require_relative 'thread_pool_shared' shared_examples :thread_pool_executor do after(:each) do subject.kill subject.wait_for_termination(0.1) end context '#initialize defaults' do subject { described_class.new } it 'defaults :min_length to DEFAULT_MIN_POOL_SIZE' do expect(subject.min_length).to eq described_class::DEFAULT_MIN_POOL_SIZE end it 'defaults :max_length to DEFAULT_MAX_POOL_SIZE' do expect(subject.max_length).to eq described_class::DEFAULT_MAX_POOL_SIZE end it 'defaults :idletime to DEFAULT_THREAD_IDLETIMEOUT' do expect(subject.idletime).to eq described_class::DEFAULT_THREAD_IDLETIMEOUT end it 'defaults :max_queue to DEFAULT_MAX_QUEUE_SIZE' do expect(subject.max_queue).to eq described_class::DEFAULT_MAX_QUEUE_SIZE end it 'defaults :fallback_policy to :abort' do expect(subject.fallback_policy).to eq :abort end end context "#initialize explicit values" do it "sets :min_threads" do expect(described_class.new(min_threads: 2).min_length).to eq 2 end it "sets :max_threads" do expect(described_class.new(max_threads: 2).max_length).to eq 2 end it "sets :idletime" do expect(described_class.new(idletime: 2).idletime).to eq 2 end it "doesn't allow max_threads < min_threads" do expect { described_class.new(min_threads: 2, max_threads: 1) }.to raise_error(ArgumentError) end it 'accepts all valid fallback policies' do Concurrent::RubyThreadPoolExecutor::FALLBACK_POLICIES.each do |policy| subject = described_class.new(fallback_policy: policy) expect(subject.fallback_policy).to eq policy end end it 'raises an exception if :max_threads is less than zero' do expect { described_class.new(max_threads: -1) }.to raise_error(ArgumentError) end it 'raises an exception if :min_threads is less than zero' do expect { described_class.new(min_threads: -1) }.to raise_error(ArgumentError) end it 'raises an exception if :max_threads greater than the max allowable' do expect { described_class.new(max_threads: described_class::DEFAULT_MAX_POOL_SIZE+1) }.to raise_error(ArgumentError) end it 'raises an exception if :max_threads is less than :min_threads' do expect { described_class.new(max_threads: 1, min_threads: 100) }.to raise_error(ArgumentError) end it 'raises an exception if given an invalid :fallback_policy' do expect { described_class.new(fallback_policy: :bogus) }.to raise_error(ArgumentError) end end context '#max_queue' do let!(:expected_max){ 100 } subject{ described_class.new(max_queue: expected_max) } it 'returns the set value on creation' do expect(subject.max_queue).to eq expected_max end it 'returns the set value when running', :truffle_bug => true do # only actually fails for RubyThreadPoolExecutor trigger = Concurrent::Event.new 5.times{ subject.post{ trigger.wait } } expect(subject.max_queue).to eq expected_max trigger.set end it 'returns the set value after stopping' do 5.times{ subject.post{ nil } } subject.shutdown subject.wait_for_termination(1) expect(subject.max_queue).to eq expected_max end end context '#queue_length', :truffle_bug => true do # only actually fails for RubyThreadPoolExecutor let!(:expected_max){ 10 } subject do described_class.new( min_threads: 2, max_threads: 5, max_queue: expected_max, fallback_policy: :discard ) end it 'returns zero on creation' do expect(subject.queue_length).to eq 0 end it 'returns zero when there are no enqueued tasks' do latch = Concurrent::CountDownLatch.new(5) 5.times{ subject.post{ latch.count_down } } latch.wait(0.1) expect(subject.queue_length).to eq 0 end it 'returns the size of the queue when tasks are enqueued' do trigger = Concurrent::Event.new 20.times{ subject.post{ trigger.wait } } expect(subject.queue_length).to be > 0 trigger.set end it 'returns zero when stopped' do trigger = Concurrent::Event.new 20.times{ subject.post{ trigger.wait } } subject.shutdown trigger.set subject.wait_for_termination(1) expect(subject.queue_length).to eq 0 end it 'can never be greater than :max_queue' do trigger = Concurrent::Event.new 20.times{ subject.post{ trigger.wait } } expect(subject.queue_length).to be <= expected_max trigger.set end end context '#remaining_capacity' do let!(:expected_max){ 100 } subject{ described_class.new(max_queue: expected_max) } it 'returns -1 when :max_queue is set to zero' do executor = described_class.new(max_queue: 0) expect(executor.remaining_capacity).to eq -1 end it 'returns :max_length on creation' do expect(subject.remaining_capacity).to eq expected_max end it 'returns :max_length when stopped' do 100.times{ subject.post{ nil } } subject.shutdown subject.wait_for_termination(1) expect(subject.remaining_capacity).to eq expected_max end end context '#fallback_policy' do let!(:min_threads){ 1 } let!(:max_threads){ 1 } let!(:idletime){ 60 } let!(:max_queue){ 1 } context ':abort' do subject do described_class.new( min_threads: min_threads, max_threads: max_threads, idletime: idletime, max_queue: max_queue, fallback_policy: :abort ) end specify '#post raises an error when the queue is at capacity' do trigger = Concurrent::Event.new expect { 20.times{ subject.post{ trigger.wait } } }.to raise_error(Concurrent::RejectedExecutionError) trigger.set end specify '#<< raises an error when the queue is at capacity' do trigger = Concurrent::Event.new expect { 20.times{ subject << proc { trigger.wait } } }.to raise_error(Concurrent::RejectedExecutionError) trigger.set end specify '#post raises an error when the executor is shutting down' do trigger = Concurrent::Event.new expect { subject.shutdown; subject.post{ trigger.wait } }.to raise_error(Concurrent::RejectedExecutionError) trigger.set end specify '#<< raises an error when the executor is shutting down' do trigger = Concurrent::Event.new expect { subject.shutdown; subject << proc { trigger.wait } }.to raise_error(Concurrent::RejectedExecutionError) trigger.set end specify 'a #post task is never executed when the queue is at capacity' do all_tasks_posted = Concurrent::Event.new latch = Concurrent::CountDownLatch.new(max_threads) initial_executed = Concurrent::AtomicFixnum.new(0) subsequent_executed = Concurrent::AtomicFixnum.new(0) # Fill up all the threads (with a task that won't complete until # all tasks are posted) max_threads.times do subject.post{ latch.count_down; all_tasks_posted.wait ; initial_executed.increment;} end # Wait for all those tasks to be taken off the queue onto a # worker thread and start executing latch.wait # Fill up the queue (with a task that won't complete until # all tasks are posted) max_queue.times do subject.post{ all_tasks_posted.wait; initial_executed.increment; } end # Inject 20 more tasks, which should throw an exception 20.times do expect { subject.post { subsequent_executed.increment; } }.to raise_error(Concurrent::RejectedExecutionError) end # Trigger the event, so that the tasks in the threads and on # the queue can run to completion all_tasks_posted.set # Wait for all tasks to finish subject.shutdown subject.wait_for_termination # The tasks should have run until all the threads and the # queue filled up... expect(initial_executed.value).to be (max_threads + max_queue) # ..but been dropped after that expect(subsequent_executed.value).to be 0 end specify 'a #<< task is never executed when the queue is at capacity' do all_tasks_posted = Concurrent::Event.new latch = Concurrent::CountDownLatch.new(max_threads) initial_executed = Concurrent::AtomicFixnum.new(0) subsequent_executed = Concurrent::AtomicFixnum.new(0) # Fill up all the threads (with a task that won't complete until # all tasks are posted) max_threads.times do subject << proc { latch.count_down; all_tasks_posted.wait ; initial_executed.increment;} end # Wait for all those tasks to be taken off the queue onto a # worker thread and start executing latch.wait # Fill up the queue (with a task that won't complete until # all tasks are posted) max_queue.times do subject << proc { all_tasks_posted.wait; initial_executed.increment; } end # Inject 20 more tasks, which should throw an exeption 20.times do expect { subject << proc { subsequent_executed.increment; } }.to raise_error(Concurrent::RejectedExecutionError) end # Trigger the event, so that the tasks in the threads and on # the queue can run to completion all_tasks_posted.set # Wait for all tasks to finish subject.shutdown subject.wait_for_termination # The tasks should have run until all the threads and the # queue filled up... expect(initial_executed.value).to be (max_threads + max_queue) # ..but been rejected after that expect(subsequent_executed.value).to be 0 end end context ':discard' do subject do described_class.new( min_threads: min_threads, max_threads: max_threads, idletime: idletime, max_queue: max_queue, fallback_policy: :discard ) end specify 'a #post task is never executed when the queue is at capacity' do all_tasks_posted = Concurrent::Event.new latch = Concurrent::CountDownLatch.new(max_threads) initial_executed = Concurrent::AtomicFixnum.new(0) subsequent_executed = Concurrent::AtomicFixnum.new(0) # Fill up all the threads (with a task that won't complete until # all tasks are posted) max_threads.times do subject.post{ latch.count_down; all_tasks_posted.wait ; initial_executed.increment;} end # Wait for all those tasks to be taken off the queue onto a # worker thread and start executing latch.wait # Fill up the queue (with a task that won't complete until # all tasks are posted) max_queue.times do subject.post{ all_tasks_posted.wait; initial_executed.increment; } end # Inject 20 more tasks, which should be dropped without an exception 20.times do subject.post{ subsequent_executed.increment; } end # Trigger the event, so that the tasks in the threads and on # the queue can run to completion all_tasks_posted.set # Wait for all tasks to finish subject.shutdown subject.wait_for_termination # The tasks should have run until all the threads and the # queue filled up... expect(initial_executed.value).to be (max_threads + max_queue) # ..but been dropped after that expect(subsequent_executed.value).to be 0 end specify 'a #<< task is never executed when the queue is at capacity' do all_tasks_posted = Concurrent::Event.new latch = Concurrent::CountDownLatch.new(max_threads) initial_executed = Concurrent::AtomicFixnum.new(0) subsequent_executed = Concurrent::AtomicFixnum.new(0) # Fill up all the threads (with a task that won't complete until # all tasks are posted) max_threads.times do subject << proc { latch.count_down; all_tasks_posted.wait ; initial_executed.increment;} end # Wait for all those tasks to be taken off the queue onto a # worker thread and start executing latch.wait # Fill up the queue (with a task that won't complete until # all tasks are posted) max_queue.times do subject << proc { all_tasks_posted.wait; initial_executed.increment; } end # Inject 20 more tasks, which should be dropped without an exception 20.times do subject << proc { subsequent_executed.increment; } end # Trigger the event, so that the tasks in the threads and on # the queue can run to completion all_tasks_posted.set # Wait for all tasks to finish subject.shutdown subject.wait_for_termination # The tasks should have run until all the threads and the # queue filled up... expect(initial_executed.value).to be (max_threads + max_queue) # ..but been dropped after that expect(subsequent_executed.value).to be 0 end specify 'a #post task is never executed when the executor is shutting down' do executed = Concurrent::AtomicFixnum.new(0) subject.shutdown subject.post{ executed.increment } # Wait for all tasks to finish subject.wait_for_termination expect(executed.value).to be 0 end specify 'a #<< task is never executed when the executor is shutting down' do executed = Concurrent::AtomicFixnum.new(0) subject.shutdown subject << proc { executed.increment } # Wait for all tasks to finish subject.wait_for_termination expect(executed.value).to be 0 end specify '#post returns false when the executor is shutting down' do subject.shutdown ret = subject.post{ nil } expect(ret).to be false end end context ':caller_runs' do let(:executor) do described_class.new( min_threads: 1, max_threads: 1, idletime: idletime, max_queue: 1, fallback_policy: :caller_runs ) end after(:each) do # need to replicate this w/i scope otherwise rspec may complain executor.kill executor.wait_for_termination(0.1) end specify '#post does not create any new threads when the queue is at capacity' do trigger = Concurrent::Event.new initial = Thread.list.length executor = described_class.new( min_threads: 1, max_threads: 1, idletime: idletime, max_queue: 1, fallback_policy: :caller_runs ) # Post several tasks to the executor. Has to be a new thread, # because it will start blocking once the queue fills up. Thread.new do 5.times{ executor.post{ trigger.wait } } end expect(Thread.list.length).to be < initial + 1 + 5 # Let the executor tasks complete. trigger.set end specify '#<< executes the task on the current thread when the queue is at capacity' do trigger = Concurrent::Event.new latch = Concurrent::CountDownLatch.new(5) executor.post{ trigger.wait } 5.times{|i| executor << proc { latch.count_down } } latch.wait(0.1) trigger.set end specify '#post executes the task on the current thread when the queue is at capacity' do trigger = Concurrent::Event.new latch = Concurrent::CountDownLatch.new(5) executor.post{ trigger.wait } 5.times{|i| executor.post{ latch.count_down } } latch.wait(0.1) trigger.set end specify '#post executes the task on the current thread when the executor is shutting down' do latch = Concurrent::CountDownLatch.new(1) executor.shutdown executor.post{ latch.count_down } latch.wait(0.1) end specify '#<< executes the task on the current thread when the executor is shutting down' do latch = Concurrent::CountDownLatch.new(1) executor.shutdown executor << proc { latch.count_down } latch.wait(0.1) end end end end concurrent-ruby-1.0.5/spec/concurrent/executor/thread_pool_shared.rb000066400000000000000000000053771305460430400260160ustar00rootroot00000000000000require_relative 'executor_service_shared' shared_examples :thread_pool do after(:each) do subject.kill subject.wait_for_termination(0.1) end it_should_behave_like :executor_service let(:latch) { Concurrent::CountDownLatch.new } context '#auto_terminate?' do it 'returns true by default' do expect(subject.auto_terminate?).to be true end it 'returns true when :enable_at_exit_handler is true' do if described_class.to_s =~ /FixedThreadPool$/ subject = described_class.new(1, auto_terminate: true) else subject = described_class.new(auto_terminate: true) end expect(subject.auto_terminate?).to be true end it 'returns false when :enable_at_exit_handler is false' do if described_class.to_s =~ /FixedThreadPool$/ subject = described_class.new(1, auto_terminate: false) else subject = described_class.new(auto_terminate: false) end expect(subject.auto_terminate?).to be false end end context '#length' do it 'returns zero on creation' do expect(subject.length).to eq 0 end it 'returns zero once shut down' do 5.times{ subject.post{ sleep(0.1) } } subject.post { latch.count_down } latch.wait(0.1) subject.shutdown subject.wait_for_termination(1) expect(subject.length).to eq 0 end end context '#scheduled_task_count' do it 'returns zero on creation' do expect(subject.scheduled_task_count).to eq 0 end it 'returns the approximate number of tasks that have been post thus far' do 10.times{ subject.post{ nil } } subject.post { latch.count_down } latch.wait(0.1) expect(subject.scheduled_task_count).to be > 0 end it 'returns the approximate number of tasks that were post' do 10.times{ subject.post{ nil } } subject.post { latch.count_down } latch.wait(0.1) subject.shutdown subject.wait_for_termination(1) expect(subject.scheduled_task_count).to be > 0 end end context '#completed_task_count' do it 'returns zero on creation' do expect(subject.completed_task_count).to eq 0 end unless Concurrent.on_jruby? it 'returns the approximate number of tasks that have been completed thus far' do 5.times{ subject.post{ raise StandardError } } 5.times{ subject.post{ nil } } subject.post { latch.count_down } latch.wait(1) expect(subject.completed_task_count).to be > 0 end end end context '#shutdown' do it 'allows threads to exit normally' do 10.times{ subject << proc{ nil } } expect(subject.length).to be > 0 sleep(0.1) subject.shutdown sleep(1) expect(subject.length).to eq(0) end end end concurrent-ruby-1.0.5/spec/concurrent/executor/timer_set_spec.rb000066400000000000000000000300351305460430400251620ustar00rootroot00000000000000require 'timecop' module Concurrent describe TimerSet do let(:executor){ Concurrent::ImmediateExecutor.new } subject{ TimerSet.new(executor: executor) } after(:each){ subject.kill } context 'construction' do before(:all) do reset_gem_configuration end after(:each) do reset_gem_configuration end it 'uses the executor given at construction' do executor = Concurrent.global_immediate_executor expect(executor).to receive(:post).with(no_args) subject = TimerSet.new(executor: executor) subject.post(0){ nil } end it 'uses the global io executor be default' do latch = Concurrent::CountDownLatch.new(1) expect(Concurrent.global_io_executor).to receive(:post).with(no_args) subject = TimerSet.new subject.post(0){ latch.count_down } latch.wait(0.1) end end context '#post' do it 'raises an exception when given a task with a delay less than zero' do expect { subject.post(-10){ nil } }.to raise_error(ArgumentError) end it 'raises an exception when no block given' do expect { subject.post(10) }.to raise_error(ArgumentError) end it 'immediately posts a task when the delay is zero' do timer = subject.instance_variable_get(:@timer_executor) expect(timer).not_to receive(:post).with(any_args) subject.post(0){ true } end end context 'execution' do it 'executes a given task when given an interval in seconds' do latch = CountDownLatch.new(1) subject.post(0.1){ latch.count_down } expect(latch.wait(0.2)).to be_truthy end it 'returns an IVar when posting a task' do expect(subject.post(0.1) { nil }).to be_a Concurrent::IVar end it 'executes a given task when given an interval in seconds, even if longer tasks have been scheduled' do latch = CountDownLatch.new(1) subject.post(0.5){ nil } subject.post(0.1){ latch.count_down } expect(latch.wait(0.2)).to be_truthy end it 'passes all arguments to the task on execution' do expected = AtomicReference.new latch = CountDownLatch.new(1) subject.post(0.1, 1, 2, 3) do |*args| expected.value = args latch.count_down end expect(latch.wait(0.2)).to be_truthy expect(expected.value).to eq [1, 2, 3] end it 'does not execute tasks early' do latch = Concurrent::CountDownLatch.new(1) start = Time.now.to_f subject.post(0.2){ latch.count_down } expect(latch.wait(1)).to be true expect(Time.now.to_f - start).to be >= 0.19 end it 'executes all tasks scheduled for the same time' do latch = CountDownLatch.new(5) 5.times{ subject.post(0.1){ latch.count_down } } expect(latch.wait(1)).to be_truthy end it 'executes tasks with different times in schedule order' do latch = CountDownLatch.new(3) expected = [] 3.times{|i| subject.post(i/10){ expected << i; latch.count_down } } latch.wait(1) expect(expected).to eq [0, 1, 2] end it 'executes tasks with different times in schedule time' do tests = 3 interval = 0.1 latch = CountDownLatch.new(tests) expected = Queue.new start = Time.now (1..tests).each do |i| subject.post(interval * i) { expected << Time.now - start; latch.count_down } end expect(latch.wait((tests * interval) + 1)).to be true (1..tests).each do |i| delta = expected.pop expect(delta).to be_within(0.1).of((i * interval) + 0.05) end end it 'continues to execute new tasks even after the queue is emptied' do 3.times do |i| task = subject.post(0.1){ i } expect(task.value).to eq i end end end context 'resolution' do it 'sets the IVar value on success when delay is zero' do job = subject.post(0){ 42 } expect(job.value).to eq 42 expect(job.reason).to be_nil expect(job).to be_fulfilled end it 'sets the IVar value on success when given a delay' do job = subject.post(0.1){ 42 } expect(job.value).to eq 42 expect(job.reason).to be_nil expect(job).to be_fulfilled end it 'sets the IVar reason on failure when delay is zero' do error = ArgumentError.new('expected error') job = subject.post(0){ raise error } expect(job.value).to be_nil expect(job.reason).to eq error expect(job).to be_rejected end it 'sets the IVar reason on failure when given a delay' do error = ArgumentError.new('expected error') job = subject.post(0.1){ raise error } expect(job.value).to be_nil expect(job.reason).to eq error expect(job).to be_rejected end end context 'task cancellation' do after(:each) do Timecop.return end it 'fails to cancel the task once processing has begun' do start_latch = Concurrent::CountDownLatch.new continue_latch = Concurrent::CountDownLatch.new job = subject.post(0.1) do start_latch.count_down continue_latch.wait(2) 42 end start_latch.wait(2) success = job.cancel continue_latch.count_down expect(success).to be false expect(job.value).to eq 42 expect(job.reason).to be_nil end it 'fails to cancel the task once processing is complete' do job = subject.post(0.1){ 42 } job.wait(2) success = job.cancel expect(success).to be false expect(job.value).to eq 42 expect(job.reason).to be_nil end it 'cancels a pending task' do actual = AtomicBoolean.new(false) Timecop.freeze job = subject.post(0.1){ actual.make_true } success = job.cancel Timecop.travel(1) expect(success).to be true expect(job.value(0)).to be_nil expect(job.reason).to be_a CancelledOperationError end it 'returns false when not running' do task = subject.post(10){ nil } subject.shutdown subject.wait_for_termination(1) expect(task.cancel).to be false end end context 'task rescheduling' do let(:queue) { subject.instance_variable_get(:@queue) } it 'raises an exception when given an invalid time' do task = subject.post(10){ nil } expect{ task.reschedule(-1) }.to raise_error(ArgumentError) end it 'does not change the current schedule when given an invalid time' do task = subject.post(10){ nil } expected = task.schedule_time begin task.reschedule(-1) rescue end expect(task.schedule_time).to eq expected end it 'reschdules a pending and unpost task when given a valid time' do initial_delay = 10 rescheduled_delay = 20 task = subject.post(initial_delay){ nil } original_schedule = task.schedule_time success = task.reschedule(rescheduled_delay) expect(success).to be true expect(task.initial_delay).to be_within(0.01).of(rescheduled_delay) expect(task.schedule_time).to be > original_schedule end it 'returns false once the task has been post to the executor' do start_latch = Concurrent::CountDownLatch.new continue_latch = Concurrent::CountDownLatch.new task = subject.post(0.1) do start_latch.count_down continue_latch.wait(2) end start_latch.wait(2) expected = task.schedule_time success = task.reschedule(10) continue_latch.count_down expect(success).to be false expect(task.schedule_time).to eq expected end it 'returns false once the task is processing' do start_latch = Concurrent::CountDownLatch.new continue_latch = Concurrent::CountDownLatch.new task = subject.post(0.1) do start_latch.count_down continue_latch.wait(2) end start_latch.wait(2) expected = task.schedule_time success = task.reschedule(10) continue_latch.count_down expect(success).to be false expect(task.schedule_time).to eq expected end it 'returns false once the task has is complete' do task = subject.post(0.1){ nil } task.value(2) expected = task.schedule_time success = task.reschedule(10) expect(success).to be false expect(task.schedule_time).to eq expected end it 'returns false when not running' do task = subject.post(10){ nil } subject.shutdown subject.wait_for_termination(1) expected = task.schedule_time success = task.reschedule(10) expect(success).to be false expect(task.schedule_time).to be_within(0.01).of(expected) end end context 'task resetting' do it 'calls #reschedule with the original delay' do initial_delay = 10 task = subject.post(initial_delay){ nil } expect(task).to receive(:ns_reschedule).with(initial_delay) task.reset end end context 'termination' do it 'cancels all pending tasks on #shutdown' do queue = subject.instance_variable_get(:@queue) expect(queue).to receive(:clear).with(no_args).at_least(:once) subject.shutdown end it 'cancels all pending tasks on #kill' do queue = subject.instance_variable_get(:@queue) expect(queue).to receive(:clear).with(no_args).at_least(:once) subject.kill end it 'stops the monitor thread on #shutdown' do timer_executor = subject.instance_variable_get(:@timer_executor) subject.shutdown subject.wait_for_termination(1) expect(timer_executor).not_to be_running end it 'kills the monitor thread on #kill' do timer_executor = subject.instance_variable_get(:@timer_executor) subject.kill subject.wait_for_termination(1) expect(timer_executor).not_to be_running end it 'rejects tasks once shutdown' do queue = subject.instance_variable_get(:@queue) subject.shutdown subject.wait_for_termination(1) subject.post(1) { nil } expect(queue).to be_empty end it 'rejects tasks once killed' do queue = subject.instance_variable_get(:@queue) subject.kill subject.wait_for_termination(1) subject.post(1) { nil } expect(queue).to be_empty end specify '#wait_for_termination returns true if shutdown completes before timeout' do latch = Concurrent::CountDownLatch.new(1) subject.post(0){ latch.count_down } latch.wait(1) subject.shutdown expect(subject.wait_for_termination(0.1)).to be_truthy end specify '#wait_for_termination returns false on timeout' do latch = Concurrent::CountDownLatch.new(1) subject.post(0){ latch.count_down } latch.wait(0.1) # do not call shutdown -- force timeout expect(subject.wait_for_termination(0.1)).to be_falsey end end context 'state' do it 'is running? when first created' do expect(subject).to be_running expect(subject).not_to be_shutdown end it 'is running? after tasks have been post' do subject.post(0.1){ nil } expect(subject).to be_running expect(subject).not_to be_shutdown end it 'is shutdown? after shutdown completes' do subject.shutdown subject.wait_for_termination(1) expect(subject).not_to be_running expect(subject).to be_shutdown end it 'is shutdown? after being killed' do subject.kill subject.wait_for_termination(1) expect(subject).not_to be_running expect(subject).to be_shutdown end end end end concurrent-ruby-1.0.5/spec/concurrent/future_spec.rb000066400000000000000000000270721305460430400226520ustar00rootroot00000000000000require_relative 'ivar_shared' require_relative 'thread_arguments_shared' module Concurrent describe Future do let!(:value) { 10 } let(:executor) { SimpleExecutorService.new } subject do Future.new(executor: executor){ value }.execute.tap{ sleep(0.1) } end let!(:fulfilled_value) { 10 } let!(:rejected_reason) { StandardError.new('mojo jojo') } let(:pending_subject) do executor = Concurrent::SingleThreadExecutor.new executor.post{ sleep(5) } Future.execute(executor: executor){ fulfilled_value } end let(:fulfilled_subject) do Future.new(executor: :immediate){ fulfilled_value }.execute end let(:rejected_subject) do Future.new(executor: :immediate){ raise rejected_reason }.execute end it_should_behave_like :ivar do subject { Future.new(executor: :immediate){ value } } def dereferenceable_subject(value, opts = {}) opts = opts.merge(executor: executor) Future.new(opts){ value }.execute.tap{ sleep(0.1) } end def dereferenceable_observable(opts = {}) opts = opts.merge(executor: executor) Future.new(opts){ 'value' } end def execute_dereferenceable(subject) subject.execute sleep(0.1) end def trigger_observable(observable) observable.execute sleep(0.1) end end it_should_behave_like :thread_arguments do def get_ivar_from_no_args Concurrent::Future.execute{|*args| args } end def get_ivar_from_args(opts) Concurrent::Future.execute(opts){|*args| args } end end context '#initialize' do let(:executor) { ImmediateExecutor.new } it 'sets the state to :unscheduled' do expect(Future.new(executor: executor){ nil }).to be_unscheduled end it 'raises an exception when no block given' do expect { Future.new.execute }.to raise_error(ArgumentError) end it 'uses the executor given with the :executor option' do expect(executor).to receive(:post) Future.execute(executor: executor){ nil } end it 'uses the global io executor by default' do allow(Concurrent).to receive(:global_io_executor).and_return(executor) expect(executor).to receive(:post).and_call_original Future.execute{ nil } end end context 'instance #execute' do it 'does nothing unless the state is :unscheduled' do executor = ImmediateExecutor.new expect(executor).not_to receive(:post).with(any_args) future = Future.new(executor: executor){ nil } future.instance_variable_set(:@state, :pending) future.execute future.instance_variable_set(:@state, :rejected) future.execute future.instance_variable_set(:@state, :fulfilled) future.execute end it 'posts the block given on construction' do expect(executor).to receive(:post).with(any_args) future = Future.new(executor: executor){ nil } future.execute end it 'sets the state to :pending' do latch = Concurrent::CountDownLatch.new executor = Concurrent::SingleThreadExecutor.new executor.post{ latch.wait(2) } future = Future.new(executor: executor){ 42 } future.execute expect(future).to be_pending latch.count_down end it 'returns self' do future = Future.new(executor: executor){ nil } expect(future.execute).to be future end end context 'class #execute' do let(:executor) { ImmediateExecutor.new } it 'creates a new Future' do future = Future.execute(executor: executor){ nil } expect(future).to be_a(Future) end it 'passes the block to the new Future' do @expected = false Future.execute(executor: executor){ @expected = true } expect(@expected).to be_truthy end it 'calls #execute on the new Future' do future = double('future') allow(Future).to receive(:new).with(any_args).and_return(future) expect(future).to receive(:execute).with(no_args) Future.execute{ nil } end end context 'fulfillment' do let(:executor) { ImmediateExecutor.new } it 'sets the state to :processing while the task is executing' do start_latch = Concurrent::CountDownLatch.new continue_latch = Concurrent::CountDownLatch.new executor = Concurrent::SingleThreadExecutor.new future = Future.execute(executor: executor) do start_latch.count_down continue_latch.wait(2) 42 end start_latch.wait(2) state = future.state continue_latch.count_down future.value expect(state).to eq :processing end it 'passes all arguments to handler' do expected = false Future.new(executor: executor){ expected = true }.execute expect(expected).to be_truthy end it 'sets the value to the result of the handler' do future = Future.new(executor: executor){ 42 }.execute expect(future.value).to eq 42 end it 'sets the state to :fulfilled when the block completes' do future = Future.new(executor: executor){ 42 }.execute expect(future).to be_fulfilled end it 'sets the value to nil when the handler raises an exception' do future = Future.new(executor: executor){ raise StandardError }.execute expect(future.value).to be_nil end it 'sets the value to nil when the handler raises Exception' do future = Future.new(executor: executor){ raise Exception }.execute expect(future.value).to be_nil end it 'sets the reason to the Exception instance when the handler raises Exception' do future = Future.new(executor: executor){ raise Exception }.execute expect(future.reason).to be_a(Exception) end it 'sets the state to :rejected when the handler raises an exception' do future = Future.new(executor: executor){ raise StandardError }.execute expect(future).to be_rejected end context 'aliases' do it 'aliases #realized? for #fulfilled?' do expect(subject).to be_realized end it 'aliases #deref for #value' do expect(subject.deref).to eq value end end end context 'cancellation' do context '#cancel' do it 'fails to cancel the task once processing has begun' do start_latch = Concurrent::CountDownLatch.new continue_latch = Concurrent::CountDownLatch.new f = Future.execute do start_latch.count_down continue_latch.wait(2) 42 end start_latch.wait(2) cancelled = f.cancel continue_latch.count_down expect(cancelled).to be false expect(f.value).to eq 42 expect(f).to be_fulfilled end it 'fails to cancel the task once processing is complete' do f = Future.execute{ 42 } f.wait cancelled = f.cancel expect(cancelled).to be false expect(f.value).to eq 42 expect(f).to be_fulfilled end it 'cancels a pending task' do executor = Concurrent::SingleThreadExecutor.new latch = Concurrent::CountDownLatch.new executor.post{ latch.wait(2) } f = Future.execute(executor: executor){ 42 } cancelled = f.cancel latch.count_down expect(cancelled).to be true expect(f.value).to be_nil expect(f).to be_rejected expect(f.reason).to be_a Concurrent::CancelledOperationError end end context '#wait_or_cancel' do it 'returns true if the operation completes before timeout' do f = Future.execute{ 42 } success = f.wait_or_cancel(1) expect(success).to be true expect(f.value).to eq 42 expect(f).to be_fulfilled end it 'cancels the task on timeout' do latch = Concurrent::CountDownLatch.new executor = Concurrent::SingleThreadExecutor.new executor.post{ latch.wait(2) } f = Future.execute(executor: executor){ 42 } success = f.wait_or_cancel(0.1) latch.count_down expect(success).to be false expect(f.value).to be_nil expect(f).to be_rejected expect(f.reason).to be_a Concurrent::CancelledOperationError end end end context 'observation' do let(:executor) { ImmediateExecutor.new } let(:clazz) do Class.new do attr_reader :value attr_reader :reason attr_reader :count define_method(:update) do |time, value, reason| @count = @count.to_i + 1 @value = value @reason = reason end end end let(:observer) { clazz.new } it 'notifies all observers on fulfillment' do future = Future.new(executor: executor){ 42 } future.add_observer(observer) future.execute expect(observer.value).to eq(42) expect(observer.reason).to be_nil end it 'notifies all observers on rejection' do future = Future.new(executor: executor){ raise StandardError } future.add_observer(observer) future.execute expect(observer.value).to be_nil expect(observer.reason).to be_a(StandardError) end it 'notifies an observer added after fulfillment' do future = Future.new(executor: executor){ 42 }.execute future.add_observer(observer) expect(observer.value).to eq(42) end it 'notifies an observer added after rejection' do future = Future.new(executor: executor){ raise StandardError }.execute future.add_observer(observer) expect(observer.reason).to be_a(StandardError) end it 'does not notify existing observers when a new observer added after fulfillment' do future = Future.new(executor: executor){ 42 }.execute future.add_observer(observer) expect(observer.count).to eq(1) o2 = clazz.new future.add_observer(o2) expect(observer.count).to eq(1) expect(o2.value).to eq(42) end it 'does not notify existing observers when a new observer added after rejection' do future = Future.new(executor: executor){ raise StandardError }.execute future.add_observer(observer) expect(observer.count).to eq(1) o2 = clazz.new future.add_observer(o2) expect(observer.count).to eq(1) expect(o2.reason).to be_a(StandardError) end context 'deadlock avoidance' do def reentrant_observer(future) obs = Object.new obs.define_singleton_method(:update) do |time, value, reason| @value = future.value end obs.define_singleton_method(:value) { @value } obs end it 'should notify observers outside mutex lock' do future = Future.new(executor: executor){ 42 } obs = reentrant_observer(future) future.add_observer(obs) future.execute expect(obs.value).to eq 42 end it 'should notify a new observer added after fulfillment outside lock' do future = Future.new(executor: executor){ 42 }.execute obs = reentrant_observer(future) future.add_observer(obs) expect(obs.value).to eq 42 end end end end end concurrent-ruby-1.0.5/spec/concurrent/hash_spec.rb000066400000000000000000000005351305460430400222560ustar00rootroot00000000000000module Concurrent describe Hash do let!(:hsh) { described_class.new } it 'concurrency' do (1..THREADS).map do |i| Thread.new do 1000.times do |j| hsh[i * 1000 + j] = i hsh[i * 1000 + j] hsh.delete(i * 1000 + j) end end end.map(&:join) end end end concurrent-ruby-1.0.5/spec/concurrent/immutable_struct_spec.rb000066400000000000000000000002521305460430400247120ustar00rootroot00000000000000require_relative 'struct_shared' module Concurrent describe ImmutableStruct do it_should_behave_like :struct it_should_behave_like :mergeable_struct end end concurrent-ruby-1.0.5/spec/concurrent/ivar_shared.rb000066400000000000000000000071321305460430400226100ustar00rootroot00000000000000require_relative 'concern/dereferenceable_shared' require_relative 'concern/obligation_shared' require_relative 'concern/observable_shared' shared_examples :ivar do it_should_behave_like :obligation it_should_behave_like :dereferenceable it_should_behave_like :observable context 'initialization' do it 'sets the state to incomplete' do expect(subject).to be_incomplete end end context '#set' do it 'sets the state to be fulfilled' do subject.set(14) expect(subject).to be_fulfilled end it 'sets the value' do subject.set(14) expect(subject.value).to eq 14 end it 'raises an exception if set more than once' do subject.set(14) expect {subject.set(2)}.to raise_error(Concurrent::MultipleAssignmentError) expect(subject.value).to eq 14 end it 'returns self' do expect(subject.set(42)).to eq subject end it 'fulfils when given a block which executes successfully' do subject.set{ 42 } expect(subject.value).to eq 42 end it 'rejects when given a block which raises an exception' do expected = ArgumentError.new subject.set{ raise expected } expect(subject.reason).to eq expected end it 'raises an exception when given a value and a block' do expect { subject.set(42){ :guide } }.to raise_error(ArgumentError) end it 'raises an exception when given neither a value nor a block' do expect { subject.set }.to raise_error(ArgumentError) end end context '#fail' do it 'sets the state to be rejected' do subject.fail expect(subject).to be_rejected end it 'sets the value to be nil' do subject.fail expect(subject.value).to be_nil end it 'sets the reason to the given exception' do expected = ArgumentError.new subject.fail(expected) expect(subject.reason).to eq expected end it 'raises an exception if set more than once' do subject.fail expect {subject.fail}.to raise_error(Concurrent::MultipleAssignmentError) expect(subject.value).to be_nil end it 'defaults the reason to a StandardError' do subject.fail expect(subject.reason).to be_a StandardError end it 'returns self' do expect(subject.fail).to eq subject end end describe '#try_set' do context 'when unset' do it 'assigns the value' do subject.try_set(32) expect(subject.value).to eq 32 end it 'assigns the block result' do subject.try_set{ 32 } expect(subject.value).to eq 32 end it 'returns true' do expect(subject.try_set('hi')).to eq true end end context 'when fulfilled' do before(:each) { subject.set(27) } it 'does not assign the value' do subject.try_set(88) expect(subject.value).to eq 27 end it 'does not assign the block result' do subject.try_set{ 88 } expect(subject.value).to eq 27 end it 'returns false' do expect(subject.try_set('hello')).to eq false end end context 'when rejected' do before(:each) { subject.fail } it 'does not assign the value' do subject.try_set(88) expect(subject).to be_rejected end it 'does not assign the block result' do subject.try_set{ 88 } expect(subject).to be_rejected end it 'has a nil value' do expect(subject.value).to be_nil end it 'returns false' do expect(subject.try_set('hello')).to eq false end end end end concurrent-ruby-1.0.5/spec/concurrent/ivar_spec.rb000066400000000000000000000060201305460430400222670ustar00rootroot00000000000000require_relative 'ivar_shared' module Concurrent describe IVar do let!(:value) { 10 } let!(:fulfilled_value) { 10 } let(:rejected_reason) { StandardError.new('Boom!') } subject { IVar.new(value) } let(:pending_subject) do ivar = IVar.new Thread.new do sleep(0.1) ivar.set(fulfilled_value) end ivar end let(:fulfilled_subject) do IVar.new.set(fulfilled_value) end let(:rejected_subject) do IVar.new.fail(rejected_reason) end it_should_behave_like :ivar do subject{ IVar.new } def dereferenceable_subject(value, opts = {}) IVar.new(value, opts) end def dereferenceable_observable(opts = {}) IVar.new(NULL, opts) end def execute_dereferenceable(subject) subject.set('value') end def trigger_observable(observable) observable.set('value') end end context '#initialize' do it 'does not have to set an initial value' do i = IVar.new expect(i).to be_incomplete end it 'does not set an initial value if you pass NULL' do i = IVar.new(NULL) expect(i).to be_incomplete end it 'can set an initial value' do i = IVar.new(14) expect(i).to be_complete expect(i.value).to eq 14 end it 'can set an initial value with a block' do i = IVar.new{ 42 } expect(i).to be_complete expect(i.value).to eq 42 end it 'raises an exception if given both a value and a block' do expect { IVar.new(42){ 42 } }.to raise_error(ArgumentError) end end context 'observation' do let(:clazz) do Class.new do attr_reader :value attr_reader :reason attr_reader :count define_method(:update) do |time, value, reason| @count = @count.to_i + 1 @value = value @reason = reason end end end let(:observer) { clazz.new } it 'notifies all observers on #set' do i = IVar.new i.add_observer(observer) i.set(42) expect(observer.value).to eq(42) expect(observer.reason).to be_nil end context 'deadlock avoidance' do def reentrant_observer(i) obs = Object.new obs.define_singleton_method(:update) do |time, value, reason| @value = i.value end obs.define_singleton_method(:value) { @value } obs end it 'should notify observers outside mutex lock' do i = IVar.new obs = reentrant_observer(i) i.add_observer(obs) i.set(42) expect(obs.value).to eq 42 end it 'should notify a new observer added after fulfillment outside lock' do i = IVar.new i.set(42) obs = reentrant_observer(i) i.add_observer(obs) expect(obs.value).to eq 42 end end end end end concurrent-ruby-1.0.5/spec/concurrent/lazy_register_spec.rb000066400000000000000000000001051305460430400242070ustar00rootroot00000000000000module Concurrent describe LazyRegister do pending end end concurrent-ruby-1.0.5/spec/concurrent/map_spec.rb000066400000000000000000000655671305460430400221300ustar00rootroot00000000000000require_relative 'collection_each_shared' Thread.abort_on_exception = true module Concurrent describe Map do before(:each) do @cache = described_class.new end it 'concurrency' do (1..THREADS).map do |i| Thread.new do 1000.times do |j| key = i * 1000 + j @cache[key] = i @cache[key] @cache.delete(key) end end end.map(&:join) end it 'retrieval' do expect_size_change(1) do expect(nil).to eq @cache[:a] expect(nil).to eq @cache.get(:a) @cache[:a] = 1 expect(1).to eq @cache[:a] expect(1).to eq @cache.get(:a) end end it '#put_if_absent' do with_or_without_default_proc do expect_size_change(1) do expect(nil).to eq @cache.put_if_absent(:a, 1) expect(1).to eq @cache.put_if_absent(:a, 1) expect(1).to eq @cache.put_if_absent(:a, 2) expect(1).to eq @cache[:a] end end end describe '#compute_if_absent' do it 'common' do with_or_without_default_proc do expect_size_change(3) do expect(1).to eq @cache.compute_if_absent(:a) { 1 } expect(1).to eq @cache.compute_if_absent(:a) { 2 } expect(1).to eq @cache[:a] @cache[:b] = nil expect(nil).to eq @cache.compute_if_absent(:b) { 1 } expect(nil).to eq @cache.compute_if_absent(:c) {} expect(nil).to eq @cache[:c] expect(true).to eq @cache.key?(:c) end end end it 'with return' do with_or_without_default_proc do expect_handles_return_lambda(:compute_if_absent, :a) end end it 'exception' do with_or_without_default_proc do expect_handles_exception(:compute_if_absent, :a) end end it 'atomicity' do late_compute_threads_count = 10 late_put_if_absent_threads_count = 10 getter_threads_count = 5 compute_started = Concurrent::CountDownLatch.new(1) compute_proceed = Concurrent::CountDownLatch.new( late_compute_threads_count + late_put_if_absent_threads_count + getter_threads_count ) block_until_compute_started = lambda do |name| # what does it mean? if (v = @cache[:a]) != nil expect(nil).to v end compute_proceed.count_down compute_started.wait end expect_size_change 1 do late_compute_threads = Array.new(late_compute_threads_count) do Thread.new do block_until_compute_started.call('compute_if_absent') expect(1).to eq @cache.compute_if_absent(:a) { fail } end end late_put_if_absent_threads = Array.new(late_put_if_absent_threads_count) do Thread.new do block_until_compute_started.call('put_if_absent') expect(1).to eq @cache.put_if_absent(:a, 2) end end getter_threads = Array.new(getter_threads_count) do Thread.new do block_until_compute_started.call('getter') Thread.pass while @cache[:a].nil? expect(1).to eq @cache[:a] end end Thread.new do @cache.compute_if_absent(:a) do compute_started.count_down compute_proceed.wait sleep(0.2) 1 end end.join (late_compute_threads + late_put_if_absent_threads + getter_threads).each(&:join) end end end describe '#compute_if_present' do it 'common' do with_or_without_default_proc do expect_no_size_change do expect(nil).to eq @cache.compute_if_present(:a) {} expect(nil).to eq @cache.compute_if_present(:a) { 1 } expect(nil).to eq @cache.compute_if_present(:a) { fail } expect(false).to eq @cache.key?(:a) end @cache[:a] = 1 expect_no_size_change do expect(1).to eq @cache.compute_if_present(:a) { 1 } expect(1).to eq @cache[:a] expect(2).to eq @cache.compute_if_present(:a) { 2 } expect(2).to eq @cache[:a] expect(false).to eq @cache.compute_if_present(:a) { false } expect(false).to eq @cache[:a] @cache[:a] = 1 yielded = false @cache.compute_if_present(:a) do |old_value| yielded = true expect(1).to eq old_value 2 end expect(true).to eq yielded end expect_size_change(-1) do expect(nil).to eq @cache.compute_if_present(:a) {} expect(false).to eq @cache.key?(:a) expect(nil).to eq @cache.compute_if_present(:a) { 1 } expect(false).to eq @cache.key?(:a) end end end it 'with return' do with_or_without_default_proc do @cache[:a] = 1 expect_handles_return_lambda(:compute_if_present, :a) end end it 'exception' do with_or_without_default_proc do @cache[:a] = 1 expect_handles_exception(:compute_if_present, :a) end end end describe '#compute' do it 'common' do with_or_without_default_proc do expect_no_size_change do expect_compute(:a, nil, nil) {} end expect_size_change(1) do expect_compute(:a, nil, 1) { 1 } expect_compute(:a, 1, 2) { 2 } expect_compute(:a, 2, false) { false } expect(false).to eq @cache[:a] end expect_size_change(-1) do expect_compute(:a, false, nil) {} end end end it 'with return' do with_or_without_default_proc do expect_handles_return_lambda(:compute, :a) @cache[:a] = 1 expect_handles_return_lambda(:compute, :a) end end it 'exception' do with_or_without_default_proc do expect_handles_exception(:compute, :a) @cache[:a] = 2 expect_handles_exception(:compute, :a) end end end describe '#merge_pair' do it 'common' do with_or_without_default_proc do expect_size_change(1) do expect(nil).to eq @cache.merge_pair(:a, nil) { fail } expect(true).to eq @cache.key?(:a) expect(nil).to eq @cache[:a] end expect_no_size_change do expect_merge_pair(:a, nil, nil, false) { false } expect_merge_pair(:a, nil, false, 1) { 1 } expect_merge_pair(:a, nil, 1, 2) { 2 } end expect_size_change(-1) do expect_merge_pair(:a, nil, 2, nil) {} expect(false).to eq @cache.key?(:a) end end end it 'with return' do with_or_without_default_proc do @cache[:a] = 1 expect_handles_return_lambda(:merge_pair, :a, 2) end end it 'exception' do with_or_without_default_proc do @cache[:a] = 1 expect_handles_exception(:merge_pair, :a, 2) end end end it 'updates dont block reads' do getters_count = 20 key_klass = Concurrent::ThreadSafe::Test::HashCollisionKey keys = [key_klass.new(1, 100), key_klass.new(2, 100), key_klass.new(3, 100)] # hash colliding keys inserted_keys = [] keys.each do |key, i| compute_started = Concurrent::CountDownLatch.new(1) compute_finished = Concurrent::CountDownLatch.new(1) getters_started = Concurrent::CountDownLatch.new(getters_count) getters_finished = Concurrent::CountDownLatch.new(getters_count) computer_thread = Thread.new do getters_started.wait @cache.compute_if_absent(key) do compute_started.count_down getters_finished.wait 1 end compute_finished.count_down end getter_threads = (1..getters_count).map do Thread.new do getters_started.count_down inserted_keys.each do |inserted_key| expect(true).to eq @cache.key?(inserted_key) expect(1).to eq @cache[inserted_key] end expect(false).to eq @cache.key?(key) compute_started.wait inserted_keys.each do |inserted_key| expect(true).to eq @cache.key?(inserted_key) expect(1).to eq @cache[inserted_key] end expect(false).to eq @cache.key?(key) expect(nil).to eq @cache[key] getters_finished.count_down compute_finished.wait expect(true).to eq @cache.key?(key) expect(1).to eq @cache[key] end end (getter_threads << computer_thread).map do |t| expect(t.join(2)).to be_truthy end # asserting no deadlocks inserted_keys << key end end specify 'collision resistance' do expect_collision_resistance( (0..1000).map { |i| Concurrent::ThreadSafe::Test::HashCollisionKey(i, 1) } ) end specify 'collision resistance with arrays' do special_array_class = Class.new(Array) do def key # assert_collision_resistance expects to be able to call .key to get the "real" key first.key end end # Test collision resistance with a keys that say they responds_to <=>, but then raise exceptions # when actually called (ie: an Array filled with non-comparable keys). # See https://github.com/headius/thread_safe/issues/19 for more info. expect_collision_resistance( (0..100).map do |i| special_array_class.new( [Concurrent::ThreadSafe::Test::HashCollisionKeyNonComparable.new(i, 1)] ) end ) end it '#replace_pair' do with_or_without_default_proc do expect_no_size_change do expect(false).to eq @cache.replace_pair(:a, 1, 2) expect(false).to eq @cache.replace_pair(:a, nil, nil) expect(false).to eq @cache.key?(:a) end end @cache[:a] = 1 expect_no_size_change do expect(true).to eq @cache.replace_pair(:a, 1, 2) expect(false).to eq @cache.replace_pair(:a, 1, 2) expect(2).to eq @cache[:a] expect(true).to eq @cache.replace_pair(:a, 2, 2) expect(2).to eq @cache[:a] expect(true).to eq @cache.replace_pair(:a, 2, nil) expect(false).to eq @cache.replace_pair(:a, 2, nil) expect(nil).to eq @cache[:a] expect(true).to eq @cache.key?(:a) expect(true).to eq @cache.replace_pair(:a, nil, nil) expect(true).to eq @cache.key?(:a) expect(true).to eq @cache.replace_pair(:a, nil, 1) expect(1).to eq @cache[:a] end end it '#replace_if_exists' do with_or_without_default_proc do expect_no_size_change do expect(nil).to eq @cache.replace_if_exists(:a, 1) expect(false).to eq @cache.key?(:a) end @cache[:a] = 1 expect_no_size_change do expect(1).to eq @cache.replace_if_exists(:a, 2) expect(2).to eq @cache[:a] expect(2).to eq @cache.replace_if_exists(:a, nil) expect(nil).to eq @cache[:a] expect(true).to eq @cache.key?(:a) expect(nil).to eq @cache.replace_if_exists(:a, 1) expect(1).to eq @cache[:a] end end end it '#get_and_set' do with_or_without_default_proc do expect(nil).to eq @cache.get_and_set(:a, 1) expect(true).to eq @cache.key?(:a) expect(1).to eq @cache[:a] expect(1).to eq @cache.get_and_set(:a, 2) expect(2).to eq @cache.get_and_set(:a, nil) expect(nil).to eq @cache[:a] expect(true).to eq @cache.key?(:a) expect(nil).to eq @cache.get_and_set(:a, 1) expect(1).to eq @cache[:a] end end it '#key' do with_or_without_default_proc do expect(nil).to eq @cache.key(1) @cache[:a] = 1 expect(:a).to eq @cache.key(1) expect(nil).to eq @cache.key(0) end end it '#key?' do with_or_without_default_proc do expect(false).to eq @cache.key?(:a) @cache[:a] = 1 expect(true).to eq @cache.key?(:a) end end it '#value?' do with_or_without_default_proc do expect(false).to eq @cache.value?(1) @cache[:a] = 1 expect(true).to eq @cache.value?(1) end end it '#delete' do with_or_without_default_proc do |default_proc_set| expect_no_size_change do expect(nil).to eq @cache.delete(:a) end @cache[:a] = 1 expect_size_change -1 do expect(1).to eq @cache.delete(:a) end expect_no_size_change do expect(nil).to eq @cache[:a] unless default_proc_set expect(false).to eq @cache.key?(:a) expect(nil).to eq @cache.delete(:a) end end end it '#delete_pair' do with_or_without_default_proc do expect_no_size_change do expect(false).to eq @cache.delete_pair(:a, 2) expect(false).to eq @cache.delete_pair(:a, nil) end @cache[:a] = 1 expect_no_size_change do expect(false).to eq @cache.delete_pair(:a, 2) end expect_size_change(-1) do expect(1).to eq @cache[:a] expect(true).to eq @cache.delete_pair(:a, 1) expect(false).to eq @cache.delete_pair(:a, 1) expect(false).to eq @cache.key?(:a) end end end specify 'default proc' do @cache = cache_with_default_proc(1) expect_no_size_change do expect(false).to eq @cache.key?(:a) end expect_size_change(1) do expect(1).to eq @cache[:a] expect(true).to eq @cache.key?(:a) end end specify 'falsy default proc' do @cache = cache_with_default_proc(nil) expect_no_size_change do expect(false).to eq @cache.key?(:a) end expect_size_change(1) do expect(nil).to eq @cache[:a] expect(true).to eq @cache.key?(:a) end end describe '#fetch' do it 'common' do with_or_without_default_proc do |default_proc_set| expect_no_size_change do expect(1).to eq @cache.fetch(:a, 1) expect(1).to eq @cache.fetch(:a) { 1 } expect(false).to eq @cache.key?(:a) expect(nil).to eq @cache[:a] unless default_proc_set end @cache[:a] = 1 expect_no_size_change do expect(1).to eq @cache.fetch(:a) { fail } end expect { @cache.fetch(:b) }.to raise_error(KeyError) expect_no_size_change do expect(1).to eq @cache.fetch(:b, :c) {1} # assert block supersedes default value argument expect(false).to eq @cache.key?(:b) end end end it 'falsy' do with_or_without_default_proc do expect(false).to eq @cache.key?(:a) expect_no_size_change do expect(nil).to eq @cache.fetch(:a, nil) expect(false).to eq @cache.fetch(:a, false) expect(nil).to eq @cache.fetch(:a) {} expect(false).to eq @cache.fetch(:a) { false } end @cache[:a] = nil expect_no_size_change do expect(true).to eq @cache.key?(:a) expect(nil).to eq @cache.fetch(:a) { fail } end end end it 'with return' do with_or_without_default_proc do r = fetch_with_return # r = lambda do # @cache.fetch(:a) { return 10 } # end.call expect_no_size_change do expect(10).to eq r expect(false).to eq @cache.key?(:a) end end end end describe '#fetch_or_store' do it 'common' do with_or_without_default_proc do |default_proc_set| expect_size_change(1) do expect(1).to eq @cache.fetch_or_store(:a, 1) expect(1).to eq @cache[:a] end @cache.delete(:a) expect_size_change 1 do expect(1).to eq @cache.fetch_or_store(:a) { 1 } expect(1).to eq @cache[:a] end expect_no_size_change do expect(1).to eq @cache.fetch_or_store(:a) { fail } end expect { @cache.fetch_or_store(:b) }. to raise_error(KeyError) expect_size_change(1) do expect(1).to eq @cache.fetch_or_store(:b, :c) { 1 } # assert block supersedes default value argument expect(1).to eq @cache[:b] end end end it 'falsy' do with_or_without_default_proc do expect(false).to eq @cache.key?(:a) expect_size_change(1) do expect(nil).to eq @cache.fetch_or_store(:a, nil) expect(nil).to eq @cache[:a] expect(true).to eq @cache.key?(:a) end @cache.delete(:a) expect_size_change(1) do expect(false).to eq @cache.fetch_or_store(:a, false) expect(false).to eq @cache[:a] expect(true).to eq @cache.key?(:a) end @cache.delete(:a) expect_size_change(1) do expect(nil).to eq @cache.fetch_or_store(:a) {} expect(nil).to eq @cache[:a] expect(true).to eq @cache.key?(:a) end @cache.delete(:a) expect_size_change(1) do expect(false).to eq @cache.fetch_or_store(:a) { false } expect(false).to eq @cache[:a] expect(true).to eq @cache.key?(:a) end @cache[:a] = nil expect_no_size_change do expect(nil).to eq @cache.fetch_or_store(:a) { fail } end end end it 'with return' do with_or_without_default_proc do r = fetch_or_store_with_return expect_no_size_change do expect(10).to eq r expect(false).to eq @cache.key?(:a) end end end end it '#clear' do @cache[:a] = 1 expect_size_change(-1) do expect(@cache).to eq @cache.clear expect(false).to eq @cache.key?(:a) expect(nil).to eq @cache[:a] end end describe '#each_pair' do it_should_behave_like :collection_each do let(:method) { :each_pair } end end describe '#each' do it_should_behave_like :collection_each do let(:method) { :each } end end it '#keys' do expect([]).to eq @cache.keys @cache[1] = 1 expect([1]).to eq @cache.keys @cache[2] = 2 expect([1, 2]).to eq @cache.keys.sort end it '#values' do expect([]).to eq @cache.values @cache[1] = 1 expect([1]).to eq @cache.values @cache[2] = 2 expect([1, 2]).to eq @cache.values.sort end it '#each_key' do expect(@cache).to eq @cache.each_key { fail } @cache[1] = 1 arr = [] @cache.each_key { |k| arr << k } expect([1]).to eq arr @cache[2] = 2 arr = [] @cache.each_key { |k| arr << k } expect([1, 2]).to eq arr.sort end it '#each_value' do expect(@cache).to eq @cache.each_value { fail } @cache[1] = 1 arr = [] @cache.each_value { |k| arr << k } expect([1]).to eq arr @cache[2] = 2 arr = [] @cache.each_value { |k| arr << k } expect([1, 2]).to eq arr.sort end it '#empty' do expect(true).to eq @cache.empty? @cache[:a] = 1 expect(false).to eq @cache.empty? end it 'options validation' do expect_valid_options(nil) expect_valid_options({}) expect_valid_options(foo: :bar) end it 'initial capacity options validation' do expect_valid_option(:initial_capacity, nil) expect_valid_option(:initial_capacity, 1) expect_invalid_option(:initial_capacity, '') expect_invalid_option(:initial_capacity, 1.0) expect_invalid_option(:initial_capacity, -1) end it 'load factor options validation' do expect_valid_option(:load_factor, nil) expect_valid_option(:load_factor, 0.01) expect_valid_option(:load_factor, 0.75) expect_valid_option(:load_factor, 1) expect_invalid_option(:load_factor, '') expect_invalid_option(:load_factor, 0) expect_invalid_option(:load_factor, 1.1) expect_invalid_option(:load_factor, 2) expect_invalid_option(:load_factor, -1) end it '#size' do expect(0).to eq @cache.size @cache[:a] = 1 expect(1).to eq @cache.size @cache[:b] = 1 expect(2).to eq @cache.size @cache.delete(:a) expect(1).to eq @cache.size @cache.delete(:b) expect(0).to eq @cache.size end it '#get_or_default' do with_or_without_default_proc do expect(1).to eq @cache.get_or_default(:a, 1) expect(nil).to eq @cache.get_or_default(:a, nil) expect(false).to eq @cache.get_or_default(:a, false) expect(false).to eq @cache.key?(:a) @cache[:a] = 1 expect(1).to eq @cache.get_or_default(:a, 2) end end it '#dup,#clone' do [:dup, :clone].each do |meth| cache = cache_with_default_proc(:default_value) cache[:a] = 1 dupped = cache.send(meth) expect(1).to eq dupped[:a] expect(1).to eq dupped.size expect_size_change(1, cache) do expect_no_size_change(dupped) do cache[:b] = 1 end end expect(false).to eq dupped.key?(:b) expect_no_size_change(cache) do expect_size_change(-1, dupped) do dupped.delete(:a) end end expect(false).to eq dupped.key?(:a) expect(true).to eq cache.key?(:a) # test default proc expect_size_change(1, cache) do expect_no_size_change dupped do expect(:default_value).to eq cache[:c] expect(false).to eq dupped.key?(:c) end end expect_no_size_change cache do expect_size_change 1, dupped do expect(:default_value).to eq dupped[:d] expect(false).to eq cache.key?(:d) end end end end it 'is unfreezable' do expect { @cache.freeze }.to raise_error(NoMethodError) end it 'marshal dump load' do new_cache = Marshal.load(Marshal.dump(@cache)) expect(new_cache).to be_an_instance_of Concurrent::Map expect(0).to eq new_cache.size @cache[:a] = 1 new_cache = Marshal.load(Marshal.dump(@cache)) expect(1).to eq @cache[:a] expect(1).to eq new_cache.size end it 'marshal dump doesnt work with default proc' do expect { Marshal.dump(Concurrent::Map.new {}) }.to raise_error(TypeError) end it '#inspect' do regexp = /\A#\Z/i expect(Concurrent::Map.new.inspect).to match(regexp) expect((Concurrent::Map.new {}).inspect).to match(regexp) map = Concurrent::Map.new map[:foo] = :bar expect(map.inspect).to match(regexp) end private def with_or_without_default_proc(&block) block.call(false) @cache = Concurrent::Map.new { |h, k| h[k] = :default_value } block.call(true) end def cache_with_default_proc(default_value = 1) Concurrent::Map.new { |cache, k| cache[k] = default_value } end def expect_size_change(change, cache = @cache, &block) start = cache.size block.call expect(change).to eq cache.size - start end def expect_valid_option(option_name, value) expect_valid_options(option_name => value) end def expect_valid_options(options) c = Concurrent::Map.new(options) expect(c).to be_an_instance_of Concurrent::Map end def expect_invalid_option(option_name, value) expect_invalid_options(option_name => value) end def expect_invalid_options(options) expect { Concurrent::Map.new(options) }.to raise_error(ArgumentError) end def expect_no_size_change(cache = @cache, &block) expect_size_change(0, cache, &block) end def expect_handles_return_lambda(method, key, *args) before_had_key = @cache.key?(key) before_had_value = before_had_key ? @cache[key] : nil returning_lambda = lambda do @cache.send(method, key, *args) { return :direct_return } end expect_no_size_change do expect(:direct_return).to eq returning_lambda.call expect(before_had_key).to eq @cache.key?(key) expect(before_had_value).to eq @cache[key] if before_had_value end end class TestException < Exception; end def expect_handles_exception(method, key, *args) before_had_key = @cache.key?(key) before_had_value = before_had_key ? @cache[key] : nil expect_no_size_change do expect { @cache.send(method, key, *args) { raise TestException, '' } }. to raise_error(TestException) expect(before_had_key).to eq @cache.key?(key) expect(before_had_value).to eq @cache[key] if before_had_value end end def expect_compute(key, expected_old_value, expected_result, &block) result = @cache.compute(:a) do |old_value| expect(expected_old_value).to eq old_value block.call end expect(expected_result).to eq result end def expect_merge_pair(key, value, expected_old_value, expected_result, &block) result = @cache.merge_pair(key, value) do |old_value| expect(expected_old_value).to eq old_value block.call end expect(expected_result).to eq result end def expect_collision_resistance(keys) keys.each { |k| @cache[k] = k.key } 10.times do |i| size = keys.size while i < size k = keys[i] expect(k.key == @cache.delete(k) && !@cache.key?(k) && (@cache[k] = k.key; @cache[k] == k.key)).to be_truthy i += 10 end end expect(keys.all? { |k| @cache[k] == k.key }).to be_truthy end # Took out for compatibility with Rubinius, see https://github.com/rubinius/rubinius/issues/1312 def fetch_with_return lambda do @cache.fetch(:a) { return 10 } end.call end # Took out for compatibility with Rubinius, see https://github.com/rubinius/rubinius/issues/1312 def fetch_or_store_with_return lambda do @cache.fetch_or_store(:a) { return 10 } end.call end end end concurrent-ruby-1.0.5/spec/concurrent/maybe_spec.rb000066400000000000000000000135001305460430400224240ustar00rootroot00000000000000module Concurrent describe Maybe do context 'construction' do it 'hides Maybe.new' do expect { Maybe.new }.to raise_error(NoMethodError) end context 'Maybe.from' do it 'raises an exception when no block is given' do expect { Maybe.from }.to raise_error(ArgumentError) end it 'passes all arguments to the block' do expected = [1, 2, 3] actual = nil maybe = Maybe.from(*expected) do |*args| actual = args end expect(actual).to eq expected end it 'creates a Just Maybe on success' do maybe = Maybe.from{ 42 } expect(maybe).to be_just end it 'sets the value to the block result on success' do maybe = Maybe.from{ 42 } expect(maybe.just).to eq 42 end it 'creates a Nothing Maybe on exception' do maybe = Maybe.from{ raise StandardError.new } expect(maybe).to be_nothing end it 'sets the reason to the error object on exception' do ex = StandardError.new maybe = Maybe.from{ raise ex } expect(maybe.nothing).to eq ex end end context 'Maybe.just' do let!(:value) { 42 } subject { Maybe.just(value) } it 'creates a new Just Maybe' do expect(subject).to be_a Maybe expect(subject).to be_just end end context 'Maybe.nothing' do let!(:error) { StandardError.new } subject { Maybe.nothing(error) } it 'creates a new Nothing Maybe' do expect(subject).to be_a Maybe expect(subject).to be_nothing end it 'uses the given Error object' do error = NoMethodError.new maybe = Maybe.nothing(error) expect(maybe.nothing).to be error end it 'creates a new error object with the given string' do message = 'What do you get when you multiply six by nine?' maybe = Maybe.nothing(message) expect(maybe.nothing).to be_a StandardError expect(maybe.nothing.message).to eq message end it 'creates a new error object when given nothing' do maybe = Maybe.nothing expect(maybe.nothing).to be_a StandardError expect(maybe.nothing.message).to be_empty end end end context 'when just' do let!(:value) { 42 } subject { Maybe.just(value) } specify '#just? returns true' do expect(subject).to be_just end specify '#fulfilled? returns true' do expect(subject).to be_fulfilled end specify '#nothing? returns false' do expect(subject).to_not be_nothing end specify '#rejected? returns false' do expect(subject).to_not be_rejected end specify '#just returns the value' do expect(subject.just).to eq value end specify '#value returns the value' do expect(subject.value).to eq value end specify '#nothing returns NONE' do expect(subject.nothing).to be Maybe::NONE end specify '#reason returns NONE' do expect(subject.reason).to be Maybe::NONE end end context 'when nothing' do let!(:error) { StandardError.new } subject { Maybe.nothing(error) } specify '#just? returns false' do expect(subject).to_not be_just end specify '#fulfilled? returns false' do expect(subject).to_not be_fulfilled end specify '#nothing? returns true' do expect(subject).to be_nothing end specify '#rejected? returns true' do expect(subject).to be_rejected end specify '#just returns NONE' do expect(subject.just).to eq Maybe::NONE end specify '#value returns NONE' do expect(subject.value).to eq Maybe::NONE end specify '#nothing returns the raised error' do expect(subject.nothing).to be error end specify '#reason returns the raised error' do expect(subject.reason).to be error end end context 'comparison' do let!(:something_big) { Maybe.just(42) } let!(:something_small) { Maybe.just(1) } let!(:nothing_big) { Maybe.nothing(StandardError.new) } let!(:nothing_small) { Maybe.nothing(ArgumentError.new) } specify 'something is not equal to nothing' do expect(something_big).to_not eq nothing_big end specify 'nothing is equal to nothing' do expect(nothing_big).to eq nothing_small end specify 'something is equal to the same value' do first = Maybe.just(42) second = Maybe.just(42) expect(first).to eq second end specify 'something is not equal to a different value' do expect(something_big).to_not eq something_small end specify 'something is greater than a smaller value' do expect(something_big).to be > something_small expect(something_big).to be >= something_small end specify 'something is less than a bigger value' do expect(something_small).to be < something_big expect(something_small).to be <= something_big end specify 'nothing is not less than nothing' do expect(nothing_small).to_not be < nothing_big end specify 'nothing is not greater than nothing' do expect(nothing_big).to_not be > nothing_small end end context '#or' do it 'returns the value when something' do maybe = Maybe.just(42) actual = maybe.or(100) expect(actual).to eq 42 end it 'returns the other when nothing' do maybe = Maybe.nothing actual = maybe.or(100) expect(actual).to eq 100 end end end end concurrent-ruby-1.0.5/spec/concurrent/mutable_struct_spec.rb000066400000000000000000000116241305460430400243710ustar00rootroot00000000000000require_relative 'struct_shared' module Concurrent describe MutableStruct do it_should_behave_like :struct it_should_behave_like :mergeable_struct let(:anonymous) { described_class.new(:name, :address, :zip) } let!(:customer) { described_class.new('Customer', :name, :address, :zip) } let(:joe) { customer.new('Joe Smith', '123 Maple, Anytown NC', 12345) } subject { anonymous.new('Joe Smith', '123 Maple, Anytown NC', 12345) } context 'definition' do it 'defines a setter for each member' do members = [:Foo, :bar, 'baz'] structs = [ described_class.new(*members).new, described_class.new('ClassForCheckingSetterDefinition', *members).new ] structs.each do |struct| members.each do |member| func = "#{member}=" expect(struct).to respond_to func method = struct.method(func) expect(method.arity).to eq 1 end end end end context '#[member]=' do it 'sets the value when given a valid symbol member' do expect(joe[:name] = 'Jane').to eq 'Jane' expect(subject[:name] = 'Jane').to eq 'Jane' end it 'sets the value when given a valid string member' do expect(joe['name'] = 'Jane').to eq 'Jane' expect(subject['name'] = 'Jane').to eq 'Jane' end it 'raises an exception when given a non-existent symbol member' do expect{joe[:fooarbaz] = 'Jane'}.to raise_error(NameError) expect{subject[:fooarbaz] = 'Jane'}.to raise_error(NameError) end it 'raises an exception when given a non-existent string member' do expect{joe['fooarbaz'] = 'Jane'}.to raise_error(NameError) expect{subject['fooarbaz'] = 'Jane'}.to raise_error(NameError) end end context '#[index]=' do it 'sets the value when given a valid index' do expect(joe[0] = 'Jane').to eq 'Jane' expect(subject[0] = 'Jane').to eq 'Jane' end it 'raises an exception when given an out-of-bound index' do expect{joe[100] = 'Jane'}.to raise_error(IndexError) expect{subject[100] = 'Jane'}.to raise_error(IndexError) end end context 'synchronization' do it 'protects #values' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject.values end it 'protects #values_at' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject.values_at(0) end it 'protects #[index]' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject[0] end it 'protects #[member]' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject[:name] end it 'protects getter methods' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject.name end it 'protects #[index]=' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject[0] = :foo end it 'protects #[member]=' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject[:name] = :foo end it 'protects getter methods' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject.name = :foo end it 'protects #to_s' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject.to_s end it 'protects #inspect' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject.inspect end it 'protects #merge' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject.merge(subject.members.first => subject.values.first) end it 'protects #to_h' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject.to_h end it 'protects #==' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject == joe end it 'protects #each' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject.each{|value| nil } end it 'protects #each_pair' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject.each_pair{|member, value| nil } end it 'protects #select' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject.select{|value| false } end end end end concurrent-ruby-1.0.5/spec/concurrent/mvar_spec.rb000066400000000000000000000214571305460430400223060ustar00rootroot00000000000000require_relative 'concern/dereferenceable_shared' module Concurrent describe MVar do context 'behavior' do # dereferenceable def dereferenceable_subject(value, opts = {}) MVar.new(value, opts) end it_should_behave_like :dereferenceable end describe '#initialize' do it 'accepts no initial value' do m = MVar.new expect(m).to be_empty end it 'accepts an empty initial value' do m = MVar.new(MVar::EMPTY) expect(m).to be_empty end it 'accepts an initial value' do m = MVar.new(14) expect(m).not_to be_empty end it 'accepts a nil initial value' do m = MVar.new(nil) expect(m).not_to be_empty end end describe '#take' do it 'sets the MVar to empty' do m = MVar.new(14) m.take expect(m).to be_empty end it 'returns the value on a full MVar' do m = MVar.new(14) expect(m.take).to eq 14 end it 'waits for another thread to #put' do m = MVar.new putter = Thread.new { sleep(0.1) m.put 14 } expect(m.take).to eq 14 end it 'returns TIMEOUT on timeout on an empty MVar' do m = MVar.new expect(m.take(0.1)).to eq MVar::TIMEOUT end end describe '#borrow' do it 'yields current value to the block and puts back value' do m = MVar.new(14) expect { |b| m.borrow(&b) }.to yield_with_args(14) expect(m.take).to eq(14) end it 'puts back value even if an exception is raised' do m = MVar.new(14) expect { m.borrow { fail 'boom!' } }.to raise_error('boom!') expect(m.take).to eq(14) end it 'returns the returned value of the block' do m = MVar.new(14) expect(m.borrow{2}).to eq(2) expect(m.take).to eq(14) end it 'returns TIMEOUT on timeout on an empty MVar' do m = MVar.new expect(m.borrow(0.1){}).to eq MVar::TIMEOUT end end describe '#put' do it 'sets the MVar to be empty' do m = MVar.new(14) m.take expect(m).to be_empty end it 'sets a new value on an empty MVar' do m = MVar.new m.put 14 expect(m.take).to eq 14 end it 'waits for another thread to #take' do m = MVar.new(14) putter = Thread.new { sleep(0.1) m.take } expect(m.put(14)).to eq 14 end it 'returns TIMEOUT on timeout on a full MVar' do m = MVar.new(14) expect(m.put(14, 0.1)).to eq MVar::TIMEOUT end it 'returns the value' do m = MVar.new expect(m.put(14)).to eq 14 end end describe '#empty?' do it 'returns true on an empty MVar' do m = MVar.new expect(m).to be_empty end it 'returns false on a full MVar' do m = MVar.new(14) expect(m).not_to be_empty end end describe '#full?' do it 'returns false on an empty MVar' do m = MVar.new expect(m).not_to be_full end it 'returns true on a full MVar' do m = MVar.new(14) expect(m).to be_full end end describe '#modify' do it 'raises an exception when no block given' do m = MVar.new(14) expect { m.modify }.to raise_error(ArgumentError) end it 'modifies a full MVar' do m = MVar.new(14) m.modify{ |v| v + 2 } expect(m.take).to eq 16 end it 'returns the unmodified value' do m = MVar.new(14) expect(m.modify{ |v| v + 2 }).to eq 14 end it 'waits for another thread to #put' do m = MVar.new putter = Thread.new { sleep(0.1) m.put 14 } expect(m.modify{ |v| v + 2 }).to eq 14 end it 'is atomic' do m = MVar.new(0) # #modify conceptually does #take and #put - but it should be atomic. # Check that another #put can't sneak it during the #modify. modifier = Thread.new { m.modify do |v| sleep(0.5) 1 end } sleep(0.1) expect(m.put(2, 0.5)).to eq MVar::TIMEOUT expect(m.take).to eq 1 end it 'returns TIMEOUT on timeout on an empty MVar' do m = MVar.new expect(m.modify(0.1){ |v| v + 2 }).to eq MVar::TIMEOUT end end describe '#try_put!' do it 'returns true an empty MVar' do m = MVar.new expect(m.try_put!(14)).to eq true end it 'returns false on a full MVar' do m = MVar.new(14) expect(m.try_put!(14)).to eq false end it 'sets an empty MVar to be full' do m = MVar.new m.try_put! 14 expect(m).to be_full end end describe '#try_take!' do it 'returns EMPTY an empty MVar' do m = MVar.new expect(m.try_take!).to eq MVar::EMPTY end it 'returns the value on a full MVar' do m = MVar.new(14) expect(m.try_take!).to eq 14 end it 'sets a full MVar to be empty' do m = MVar.new(14) m.try_take! expect(m).to be_empty end end describe '#set!' do it 'sets an empty MVar to be full' do m = MVar.new m.set! 14 expect(m).to be_full end it 'sets a full MVar to be full' do m = MVar.new(2) m.set! 14 expect(m).to be_full expect(m.take).to eq 14 end it 'returns EMPTY on an empty MVar' do m = MVar.new expect(m.set!(2)).to eq MVar::EMPTY end it 'returns the original value on a full MVar' do m = MVar.new(14) expect(m.set!(2)).to eq 14 end end describe '#modify!' do it 'raises an exception when no block given' do m = MVar.new(14) expect { m.modify! }.to raise_error(ArgumentError) end it 'modifies a full MVar' do m = MVar.new(14) m.modify!{ |v| v + 2 } expect(m.take).to eq 16 end it 'modifies an empty MVar' do m = MVar.new m.modify!{ |v| 14 } expect(m.take).to eq 14 end it 'can be used to set a full MVar to empty' do m = MVar.new(14) m.modify!{ |v| MVar::EMPTY } expect(m).to be_empty end it 'can be used to set an empty MVar to empty' do m = MVar.new m.modify!{ |v| MVar::EMPTY } expect(m).to be_empty end it 'returns the unmodified value' do m = MVar.new(14) expect(m.modify!{ |v| v + 2 }).to eq 14 end end context 'spurious wake ups' do let(:m) { MVar.new } before(:each) do def m.simulate_spurious_wake_up @mutex.synchronize do @full_condition.broadcast @empty_condition.broadcast end end end describe '#take' do it 'waits for another thread to #put' do Thread.new { sleep(0.5); m.put 14 } Thread.new { sleep(0.1); m.simulate_spurious_wake_up } expect(m.take).to eq 14 end it 'returns TIMEOUT on timeout on an empty MVar' do result = nil Thread.new { result = m.take(0.3) } sleep(0.1) Thread.new { m.simulate_spurious_wake_up } sleep(0.1) expect(result).to be_nil sleep(0.2) expect(result).to eq MVar::TIMEOUT end end describe '#modify' do it 'waits for another thread to #put' do Thread.new { sleep(0.5); m.put 14 } Thread.new { sleep(0.1); m.simulate_spurious_wake_up } expect(m.modify{ |v| v + 2 }).to eq 14 end it 'returns TIMEOUT on timeout on an empty MVar' do result = nil Thread.new { result = m.modify(0.3){ |v| v + 2 } } sleep(0.1) Thread.new { m.simulate_spurious_wake_up } sleep(0.1) expect(result).to be_nil sleep(0.2) expect(result).to eq MVar::TIMEOUT end end describe '#put' do before(:each) { m.put(42) } it 'waits for another thread to #take' do Thread.new { sleep(0.5); m.take } Thread.new { sleep(0.1); m.simulate_spurious_wake_up } expect(m.put(14)).to eq 14 end it 'returns TIMEOUT on timeout on a full MVar', buggy: true do # TODO (pitr-ch 15-Oct-2016): fails on jruby result = nil Thread.new { result = m.put(14, 0.3) } sleep(0.1) Thread.new { m.simulate_spurious_wake_up } sleep(0.1) expect(result).to be_nil sleep(0.2) expect(result).to eq MVar::TIMEOUT end end end end end concurrent-ruby-1.0.5/spec/concurrent/options_spec.rb000066400000000000000000000023011305460430400230170ustar00rootroot00000000000000module Concurrent describe Options do context '.executor_from_options' do let(:executor) { ImmediateExecutor.new } let(:io_executor) { ImmediateExecutor.new } let(:fast_executor) { ImmediateExecutor.new } it 'returns the given :executor' do expect(Options.executor_from_options(executor: executor)).to eq executor end it 'returns the global io executor when :executor is :io' do executor = Options.executor_from_options(executor: :io) expect(executor).to eq Concurrent.global_io_executor end it 'returns the global fast executor when :executor is :fast' do executor = Options.executor_from_options(executor: :fast) expect(executor).to eq Concurrent.global_fast_executor end it 'returns an immediate executor when :executor is :immediate' do executor = Options.executor_from_options(executor: :immediate) expect(executor).to be_a Concurrent::ImmediateExecutor end it 'raises an exception when :executor is an unrecognized symbol' do expect { Options.executor_from_options(executor: :bogus) }.to raise_error(ArgumentError) end end end end concurrent-ruby-1.0.5/spec/concurrent/promise_spec.rb000066400000000000000000000463341305460430400230200ustar00rootroot00000000000000require_relative 'ivar_shared' require_relative 'thread_arguments_shared' module Concurrent describe Promise do let!(:value) { 10 } let(:executor) { SimpleExecutorService.new } let(:empty_root) { Promise.new(executor: executor){ nil } } let!(:fulfilled_value) { 10 } let!(:rejected_reason) { StandardError.new('mojo jojo') } let(:pending_subject) do executor = Concurrent::SingleThreadExecutor.new executor.post{ sleep(5) } Promise.execute(executor: executor){ fulfilled_value } end let(:fulfilled_subject) do Promise.new(executor: :immediate){ fulfilled_value }.execute end let(:rejected_subject) do Promise.new(executor: :immediate){ raise rejected_reason }.execute end it_should_behave_like :ivar do subject{ Promise.new(executor: :immediate){ value } } def dereferenceable_subject(value, opts = {}) opts = opts.merge(executor: executor) Promise.new(opts){ value }.execute.tap{ sleep(0.1) } end def dereferenceable_observable(opts = {}) opts = opts.merge(executor: executor) Promise.new(opts){ 'value' } end def execute_dereferenceable(subject) subject.execute sleep(0.1) end def trigger_observable(observable) observable.execute sleep(0.1) end end it_should_behave_like :thread_arguments do def get_ivar_from_no_args Concurrent::Promise.execute{|*args| args } end def get_ivar_from_args(opts) Concurrent::Promise.execute(opts){|*args| args } end end context 'initializers' do describe '.fulfill' do subject { Promise.fulfill(10) } it 'should return a Promise' do expect(subject).to be_a Promise end it 'should return a fulfilled Promise' do expect(subject).to be_fulfilled end it 'should return a Promise with set value' do expect(subject.value).to eq 10 end end describe '.reject' do let(:reason) { ArgumentError.new } subject { Promise.reject(reason) } it 'should return a Promise' do expect(subject).to be_a Promise end it 'should return a rejected Promise' do expect(subject).to be_rejected end it 'should return a Promise with set reason' do expect(subject.reason).to be reason end end describe '.new' do it 'should return an unscheduled Promise' do p = Promise.new(executor: :immediate){ nil } expect(p).to be_unscheduled end end describe '.execute' do it 'creates a new Promise' do p = Promise.execute(executor: :immediate){ nil } expect(p).to be_a(Promise) end it 'passes the block to the new Promise' do p = Promise.execute(executor: :immediate){ 20 } expect(p.value).to eq 20 end it 'calls #execute on the new Promise' do p = double('promise') allow(Promise).to receive(:new).with(any_args).and_return(p) expect(p).to receive(:execute).with(no_args) Promise.execute(executor: :immediate){ nil } end end end context '#execute' do context 'unscheduled' do it 'sets the promise to :pending' do start_latch = CountDownLatch.new end_latch = CountDownLatch.new p = Promise.new(executor: executor) do start_latch.count_down end_latch.wait(1) end start_latch.wait(1) p.execute expect(p).to be_pending end_latch.count_down end it 'posts the block given in construction' do executor = ImmediateExecutor.new expect(executor).to receive(:post).with(any_args).and_call_original Promise.new(executor: executor){ nil }.execute end end context 'pending' do it 'sets the promise to :pending' do latch = CountDownLatch.new p = Promise.new{ latch.wait(1) }.execute expect(p).to be_pending latch.count_down end it 'does not post again' do executor = SimpleExecutorService.new expect(executor).to receive(:post).with(any_args).once latch = CountDownLatch.new p = Promise.new(executor: executor){ latch.wait(1) }.execute 10.times { p.execute } latch.count_down end end describe 'with children' do let(:start_latch) { CountDownLatch.new(4) } let(:end_latch) { CountDownLatch.new(1) } let(:root) { Promise.new(executor: executor){ start_latch.count_down; end_latch.wait(5) } } let(:c1) { root.then { start_latch.count_down; end_latch.wait(5) } } let(:c2) { root.then { start_latch.count_down; end_latch.wait(5) } } let(:c2_1) { c2.then { start_latch.count_down; end_latch.wait(5) } } context 'when called on the root' do it 'should set all promises to :pending' do root.execute start_latch.wait(1) [root, c1, c2, c2_1].each { |p| expect(p).to be_pending } end_latch.count_down end end context 'when called on a child' do it 'should set all promises to :pending' do c2_1.execute start_latch.wait(1) [root, c1, c2, c2_1].each { |p| expect(p).to be_pending } end_latch.count_down end end end end describe '#then' do it 'returns a new promise when a block is passed' do child = empty_root.then { nil } expect(child).to be_a Promise expect(child).not_to be empty_root end it 'returns a new promise when a rescuer is passed' do child = empty_root.then(Proc.new{}) expect(child).to be_a Promise expect(child).not_to be empty_root end it 'returns a new promise when a block and rescuer are passed' do child = empty_root.then(Proc.new{}) { nil } expect(child).to be_a Promise expect(child).not_to be empty_root end it 'returns a new promise when a block, rescuer and executor are passed' do new_executor = Concurrent::SingleThreadExecutor.new child = empty_root.then(Proc.new{}, new_executor) { nil } expect(child).to be_a Promise expect(child).not_to be empty_root expect(child.instance_variable_get(:@executor)).to be(new_executor) end it 'should have block or rescuers' do expect { empty_root.then }.to raise_error(ArgumentError) end context 'unscheduled' do let(:p1) { Promise.new(executor: executor){nil} } let(:child) { p1.then{} } it 'returns a new promise' do expect(child).to be_a Promise expect(p1).not_to be child end it 'returns an unscheduled promise' do expect(child).to be_unscheduled end end context 'pending' do let(:child) { pending_subject.then{} } it 'returns a new promise' do expect(child).to be_a Promise expect(pending_subject).not_to be child end it 'returns a pending promise' do expect(child).to be_pending end end context 'fulfilled' do it 'returns a new Promise' do p1 = fulfilled_subject p2 = p1.then{} expect(p2).to be_a(Promise) expect(p1).not_to eq p2 end it 'notifies fulfillment to new child' do child = fulfilled_subject.then(Proc.new{ 7 }) { |v| v + 5 } expect(child.value).to eq fulfilled_value + 5 end end context 'rejected' do it 'returns a new Promise when :rejected' do p1 = rejected_subject p2 = p1.then{} expect(p2).to be_a(Promise) expect(p1).not_to eq p2 end it 'notifies rejection to new child' do child = rejected_subject.then(Proc.new{ 7 }) { |v| v + 5 } expect(child.value).to eq 7 end end it 'can be called more than once' do p = pending_subject p1 = p.then{} p2 = p.then{} expect(p1).not_to be p2 end end describe 'on_success' do it 'should have a block' do expect { empty_root.on_success }.to raise_error(ArgumentError) end it 'returns a new promise' do child = empty_root.on_success { nil } expect(child).to be_a Promise expect(child).not_to be empty_root end end context '#rescue' do it 'returns a new promise' do child = empty_root.rescue { nil } expect(child).to be_a Promise expect(child).not_to be empty_root end end describe '#flat_map' do it 'returns a promise' do child = empty_root.flat_map { nil } expect(child).to be_a Promise expect(child).not_to be empty_root end it 'succeeds if both promises succeed' do child = Promise.new(executor: :immediate) { 1 }. flat_map { |v| Promise.new(executor: :immediate) { v + 10 } }.execute.wait expect(child.value!).to eq(11) end it 'fails if the left promise fails' do child = Promise.new(executor: :immediate) { fail }. flat_map { |v| Promise.new(executor: :immediate) { v + 10 } }.execute.wait expect(child).to be_rejected end it 'fails if the right promise fails' do child = Promise.new(executor: :immediate) { 1 }. flat_map { |v| Promise.new(executor: :immediate) { fail } }.execute.wait expect(child).to be_rejected end it 'fails if the generating block fails' do child = Promise.new(executor: :immediate) { }.flat_map { fail }.execute.wait expect(child).to be_rejected end end describe '#zip' do let(:promise1) { Promise.new(executor: :immediate) { 1 } } let(:promise2) { Promise.new(executor: :immediate) { 2 } } let(:promise3) { Promise.new(executor: :immediate) { [3] } } it 'yields the results as an array' do composite = promise1.zip(promise2, promise3).execute.wait expect(composite.value).to eq([1, 2, [3]]) end it 'fails if one component fails' do composite = promise1.zip(promise2, rejected_subject, promise3).execute.wait expect(composite).to be_rejected end end describe '.zip' do let(:promise1) { Promise.new(executor: :immediate) { 1 } } let(:promise2) { Promise.new(executor: :immediate) { 2 } } let(:promise3) { Promise.new(executor: :immediate) { [3] } } it 'yields the results as an array' do composite = Promise.zip(promise1, promise2, promise3).execute.wait expect(composite.value).to eq([1, 2, [3]]) end it 'fails if one component fails' do composite = Promise.zip(promise1, promise2, rejected_subject, promise3).execute.wait expect(composite).to be_rejected end end describe 'aggregators' do let(:promise1) { Promise.new(executor: :immediate) { 1 } } let(:promise2) { Promise.new(executor: :immediate) { 2 } } let(:promise3) { Promise.new(executor: :immediate) { [3] } } describe '.all?' do it 'returns a new Promise' do composite = Promise.all?(promise1, promise2, promise3).execute expect(composite).to be_a Concurrent::Promise end it 'does not execute the returned Promise' do composite = Promise.all?(promise1, promise2, promise3) expect(composite).to be_unscheduled end it 'executes the #then condition when all components succeed' do counter = Concurrent::AtomicFixnum.new(0) latch = Concurrent::CountDownLatch.new(1) composite = Promise.all?(promise1, promise2, promise3). then { counter.up; latch.count_down }. rescue { counter.down; latch.count_down }. execute latch.wait(1) expect(counter.value).to eq 1 end it 'executes the #then condition when no promises are given' do counter = Concurrent::AtomicFixnum.new(0) latch = Concurrent::CountDownLatch.new(1) composite = Promise.all?. then { counter.up; latch.count_down }. rescue { counter.down; latch.count_down }. execute latch.wait(1) expect(counter.value).to eq 1 end it 'executes the #rescue handler if even one component fails' do counter = Concurrent::AtomicFixnum.new(0) latch = Concurrent::CountDownLatch.new(1) composite = Promise.all?(promise1, promise2, rejected_subject, promise3). then { counter.up; latch.count_down }. rescue { counter.down; latch.count_down }. execute latch.wait(1) expect(counter.value).to eq -1 end end describe '.any?' do it 'returns a new Promise' do composite = Promise.any?(promise1, promise2, promise3).execute expect(composite).to be_a Concurrent::Promise end it 'does not execute the returned Promise' do composite = Promise.any?(promise1, promise2, promise3) expect(composite).to be_unscheduled end it 'executes the #then condition when any components succeed' do counter = Concurrent::AtomicFixnum.new(0) latch = Concurrent::CountDownLatch.new(1) composite = Promise.any?(promise1, promise2, rejected_subject, promise3). then { counter.up; latch.count_down }. rescue { counter.down; latch.count_down }. execute latch.wait(1) expect(counter.value).to eq 1 end it 'executes the #then condition when no promises are given' do counter = Concurrent::AtomicFixnum.new(0) latch = Concurrent::CountDownLatch.new(1) composite = Promise.any?. then { counter.up; latch.count_down }. rescue { counter.down; latch.count_down }. execute latch.wait(1) expect(counter.value).to eq 1 end it 'executes the #rescue handler if all componenst fail' do counter = Concurrent::AtomicFixnum.new(0) latch = Concurrent::CountDownLatch.new(1) composite = Promise.any?(rejected_subject, rejected_subject, rejected_subject, rejected_subject). then { counter.up; latch.count_down }. rescue { counter.down; latch.count_down }. execute latch.wait(1) expect(counter.value).to eq -1 end end end context 'fulfillment' do context '#set' do it '#can only be called on the root promise' do root = Promise.new{ :foo } child = root.then{ :bar } expect { child.set('foo') }.to raise_error PromiseExecutionError expect { root.set('foo') }.not_to raise_error end it 'triggers children' do expected = nil root = Promise.new(executor: :immediate){ nil } root.then{ |result| expected = result } root.set(20) expect(expected).to eq 20 end it 'can be called with a block' do p = Promise.new(executor: :immediate) ch = p.then(&:to_s) p.set { :value } expect(p.value).to eq :value expect(p.state).to eq :fulfilled expect(ch.value).to eq 'value' expect(ch.state).to eq :fulfilled end end context '#fail' do it 'can only be called on the root promise' do root = Promise.new{ :foo } child = root.then{ :bar } expect { child.fail }.to raise_error PromiseExecutionError expect { root.fail }.not_to raise_error end it 'rejects children' do expected = nil root = Promise.new(executor: :immediate) root.then(Proc.new{ |reason| expected = reason }) root.fail(ArgumentError.new('simulated error')) expect(expected).to be_a ArgumentError end end it 'passes the result of each block to all its children' do expected = nil Promise.new(executor: :immediate){ 20 }.then{ |result| expected = result }.execute expect(expected).to eq 20 end it 'sets the promise value to the result if its block' do root = Promise.new(executor: :immediate){ 20 } p = root.then{ |result| result * 2}.execute expect(root.value).to eq 20 expect(p.value).to eq 40 end it 'sets the promise state to :fulfilled if the block completes' do p = Promise.new(executor: :immediate){ 10 * 2 }.then{|result| result * 2}.execute expect(p).to be_fulfilled end it 'passes the last result through when a promise has no block' do expected = nil Promise.new(executor: :immediate){ 20 }.then(Proc.new{}).then{|result| expected = result}.execute expect(expected).to eq 20 end it 'uses result as fulfillment value when a promise has no block' do p = Promise.new(executor: :immediate){ 20 }.then(Proc.new{}).execute expect(p.value).to eq 20 end it 'can manage long chain' do root = Promise.new(executor: :immediate){ 20 } p1 = root.then { |b| b * 3 } p2 = root.then { |c| c + 2 } p3 = p1.then { |d| d + 7 } root.execute expect(root.value).to eq 20 expect(p1.value).to eq 60 expect(p2.value).to eq 22 expect(p3.value).to eq 67 end end context 'rejection' do it 'passes the reason to all its children' do expected = nil handler = proc { |reason| expected = reason } Promise.new(executor: :immediate){ raise ArgumentError }.then(handler).execute expect(expected).to be_a ArgumentError end it 'sets the promise value to the result if its block' do root = Promise.new(executor: :immediate){ raise ArgumentError } p = root.then(Proc.new{ |reason| 42 }).execute expect(p.value).to eq 42 end it 'sets the promise state to :rejected if the block completes' do p = Promise.new(executor: :immediate){ raise ArgumentError }.execute expect(p).to be_rejected end it 'uses reason as rejection reason when a promise has no rescue callable' do p = Promise.new(executor: :immediate){ raise ArgumentError }.then{ |val| val }.execute expect(p).to be_rejected expect(p.reason).to be_a ArgumentError end it 'rejects on Exception' do p = Promise.new(executor: :immediate){ raise Exception }.execute expect(p).to be_rejected end end context 'aliases' do it 'aliases #realized? for #fulfilled?' do expect(fulfilled_subject).to be_realized end it 'aliases #deref for #value' do expect(fulfilled_subject.deref).to eq fulfilled_value end it 'aliases #catch for #rescue' do child = rejected_subject.catch { 7 } expect(child.value).to eq 7 end it 'aliases #on_error for #rescue' do child = rejected_subject.on_error { 7 } expect(child.value).to eq 7 end end end end concurrent-ruby-1.0.5/spec/concurrent/scheduled_task_spec.rb000066400000000000000000000177621305460430400243270ustar00rootroot00000000000000require 'timecop' require_relative 'concern/dereferenceable_shared' require_relative 'concern/obligation_shared' require_relative 'concern/observable_shared' module Concurrent describe ScheduledTask do context 'behavior' do let!(:fulfilled_value) { 10 } let!(:rejected_reason) { StandardError.new('mojo jojo') } let(:pending_subject) do ScheduledTask.new(1){ fulfilled_value }.execute end let(:fulfilled_subject) do ScheduledTask.new(0, executor: :immediate){ fulfilled_value }.execute end let(:rejected_subject) do ScheduledTask.new(0, executor: :immediate){ raise rejected_reason }.execute end def dereferenceable_subject(value, opts = {}) task = ScheduledTask.execute(0, opts){ value }.execute task.value task end def dereferenceable_observable(opts = {}) ScheduledTask.new(0, opts){ 'value' } end def execute_dereferenceable(subject) subject.execute subject.value end def trigger_observable(observable) observable.execute sleep(0.2) end subject{ ScheduledTask.new(0.1){ nil } } it_should_behave_like :obligation it_should_behave_like :dereferenceable it_should_behave_like :observable end context '#initialize' do it 'accepts a number of seconds (from now) as the schedule time' do expected = 60 Timecop.freeze do now = Time.now task = ScheduledTask.new(expected){ nil }.execute expect(task.initial_delay).to be_within(0.1).of(expected) end end it 'raises an exception when seconds is less than zero' do expect { ScheduledTask.new(-1){ nil } }.to raise_error(ArgumentError) end it 'raises an exception when no block given' do expect { ScheduledTask.new(1) }.to raise_error(ArgumentError) end it 'sets the initial state to :unscheduled' do task = ScheduledTask.new(1){ nil } expect(task).to be_unscheduled end end context 'instance #execute' do it 'does nothing unless the state is :unscheduled' do expect(Concurrent).not_to receive(:timer).with(any_args) task = ScheduledTask.new(1){ nil } task.instance_variable_set(:@state, :pending) task.execute task.instance_variable_set(:@state, :rejected) task.execute task.instance_variable_set(:@state, :fulfilled) task.execute end it 'sets the sate to :pending' do task = ScheduledTask.new(1){ nil } task.execute expect(task).to be_pending end it 'returns self' do task = ScheduledTask.new(1){ nil } expect(task.execute).to eq task end end context 'class #execute' do it 'creates a new ScheduledTask' do task = ScheduledTask.execute(1){ nil } expect(task).to be_a(ScheduledTask) end it 'passes the block to the new ScheduledTask' do @expected = false task = ScheduledTask.execute(0.1){ @expected = true } task.value(1) expect(@expected).to be_truthy end it 'calls #execute on the new ScheduledTask' do task = ScheduledTask.new(0.1){ nil } allow(ScheduledTask).to receive(:new).with(any_args).and_return(task) expect(task).to receive(:execute).with(no_args) ScheduledTask.execute(0.1){ nil } end end context 'execution' do it 'passes :args from the options to the block' do expected = [1, 2, 3] actual = nil latch = Concurrent::CountDownLatch.new task = ScheduledTask.execute(0, args: expected) do |*args| actual = args latch.count_down end latch.wait(2) expect(actual).to eq expected end it 'uses the :executor from the options' do latch = Concurrent::CountDownLatch.new executor = Concurrent::ImmediateExecutor.new expect(executor).to receive(:post).once.with(any_args).and_call_original task = ScheduledTask.execute(0, executor: executor) do latch.count_down end latch.wait(2) end it 'uses the :timer_set from the options' do timer = Concurrent::TimerSet.new queue = timer.instance_variable_get(:@queue) task = ScheduledTask.execute(1, timer_set: timer){ nil } expect(queue.size).to eq 1 task.cancel end it 'sets the state to :processing when the task is running' do start_latch = Concurrent::CountDownLatch.new(1) continue_latch = Concurrent::CountDownLatch.new(1) task = ScheduledTask.new(0.1) { start_latch.count_down continue_latch.wait(2) }.execute start_latch.wait(2) state = task.state continue_latch.count_down expect(state).to eq :processing end end context '#cancel' do it 'returns false if the task has already been performed' do task = ScheduledTask.new(0.1){ 42 }.execute task.value(1) expect(task.cancel).to be_falsey end it 'returns false if the task is already in progress' do latch = Concurrent::CountDownLatch.new(1) task = ScheduledTask.new(0.1) { latch.count_down sleep(1) }.execute latch.wait(1) expect(task.cancel).to be_falsey end it 'cancels the task if it has not yet scheduled' do latch = Concurrent::CountDownLatch.new(1) task = ScheduledTask.new(0.1){ latch.count_down } task.cancel task.execute expect(latch.wait(0.3)).to be_falsey end it 'cancels the task if it has not yet started' do latch = Concurrent::CountDownLatch.new(1) task = ScheduledTask.new(0.3){ latch.count_down }.execute sleep(0.1) task.cancel expect(latch.wait(0.5)).to be_falsey end it 'returns true on success' do task = ScheduledTask.new(10){ nil }.execute sleep(0.1) expect(task.cancel).to be_truthy end it 'sets the reason to CancelledOperationError when cancelled' do task = ScheduledTask.new(10){ 42 }.execute sleep(0.1) task.cancel expect(task).to be_rejected expect(task.reason).to be_a CancelledOperationError end end context 'observation' do let(:clazz) do Class.new do attr_reader :value attr_reader :reason attr_reader :count attr_reader :latch def initialize @latch = Concurrent::CountDownLatch.new(1) end def update(time, value, reason) @count = @count.to_i + 1 @value = value @reason = reason @latch.count_down end end end let(:observer) { clazz.new } it 'returns true for an observer added while :unscheduled' do task = ScheduledTask.new(0.1){ 42 } expect(task.add_observer(observer)).to be_truthy end it 'returns true for an observer added while :pending' do task = ScheduledTask.new(0.1){ 42 }.execute expect(task.add_observer(observer)).to be_truthy end it 'returns true for an observer added while :processing' do task = ScheduledTask.new(0.1){ sleep(1); 42 }.execute sleep(0.2) expect(task.add_observer(observer)).to be_truthy end it 'notifies all observers on fulfillment' do task = ScheduledTask.new(0.1){ 42 }.execute task.add_observer(observer) observer.latch.wait(1) expect(observer.value).to eq(42) expect(observer.reason).to be_nil end it 'notifies all observers on rejection' do task = ScheduledTask.new(0.1){ raise StandardError }.execute task.add_observer(observer) observer.latch.wait(1) expect(observer.value).to be_nil expect(observer.reason).to be_a(StandardError) end end end end concurrent-ruby-1.0.5/spec/concurrent/settable_struct_spec.rb000066400000000000000000000134341305460430400245440ustar00rootroot00000000000000require_relative 'struct_shared' module Concurrent describe SettableStruct do it_should_behave_like :struct it_should_behave_like :mergeable_struct let(:anonymous) { described_class.new(:name, :address, :zip) } let!(:customer) { described_class.new('Customer', :name, :address, :zip) } let(:joe) { customer.new('Joe Smith', '123 Maple, Anytown NC', 12345) } let(:empty) { customer.new } subject { anonymous.new } context 'definition' do it 'defines a setter for each member' do members = [:Foo, :bar, 'baz'] structs = [ described_class.new(*members).new, described_class.new('ClassForCheckingSetterDefinition', *members).new ] structs.each do |struct| members.each do |member| func = "#{member}=" expect(struct).to respond_to func method = struct.method(func) expect(method.arity).to eq 1 end end end end context '#[member]=' do it 'sets the value when given a valid symbol member' do expect(empty[:name] = 'Jane').to eq 'Jane' expect(subject[:name] = 'Jane').to eq 'Jane' end it 'sets the value when given a valid string member' do expect(empty['name'] = 'Jane').to eq 'Jane' expect(subject['name'] = 'Jane').to eq 'Jane' end it 'raises an exception when given a non-existent symbol member' do expect{empty[:fooarbaz] = 'Jane'}.to raise_error(NameError) expect{subject[:fooarbaz] = 'Jane'}.to raise_error(NameError) end it 'raises an exception when given a non-existent string member' do expect{empty['fooarbaz'] = 'Jane'}.to raise_error(NameError) expect{subject['fooarbaz'] = 'Jane'}.to raise_error(NameError) end it 'raises an exception when given a symbol member that has already been set' do empty[:name] = 'John' subject[:name] = 'John' expect{empty[:name] = 'Jane'}.to raise_error(ImmutabilityError) expect{subject[:name] = 'Jane'}.to raise_error(ImmutabilityError) end it 'raises an exception when given a string member that has already been set' do empty['name'] = 'John' subject['name'] = 'John' expect{empty['name'] = 'Jane'}.to raise_error(ImmutabilityError) expect{subject['name'] = 'Jane'}.to raise_error(ImmutabilityError) end end context '#[index]=' do it 'sets the value when given a valid index' do expect(empty[0] = 'Jane').to eq 'Jane' expect(subject[0] = 'Jane').to eq 'Jane' end it 'raises an exception when given an out-of-bound index' do expect{empty[100] = 'Jane'}.to raise_error(IndexError) expect{subject[100] = 'Jane'}.to raise_error(IndexError) end it 'raises an exception when given an index that has already been set' do empty[0] = 'John' subject[0] = 'John' expect{empty[0] = 'Jane'}.to raise_error(ImmutabilityError) expect{subject[0] = 'Jane'}.to raise_error(ImmutabilityError) end end context 'synchronization' do it 'protects #values' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject.values end it 'protects #values_at' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject.values_at(0) end it 'protects #[index]' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject[0] end it 'protects #[member]' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject[:name] end it 'protects getter methods' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject.name end it 'protects #[index]=' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject[0] = :foo end it 'protects #[member]=' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject[:name] = :foo end it 'protects getter methods' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject.name = :foo end it 'protects #to_s' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject.to_s end it 'protects #inspect' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject.inspect end it 'protects #to_h' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject.to_h end it 'protects #merge' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject.merge(subject.members.first => subject.values.first) end it 'protects #==' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject == joe end it 'protects #each' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject.each{|value| nil } end it 'protects #each_pair' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject.each_pair{|member, value| nil } end it 'protects #select' do expect(subject).to receive(:synchronize).at_least(:once).with(no_args).and_call_original subject.select{|value| false } end end end end concurrent-ruby-1.0.5/spec/concurrent/struct_shared.rb000066400000000000000000000343761305460430400232050ustar00rootroot00000000000000shared_examples :struct do context 'definition' do it 'registers the class when given a class name' do class_name = 'ValidClassName' clazz = described_class.new(class_name) expect{ described_class.const_get(class_name) }.to_not raise_error expect(clazz).to be_a Class expect(clazz.ancestors).to include described_class end it 'creates an anonymous class when given at least one member' do clazz = described_class.new(:foo) expect{ described_class.const_get(clazz.to_s) }.to raise_error(NameError) expect(clazz).to be_a Class expect(clazz.ancestors).to include described_class end it 'raises an exception when given an invalid class name' do expect{ described_class.new('lowercase') }.to raise_error(NameError) expect{ described_class.new('_') }.to raise_error(NameError) expect{ described_class.new('1') }.to raise_error(NameError) end it 'defines a getter for each member' do members = [:Foo, :bar, 'baz'] structs = [ described_class.new(*members).new, described_class.new('ClassForCheckingGetterDefinition', *members).new ] structs.each do |struct| members.each do |member| expect(struct).to respond_to member method = struct.method(member) expect(method.arity).to eq 0 end end end it 'raises an exception when given no members' do expect{ described_class.new() }.to raise_error(ArgumentError) end it 'raise an exception when given an invalid member' do expect{ described_class.new('ClassForCheckingValidFieldNames1', 1) }.to raise_error(TypeError) end it 'evalues a given block against the new class' do clazz1 = described_class.new('ClassForCheckingBlockProcessing', :foo, :bar) do def baz(foo, bar) foo + bar; end end clazz2 = described_class.new(:foo, :bar) do def baz(foo, bar) foo + bar; end end [clazz1, clazz2].each do |clazz| struct = clazz.new expect(struct).to respond_to :baz expect(struct.method(:baz).arity).to eq 2 expect(struct.baz(40, 2)).to eq 42 end end end context 'construction' do let!(:members){ [:Foo, :bar, 'baz'] } let!(:values){ [42, '42', :fortytwo] } let!(:classes) do [ described_class.new(*members), described_class.new('StructConstructionTester', *members) ] end it 'sets all absent members to nil' do classes.each do |clazz| struct = clazz.new members.each do |member| expect(struct.send(member)).to be_nil end end end it 'sets all given members in order' do classes.each do |clazz| struct = clazz.new(*values) members.each_with_index do |member, index| expect(struct.send(member)).to eq values[index] end end end it 'raises an exception when extra members are given' do classes.each do |clazz| extra_values = values << 'forty two' expect{ clazz.new(*extra_values) }.to raise_error(ArgumentError) end end end context 'properties' do let!(:anon_struct_members) { [:name, :address, :zip] } let(:anon_struct) { described_class.new(*anon_struct_members) } let!(:named_struct_members) { [:left, :right] } let(:named_struct) do described_class.new("Test#{described_class}Properties".gsub(/::/, ''), *named_struct_members) end context '#length' do it 'returns the number of struct members' do expect(anon_struct.new.length).to eq anon_struct_members.length expect(named_struct.new.length).to eq named_struct_members.length end end context '#members' do it 'returns the struct members as an array of symbols' do expect(anon_struct.new.members).to eq anon_struct_members expect(named_struct.new.members).to eq named_struct_members end it 'returns a different object than the array passed at definition' do expect(anon_struct.new.members.object_id).to_not eq anon_struct_members.object_id expect(named_struct.new.members.object_id).to_not eq named_struct_members.object_id end end context '#size' do it 'returns the number of struct members' do expect(anon_struct.new.size).to eq anon_struct_members.size expect(named_struct.new.size).to eq named_struct_members.size end end context '#values' do it 'returns the values of the struct as an array in order' do expect(anon_struct.new().values).to eq [nil, nil, nil] expect(named_struct.new().values).to eq [nil, nil] expect(anon_struct.new(:foo, :bar, :baz).values).to eq [:foo, :bar, :baz] expect(named_struct.new(:yes, :no).values).to eq [:yes, :no] end end context '#values_at' do let(:anon_struct) do described_class.new(:zero, :one, :two, :three, :four, :five, :six, :seven, :eight, :nine). new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) end let!(:named_struct) do described_class.new("Test#{described_class}ValuesAtAccessor".gsub(/::/, ''), :zero, :one, :two, :three, :four, :five, :six, :seven, :eight, :nine). new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) end it 'returns the value at the given offset' do expect(anon_struct.values_at(3)).to eq [3] expect(named_struct.values_at(7)).to eq [7] end it 'returns the values at multiple given offsets' do expect(anon_struct.values_at(4, 1, 7)).to eq [4, 1, 7] expect(named_struct.values_at(2, 4, 6)).to eq [2, 4, 6] end it 'returns values at offsets in a given range' do expect(anon_struct.values_at(4..7)).to eq [4, 5, 6, 7] expect(named_struct.values_at(1..3)).to eq [1, 2, 3] end it 'returns values for multiple ranges' do expect(anon_struct.values_at(1..3, 4..7)).to eq [1, 2, 3, 4, 5, 6, 7] expect(named_struct.values_at(1..3, 4..7)).to eq [1, 2, 3, 4, 5, 6, 7] end it 'returns values for ranges and offsets' do expect(anon_struct.values_at(1, 2, 3, 4..7)).to eq [1, 2, 3, 4, 5, 6, 7] expect(named_struct.values_at(1, 2, 3, 4..7)).to eq [1, 2, 3, 4, 5, 6, 7] end end end context 'accessors' do let!(:anon_struct_members) { [:name, :address, :zip] } let(:anon_struct) { described_class.new(*anon_struct_members) } let!(:named_struct_members) { [:left, :right] } let(:named_struct) do described_class.new("Test#{described_class}Properties".gsub(/::/, ''), *named_struct_members) end let(:anon_instance){ anon_struct.new('Douglass Adams', 'Earth', 42) } let(:named_instance){ named_struct.new('up', 'down') } context '#[member]' do it 'retrieves the value when given a valid symbol member' do expect(anon_instance[:address]).to eq 'Earth' expect(named_instance[:right]).to eq 'down' end it 'retrieves the value when given a valid string member' do expect(anon_instance['address']).to eq 'Earth' expect(named_instance['right']).to eq 'down' end it 'raises an exception when given a non-existent symbol member' do expect{anon_instance[:foo]}.to raise_error(NameError) expect{named_instance[:bar]}.to raise_error(NameError) end it 'raises an exception when given a non-existent string member' do expect{anon_instance['foo']}.to raise_error(NameError) expect{named_instance['bar']}.to raise_error(NameError) end end context '#[index]' do it 'retrieves the value when given a valid index' do expect(anon_instance[1]).to eq 'Earth' expect(named_instance[1]).to eq 'down' end it 'raises an exception when given an out-of-bound index' do expect{anon_instance[100]}.to raise_error(IndexError) expect{named_instance[100]}.to raise_error(IndexError) end end end context 'comparison' do let(:customer) { described_class.new(:name, :address, :zip) } let(:employer) { described_class.new(:name, :address, :zip) } let!(:joe) { customer.new('Joe Smith', '123 Maple, Anytown NC', 12345) } let!(:joejr) { customer.new('Joe Smith', '123 Maple, Anytown NC', 12345) } let!(:jane) { customer.new('Jane Doe', '456 Elm, Anytown NC', 12345) } let!(:janejr){ employer.new('Jane Doe', '456 Elm, Anytown NC', 12345) } context '#==' do it 'returns true if other has same struct subclass and equal values' do expect(joe == joejr).to be true end it 'returns false if other has different struct subclass' do expect(jane == janejr).to be false end it 'returns false if other has different values' do expect(jane == joe).to be false end end context '#!=' do it 'returns false if other has same struct subclass and equal values' do expect(joe != joejr).to be false end it 'returns true if other has different struct subclass' do expect(jane != janejr).to be true end it 'returns true if other has different values' do expect(jane != joe).to be true end end end context 'enumeration' do let(:members) { [:name, :address, :zip] } let(:values) { ['Joe Smith', '123 Maple, Anytown NC', 12345] } let(:customer) { described_class.new(*members) } let!(:joe) { customer.new(*values) } context '#each' do it 'yields the value of each struct member in order' do index = 0 joe.each do |value| expect(joe[index]).to eq value index += 1 end expect(index).to eq 3 end it 'returns an enumerator when no block is given' do expect(joe.each).to be_a Enumerator end end context '#each_pair' do it 'yields the name and value of each struct member in order' do index = 0 joe.each_pair do |name, value| expect(joe.members[index]).to eq name expect(joe[index]).to eq value index += 1 end expect(index).to eq 3 end it 'returns an enumerator when no block is given' do expect(joe.each_pair).to be_a Enumerator end end context '#select' do it 'yields each value' do index = 0 joe.select do |value| expect(joe[index]).to eq value index += 1 end expect(index).to eq 3 end it 'returns an Array with the values from for which the block returns true' do result = joe.select{|value| value.is_a?(String) } expect(result).to eq ['Joe Smith', '123 Maple, Anytown NC'] end it 'returns an enumerator when no block is given' do expect(joe.select).to be_a Enumerator end end end context 'conversion' do let!(:anon_struct_members) { [:name, :address, :zip] } let(:anon_struct) { described_class.new(*anon_struct_members) } let!(:named_struct_members) { [:left, :right] } let(:named_struct) do described_class.new("Test#{described_class}Properties".gsub(/::/, ''), *named_struct_members) end context '#to_s' do it 'includes the name of the class when registered' do expect(named_struct.new.to_s).to match(/#{named_struct}/) end it 'includes the names of all members' do string = anon_struct.new.to_s anon_struct_members.each do |member| expect(string).to match(/#{member}/) end string = named_struct.new.to_s named_struct_members.each do |member| expect(string).to match(/#{member}/) end end it 'includes all values' do values = [:foo, 'bar', 42] string = anon_struct.new(*values).to_s values.each do |value| expect(string).to match(/#{value}/) end values = ['bar', 42] string = named_struct.new(*values).to_s values.each do |value| expect(string).to match(/#{value}/) end end it 'returns the same string as #inspect' do values = [:foo, 'bar', 42] struct = anon_struct.new(*values) expect(struct.to_s).to eq struct.inspect values = ['bar', 42] struct = named_struct.new(*values) expect(struct.to_s).to eq struct.inspect end end context '#to_a' do it 'returns the to_a for this struct as an array' do expect(anon_struct.new().to_a).to eq [nil, nil, nil] expect(named_struct.new().to_a).to eq [nil, nil] expect(anon_struct.new(:foo, :bar, :baz).to_a).to eq [:foo, :bar, :baz] expect(named_struct.new(:yes, :no).to_a).to eq [:yes, :no] end end context '#to_h' do it 'returns a Hash containing the names and values in order' do expected = {name: nil, address: nil, zip: nil} expect(anon_struct.new().to_h).to eq expected expected = {left: nil, right: nil} expect(named_struct.new().to_h).to eq expected expected = {name: :foo, address: :bar, zip: :baz} expect(anon_struct.new(:foo, :bar, :baz).to_h).to eq expected expected = {left: :yes, right: :no} expect(named_struct.new(:yes, :no).to_h).to eq expected end end end end shared_examples :mergeable_struct do let(:this){ described_class.new(:foo, :bar, :baz).new('foo', nil, nil)} let(:other){ {baz: 42} } context '#merge' do it 'updates all members with the new values from a given hash' do expect(this.merge(other).baz).to eq 42 end it 'calls the given block for each key in `other`' do actual = 0 this = described_class.new(:foo, :bar, :baz).new('foo', :bar, 42) this.merge(bar: :yes, baz: :no){|member, thisval, otherval| actual += 1 } expect(actual).to eq 2 end it 'retains the value for all members not without values in the given hash' do expect(this.merge(other).foo).to eq 'foo' end it 'raises an exception when given a hash with members not in the struct' do expect{this.merge(bogus: true)}.to raise_exception(ArgumentError) end it 'returns a new object' do expect(this.merge(other).object_id).to_not eq this.object_id expect(this.merge(other).object_id).to_not eq other.object_id end end end concurrent-ruby-1.0.5/spec/concurrent/synchronization_spec.rb000066400000000000000000000133541305460430400245770ustar00rootroot00000000000000require 'timeout' module Concurrent describe Synchronization do shared_examples :attr_volatile do specify 'older writes are always visible' do # store = BClass.new store.not_volatile = 0 store.volatile = 0 t1 = Thread.new do Thread.abort_on_exception = true 1000000000.times do |i| store.not_volatile = i store.volatile = i end end t2 = Thread.new do 10.times do volatile = store.volatile not_volatile = store.not_volatile expect(not_volatile).to be >= volatile Thread.pass end end t2.join t1.kill end end describe Synchronization::Object do class AAClass < Synchronization::Object end class ABClass < AAClass safe_initialization! end class ACClass < ABClass end class ADClass < ACClass safe_initialization! end it 'does not ensure visibility when not needed' do expect_any_instance_of(AAClass).not_to receive(:full_memory_barrier) AAClass.new end it "does ensure visibility when specified" do expect_any_instance_of(ABClass).to receive(:full_memory_barrier) ABClass.new end it "does ensure visibility when specified in a parent" do expect_any_instance_of(ACClass).to receive(:full_memory_barrier) ACClass.new end it "does ensure visibility once when specified in child again" do expect_any_instance_of(ADClass).to receive(:full_memory_barrier) ADClass.new end # TODO (pitr 12-Sep-2015): give a whole gem a pass to find classes with final fields without using the convention and migrate Synchronization::Object.ensure_safe_initialization_when_final_fields_are_present class VolatileFieldClass < Synchronization::Object attr_volatile :volatile attr_accessor :not_volatile end let(:store) { VolatileFieldClass.new } it_should_behave_like :attr_volatile end describe Synchronization::LockableObject do class BClass < Synchronization::LockableObject safe_initialization! attr_volatile :volatile attr_accessor :not_volatile def initialize(value = nil) super() @Final = value ns_initialize end def final @Final end def count synchronize { @count += 1 } end def wait(timeout = nil) synchronize { ns_wait(timeout) } end public :synchronize private def ns_initialize @count = 0 end end subject { BClass.new } describe '#wait' do it 'puts the current thread to sleep' do t = Thread.new do Thread.abort_on_exception = true subject.wait end sleep 0.1 expect(t.status).to eq 'sleep' end it 'allows the sleeping thread to be killed' do t = Thread.new do Thread.abort_on_exception = true subject.wait rescue nil end sleep 0.1 t.kill sleep 0.1 expect(t.status).to eq false expect(t.alive?).to eq false end it 'releases the lock on the current object' do expect { Timeout.timeout(3) do t = Thread.new { subject.wait } sleep 0.1 # TODO (pitr-ch 15-Oct-2016): https://travis-ci.org/pitr-ch/concurrent-ruby/jobs/167933569 expect(t.status).to eq 'sleep' subject.synchronize {} # we will deadlock here if #wait doesn't release lock end }.not_to raise_error end it 'can be called from within a #synchronize block' do expect { Timeout.timeout(3) do # #wait should release lock, even if it was already held on entry t = Thread.new { subject.synchronize { subject.wait } } sleep 0.1 expect(t.status).to eq 'sleep' subject.synchronize {} # we will deadlock here if lock wasn't released end }.not_to raise_error end end describe '#synchronize' do it 'allows only one thread to execute count' do threads = 10.times.map { Thread.new(subject) { 100.times { subject.count } } } threads.each(&:join) expect(subject.count).to eq 1001 end end describe 'signaling' do pending 'for now pending, tested pretty well by Event' end specify 'final field always visible' do store = BClass.new 'asd' t1 = Thread.new { 1000000000.times { |i| store = BClass.new i.to_s } } t2 = Thread.new { 10.times { expect(store.final).not_to be_nil; Thread.pass } } t2.join t1.kill end let(:store) { BClass.new } it_should_behave_like :attr_volatile end describe 'Concurrent::Synchronization::Volatile module' do class BareClass include Synchronization::Volatile attr_volatile :volatile attr_accessor :not_volatile end let(:store) { BareClass.new } it_should_behave_like :attr_volatile end describe 'attr_atomic' do specify do a = Class.new(Synchronization::Object) do attr_atomic :a def initialize(*rest) super self.a = :a end end b = Class.new(a) do attr_atomic :b def initialize super self.b = :b end end instance = b.new expect(instance.a).to be == :a expect(instance.b).to be == :b end end end end concurrent-ruby-1.0.5/spec/concurrent/thread_arguments_shared.rb000066400000000000000000000025511305460430400252030ustar00rootroot00000000000000 shared_examples :thread_arguments do it 'passes an empty array when opts is not given' do future = get_ivar_from_no_args expect(future.value).to eq [] end it 'passes an empty array when opts is an empty hash' do future = get_ivar_from_args({}) expect(future.value).to eq [] end it 'passes an empty array when there is no :args key' do future = get_ivar_from_args(foo: 'bar') expect(future.value).to eq [] end it 'passes an empty array when the :args key has a nil value' do future = get_ivar_from_args(args: nil) expect(future.value).to eq [] end it 'passes a one-element array when the :args key has a non-array value' do future = get_ivar_from_args(args: 'foo') expect(future.value).to eq ['foo'] end it 'passes an array when when the :args key has an array value' do expected = [1, 2, 3, 4] future = get_ivar_from_args(args: expected) expect(future.value).to eq expected end it 'passes the given array when the :args key has a complex array value' do expected = [(1..10).to_a, (20..30).to_a, (100..110).to_a] future = get_ivar_from_args(args: expected) expect(future.value).to eq expected end it 'allows the given arguments array to be dereferenced' do expected = [1, 2, 3, 4] future = get_ivar_from_args(args: expected) expect(future.value).to eq expected end end concurrent-ruby-1.0.5/spec/concurrent/thread_safe/000077500000000000000000000000001305460430400222365ustar00rootroot00000000000000concurrent-ruby-1.0.5/spec/concurrent/thread_safe/map_loops_spec.rb000066400000000000000000000361551305460430400256000ustar00rootroot00000000000000Thread.abort_on_exception = true module Concurrent describe 'MapTorture', stress: true, notravis: true do THREAD_COUNT = 40 KEY_COUNT = (((2**13) - 2) * 0.75).to_i # get close to the doubling cliff LOW_KEY_COUNT = (((2**8 ) - 2) * 0.75).to_i # get close to the doubling cliff INITIAL_VALUE_CACHE_SETUP = lambda do |options, keys| cache = Concurrent::Map.new initial_value = options[:initial_value] || 0 keys.each { |key| cache[key] = initial_value } cache end ZERO_VALUE_CACHE_SETUP = lambda do |options, keys| INITIAL_VALUE_CACHE_SETUP.call(options.merge(:initial_value => 0), keys) end DEFAULTS = { key_count: KEY_COUNT, thread_count: THREAD_COUNT, loop_count: 1, prelude: '', cache_setup: lambda { |options, keys| Concurrent::Map.new } } LOW_KEY_COUNT_OPTIONS = {loop_count: 150, key_count: LOW_KEY_COUNT} SINGLE_KEY_COUNT_OPTIONS = {loop_count: 100_000, key_count: 1} it 'concurrency' do code = <<-RUBY_EVAL cache[key] cache[key] = key cache[key] cache.delete(key) RUBY_EVAL do_thread_loop(:concurrency, code) end it '#put_if_absent' do do_thread_loop( :put_if_absent, 'acc += 1 unless cache.put_if_absent(key, key)', key_count: 100_000 ) do |result, cache, options, keys| expect_standard_accumulator_test_result(result, cache, options, keys) end end it '#compute_put_if_absent' do code = <<-RUBY_EVAL if key.even? cache.compute_if_absent(key) { acc += 1; key } else acc += 1 unless cache.put_if_absent(key, key) end RUBY_EVAL do_thread_loop(:compute_if_absent, code) do |result, cache, options, keys| expect_standard_accumulator_test_result(result, cache, options, keys) end end it '#compute_if_absent_and_present' do compute_if_absent_and_present compute_if_absent_and_present(LOW_KEY_COUNT_OPTIONS) compute_if_absent_and_present(SINGLE_KEY_COUNT_OPTIONS) end it 'add_remove_to_zero' do add_remove_to_zero add_remove_to_zero(LOW_KEY_COUNT_OPTIONS) add_remove_to_zero(SINGLE_KEY_COUNT_OPTIONS) end it 'add_remove_to_zero_via_merge_pair' do add_remove_to_zero_via_merge_pair add_remove_to_zero_via_merge_pair(LOW_KEY_COUNT_OPTIONS) add_remove_to_zero_via_merge_pair(SINGLE_KEY_COUNT_OPTIONS) end it 'add_remove' do add_remove add_remove(LOW_KEY_COUNT_OPTIONS) add_remove(SINGLE_KEY_COUNT_OPTIONS) end it 'add_remove_via_compute' do add_remove_via_compute add_remove_via_compute(LOW_KEY_COUNT_OPTIONS) add_remove_via_compute(SINGLE_KEY_COUNT_OPTIONS) end it 'add_remove_via_compute_if_absent_present' do add_remove_via_compute_if_absent_present add_remove_via_compute_if_absent_present(LOW_KEY_COUNT_OPTIONS) add_remove_via_compute_if_absent_present(SINGLE_KEY_COUNT_OPTIONS) end it 'add_remove_indiscriminate' do add_remove_indiscriminate add_remove_indiscriminate(LOW_KEY_COUNT_OPTIONS) add_remove_indiscriminate(SINGLE_KEY_COUNT_OPTIONS) end it 'count_up' do count_up count_up(LOW_KEY_COUNT_OPTIONS) count_up(SINGLE_KEY_COUNT_OPTIONS) end it 'count_up_via_compute' do count_up_via_compute count_up_via_compute(LOW_KEY_COUNT_OPTIONS) count_up_via_compute(SINGLE_KEY_COUNT_OPTIONS) end it 'count_up_via_merge_pair' do count_up_via_merge_pair count_up_via_merge_pair(LOW_KEY_COUNT_OPTIONS) count_up_via_merge_pair(SINGLE_KEY_COUNT_OPTIONS) end it 'count_race' do prelude = 'change = (rand(2) == 1) ? 1 : -1' code = <<-RUBY_EVAL v = cache[key] acc += change if cache.replace_pair(key, v, v + change) RUBY_EVAL do_thread_loop( :count_race, code, loop_count: 5, prelude: prelude, cache_setup: ZERO_VALUE_CACHE_SETUP ) do |result, cache, options, keys| result_sum = sum(result) expect(sum(keys.map { |key| cache[key] })).to eq result_sum expect(sum(cache.values)).to eq result_sum expect(options[:key_count]).to eq cache.size end end it 'get_and_set_new' do code = 'acc += 1 unless cache.get_and_set(key, key)' do_thread_loop(:get_and_set_new, code) do |result, cache, options, keys| expect_standard_accumulator_test_result(result, cache, options, keys) end end it 'get_and_set_existing' do code = 'acc += 1 if cache.get_and_set(key, key) == -1' do_thread_loop( :get_and_set_existing, code, cache_setup: INITIAL_VALUE_CACHE_SETUP, initial_value: -1 ) do |result, cache, options, keys| expect_standard_accumulator_test_result(result, cache, options, keys) end end private def compute_if_absent_and_present(opts = {}) prelude = 'on_present = rand(2) == 1' code = <<-RUBY_EVAL if on_present cache.compute_if_present(key) { |old_value| acc += 1; old_value + 1 } else cache.compute_if_absent(key) { acc += 1; 1 } end RUBY_EVAL do_thread_loop( __method__, code, {loop_count: 5, prelude: prelude}.merge(opts) ) do |result, cache, options, keys| stored_sum = 0 stored_key_count = 0 keys.each do |k| if value = cache[k] stored_sum += value stored_key_count += 1 end end expect(stored_sum).to eq sum(result) expect(stored_key_count).to eq cache.size end end def add_remove(opts = {}) prelude = 'do_add = rand(2) == 1' code = <<-RUBY_EVAL if do_add acc += 1 unless cache.put_if_absent(key, key) else acc -= 1 if cache.delete_pair(key, key) end RUBY_EVAL do_thread_loop( __method__, code, {loop_count: 5, prelude: prelude}.merge(opts) ) do |result, cache, options, keys| expect_all_key_mappings_exist(cache, keys, false) expect(cache.size).to eq sum(result) end end def add_remove_via_compute(opts = {}) prelude = 'do_add = rand(2) == 1' code = <<-RUBY_EVAL cache.compute(key) do |old_value| if do_add acc += 1 unless old_value key else acc -= 1 if old_value nil end end RUBY_EVAL do_thread_loop( __method__, code, {loop_count: 5, prelude: prelude}.merge(opts) ) do |result, cache, options, keys| expect_all_key_mappings_exist(cache, keys, false) expect(cache.size).to eq sum(result) end end def add_remove_via_compute_if_absent_present(opts = {}) prelude = 'do_add = rand(2) == 1' code = <<-RUBY_EVAL if do_add cache.compute_if_absent(key) { acc += 1; key } else cache.compute_if_present(key) { acc -= 1; nil } end RUBY_EVAL do_thread_loop( __method__, code, {loop_count: 5, prelude: prelude}.merge(opts) ) do |result, cache, options, keys| expect_all_key_mappings_exist(cache, keys, false) expect(cache.size).to eq sum(result) end end def add_remove_indiscriminate(opts = {}) prelude = 'do_add = rand(2) == 1' code = <<-RUBY_EVAL if do_add acc += 1 unless cache.put_if_absent(key, key) else acc -= 1 if cache.delete(key) end RUBY_EVAL do_thread_loop( __method__, code, {loop_count: 5, prelude: prelude}.merge(opts) ) do |result, cache, options, keys| expect_all_key_mappings_exist(cache, keys, false) expect(cache.size).to eq sum(result) end end def count_up(opts = {}) code = <<-RUBY_EVAL v = cache[key] acc += 1 if cache.replace_pair(key, v, v + 1) RUBY_EVAL do_thread_loop( __method__, code, {loop_count: 5, cache_setup: ZERO_VALUE_CACHE_SETUP}.merge(opts) ) do |result, cache, options, keys| expect_count_up(result, cache, options, keys) end end def count_up_via_compute(opts = {}) code = <<-RUBY_EVAL cache.compute(key) do |old_value| acc += 1 old_value ? old_value + 1 : 1 end RUBY_EVAL do_thread_loop( __method__, code, {loop_count: 5}.merge(opts) ) do |result, cache, options, keys| expect_count_up(result, cache, options, keys) result.inject(nil) do |previous_value, next_value| # since compute guarantees atomicity all count ups should be equal expect(previous_value).to eq next_value if previous_value next_value end end end def count_up_via_merge_pair(opts = {}) code = <<-RUBY_EVAL cache.merge_pair(key, 1) { |old_value| old_value + 1 } RUBY_EVAL do_thread_loop( __method__, code, {loop_count: 5}.merge(opts) ) do |result, cache, options, keys| all_match = true expected_value = options[:loop_count] * options[:thread_count] keys.each do |key| value = cache[key] if expected_value != value all_match = false break end end expect(all_match).to be_truthy end end def add_remove_to_zero(opts = {}) code = <<-RUBY_EVAL acc += 1 unless cache.put_if_absent(key, key) acc -= 1 if cache.delete_pair(key, key) RUBY_EVAL do_thread_loop( __method__, code, {loop_count: 5}.merge(opts) ) do |result, cache, options, keys| expect_all_key_mappings_exist(cache, keys, false) expect(cache.size).to eq sum(result) end end def add_remove_to_zero_via_merge_pair(opts = {}) code = <<-RUBY_EVAL acc += (cache.merge_pair(key, key) {}) ? 1 : -1 RUBY_EVAL do_thread_loop( __method__, code, {loop_count: 5}.merge(opts) ) do |result, cache, options, keys| expect_all_key_mappings_exist(cache, keys, false) expect(cache.size).to eq sum(result) end end def do_thread_loop(name, code, options = {}, &block) options = DEFAULTS.merge(options) meth = define_loop(name, code, options[:prelude]) keys = to_keys_array(options[:key_count]) run_thread_loop(meth, keys, options, &block) if options[:key_count] > 1 options[:key_count] = (options[:key_count] / 40).to_i keys = to_hash_collision_keys_array(options[:key_count]) run_thread_loop( meth, keys, options.merge(loop_count: options[:loop_count] * 5), &block ) end end def run_thread_loop(meth, keys, options, &block) cache = options[:cache_setup].call(options, keys) barrier = Concurrent::ThreadSafe::Test::Barrier.new(options[:thread_count]) result = (1..options[:thread_count]).map do Thread.new do setup_sync_and_start_loop( meth, cache, keys, barrier, options[:loop_count] ) end end.map(&:value) block.call(result, cache, options, keys) if block_given? end def setup_sync_and_start_loop(meth, cache, keys, barrier, loop_count) my_keys = keys.shuffle barrier.await if my_keys.size == 1 key = my_keys.first send("#{meth}_single_key", cache, key, loop_count) else send("#{meth}_multiple_keys", cache, my_keys, loop_count) end end def define_loop(name, body, prelude) inner_meth_name = :"_#{name}_loop_inner" outer_meth_name = :"_#{name}_loop_outer" # looping is splitted into the "loop methods" to trigger the JIT self.class.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 def #{inner_meth_name}_multiple_keys(cache, keys, i, length, acc) #{prelude} target = i + length while i < target key = keys[i] #{body} i += 1 end acc end unless method_defined?(:#{inner_meth_name}_multiple_keys) RUBY_EVAL self.class.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 def #{inner_meth_name}_single_key(cache, key, i, length, acc) #{prelude} target = i + length while i < target #{body} i += 1 end acc end unless method_defined?(:#{inner_meth_name}_single_key) RUBY_EVAL self.class.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 def #{outer_meth_name}_multiple_keys(cache, keys, loop_count) total_length = keys.size acc = 0 inc = 100 loop_count.times do i = 0 pre_loop_inc = total_length % inc acc = #{inner_meth_name}_multiple_keys(cache, keys, i, pre_loop_inc, acc) i += pre_loop_inc while i < total_length acc = #{inner_meth_name}_multiple_keys(cache, keys, i, inc, acc) i += inc end end acc end unless method_defined?(:#{outer_meth_name}_multiple_keys) RUBY_EVAL self.class.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 def #{outer_meth_name}_single_key(cache, key, loop_count) acc = 0 i = 0 inc = 100 pre_loop_inc = loop_count % inc acc = #{inner_meth_name}_single_key(cache, key, i, pre_loop_inc, acc) i += pre_loop_inc while i < loop_count acc = #{inner_meth_name}_single_key(cache, key, i, inc, acc) i += inc end acc end unless method_defined?(:#{outer_meth_name}_single_key) RUBY_EVAL outer_meth_name end def to_keys_array(key_count) arr = [] key_count.times {|i| arr << i} arr end def to_hash_collision_keys_array(key_count) to_keys_array(key_count).map { |key| Concurrent::ThreadSafe::Test::HashCollisionKey(key) } end def sum(result) result.inject(0) { |acc, i| acc + i } end def expect_standard_accumulator_test_result(result, cache, options, keys) expect_all_key_mappings_exist(cache, keys) expect(options[:key_count]).to eq sum(result) expect(options[:key_count]).to eq cache.size end def expect_all_key_mappings_exist(cache, keys, all_must_exist = true) keys.each do |key| value = cache[key] if value || all_must_exist expect(key).to eq value unless key == value # don't do a bazzilion assertions unless necessary end end end def expect_count_up(result, cache, options, keys) keys.each do |key| value = cache[key] expect(value).to be_truthy unless value end expect(sum(cache.values)).to eq sum(result) expect(options[:key_count]).to eq cache.size end end unless RUBY_ENGINE == 'rbx' || ENV['TRAVIS'] end concurrent-ruby-1.0.5/spec/concurrent/thread_safe/no_unsafe_spec.rb000066400000000000000000000015611305460430400255550ustar00rootroot00000000000000if defined?(JRUBY_VERSION) && ENV['TEST_NO_UNSAFE'] # to be used like this: rake test TEST_NO_UNSAFE=true load 'test/package.jar' java_import 'thread_safe.SecurityManager' manager = SecurityManager.new # Prevent accessing internal classes manager.deny(java.lang.RuntimePermission.new('accessClassInPackage.sun.misc')) java.lang.System.setSecurityManager(manager) module Concurrent describe 'no_unsafe' do it 'security_manager_is_used' do begin java_import 'sun.misc.Unsafe' fail rescue SecurityError end end it 'no_unsafe_version_of_chmv8_is_used' do require 'concurrent/thread_safe/jruby_cache_backend' # make sure the jar has been loaded expect(!Java::OrgJrubyExtThread_safe::JRubyMapBackendLibrary::JRubyMapBackend::CAN_USE_UNSAFE_CHM).to be_truthy end end end end concurrent-ruby-1.0.5/spec/concurrent/thread_safe/synchronized_delegator_spec.rb000066400000000000000000000034721305460430400303500ustar00rootroot00000000000000require 'concurrent/thread_safe/synchronized_delegator.rb' module Concurrent describe SynchronizedDelegator do it 'wraps array' do array = ::Array.new sync_array = described_class.new(array) array << 1 expect(1).to eq sync_array[0] sync_array << 2 expect(2).to eq array[1] end it 'synchronizes access' do t1_continue, t2_continue = false, false hash = ::Hash.new do |hash, key| t2_continue = true unless hash.find { |e| e[1] == key.to_s } # just to do something hash[key] = key.to_s Thread.pass until t1_continue end end sync_hash = described_class.new(hash) sync_hash[1] = 'egy' t1 = Thread.new do sync_hash[2] = 'dva' sync_hash[3] # triggers t2_continue end t2 = Thread.new do Thread.pass until t2_continue sync_hash[4] = '42' end sleep(0.05) # sleep some to allow threads to boot until t2.status == 'sleep' do Thread.pass end expect(3).to eq hash.keys.size t1_continue = true t1.join; t2.join expect(4).to eq sync_hash.size end it 'synchronizes access with block' do t1_continue, t2_continue = false, false array = ::Array.new sync_array = described_class.new(array) t1 = Thread.new do sync_array << 1 sync_array.each do t2_continue = true Thread.pass until t1_continue end end t2 = Thread.new do # sleep(0.01) Thread.pass until t2_continue sync_array << 2 end until t2.status == 'sleep' || t2.status == false Thread.pass end expect(1).to eq array.size t1_continue = true t1.join; t2.join expect([1, 2]).to eq array end end end concurrent-ruby-1.0.5/spec/concurrent/timer_task_spec.rb000066400000000000000000000171621305460430400235010ustar00rootroot00000000000000require_relative 'concern/dereferenceable_shared' require_relative 'concern/observable_shared' module Concurrent describe TimerTask do context :dereferenceable do def kill_subject @subject.kill if @subject rescue Exception => ex # prevent exceptions with mocks in tests end after(:each) do kill_subject end def dereferenceable_subject(value, opts = {}) kill_subject opts = opts.merge(execution_interval: 0.1, run_now: true) @subject = TimerTask.new(opts) { value }.execute.tap { sleep(0.1) } end def dereferenceable_observable(opts = {}) opts = opts.merge(execution_interval: 0.1, run_now: true) @subject = TimerTask.new(opts) { 'value' } end def execute_dereferenceable(subject) subject.execute sleep(0.1) end it_should_behave_like :dereferenceable end context :observable do subject { TimerTask.new(execution_interval: 0.1) { nil } } after(:each) { subject.kill } def trigger_observable(observable) observable.execute sleep(0.2) end it_should_behave_like :observable end context 'created with #new' do context '#initialize' do it 'raises an exception if no block given' do expect { Concurrent::TimerTask.new }.to raise_error(ArgumentError) end it 'raises an exception if :execution_interval is not greater than zero' do expect { Concurrent::TimerTask.new(execution_interval: 0) { nil } }.to raise_error(ArgumentError) end it 'raises an exception if :execution_interval is not an integer' do expect { Concurrent::TimerTask.new(execution_interval: 'one') { nil } }.to raise_error(ArgumentError) end it 'raises an exception if :timeout_interval is not greater than zero' do expect { Concurrent::TimerTask.new(timeout_interval: 0) { nil } }.to raise_error(ArgumentError) end it 'raises an exception if :timeout_interval is not an integer' do expect { Concurrent::TimerTask.new(timeout_interval: 'one') { nil } }.to raise_error(ArgumentError) end it 'uses the default execution interval when no interval is given' do subject = TimerTask.new { nil } expect(subject.execution_interval).to eq TimerTask::EXECUTION_INTERVAL end it 'uses the default timeout interval when no interval is given' do subject = TimerTask.new { nil } expect(subject.timeout_interval).to eq TimerTask::TIMEOUT_INTERVAL end it 'uses the given execution interval' do subject = TimerTask.new(execution_interval: 5) { nil } expect(subject.execution_interval).to eq 5 end it 'uses the given timeout interval' do subject = TimerTask.new(timeout_interval: 5) { nil } expect(subject.timeout_interval).to eq 5 end end context '#kill' do it 'returns true on success' do task = TimerTask.execute(run_now: false) { nil } sleep(0.1) expect(task.kill).to be_truthy end end context '#shutdown' do it 'returns true on success' do task = TimerTask.execute(run_now: false) { nil } sleep(0.1) expect(task.shutdown).to be_truthy end end end context 'arguments' do it 'raises an exception if no block given' do expect { Concurrent::TimerTask.execute }.to raise_error end specify '#execution_interval is writeable' do latch = CountDownLatch.new(1) subject = TimerTask.new(timeout_interval: 1, execution_interval: 1, run_now: true) do |task| task.execution_interval = 3 latch.count_down end expect(subject.execution_interval).to eq(1) subject.execution_interval = 0.1 expect(subject.execution_interval).to eq(0.1) subject.execute latch.wait(0.2) expect(subject.execution_interval).to eq(3) subject.kill end specify '#timeout_interval is writeable' do latch = CountDownLatch.new(1) subject = TimerTask.new(timeout_interval: 1, execution_interval: 0.1, run_now: true) do |task| task.timeout_interval = 3 latch.count_down end expect(subject.timeout_interval).to eq(1) subject.timeout_interval = 2 expect(subject.timeout_interval).to eq(2) subject.execute latch.wait(0.2) expect(subject.timeout_interval).to eq(3) subject.kill end end context 'execution' do it 'runs the block immediately when the :run_now option is true' do latch = CountDownLatch.new(1) subject = TimerTask.execute(execution: 500, now: true) { latch.count_down } expect(latch.wait(1)).to be_truthy subject.kill end it 'waits for :execution_interval seconds when the :run_now option is false' do latch = CountDownLatch.new(1) subject = TimerTask.execute(execution: 0.1, now: false) { latch.count_down } expect(latch.count).to eq 1 expect(latch.wait(1)).to be_truthy subject.kill end it 'waits for :execution_interval seconds when the :run_now option is not given' do latch = CountDownLatch.new(1) subject = TimerTask.execute(execution: 0.1, now: false) { latch.count_down } expect(latch.count).to eq 1 expect(latch.wait(1)).to be_truthy subject.kill end it 'passes a "self" reference to the block as the sole argument' do expected = nil latch = CountDownLatch.new(1) subject = TimerTask.new(execution_interval: 1, run_now: true) do |task| expected = task latch.sount_down end subject.execute latch.wait(1) expect(expected).to eq subject subject.kill end end context 'observation' do let(:observer) do Class.new do attr_reader :time attr_reader :value attr_reader :ex attr_reader :latch define_method(:initialize) { @latch = CountDownLatch.new(1) } define_method(:update) do |time, value, ex| @time = time @value = value @ex = ex @latch.count_down end end.new end it 'notifies all observers on success' do subject = TimerTask.new(execution: 0.1) { 42 } subject.add_observer(observer) subject.execute observer.latch.wait(1) expect(observer.value).to eq(42) expect(observer.ex).to be_nil subject.kill end it 'notifies all observers on timeout' do subject = TimerTask.new(execution: 0.1, timeout: 0.1) { sleep } subject.add_observer(observer) subject.execute observer.latch.wait(1) expect(observer.value).to be_nil expect(observer.ex).to be_a(Concurrent::TimeoutError) subject.kill end it 'notifies all observers on error' do subject = TimerTask.new(execution: 0.1) { raise ArgumentError } subject.add_observer(observer) subject.execute observer.latch.wait(1) expect(observer.value).to be_nil expect(observer.ex).to be_a(ArgumentError) subject.kill end end end end concurrent-ruby-1.0.5/spec/concurrent/tvar_spec.rb000066400000000000000000000102031305460430400223000ustar00rootroot00000000000000module Concurrent describe TVar do context '#initialize' do it 'accepts an initial value' do t = TVar.new(14) expect(t.value).to eq 14 end end context '#value' do it 'gets the value' do t = TVar.new(14) expect(t.value).to eq 14 end end context '#value=' do it 'sets the value' do t = TVar.new(14) t.value = 2 expect(t.value).to eq 2 end end end describe '#atomically' do it 'raises an exception when no block given' do expect { Concurrent::atomically }.to raise_error(ArgumentError) end it 'raises the same exception that was raised in Concurrent::atomically' do expect { Concurrent::atomically do raise StandardError, 'This is an error!' end }.to raise_error(StandardError, 'This is an error!') end it 'retries on abort' do count = 0 Concurrent::atomically do if count == 0 count = 1 Concurrent::abort_transaction else count = 2 end end expect(count).to eq 2 end it 'commits writes if the transaction succeeds' do t = TVar.new(0) Concurrent::atomically do t.value = 1 end expect(t.value).to eq 1 end it 'undoes writes if the transaction is aborted' do t = TVar.new(0) count = 0 Concurrent::atomically do if count == 0 t.value = 1 count = 1 Concurrent::abort_transaction end end expect(t.value).to eq 0 end it 'provides atomicity' do t1 = TVar.new(0) t2 = TVar.new(0) count = 0 Concurrent::atomically do if count == 0 count = 1 t1.value = 1 Concurrent::abort_transaction t2.value = 2 end end expect(t1.value).to eq 0 expect(t2.value).to eq 0 end it 'provides weak isolation' do t = TVar.new(0) a = CountDownLatch.new b = CountDownLatch.new Thread.new do Concurrent::atomically do t.value = 1 a.count_down b.wait Concurrent.leave_transaction end end Concurrent::atomically do a.wait expect(t.value).to eq 0 b.count_down Concurrent.leave_transaction end end it 'is implemented with lazy writes' do t = TVar.new(0) a = CountDownLatch.new b = CountDownLatch.new Thread.new do Concurrent::atomically do t.value = 1 a.count_down b.wait end end a.wait expect(t.value).to eq 0 b.count_down end it 'nests' do t = TVar.new(0) Concurrent::atomically do expect(t.value).to eq 0 t.value = 1 Concurrent::atomically do expect(t.value).to eq 1 t.value = 2 Concurrent::atomically do expect(t.value).to eq 2 t.value = 3 end expect(t.value).to eq 3 t.value = 4 end expect(t.value).to eq 4 t.value = 5 end expect(t.value).to eq 5 end it 'reflects transactional writes from within the same transaction' do t = TVar.new(0) Concurrent::atomically do expect(t.value).to eq 0 t.value = 14 expect(t.value).to eq 14 t.value = 2 expect(t.value).to eq 2 end end end describe '#abort_transaction' do it 'raises an exception outside an #atomically block' do expect { Concurrent::abort_transaction }.to raise_error(Concurrent::Transaction::AbortError) end end describe '#leave_transaction' do it 'raises an exception outside an #atomically block' do expect { Concurrent::leave_transaction }.to raise_error(Concurrent::Transaction::LeaveError) end it 'neither commits nor aborts a transaction' do t = TVar.new(0) Concurrent::atomically do expect(t.value).to eq 0 t.value = 14 Concurrent::leave_transaction end expect(t.value).to eq 0 end end end concurrent-ruby-1.0.5/spec/concurrent/utility/000077500000000000000000000000001305460430400214745ustar00rootroot00000000000000concurrent-ruby-1.0.5/spec/concurrent/utility/processor_count_spec.rb000066400000000000000000000006751305460430400262720ustar00rootroot00000000000000module Concurrent describe '#processor_count' do it 'retuns a positive integer' do expect(Concurrent::processor_count).to be_a Integer expect(Concurrent::processor_count).to be >= 1 end end describe '#physical_processor_count' do it 'retuns a positive integer' do expect(Concurrent::physical_processor_count).to be_a Integer expect(Concurrent::physical_processor_count).to be >= 1 end end end concurrent-ruby-1.0.5/spec/spec_helper.rb000066400000000000000000000014751305460430400204340ustar00rootroot00000000000000if ENV['COVERAGE'] require 'simplecov' require 'coveralls' if ENV['TRAVIS'] SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[ SimpleCov::Formatter::HTMLFormatter, Coveralls::SimpleCov::Formatter ] else SimpleCov.formatter = SimpleCov::Formatter::HTMLFormatter end SimpleCov.start do project_name 'concurrent-ruby' add_filter '/build-tests/' add_filter '/examples/' add_filter '/spec/' end end require 'concurrent' require 'concurrent-edge' Concurrent.use_simple_logger Logger::FATAL # import all the support files Dir[File.join(File.dirname(__FILE__), 'support/**/*.rb')].each { |f| require File.expand_path(f) } RSpec.configure do |config| #config.raise_errors_for_deprecations! config.filter_run_excluding stress: true config.order = 'random' end concurrent-ruby-1.0.5/spec/support/000077500000000000000000000000001305460430400173235ustar00rootroot00000000000000concurrent-ruby-1.0.5/spec/support/.gitignore000066400000000000000000000000001305460430400213010ustar00rootroot00000000000000concurrent-ruby-1.0.5/spec/support/example_group_extensions.rb000066400000000000000000000024351305460430400250020ustar00rootroot00000000000000require 'rbconfig' require 'concurrent/synchronization' module Concurrent module TestHelpers extend self def delta(v1, v2) if block_given? v1 = yield(v1) v2 = yield(v2) end return (v1 - v2).abs end include Utility::EngineDetector def use_c_extensions? Concurrent.allow_c_extensions? end GLOBAL_EXECUTORS = [ [:GLOBAL_FAST_EXECUTOR, -> { Delay.new { Concurrent.new_fast_executor(auto_terminate: true) } }], [:GLOBAL_IO_EXECUTOR, -> { Delay.new { Concurrent.new_io_executor(auto_terminate: true) } }], [:GLOBAL_TIMER_SET, -> { Delay.new { Concurrent::TimerSet.new(auto_terminate: true) } }], ] def reset_gem_configuration GLOBAL_EXECUTORS.each do |var, factory| executor = Concurrent.const_get(var).value! executor.shutdown executor.wait_for_termination(0.2) executor.kill Concurrent.const_set(var, factory.call) end end def monotonic_interval raise ArgumentError.new('no block given') unless block_given? start_time = GLOBAL_MONOTONIC_CLOCK.get_time yield GLOBAL_MONOTONIC_CLOCK.get_time - start_time end end end class RSpec::Core::ExampleGroup include Concurrent::TestHelpers extend Concurrent::TestHelpers end concurrent-ruby-1.0.5/spec/support/less_than_or_equal_to_matcher.rb000066400000000000000000000001631305460430400257240ustar00rootroot00000000000000RSpec::Matchers.define :be_less_than_or_equal_to do |expected| match do |actual| actual <= expected end endconcurrent-ruby-1.0.5/spec/support/threads.rb000066400000000000000000000000551305460430400213020ustar00rootroot00000000000000THREADS = (RUBY_ENGINE == 'ruby' ? 100 : 10) concurrent-ruby-1.0.5/spec/support/threadsafe_test.rb000066400000000000000000000032361305460430400230210ustar00rootroot00000000000000module Concurrent module ThreadSafe module Test class Barrier def initialize(count = 1) @count = count @mutex = Mutex.new @cond = ConditionVariable.new end def release @mutex.synchronize do @count -= 1 if @count > 0 @cond.broadcast if @count.zero? end end def await @mutex.synchronize do if @count.zero? # fall through elsif @count > 0 @count -= 1 @count.zero? ? @cond.broadcast : @cond.wait(@mutex) end end end end class HashCollisionKey attr_reader :hash, :key def initialize(key, hash = key.hash % 3) @key = key @hash = hash end def eql?(other) other.kind_of?(self.class) && @key.eql?(other.key) end def even? @key.even? end def <=>(other) @key <=> other.key end end # having 4 separate HCK classes helps for a more thorough CHMV8 testing class HashCollisionKey2 < HashCollisionKey; end class HashCollisionKeyNoCompare < HashCollisionKey def <=>(other) 0 end end class HashCollisionKey4 < HashCollisionKeyNoCompare; end HASH_COLLISION_CLASSES = [HashCollisionKey, HashCollisionKey2, HashCollisionKeyNoCompare, HashCollisionKey4] def self.HashCollisionKey(key, hash = key.hash % 3) HASH_COLLISION_CLASSES[rand(4)].new(key, hash) end class HashCollisionKeyNonComparable < HashCollisionKey undef <=> end end end end concurrent-ruby-1.0.5/support/000077500000000000000000000000001305460430400163715ustar00rootroot00000000000000concurrent-ruby-1.0.5/support/file_map.rb000066400000000000000000000011001305460430400204620ustar00rootroot00000000000000module FileMap GIT_FILES = `git ls-files`.split("\n") ALL_LIB_FILES = Dir['lib/concurrent/**/*.rb'] & GIT_FILES EDGE_LIB_FILES = Dir['lib/concurrent/actor.rb', 'lib/concurrent/actor/**/*.rb', 'lib/concurrent/channel.rb', 'lib/concurrent/channel/**/*.rb', 'lib/concurrent/edge/**/*.rb'] & GIT_FILES CORE_LIB_FILES = ALL_LIB_FILES - EDGE_LIB_FILES MAP = { core: CORE_LIB_FILES + %w(lib/concurrent.rb), edge: EDGE_LIB_FILES + %w(lib/concurrent-edge.rb) } end concurrent-ruby-1.0.5/support/publish-concurrent-ruby.rb000077500000000000000000000011161305460430400235250ustar00rootroot00000000000000#!/usr/bin/env ruby # get the current gem version require_relative './lib/concurrent/version' GEMS = [ "concurrent-ruby-#{Concurrent::VERSION}.gem", "concurrent-ruby-#{Concurrent::VERSION}-java.gem", "concurrent-ruby-ext-#{Concurrent::VERSION}.gem", "concurrent-ruby-ext-#{Concurrent::VERSION}-x86-mingw32.gem", "concurrent-ruby-ext-#{Concurrent::VERSION}-x64-mingw32.gem", "concurrent-ruby-edge-#{Concurrent::EDGE_VERSION}.gem", ] GEMS.each do |gem| file = File.join("pkg", gem) basename = File.basename(file) puts "Publishing #{basename}..." `gem push #{file}` end concurrent-ruby-1.0.5/support/release.sh000077500000000000000000000106331305460430400203530ustar00rootroot00000000000000#!/usr/bin/env bash set -e log() { echo "[release] $@" } if [[ pitr != $(whoami) ]] then log "!!! This script takes a lot of assumptions based on @pitr-ch's environment." log "!!! Use it at your own risk." fi version=$(ruby -r ./lib/concurrent/version -e 'puts Concurrent::VERSION') edge_version=$(ruby -r ./lib/concurrent/version -e 'puts Concurrent::EDGE_VERSION') (echo ${version} | grep pre) && prerelease='true' || prerelease='false' log "concurrent-ruby: $version" log "concurrent-ruby-edge: $edge_version" log "prerelease: $prerelease" set -x mriVersion="2.4.0" jrubyVersion="jruby-9.1.7.0" if [[ "$@" =~ 'build' || $@ =~ 'all' ]] then log Building rbenv versions | grep $mriVersion export RBENV_VERSION=$mriVersion docker-machine status | grep Running || docker-machine start eval $(docker-machine env --shell sh default) rbenv version bundle install bundle exec rake clean bundle exec rake build docker-machine stop rbenv versions | grep $jrubyVersion export RBENV_VERSION=$jrubyVersion rbenv version rm Gemfile.lock || true bundle install bundle exec rake clean bundle exec rake build fi if [[ "$@" =~ "test" ]] #|| $@ =~ 'all' ]] then log Testing # TODO (pitr-ch 24-Feb-2017): fix it's unreliable cd .. # TODO (pitr-ch 17-Dec-2016): dry: duplicates rake task rspec_options='--color --backtrace --seed 1 --format documentation --tag ~unfinished --tag ~notravis --tag ~buggy' # Install and test MRI version export RBENV_VERSION=$mriVersion gem install concurrent-ruby/pkg/concurrent-ruby-${version}.gem gem install concurrent-ruby/pkg/concurrent-ruby-edge-${edge_version}.gem gem install concurrent-ruby/pkg/concurrent-ruby-ext-${version}.gem ruby -r concurrent-edge -I concurrent-ruby/spec -r spec_helper -S rspec concurrent-ruby/spec ${rspec_options} gem uninstall concurrent-ruby-ext --version ${version} gem uninstall concurrent-ruby-edge --version ${edge_version} gem uninstall concurrent-ruby --version ${version} # Install and test JRuby version export RBENV_VERSION=$jrubyVersion gem install concurrent-ruby/pkg/concurrent-ruby-${version}-java.gem gem install concurrent-ruby/pkg/concurrent-ruby-edge-${edge_version}.gem ruby -r concurrent-edge -S rspec concurrent-ruby/spec ${rspec_options} gem uninstall concurrent-ruby-edge --version ${edge_version} gem uninstall concurrent-ruby --version ${version} cd concurrent-ruby # TODO (pitr-ch 17-Dec-2016): test windows build fi if [[ "$@" =~ "push" || $@ =~ 'all' ]] then log Pushing # Test that we are on pushed commit git fetch test -z "$(git log --oneline master..upstream/master)" test -z "$(git log --oneline upstream/master..master)" # Tags git tag "v${version}" git tag "edge-v${edge_version}" git push --tags # Push to rubygems gem push pkg/concurrent-ruby-${version}.gem gem push pkg/concurrent-ruby-${version}-java.gem gem push pkg/concurrent-ruby-edge-${edge_version}.gem gem push pkg/concurrent-ruby-ext-${version}.gem gem push pkg/concurrent-ruby-ext-${version}-x64-mingw32.gem gem push pkg/concurrent-ruby-ext-${version}-x86-mingw32.gem fi if [[ "$@" =~ "notify" || $@ =~ 'all' ]] then log "Notifying" log "TODO: create release" # TODO (pitr-ch 16-Dec-2016): Release # Patch release. # # concurrent-ruby: # # - Nothing # # concurrent-ruby-edge: # # - New promises' API renamed, lots of improvements, edge bumped to 0.3.0 # - Incompatible with previous 0.2.3 version log "TODO: send email same as release" # TODO (pitr-ch 17-Dec-2016): send email # same as release # Update documentation # TODO (pitr-ch 24-Feb-2017): check bundle exec rake yard:push # https://developer.github.com/v3/repos/releases/#create-a-release # token=$(cat .githubtoken) #curl -X POST \ # -H "Authorization: token ${token}" \ # -H "Content-Type: application/json" \ # -H "Cache-Control: no-cache" \ # -d "{ # \"tag_name\": \"v0.1\", # \"target_commitish\": \"master\", # \"name\": \"v0.1\", # \"body\": \"Description of the release\", # \"draft\": true, # \"prerelease\": ${prerelease} # }" \ # "https://api.github.com/repos/pitr-ch/concurrent-ruby/releases" fi concurrent-ruby-1.0.5/tasks/000077500000000000000000000000001305460430400160025ustar00rootroot00000000000000concurrent-ruby-1.0.5/tasks/metrics.rake000066400000000000000000000003551305460430400203170ustar00rootroot00000000000000unless defined?(JRUBY_VERSION) desc 'Display LOC (lines of code) report' task :loc do puts `countloc -r lib` end desc 'Display code quality analysis report' task :critic do sh 'rubycritic lib --path critic' end end concurrent-ruby-1.0.5/tasks/update_doc.rake000066400000000000000000000052161305460430400207610ustar00rootroot00000000000000require 'yard' require 'md_ruby_eval' # TODO (pitr-ch 23-Feb-2017): find a proper place module YARD module Templates::Helpers # The helper module for HTML templates. module HtmlHelper def signature_types(meth, link = true) meth = convert_method_to_overload(meth) if meth.respond_to?(:object) && !meth.has_tag?(:return) meth = meth.object end type = options.default_return || "" if meth.tag(:return) && meth.tag(:return).types types = meth.tags(:return).map { |t| t.types ? t.types : [] }.flatten.uniq first = link ? h(types.first) : format_types([types.first], false) # if types.size == 2 && types.last == 'nil' # type = first + '?' # elsif types.size == 2 && types.last =~ /^(Array)?<#{Regexp.quote types.first}>$/ # type = first + '+' # elsif types.size > 2 # type = [first, '...'].join(', ') if types == ['void'] && options.hide_void_return type = "" else type = link ? h(types.join(", ")) : format_types(types, false) end elsif !type.empty? type = link ? h(type) : format_types([type], false) end type = "(#{type}) " unless type.empty? type end end end end root = File.expand_path File.join(File.dirname(__FILE__), '..') cmd = lambda do |command| puts ">> executing: #{command}" puts ">> in: #{Dir.pwd}" system command or raise "#{command} failed" end yard_doc = YARD::Rake::YardocTask.new(:yard) yard_doc.before = -> do Dir.chdir File.join(__dir__, '..', 'doc') do cmd.call 'bundle exec md-ruby-eval --auto' or raise end end namespace :yard do desc 'Pushes generated documentation to github pages: http://ruby-concurrency.github.io/concurrent-ruby/' task :push => [:setup, :yard] do message = Dir.chdir(root) do `git log -n 1 --oneline`.strip end puts "Generating commit: #{message}" Dir.chdir "#{root}/yardoc" do cmd.call "git add -A" cmd.call "git commit -m '#{message}'" cmd.call 'git push origin gh-pages' end end desc 'Setups second clone in ./yardoc dir for pushing doc to github' task :setup do unless File.exist? "#{root}/yardoc/.git" cmd.call "rm -rf #{root}/yardoc" if File.exist?("#{root}/yardoc") Dir.chdir "#{root}" do cmd.call 'git clone --single-branch --branch gh-pages git@github.com:ruby-concurrency/concurrent-ruby.git ./yardoc' end end Dir.chdir "#{root}/yardoc" do cmd.call 'git fetch origin' cmd.call 'git reset --hard origin/gh-pages' end end end concurrent-ruby-1.0.5/yard-template/000077500000000000000000000000001305460430400174255ustar00rootroot00000000000000concurrent-ruby-1.0.5/yard-template/default/000077500000000000000000000000001305460430400210515ustar00rootroot00000000000000concurrent-ruby-1.0.5/yard-template/default/fulldoc/000077500000000000000000000000001305460430400225015ustar00rootroot00000000000000concurrent-ruby-1.0.5/yard-template/default/fulldoc/html/000077500000000000000000000000001305460430400234455ustar00rootroot00000000000000concurrent-ruby-1.0.5/yard-template/default/fulldoc/html/css/000077500000000000000000000000001305460430400242355ustar00rootroot00000000000000concurrent-ruby-1.0.5/yard-template/default/fulldoc/html/css/common.css000066400000000000000000000043471305460430400262470ustar00rootroot00000000000000/* Override this file with custom rules */ body { line-height: 18px; } .docstring h1:before { content: '# '; color: silver; } .docstring h2:before { content: '## '; color: silver; } .docstring code, .docstring .object_link a, #filecontents code { padding: 0px 3px 1px 3px; border: 1px solid #eef; background: #f5f5ff; } #filecontents pre code, .docstring pre code { border: none; background: none; padding: 0; } #filecontents pre.code, .docstring pre.code, .tags pre.example, .docstring code, .docstring .object_link a, #filecontents code { -moz-border-radius: 2px; -webkit-border-radius: 2px; } /* syntax highlighting */ .source_code { display: none; padding: 3px 8px; border-left: 8px solid #ddd; margin-top: 5px; } #filecontents pre.code, .docstring pre.code, .source_code pre { font-family: monospace; } #filecontents pre.code, .docstring pre.code { display: block; } .source_code .lines { padding-right: 12px; color: #555; text-align: right; } #filecontents pre.code, .docstring pre.code, .tags pre.example { padding: 5px 12px; margin-top: 4px; border: 1px solid #eef; background: #f5f5ff; } pre.code { color: #000; } pre.code .info.file { color: #555; } pre.code .val { color: #036A07; } pre.code .tstring_content, pre.code .heredoc_beg, pre.code .heredoc_end, pre.code .qwords_beg, pre.code .qwords_end, pre.code .tstring, pre.code .dstring { color: #036A07; } pre.code .fid, pre.code .rubyid_new, pre.code .rubyid_to_s, pre.code .rubyid_to_sym, pre.code .rubyid_to_f, pre.code .rubyid_to_i, pre.code .rubyid_each { color: inherit; } pre.code .comment { color: #777; font-style: italic; } pre.code .const, pre.code .constant { color: inherit; font-weight: bold; font-style: italic; } pre.code .label, pre.code .symbol { color: #C5060B; } pre.code .kw, pre.code .rubyid_require, pre.code .rubyid_extend, pre.code .rubyid_include, pre.code .int { color: #0000FF; } pre.code .ivar { color: #660E7A; } pre.code .gvar, pre.code .rubyid_backref, pre.code .rubyid_nth_ref { color: #6D79DE; } pre.code .regexp, .dregexp { color: #036A07; } pre.code a { border-bottom: 1px dotted #bbf; } concurrent-ruby-1.0.5/yard-template/default/layout/000077500000000000000000000000001305460430400223665ustar00rootroot00000000000000concurrent-ruby-1.0.5/yard-template/default/layout/html/000077500000000000000000000000001305460430400233325ustar00rootroot00000000000000concurrent-ruby-1.0.5/yard-template/default/layout/html/footer.erb000066400000000000000000000012001305460430400253130ustar00rootroot00000000000000