From 27090cbf4a4b43794bbd87ea47ba11519f336135 Mon Sep 17 00:00:00 2001 From: Lucas Mazza Date: Sat, 19 Sep 2020 17:43:23 -0300 Subject: [PATCH 01/12] New blog, who dis --- .gitignore | 2 + .gitmodules | 3 + README.md | 1 + assets/css/overrides.css | 110 ++++++++++ bin/publish | 29 +++ config.yaml | 67 ++++++ content/about.md | 86 ++++++++ ...27-flushing-content-blocks-with-rails-4.md | 78 +++++++ ...25-extending-customizing-3rd-party-code.md | 79 ++++++++ ...es-from-rails-4-1-that-im-excited-about.md | 69 +++++++ .../posts/2014-08-13-css-at-plataformatec.md | 54 +++++ ...11-nobody-told-me-minitest-was-this-fun.md | 191 ++++++++++++++++++ content/posts/2015-09-22-custom-elements.md | 191 ++++++++++++++++++ content/posts/2015-10-01-revising-talks.md | 77 +++++++ content/posts/2015-11-24-multiverse.md | 46 +++++ content/posts/2015-12-31-books-from-2015.md | 81 ++++++++ ...nting-with-explicit-contracts-with-ruby.md | 179 ++++++++++++++++ content/posts/2018-02-20-git-field-guide.md | 126 ++++++++++++ content/talks/2012-07-02-design.md | 8 + content/talks/2013-04-09-documentation.md | 13 ++ content/talks/2013-04-11-plataformatecway.md | 15 ++ content/talks/2013-06-22-boxen.md | 17 ++ content/talks/2013-08-29-rails-front-end.md | 14 ++ content/talks/2013-10-19-oss.md | 10 + content/talks/2013-11-23-manutencao-css.md | 15 ++ content/talks/2014-05-20-sass.md | 10 + content/talks/2014-08-09-photoshop-meh.md | 15 ++ content/talks/2014-09-04-devise-en.md | 16 ++ content/talks/2014-09-13-devise-pt.md | 17 ++ content/talks/2014-11-08-front-end-rails.md | 15 ++ content/talks/2015-09-18-tools.md | 9 + content/talks/2015-10-17-10-coisas.md | 14 ++ content/talks/2016-07-23-minitest.md | 14 ++ .../2016-09-24-zen-and-art-of-refactoring.md | 20 ++ content/talks/2016-11-19-circuit-breakers.md | 9 + content/talks/2018-02-24-testes.md | 21 ++ content/talks/2018-08-25-feature-toggles.md | 21 ++ content/talks/2019-07-06-ecto-sem-sql.md | 11 + static/CNAME | 1 + .../favicons/apple-touch-icon-precomposed.png | Bin 0 -> 831 bytes static/favicons/favicon.ico | Bin 0 -> 340 bytes static/images/companies/cdc.jpg | Bin 0 -> 4128 bytes static/images/companies/magnetis.jpg | Bin 0 -> 1996 bytes static/images/companies/plataformatec.jpg | Bin 0 -> 7618 bytes static/images/companies/podium.jpg | Bin 0 -> 1357 bytes static/images/headshot.jpg | Bin 0 -> 103380 bytes static/template.zip | Bin 0 -> 40088 bytes themes/anatole | 1 + 48 files changed, 1755 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 README.md create mode 100644 assets/css/overrides.css create mode 100755 bin/publish create mode 100644 config.yaml create mode 100644 content/about.md create mode 100644 content/posts/2012-06-27-flushing-content-blocks-with-rails-4.md create mode 100644 content/posts/2013-02-25-extending-customizing-3rd-party-code.md create mode 100644 content/posts/2014-04-08-3-features-from-rails-4-1-that-im-excited-about.md create mode 100644 content/posts/2014-08-13-css-at-plataformatec.md create mode 100644 content/posts/2015-05-11-nobody-told-me-minitest-was-this-fun.md create mode 100644 content/posts/2015-09-22-custom-elements.md create mode 100644 content/posts/2015-10-01-revising-talks.md create mode 100644 content/posts/2015-11-24-multiverse.md create mode 100644 content/posts/2015-12-31-books-from-2015.md create mode 100644 content/posts/2016-02-29-experimenting-with-explicit-contracts-with-ruby.md create mode 100644 content/posts/2018-02-20-git-field-guide.md create mode 100644 content/talks/2012-07-02-design.md create mode 100644 content/talks/2013-04-09-documentation.md create mode 100644 content/talks/2013-04-11-plataformatecway.md create mode 100644 content/talks/2013-06-22-boxen.md create mode 100644 content/talks/2013-08-29-rails-front-end.md create mode 100644 content/talks/2013-10-19-oss.md create mode 100644 content/talks/2013-11-23-manutencao-css.md create mode 100644 content/talks/2014-05-20-sass.md create mode 100644 content/talks/2014-08-09-photoshop-meh.md create mode 100644 content/talks/2014-09-04-devise-en.md create mode 100644 content/talks/2014-09-13-devise-pt.md create mode 100644 content/talks/2014-11-08-front-end-rails.md create mode 100644 content/talks/2015-09-18-tools.md create mode 100644 content/talks/2015-10-17-10-coisas.md create mode 100644 content/talks/2016-07-23-minitest.md create mode 100644 content/talks/2016-09-24-zen-and-art-of-refactoring.md create mode 100644 content/talks/2016-11-19-circuit-breakers.md create mode 100644 content/talks/2018-02-24-testes.md create mode 100644 content/talks/2018-08-25-feature-toggles.md create mode 100644 content/talks/2019-07-06-ecto-sem-sql.md create mode 100644 static/CNAME create mode 100644 static/favicons/apple-touch-icon-precomposed.png create mode 100644 static/favicons/favicon.ico create mode 100644 static/images/companies/cdc.jpg create mode 100644 static/images/companies/magnetis.jpg create mode 100644 static/images/companies/plataformatec.jpg create mode 100644 static/images/companies/podium.jpg create mode 100644 static/images/headshot.jpg create mode 100644 static/template.zip create mode 160000 themes/anatole diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4636c6c --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +public +themes diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..b1b9af4 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "themes/anatole"] + path = themes/anatole + url = https://github.com/lxndrblz/anatole.git diff --git a/README.md b/README.md new file mode 100644 index 0000000..d4b6fa2 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +The source code of [https://afterhours.io](https://afterhours.io). diff --git a/assets/css/overrides.css b/assets/css/overrides.css new file mode 100644 index 0000000..06b4d3d --- /dev/null +++ b/assets/css/overrides.css @@ -0,0 +1,110 @@ +:root { + --custom-link-color: #af4849; + --custom-lighter-link-color: #C96263; + --custom-darker-link-color: #962F30; +} + +a:hover, +a:active { + color: var(--custom-link-color); +} + +.sidebar .logo-title .title h3, +.post .post-title h3 { + text-transform: none; +} + +.fadeInDown { + animation-name: none; +} + +.sidebar .logo-title .title a, +.post .post-title a, +.post .post-content a, +.list-with-title .listing .listing-post a { + color: var(--custom-link-color); +} + +.sidebar .logo-title .title a:hover, +.sidebar .social-links a:hover, +.post .post-title a:hover, +.post .post-content a:hover, +.list-with-title .listing .listing-post a:hover, +.page-top .nav a:hover { + color: var(--custom-darker-link-color); +} + +.page-top .nav a.current { + position: relative; + font-weight: bold; + color: var(--custom-link-color); + border-bottom-color: var(--custom-link-color); +} + +.page-top .nav a.current::after { + content: ""; + width: 100%; + height: 2px; + position: absolute; + bottom: 0; + left: 0; + background-color: var(--custom-link-color); +} + +ul > li { + margin: .5em 0; +} + +.post .post-footer .meta .info .date { margin-left: 10px; } + +html[data-theme="light"] .highlight > pre { + background-color: #f6f8fa !important; + border: 1px solid #DDDFE1; +} + +.highlight > pre { + border-radius: 6px; + padding: 16px; +} + +@media screen and (min-width: 960px) { + .sidebar { width: 30%; } + + .content, .page-top { width: 70%; } +} + +.yt-iframe { + display: block; + margin: 3em auto; +} + +.speakerdeck-embed-wrapper { + width: calc(100% - 6em); + margin: 3em auto; +} + +.heading-with-icon { + display: flex; + align-items: center; +} + +.heading-with-icon img { + max-height: 1.5em; + margin: 0 .5em 0 0; +} + +html[data-theme="dark"] .heading-with-icon img { + border-radius: 3px; + border: 1px solid #000; +} + +.heading-with-icon a { + margin-right: .5em; +} + +@media print { + .social-links, + .sidebar { display: none; } + + .content { margin-top: 0; } +} diff --git a/bin/publish b/bin/publish new file mode 100755 index 0000000..69f5b87 --- /dev/null +++ b/bin/publish @@ -0,0 +1,29 @@ + +#!/bin/sh + +if [ "`git status -s`" ] +then + echo "The working directory is dirty. Please commit any pending changes." + exit 1; +fi + +echo "Deleting old publication" +rm -rf public +mkdir public +git worktree prune +rm -rf .git/worktrees/public/ + +echo "Checking out gh-pages branch into public" +git worktree add -B gh-pages public origin/gh-pages + +echo "Removing existing files" +rm -rf public/* + +echo "Generating site" +hugo + +echo "Updating gh-pages branch" +cd public && git add --all && git commit -m "Publishing to gh-pages (bin/publish)" + +echo "Pushing to GitHub" +git push --all diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..ad5bea0 --- /dev/null +++ b/config.yaml @@ -0,0 +1,67 @@ +baseURL: https://afterhours.io/ +disablePathToLower: true +languageCode: en-us +title: Lucas Mazza +theme: anatole + +markup: + highlight: + style: github + goldmark: + renderer: + unsafe: true + +params: + title: "Lucas Mazza" + author: "Lucas Mazza" + description: "Software Engineer, coffee enthusiast, absent blogger" + profilePicture: "images/headshot.jpg" + customCss: + - css/overrides.css + + socialIcons: + - icon: fa-twitter + title: Twitter + url: 'https://twitter.com/lucasmazza' + - icon: fa-github + title: GitHub + url: 'https://github.com/lucasmazza' + - icon: fa-instagram + title: instagram + url: 'https://www.instagram.com/lucasmazza' + - icon: fa-envelope + title: e-mail + url: 'mailto:lucasmazza@hey.com' + +permalinks: + talks: '/talks/:slug' + +menu: + main: + - name: Home + url: / + identifier: home + weight: 100 + + - name: Posts + url: /posts/ + identifier: posts + weight: 200 + + - name: Presentations + url: /talks/ + identifier: talks + weight: 300 + + - name: About + url: /about/ + identifier: about + weight: 400 + + - name: 'Livro HTML5 e CSS 3 (pt-BR)' + url: 'https://afterhours.io/htmlcss-exemplos' + weight: 500 + + - name: Receitas (pt-BR) + url: 'https://www.notion.so/Receitas-79a5a48a2350465dad3c57ba866f95d4' + weight: 600 diff --git a/content/about.md b/content/about.md new file mode 100644 index 0000000..e30fd48 --- /dev/null +++ b/content/about.md @@ -0,0 +1,86 @@ +--- +title: Hello, I'm Lucas 👋 +--- + +## I currently live in São Paulo, Brazil and I work with web development + +I have experience doing consulting projects and product development with both [Ruby](http://www.ruby-lang.org) +and [Elixir](https://elixir-lang.org) and a deep interest on making development work +easier through automation, development tools and monitoring. + +Outside of work you can find me enjoying specialty coffee, cooking and some casual +gaming sessions. + +## On the internet + +* [GitHub](https://github.com/lucasmazza): Open source projects and contributions. +* [Twitter](https://twitter.com/lucasmazza): Occasional tweets, pt-BR or en-US. +* [Instagram](https://instagram.com/lucasmazza): mostly food pictures. +* [Presentations](/presentations/): Collection of slide decks. +* [E-mail](mailto:lucasmazza@hey.com): for everything else. + +## Experience + +

+ + Podium +

+ +#### Senior Software Engineer, since 2020 - São Paulo, Brazil / Remote + +At Podium I'm part of the Reviews team that is responsible for the maintenance of +the backend services that powers our Reviews product. + +

+ + Magnetis +

+ +#### Senior Software Engineer and Team Leader, 2017 to 2020 - São Paulo, Brazil / Remote + +As a Software Engineer, I've helped to adopt [Elixir](https://elixir-lang.org) and [Phoenix](http://www.phoenixframework.org) +for new systems, improve our Kubernetes clustering setup and level up the code +review practices of the engineering team. + +Later, as the Team Leader of the Platform team, I worked on projects improving +the integration between our product and [Easynvest](https://easynvest.com.br), +while laying ground work of our own investment broker system. The team went from +2 full time engineers to 8 people working on Elixir and Kubernetes to put the +new services online and Ruby to integrate with the existing user facing application. + +

+ + Plataformatec +

+ +#### Software Developer, 2012 to 2017 - São Paulo, Brazil + +At Plataformatec I worked on consulting projects involving greenfield development +of new Ruby on Rails systems and maintenance on apps requiring new features, +performance work and version upgrades. As the company grew over the years, I've +participated on planning and execution of our recruiting expansion and the mentoring +of new hires on Ruby, JavaScript and Git. + +I was involved on the maintenance and ownership of the company open source libraries, +[Devise](https://github.com/heartcombo/devise) and [Simple Form](https://github.com/heartcombo/simple_form), +and also had the opportunity of creating new projects like the [Faraday HTTP Cache](https://github.com/sourcelevel/faraday-http-cache) gem. + +I've bootstraped an internal tool called Ebert that was spun into its own product, +[SourceLevel](https://sourcelevel.io), working on development, infrastructure +customer support for the product by myself for almost an year. + +## Publications + +

+ + + HTML5 e CSS3: Domine a Web do Futuro + + Jul 31, 2012 +

+ + +The book is an introduction to HTML and CSS syntax along with common patterns to +design UI elements like button groups, forms and media elements, using pseudo +selectors to draw icons and avoiding code pitfalls that newcomers usually stumble +upon. diff --git a/content/posts/2012-06-27-flushing-content-blocks-with-rails-4.md b/content/posts/2012-06-27-flushing-content-blocks-with-rails-4.md new file mode 100644 index 0000000..2ef497f --- /dev/null +++ b/content/posts/2012-06-27-flushing-content-blocks-with-rails-4.md @@ -0,0 +1,78 @@ +--- +date: "2012-06-27" +summary: "Old trick with the Action Pack `content_for` helper" +title: Flushing content blocks with Rails 4 +--- + +Besides the big and shiny features that Rails 4 holds, there's a lot of small improvements on several other sections of the Rails framework - helpers, core extensions, app configurations and more - that might not even hit the Changelogs but will somehow make our lifes easier in the future. One of these hidden gems that I've found recently is an improvement on the `content_for` helper to flush and replace previous chunks of HTML with new ones. + +### The `content_for` that we are used to + +The `content_for` method is an old friend of every Rails developer, and it's a pretty simple and flexible helper. You can store a chunk of HTML from a String or a block, and grab it somewhere else in your views or `yield` it directly into your templates. It's a pretty handy trick to move data from your views into your layouts, like page titles, custom meta tags or specific `script` tags that your page needs to include. + +```erb +# On your 'application.html.erb' layout, inside the '' tag. +<%= yield :metatags %> + +# Then, into a specific view +<% content_for :metatags do %> + +<% end %> +``` + +Multiple calls of the `content_for` helper using the same identifier will concatenate them and output them together when you read it back on your views, as: + +```erb +<% content_for :example, "This will be rendered" %> +<% content_for :example do %> +

This will be rendered too!

+<% end %> +``` + +On some scenarios this behavior might not be desired, and with Rails 4 you can flush out the stored pieces of an identifier and replace it instead of adding more content to it: using the `flush: true` option. The [first implementation](https://github.com/rails/rails/pull/4226) used an extra `true` argument, but [we changed](https://github.com/rails/rails/pull/7150) to use a Hash instead, so the `flush` key can express better the behavior we're expecting. + +```erb +<% content_for :example, "This will be rendered" %> +<% content_for :example, flush: true do %> +

But this will override everything on the ':example' block.

+<% end %> +``` + +### The gallery situation + +I've stumbled upon this on a recent project, where we had a somewhat classic scenario: a partial named `_gallery`, responsible for rendering the piece of HTML to display a gallery of images that also supplies a `content_for` block with a `script` tag to include the required libraries to put the gallery to work. + +```erb + +<% content_for :scripts, javascript_include_tag('gallery') %> +``` + +It works like a charm. But with an updated requirement we had the case where multiple galleries could be present on the same page, rendering the `_gallery` partial several times. The required HTML would be present, but the `gallery.js` script would be included multiple times into the rendered page. Instead of working this out using instance variables to check that the partial was rendered at least once, we could let Rails do all the hard work for us, using the `flush` option when including the `gallery.js` script. + +```erb + +<% # We can render this partial several times and this script will be included just once %> +<% content_for :scripts, javascript_include_tag('gallery'), flush: true %> +``` + +### Back to the present: Rails 3.2 + +Well, while this seems to be a perfect solution to my problem, this feature isn't available on Rails 3.2 or on the `3-2-stable` branch - it's only available on the `master` branch that will be released with Rails 4. But, backporting this feature into a 3.x application is pretty simple, using a helper of your own. + +```ruby +def single_content_for(name, content = nil, &block) + @view_flow.set(name, ActiveSupport::SafeBuffer.new) + content_for(name, content, &block) +end +``` + +After some source diving into the ActionPack source code we're done - it just needs to replace any present content with a brand new `SafeBuffer` instance before storing the piece of HTML. + +What do you think about this little addition to Rails 4? Can you think of a similar problem that could be solved with this instead of a custom hack? + +> This post was originally published at +> http://blog.plataformatec.com.br/2012/07/flushing-content-blocks-with-rails-4/ diff --git a/content/posts/2013-02-25-extending-customizing-3rd-party-code.md b/content/posts/2013-02-25-extending-customizing-3rd-party-code.md new file mode 100644 index 0000000..c07f4b1 --- /dev/null +++ b/content/posts/2013-02-25-extending-customizing-3rd-party-code.md @@ -0,0 +1,79 @@ +--- +date: "2013-02-25" +summary: "Thoughts on dealing with code dependencies" +title: Extending and customizing 3rd party code +--- + +We have a gem available for every kind of feature or scenario we might face in our applications and that may help us focus our development time on things that are more important to our applications. But, every now and then, these packaged solutions aren't exactly what we need, and some sort of customization needs to be done on top of that - a different authentication strategy, new ways to query for data and several different things that our business rules might require. + +So, we jump on top of the existing code to bend it to our needs but sometimes things can go south and we end up in a mess of hacks, unstable code and bad experiences. After some time, we started to develop a few guidelines of our own to avoid the mistakes of the past and look forward to write better applications. These are some of the ideas that I follow to avoid complications when dealing with 3rd party code: + +## Don't fear the source + +The source code and its documentation are your best friends on this. Having a local clone of a dependency repository lets you `ack`/`grep` it inside out to see how the code is structured to identify the good and bad parts to mess with. You can test your changes against its test suite to see if you might break something or not and that's already one step closer to contribute back to the project. + +## Respect method visibility + +Method visibility is an important tool to ensure that you aren't messing with the wrong pieces of code from a gem. Public and protected methods are meant to be overriden when necessary, but private ones aren't. They are usually doing the work that you don't want the trouble to do it yourself, and maybe that's why you are using the dependency after all. + +For example, `ActiveRecord` adds a lot of private methods to handle the persistence of your models that you shouldn't mess with, but the public API is stable enough for you to use it for whatever you need. + +## Monkey patch at your own peril + +Ruby lets you monkey patch everything but that doesn't mean you should. While this might make a lot of sense for libraries that extend the Ruby stdlib (like `ActiveSupport`), monkey patching someone else constant might bite you back later. Overusing monkey patches might be a serious block when updating your application to newer versions of a big dependency of your project (for example, Rails). + +When you monkey patch, you are usually messing with a very internal piece of a component that might be far from it's public API. So, you can't predict how that class or module will behave when a new version is released or what other parts of the code are using that internal API. Classes get renamed and refactored everyday, and it's hard to ensure your patches will keep up with those changes. + +## Composition (and inheritance) as extension mechanisms + +A lot of gems provide a series of configuration options that you can drop in an initializer and get the behavior you need, or maybe a specific configuration might be missing. You might feel the urge to send a pull request adding a new configuration to the project, but hold that idea for a second. Can't you do it by overriding a method or using a custom component of your own? + +Inheritance and composition can be a better choice for a lot of customizations since they are easier to test and to isolate the effects on your application. While a configuration setting is global and affects your entire application, an isolated change will have a much smaller impact on your code. + +Take for instance the `to_param` and `to_partial_path` methods from `ActiveModel`. You can override them in your models to change how your views will interact with them, and that goes in a per model basis, since you usually won't do that for your entire application. Imagine if you need to change a configuration instead overriding a method: You would have to do something weird like this: + +```ruby +# A regular configuration inside an initializer +config.action_view.parameterize_method = :slug + +# But what if I need a per model configuration? Well, use a Hash! +config.action_view.parameterize_methods = { post: :slug, user: :id } +``` + +While just overriding the `to_param` method in your `Post` model is a lot easier than this. + +Another example of composition I came across recently was the `tokenizer` option on the `LengthValidator`. Given that you have a description column in your database that accepts HTML tags like `strong` and `em`, and you want to validate the length of the text, but not the HTML, you can provide an object that responds to `call` and strips away the HTML from the string, so the validation will be executed against the raw text instead of the whole HTML of it. + +```ruby +class MyOwnTokenizer + def call(text) + # do whatever you need with `text`. + end +end + +# on your model… +validates :description, :length { tokenizer: MyOwnTokenizer.new } +``` + +## Your code, your problem + +Remember to test your changes. Once you change a default behavior or tweak some specific configuration that might have side effects on other parts of your application, your test coverage will help ensure that this behavior won't break once you update a dependency on your project. + +You usually shouldn't worry about testing library defaults (like testing the validations on your models that you configured with `ActiveModel` validation methods), but once you customize something, that piece of code is your responsibility. + +So, if you added your own `tokenizer` use along with a `LengthValidator` on your application, be sure to write at least an unit test for it to ensure that it works as expected. + +## Contribute back + +Sometimes you might notice (or need) an improvement to a library that won't change anything on its public API but will make your life easier when extending it. You can't expect that the maintainers will discover every spot that can or might be overriden, so it's important to bring your experience on using it to the table and help others. You can extract a specific behavior to an isolated component, or improve some internal logic so it might be easier to extend it in the future. There's nothing but love for such kind of contribution. + +A while ago [this pull request](https://github.com/rails/rails/pull/3636) changed how Rails added the associations proxies to a model that is using `belongs_to` and friends. While it didn't changes a single bit about the public API for the associations, it changed how you can extend them to add your specific behavior. + +## Wrapping Up + +These steps might not fit everyone’s workflow, but we need to keep in mind that dealing with external dependencies requires a thoughtful approach to avoid the results being harmful to your projects. + +And what about you, my fellow developer: how do you approach the need for something more than a gem's default behavior? Jump on our comments thread to discuss more about it. + +> This post was originally published at +> http://blog.plataformatec.com.br/2013/02/extending-customizing-3rd-party-code/ diff --git a/content/posts/2014-04-08-3-features-from-rails-4-1-that-im-excited-about.md b/content/posts/2014-04-08-3-features-from-rails-4-1-that-im-excited-about.md new file mode 100644 index 0000000..c4ac5f5 --- /dev/null +++ b/content/posts/2014-04-08-3-features-from-rails-4-1-that-im-excited-about.md @@ -0,0 +1,69 @@ +--- +date: "2014-04-08" +summary: "A quick rundown over some Rails 4.1 features" +title: 3 features from Rails 4.1 that I'm excited about +--- + +Rails 4.1 was just released this week and I already had a great experience trying out the release candidates on my latest project, so I decided to write a bit about my favorites features on this release and some things I have learned by using them so far. + +### 1) secrets.yml + +Placing your configuration in a YAML file isn't exactly a revolutionary feature, but the usage of the `config/secrets.yml` file that comes with Rails 4.1 holds a more important idea: the promise of a default approach for environment aware custom configuration on Rails applications. Over the years the community created several ways to manage such configuration so every app out there deals with this differently, but now we can use the Rails default as a standard just like we do with the app folder or the routing patterns, taking the configuration madness outside the list of things to worry about when working with Rails. So instead of dealing with multiple YAML files or constants left out inside initializers, we can go with the `secrets.yml` as the default for our apps. + +Remember that you can place any kind of configuration - not just secrets like tokens or passwords - that need to be handled differently through your application environments, like API Endpoints or S3 bucket names. And for any gem maintainers out there, you can make your gem read these settings from the `secrets.yml` automagically through an [initializer](https://github.com/plataformatec/devise/blob/6027787930224b7c5306a15a81c26e9a7c21fe89/lib/devise/rails.rb#L32-L45) block and maybe remove a configuration step from the gem setup. Adding this to Devise on [this pull request](https://github.com/plataformatec/devise/pull/2835) was easier than I expected and I suggest you to try it out on your gems as well. + +If you want to try to organize your configuration through the `secrets.yml` without having to update to Rails 4.1 right now, Andrew White backported this feature on the [rails-secrets](https://github.com/pixeltrix/rails-secrets) gem for Rails 4.0 apps. + +So, if you are dealing with some configuration mess or aren't using something like [dotenv](https://github.com/bkeepers/dotenv) for your application, I strongly suggest that you try to migrate your config to use the `secrets.yml` file and see how it goes for your application. + +### 2) Action Pack Variants + +Variants are proving to be a great solution to render device specific views when mixed with any device detection solution like the [useragent](https://github.com/josh/useragent) or [browser](https://github.com/fnando/browser) gems, which you integrate quickly with just a `before_action` block: + +```ruby +class ApplicationController < ActionController::Base + before_action :set_variant + + private + + def set_variant + if browser.tablet? + request.variant = :tablet + elsif browser.mobile? + request.variant = :mobile + else + request.variant = :desktop + end + end +end +``` + +Even though the main examples are dealing with User Agent sniffing, this feature can be used in any context where you want to have more control of which views are rendered by your application, like: + +* A/B Testing different partials based on the user cookies. +* API versioning for your Jbuilder templates. +* Maintaining current and redesigned views for the same controller. +* Authorization aware views, like `users/index.html+admin.erb` or `products/show.html+guest.erb`. + +In the end, Variants are just a way for you to have more control over how your views will be used by the app, helping you to remove boilerplate logic from your code and letting the framework handle it through a more elegant solution. + +### 3) The improved cookies serializer + +The changes on how Rails serializes cookies are a great improvement when it comes to security and stability of web apps. Before this, any object placed in the cookies Hash would be serialized (and deserialized) through `Marshal.dump` and `Marshal.load`, which could possibly lead to remote code execution if an attacker got hold on your application secret. + +Now this serializer is configurable through the `config.action_dispatch.cookies_serializer` configuration option, and new apps will ship with a smarter default: a JSON serializer that won't recreate complex objects besides Strings, Integers and other JSON data types. And for a smooth upgrade, you can use the `:hybrid` serializer that will convert your existing marshalled cookies into JSON cookies, so this upgrade can be transparent for your application users. + +This upgrade highlights a possible bad practice in our applications where we end up placing more complex objects in the session that can't be completely restored by the JSON serializer, when we should be using more simple structures for the data stored in cookies. Thanks to a related issue reported on the [Devise](https://github.com/plataformatec/devise) issue tracker we could simplify the gem code a bit, so instead of serializing `Time` objects we could [work with numbers](https://github.com/plataformatec/devise/pull/2954). + +So, when updating your application to use the `:hybrid` serializer, don't forget to do a double check of whatever kind of data the app stores in your users cookies and look for possible backwards incompatibility. And if you want to take a closer look on how this was implemented, be sure to check the related issues and pull requests on the Rails repo: [#12881](https://github.com/rails/rails/issues/12881), [#13692](https://github.com/rails/rails/pull/13692) and [#13945](https://github.com/rails/rails/pull/13945). + +### Keeping up to date with the latest Rails changes + +Following the activity on the Rails repository over GitHub helped a lot to understand better these features and the rationale behind their implementations, but going through all the commits and discussions on Issues and Pull Requests would demand a lot of your time. If you want some of the inside scoop but don't have that much time to go through the Rails activity over the week, [Godfrey Chan](https://twitter.com/chancancode) has put up a weekly digest about Rails named [This Week in Rails](http://rails-weekly.goodbits.io/). I suggest that you subscribe to the list and even check some of the previous editions on the archive page. + +### Try it yourself! + +Take some time and upgrade one of your Rails 4 apps and try out some of the new features! I bet that some of them will help you improve your codebase or make your coworkers life a bit easier, and we are eager to hear from your experience with the 4.1 release. + +> This post was originally published at +> http://blog.plataformatec.com.br/2014/04/3-features-from-rails-4-1-that-im-excited-about/ diff --git a/content/posts/2014-08-13-css-at-plataformatec.md b/content/posts/2014-08-13-css-at-plataformatec.md new file mode 100644 index 0000000..8da0891 --- /dev/null +++ b/content/posts/2014-08-13-css-at-plataformatec.md @@ -0,0 +1,54 @@ +--- +date: "2014-08-13" +summary: A quick walkthrough on how we wrote CSS back in 2014 +title: CSS at Plataformatec +--- + +Last month some amazing developers gave a sneak peek on how they write CSS in their companies - Mark Otto has written about [CSS at GitHub](http://markdotto.com/2014/07/23/githubs-css), followed by Ian Feather's post about [Lonely Planet's CSS](http://ianfeather.co.uk/css-at-lonely-planet/) and Chris Coyier write up about [CodePen's code](http://codepen.io/chriscoyier/blog/codepens-css) - so I thought about sharing a bit of how we have been doing CSS in our projects here at Plataformatec over the last years. + +After working on different projects with different styles of CSS, we wrote some [Guidelines](http://guidelines.plataformatec.com.br/css.html) of what kind of code we would like to work with. These guidelines and some other practices have proven to be successful so far, and I want to tell you a bit about how we are doing this here. + +### Quick Facts + +* We use SCSS. +* We usually just have [Normalize.css](https://github.com/necolas/normalize.css/) (and sometimes [Bootstrap](http://getbootstrap.com)) as third party dependencies. +* Every developer in our team can jump through the codebase and work on our front end code. + +### Preprocessors and the Pipeline + +We have always used Sass (with the SCSS syntax), using most of the Sass features wherever seemed fit and without making the code too complex to grasp so developers outside the project - or without a long experience with preprocessors - could get things done right after jumping in the code. + +We do our best to use the most of the [Rails Asset Pipeline](http://guides.rubyonrails.org/asset_pipeline.html). I know that it isn't the most beloved Rails feature out there, but we are pretty happy with it. The Sprockets + Rails integration in Rails 4 is way better than it was before (you can read a bit about what was done on [this post](http://yetimedia.tumblr.com/post/33320732456/moving-forward-with-the-rails-asset-pipeline)), thanks to the work of [Guillermo](https://github.com/guilleiguaran), [Rafael](https://github.com/rafaelfranca) and [Richard](https://github.com/schneems) (the Sprocket heroes) and everybody else who contributed to [sprockets-rails](https://github.com/rails/sprockets-rails/graphs/contributors), and things will only get better on future releases. If you had a hard time with a Rails 3 app, I recommend that you try it out the latest releases and see what have improved. + +### Architecture + +We don't have strict guidelines about how we should organize and architect our CSS code, but we have some general rules and conventions. We organize most of our code into isolated partial stylesheets under something like `modules` or `components`. And we also break functions, mixins and generic placeholders into specific files and `@import` everything on the application `application.css.scss` file. + +We do our best to keep our selectors small and using only classes, somewhat based on [Wealthfront post on Functional CSS](http://eng.wealthfront.com/2013/08/functional-css-fcss.html) and OOCSS-ish. With this setup we can avoid complex nested blocks and keep things quite readable for everybody. + +### Linting + +We don't have a specific guideline on linting, but I have been experimenting with [SCSS Lint](https://github.com/causes/scss-lint) on the project that I’m current working on, and I want to evolve this into a default configuration for future projects. + +### Frameworks + +We have some different setup across our projects, but we usually just have [Normalize.css](https://github.com/necolas/normalize.css/) as our "reset" stylesheet and everything else is custom made - buttons, grids, typography rules, etc. And of all the existing CSS frameworks out there, we had some encounters with [Bootstrap](http://getbootstrap.com) and [Foundation](http://foundation.zurb.com) once. + +### Documentation + +We love documentation - not obvious code comments, but real documentation that makes easier to understand how to use a specific piece of code. + +We started writing docs for our CSS to make more sense out of a SCSS partial, so through a single file we can understand how the application can use those styles. We have adopted some loose form of the [KSS](http://warpspire.com/kss/) syntax, because we currently don't care about generating pretty styleguides with live examples of the styles in use. But the KSS format is human-readable enough and does the job of explaining the purpose of a set of classes to someone. + +### Sprites + +Last year I created a gem called [Spriteful](http://github.com/lucasmazza/spriteful) to help us manage the image sprites in some projects without having to bring [Compass](http://compass-style.org) and [compass-rails](https://github.com/Compass/compass-rails) as dependencies to our pipeline. Spriteful has proven useful to me and my coworkers, and now we can generate sprites and SCSS partials out of icons and SVG images with just a single command. + +Some close friends from outside the company have used it on their projects and it's awesome that someone else has found our little tool handy for this task. + +### Who's in charge? + +One important aspect of how we work is that every developer in the team is capable to work with the front end code of the application and build new things or fix existing bugs, not just turn some static markup into ERB blocks. This provides a higher sense of collective ownership of the code, instead of enlisting one or two programmers who are in charge of half of the application while everybody else works elsewhere without caring about that layer. + +> This post was originally published at +> http://blog.plataformatec.com.br/2014/08/css-at-plataformatec/ diff --git a/content/posts/2015-05-11-nobody-told-me-minitest-was-this-fun.md b/content/posts/2015-05-11-nobody-told-me-minitest-was-this-fun.md new file mode 100644 index 0000000..13ae783 --- /dev/null +++ b/content/posts/2015-05-11-nobody-told-me-minitest-was-this-fun.md @@ -0,0 +1,191 @@ +--- +date: "2015-05-11" +summary: Where the author kinda regrets getting too attached to RSpec +title: Nobody told me Minitest was this fun +--- + +Ever since I started working with Ruby I have been using RSpec to test my apps and gems without giving minitest much thought. Recently I started a new non-Rails project and decided to give Minitest a try just for the fun of it. Migrating from one tool to another was refreshingly fun due to the fact that that Minitest and RSpec aren't so different from each other - they both have the basic features that we need in a testing library to get things running, and if you are used to testing your code moving from one to the other might not be so scary as you might expect. + +## Translating testing idioms + +One of the first things that I looked into was how some of common RSpec idioms should be implemented when using Minitest. + +The classic ones are fairly simple: the `before` and `after` lifecycle hooks should be equivalent as implementing the `setup` and `teardown` methods in your test class, and you have control over the inheritance chain by selecting when/where to call `super`. `let` and `subject` can be achieved with methods that use memoization to cache their values. + +```ruby +# A classic RSpec subject/before usage. +require 'spec_helper' + +describe Post do + subject(:post) { Post.new } + before { post.publish! } +end + +# The equivalent with Minitest & Ruby. +require 'test_helper' + +class PostTest < Minitest::Test + def post + @post ||= Post.new + end + + def setup + post.publish! + end +end +``` + + +RSpec shared examples, where you can reuse a set of examples across your test suite, can be replicated by simply writing your tests in modules and depend on accessor methods to inject any objects your tests might depend on + +```ruby +# What used to be a shared_examples 'Serialization' can be a module... +module SerializationTests + def serializer + raise NotImplementedError + end +end + +# And your test cases can include that module to copy the tests +class JSONSerializationTest < Minitest::Test + include SerializationTests + + def serializer + JSON + end +end + +class MarshalSerializationTest < Minitest::Test + include SerializationTests + + def serializer + Marshal + end +end +``` + +Mocks and stubs, which are incredibly flexible when using RSpec, are available in Minitest without any third party gem: + +```ruby +class PostTest < Minitest::Test + def test_notifies_on_publish + notifier = Minitest::Mock.new + notifier.expect :notify!, true + + post.publish!(notifier: notifier) + notifier.verify + end + + def test_does_not_notifies_on_republish + notifier = Minitest::Mock.new + + post.stub :published?, true do + post.publish!(notifier: notifier) + notifier.verify + end + end +end +``` + +If you want a different or more fluent API, you can use something like [`mocha`](https://github.com/freerange/mocha) to improve your mocks, or even bring RSpec API into the mix - with some manual setup you can pick the [`rspec-mocks`](https://github.com/rspec/rspec-mocks) gem and define your mocks and stubs just like when using the complete RSpec tooling: + +```ruby +require 'rspec/mocks' + +class PostTest < Minitest::Test + include ::RSpec::Mocks::ExampleMethods + + def before_setup + ::RSpec::Mocks.setup + super + end + + def after_teardown + super + ::RSpec::Mocks.verify + ensure + ::RSpec::Mocks.teardown + end + + def test_notifies_on_publish + notifier = double('A notifier') + expect(notifier).to receive(:notify!) + + post.publish!(notifier: notifier) + end +end +``` + +## Know your assertions + +One of my favorite parts of RSpec is how expressive the assertions can be - from the Ruby code that we have to write to the errors that the test runner will emit when something is broken. One might think that we can have something similar when working with Minitest, but that is not exactly true. + +Let's say we want to test a method like `Post#active?`. Using a dynamic matcher from RSpec like `expect(post).to be_active` will produce a very straightforward message when that assertion fails: `expected #.active? to return false, got true`. + +With Minitest, we might be tempted to write an assertion like `assert !post.active?`, but then the failure message wouldn't be much useful for us: `Failed assertion, no message given`. But fear not, because for something like this we have the `assert_predicate` and `refute_predicate` assertions, and they can produce very straightforward failure messages like `Expected # to not be active?.`, which clearly explains what went wrong with our tests. + +Besides the predicate assertions, we have a few other assertion methods that can useful instead of playing with the plain `assert` method: `assert_includes`, `assert_same`, `assert_operator` and so on - and every one of those has a `refute_` counterpart for negative assertions. + +It's always a matter of checking the documentation - The [`Minitest::Assertions` module](http://docs.seattlerb.org/minitest/Minitest/Assertions.html) explains all the default assertions that you use with Minitest. + +And in the case where you want to write a new assertion, you can always mimic how the built-in assertions are written to write your own: + +```ruby +module ActiveModelAssertions + def assert_valid(model, msg = nil) + msg = message(msg) { "Expected #{model} to be valid, but got errors: #{errors}." } + valid = model.valid? + errors = model.errors.full_messages.join(', ') + assert valid, msg + end +end + +class PostTest < Minitest::Test + include ActiveModelAssertions + + def test_post_validations + post = Post.new(title: 'The Post') + assert_valid post + end +end +``` + +## Active Support goodies + +If you want some extra sugar in your tests, you can bring some of extensions that Active Support has for Minitest that are available when working with Rails - a more declarative API, some extra assertions, time traveling and anything else that Rails might bring to the table. + +```ruby +require 'active_support' +require 'active_support/test_case' +require 'minitest/autorun' + +ActiveSupport.test_order = :random + +class PostTest < ActiveSupport::TestCase + # setup' and teardown' can be blocks, + # like RSpec before' and after'. + setup do + @post = Post.new + end + + # 'test' is a declarative way to define + # test methods. + test 'deactivating a post' do + @post.deactivate! + refute_predicate @post, :active? + end +end +``` + +## Tweaking the toolchain + +Minitest simplicity might not be so great when it comes to the default spec runner and reporter, which lack some of my favorite parts of RSpec - the verbose and colored output, the handful of command line flags or the report on failures that get the command to run a single failure test. But on the good side, even though Minitest does not ship with some of those features by default, there are a great number of gems that can help our test suite to be more verbose and friendly whenever we need to fix a failing test. + +For instance, with the [minitest-reporters](https://rubygems.org/gems/minitest-reporters) gem you can bring some color to your tests output or make it compatible with RubyMine and TeamCity. You can use reporters that are compatible with JUnit or RubyMine if that's your thing. You can use [minitest-fail-fast](https://rubygems.org/gems/minitest-fail-fast) to bring the `--fail-fast` flag from RSpec and exit your test suite as soon as a test fails. Or you can track down object allocations in your tests using [minitest-gcstats](https://rubygems.org/gems/minitest-gcstats). + +If any of those gems aren't exactly the setup you want it, you can always mix it up a bit and [roll your own gem](https://rubygems.org/gems/minitest-utils) with reporters, helpers and improvements that are suitable for the way you write your tests. + +Thanks to this extensibility, Rails 5 will bring some improvements to how you run the tests in your app to improve the overall testing experience with Rails (be sure to check [this Pull Request](https://github.com/rails/rails/pull/19216) and the improvements from other Pull Requests). + +> This post was originally published at +> http://blog.plataformatec.com.br/2015/05/nobody-told-me-minitest-was-this-fun/ diff --git a/content/posts/2015-09-22-custom-elements.md b/content/posts/2015-09-22-custom-elements.md new file mode 100644 index 0000000..810cfb3 --- /dev/null +++ b/content/posts/2015-09-22-custom-elements.md @@ -0,0 +1,191 @@ +--- +date: "2015-09-22" +summary: An example on moving from jQuery plugins into Web Components, minus the hype +title: Sane usage of Custom Elements +--- + +Web Components have been an controversial subject that surfaced in the Front end +world over the last years that I'm still pretty skeptical about its usage on +existing and greenfield projects due the lack of good examples on how they +can be rolled out to production, but I believe there is a way to get started with them +without buying in all the hype. + +The whole [Web Components spec](https://github.com/w3c/webcomponents) holds four +different standards, but the [Custom Elements](http://w3c.github.io/webcomponents/spec/custom/) +has some interesting features that can be useful to a lot of common tasks +from regular projects. + +## The life of a JavaScript plugin + +I'm currently using `data-*` attributes to annotate DOM elements that should +receive event handlers through `delegate` binds or be accessed directly +to add the behavior our JavaScript wants when we can't simply +delegate the event handlers through the document element. + +Let's say we want to toggle the `disabled` attribute of `button` elements based +on the validation status of inputs placed inside the same `form` as the `button` +element. + +A trivial implementation could be as simple as the following: + +```js +function bindDisabledButton() { + $('[data-disabled-button]').each(function() { + let button = $(this), + form = button.parents('form'), + input = form.find('input:not(:hidden), select'); + + function updateButton() { + button.prop('disabled', !inputs.get().every(input => input.checkValidity()); + } + + inputs.on('keyup change', updateButton); + updateButton(); + }); +} + +$(bindDisabledButton); +``` +_We could `delegate` a `change` event on all inputs with validation and traverse +the DOM to grab their parent `form`, sibling inputs and `button`, but let's assume +the given code as the first implementation of this for this post._ + +The code would Probably Work™, and could be refactored to use different abstractions, +be executed only when there are elements in the page that haven't been selected +before and whatnot, but the most annoying part about this kind of implementation +(which is similar to 67.45% of JavaScript libraries and jQuery plugins we find +in the interwebs) is the fact that we manually initialize these plugins and components +by ourselves, and we have been doing this for a long time without worrying too +much about this. + +The manual initialization isn't an issue with plain HTML that is fetched and +rendered in the browser, but it can become a huge pain in the ass when we sprinkle +more and more JavaScript on it and do things like Turbolinks/Pjax transitions or +plain DOM updates through XHR requests or client side logic: since we are responsible +for initialize this element, we must remember this every time the DOM changes. + +```js +$(document).on('ready page:load pjax:complete omg:wtf:bbq', bindDisabledButton); +``` + +This can easily escalate into more code to manually handle the life and death of +our enhanced elements - we need to care about when they need to be created in +our application and sometimes even when they need to be removed, as we might need to +cleanup event handlers or related elements that aren't properly isolated with the +node that will be removed from the page. + +## If you want custom elements, then you should probably try writing Custom Elements. + +The first thing that got my attention when going through the Custom Elements spec was +the [lifecycle callbacks](http://w3c.github.io/webcomponents/spec/custom/#types-of-callbacks) +that are available for developers to implement on their elements: we know when +the element is added or removed from the DOM and when its attributes are changed +by outside collaborators, and those callbacks can be extremely handy for pushing +all this lifecycle logic that can leak through our applications into self contained +elements. + +For instance, this is how the same `[data-disabled-button]` plugin can be +re-implemented as a Custom Element: + +```js +// app/assets/javascripts/elements/disabled-button.es6 +const slice = Array.prototype.slice; + +// Public: Custom `button` element that is enabled and disabled based on the +// validity state of the inputs inside the same 'form' element as the button. +// +// Example +// +//
+// +// +//
+const DisabledButton = { + attachedCallback() { + this._form = this._findForm(this); + this._updateCallback = this._update.bind(this); + this._form.addEventListener('keyup', this._updateCallback, false); + this._form.addEventListener('change', this._updateCallback, false); + this._updateCallback(); + }, + + detachedCallback() { + this._form.removeEventListener('keyup', this._updateCallback); + this._form.removeEventListener('change', this._updateCallback); + }, + + _update() { + let inputs = this._findInputs(this._form); + + if (inputs.every(input => input.checkValidity())) { + this.removeAttribute('disabled'); + } else { + this.setAttribute('disabled', true); + } + }, + + _findInputs(form) { + let inputs = slice.call(form.querySelectorAll('input, select'), 0); + + return inputs.filter(input => input.type !== 'hidden'); + }, + + _findForm(element) { + if (element.nodeName === 'FORM') { + return element; + } else { + return this._findForm(element.parentElement); + } + } +}; + +const DisabledButtonPrototype = Object.create(HTMLButtonElement.prototype); +Object.keys(DisabledButton).forEach(prop => { + DisabledButtonPrototype[prop] = DisabledButton[prop]; +}); + +window.DisabledButtonElement = document.registerElement('disabled-button', { + prototype: DisabledButtonPrototype, + 'extends': 'button' +}); +``` + +Now, every time the browser adds a `disabled-button` element or a `button` with +`is='disabled-button'`, it will be responsible for adding +the necessary behavior to our button to be disabled when its parent form isn't +valid or not, regardless of how the element got there in the first place - a +from an page transition done through ajax or a script executed in the browser's +console that appended an element to the page. + +In order to just enhance existing elements rather than go full JSF on my markup, +I'm sticking with [type extensions](http://w3c.github.io/webcomponents/spec/custom/#type-extension-example) - +the `is="disabled-button"` instead of having a `` tag +in the markup - rather than implementing custom tags, avoiding `template` elements, +Shadow DOM and HTML imports in order to keep my markup as simple as it can be with +the benefits of better abstractions on the JavaScript code. + +In the end, the required markup change is to replace any `data-*` attribute that +is used to hook the JavaScript code with a matching `is="component-name"` for +an equivalent Custom Element implementation. + +## Similar use cases + +Besides our exceptional `button` that its a bit more clever than other plain buttons, +there are several patterns that I can think of that can benefit from a Custom Element +implementation that I've encountered in projects in the past and might experiment +by implementing them as type extensions in the future: + +* alert messages rendered using Rails `flash.notice` and `flash.alert` that should +be removed from the interface after a short delay: a `setTimeout` can be enqueued +right after the element is attached for it to be removed. +* Bootstrap [Tooltips](http://getbootstrap.com/javascript/#tooltips) or [Popovers](http://getbootstrap.com/javascript/#popovers), +plugins that need to initialized manually, and you can have a shortcut for that +by hooking it through a Custom Element. Same thing could be done to [Chosen](https://harvesthq.github.io/chosen/) +or any other `select` replacement plugin you might need to use. +* Elements that should change based on events or the state of other related elements, +like our `disabled-button` example. +* Probably any other widget you might have to use. + +Some common use cases that already have been implemented, GitHub's [`time-elements`](https://github.com/github/time-elements) +and [`include-fragment-element`](https://github.com/github/include-fragment-element) are +the first ones that come to mind. diff --git a/content/posts/2015-10-01-revising-talks.md b/content/posts/2015-10-01-revising-talks.md new file mode 100644 index 0000000..8190a78 --- /dev/null +++ b/content/posts/2015-10-01-revising-talks.md @@ -0,0 +1,77 @@ +--- +date: "2015-10-01" +summary: Recommendations on technical tasks from recent Ruby Conferences +title: Revising talks on code and craft +--- + +Over the last couple weeks I decided to get back to watching videos from +conference talks, old and new, to deal with matters of the heart and help +with some of the ongoing discussions in the current project I'm working on. + +I've always been a fan of non technical presentations that talked about we can +improve the ways we make software and deal with code rather than just dumping +new technologies and going through README sections. Talks regarding our craft +can remain relevant through many years and help several developers to fight +the chaotic mess that a software project can be. + +### Maintaining Balance while Reducing Duplication: Part II + +David's talk on duplication helped me a lot to understand better how to deal with +duplicated code instead of blindingly following the premise of *Don't Repeat Yourself* +that we often take it to literally. + +I remember watching this talk back in RubyConf Brazil 2010, but it took me a few +years to understand the things it mentions and how extracting all kinds of duplication +can increase coupling, introduce points of indirection and make the codebase +harder to work - due the higher cognitive load required to understand it - instead +of making it easier as we all expect. + + + +### All the Little Things + +One of my biggest regrets from 2014 was that I missed Sandi's talk on RailsConf +Chicago for no apparent reason. She walks us through a process of refactoring +that can teach more than the refactoring itself, showing interesting steps on +how to tackle duplication and turn it into good abstractions and the importance +of having a good process to deal with complexity. + + + +### I Estimate this Talk is 20 Minutes Long, Give or Take 10 Minutes + +Estimates aren't the favorite part of our jobs but it is a very important aspect +of how we communicate with clients and managers about our work. Even if you don't +work as a consultant or have to deal with external clients or stakeholders this +talk can help you whenever you need to estimate something, manage expectations +of interested parties or help less experienced developers to deal with this. + + + +### Communicating Code + +WindyCityRails always amazes me on how a small conference can provide such high +level talks that are so easy to understand and relate to with our day jobs - +and not just because Ray Hightower was crazy enough to let me speak there in +2014. This talk from Kyle Crum touches the important (and subjective) area of +how the way we organize our code, name or abstractions and document our actions +(through comments or commit messages) affects the way other developers will read +and approach our code as a codebase grows and changes through time. + +A must watch talk if you ever got frustrated with legacy projects and codebases +that you couldn't figure out what the hell was going on with the code. And the +reply for [one of the lightning talks](https://vimeo.com/140388283) in the +first minutes was amazing. + + + +### How to Performance + +A more technical talk to have a break from the non technical ones and see some +code in action, where Eileen from Basecamp does a great job explaining some of +the improvements that Rails' integration tests have received over the last months, +and you can use the lessons and tools mentioned in this talk to profile your +application or other gems that might use a performance bump. + + diff --git a/content/posts/2015-11-24-multiverse.md b/content/posts/2015-11-24-multiverse.md new file mode 100644 index 0000000..c4d3971 --- /dev/null +++ b/content/posts/2015-11-24-multiverse.md @@ -0,0 +1,46 @@ +--- +date: "2015-11-24" +summary: Or why we still need to say "there is no Silver Bullet" +title: Software is a multiverse +--- + +Predicting the future is hard, yet programmers like to repeat that Framework X or +Language Y is the future of programming, the savior of all large scale projects and +complex refactorings, and everything else is outdated, unfashion and +awful (I’ve seen this with most client side frameworks, a dozen of programming +languages and a couple of times when someone decided to dig deep on functional +programming). But as our small history on dealing with computers can show us, +reality doesn’t work like that. + +A lot of outdated and “boring” tools are still vastly used by good developers +and profitable business, and their trendy replacements don’t necessarily lead to +better results on their own - the arms race for technical perfection ignores all +the human variables that are part of what makes a good or bad software. + +As a helpless sci-fi fan, I like to see all these ecosystems as a series of +parallel universes where everything can co exist on their own but we can all +move back and forth through the worlds that we want to be a part of - you can +jump between different frameworks and languages as you wish/need, and they will +continue to existing on their own and grown thanks to the effort of those on it, +without having to fight (much) for space and attention with their similar universes. + +And for us, tangled in this never-ending flow of new things to work with, we can +accept that it’s OK to stick around for a while and not jump ship on the first +new blog post about a new JavaScript framework or how OOP is bad. If you are +still comfortable with your toolset and the work you do, it’s OK to keep doing +that and move forward whenever you feel like it. + +The point is that new tools that end up killing or replacing older things are +rare cases. React didn’t killed Ember that didn’t killed Angular, MySQL and +PostgreSQL are still around after the Big NoSQL Wave, and Java and C# are still +around (the rivalry between those two back in college was the worst). + +Every new ecosystem in the industry can live on its own, and people can move +freely between one world to another, or even be a part of multiple ecosystem at +once. + +The beauty of having such a diverse toolset available for us is that we can be +happy and productive with whatever we choose. If you strongly believe that `X` +is the Future of something, remember that it might just be your future (or your +company’s future), but not necessarily someone else’s future, and that’s not a +bad thing. diff --git a/content/posts/2015-12-31-books-from-2015.md b/content/posts/2015-12-31-books-from-2015.md new file mode 100644 index 0000000..33862fc --- /dev/null +++ b/content/posts/2015-12-31-books-from-2015.md @@ -0,0 +1,81 @@ +--- +date: "2015-12-31" +summary: Non technical reads from 2015 +title: Books from 2015 +--- + +2015 was the first year that I had a New Year's Eve resolution to do: to read +more books. I'm used to read a lot of blog posts and articles online but I wasn't +reading much outside of it (and most of what I was reading was strictly related to + Rails and Front end anyway), so I set a goal of 12 books, technical or not, + for 2015. + +I've got it Close Enough™ - 10 books in 12 months, and half way through the +eleventh one. I focused on fiction and YA titles, for a necessary break from +consuming only technical content over the last years. + +Here is what I have been reading over this year: + +### 📚 [Notes of a Dirty Old Man](http://www.amazon.com/Notes-Dirty-Old-Charles-Bukowski/dp/0872860744) and [Women](http://www.amazon.com/Women-A-Novel-Charles-Bukowski/dp/0061177598), by Charles Bukowski + +### 📘 [Chasers of the Light](http://tylerknott.com/chasers) by Tyler Knott Gregson + +A lightweight and lovely collection of poems. There isn't much to be said about +Tyler's work that would capture the feelings that his work might invoke in the +reader. + +His [Tumblr](http://tylerknott.com/) and [Instagram](https://www.instagram.com/tylerknott/) +feeds are an never ending source of more poems and haikus that can be a poignant +escapade from the routine of cat vines and food pictures. + +### 📚 [The Fault in Our Stars](http://johngreenbooks.com/the-fault-in-our-stars/), [Paper Towns](http://johngreenbooks.com/paper-towns/) and [Looking for Alaska](http://johngreenbooks.com/looking-for-alaska/), by John Green + +John Green does an amazing job writing YA fiction that transcends the teenage +settings of their stories with deep insights and positivism that some "coming +of age" stories lack so much. If you believe it might be too cheesy for ya, +it might still be worth a read. + +The movie adaptations for [The Fault in Our Stars](http://www.imdb.com/title/tt2582846) +and [Paper Towns](http://www.imdb.com/title/tt3622592/) are true to their source +material + +Also, John's (and Hank's, his brother) [YouTube channel](https://www.youtube.com/user/vlogbrothers) +is awesome. + +### 📘 [The Lord of the Rings: The Fellowship of the Ring](http://www.amazon.com/The-Fellowship-Ring-Being-First/dp/0618574948) by J R R Tolkien + +I've watched the movies a bazilion times, but the LoTR books have been sitting on +my bookstand for a few years now - Tolkien ain't easy for the ones with short +attention spams. + +### 📘 [Show Your Work!](http://austinkleon.com/show-your-work/), by Austin Kleon + +Austin's first book, [Steal Like an Artist](http://austinkleon.com/steal/), was +a great eye opener on creative process for non creative-ish people, and _Show Your Work_ +feels like a sequel that talks about exposing and promoting your work and process. +Perfect for saving yourself from the boredom of a 2 hours flight or similar. + +### 📘 [If You Feel Too Much](https://twloha.com/ifyoufeeltoomuch/), by Jamie Tworkowski + +[TWLOHA](https://twloha.com)'s origin is a great story of love and hope from 2006, +but what I find the most amazing is how that story is still alive through the +organization and Jamie's story, and we have a glimpse of his life and heart +throughout the book, the ups and downs, the good and the hard moments. + +### 📘 [Open](http://www.amazon.com/Open-What-Happens-Honest-Accountable/dp/1400205301), by Craig Gross & Adam Palmer + +_Open_ took me more than an year to chew and finish it up. The takes a complete +tour on addressing accountability, the inner values of openness and the how-tos +to be a part of an accountability group and so on. Even if you don't intent to +go all the way on the path that Craig suggests, the book is a pint of renewed +honesty that you might find it handy. + +The unfinished eleventh entry to the list is [Quiet: The Power of Introverts in a World That Can't Stop Talking](http://www.amazon.com/Quiet-Power-Introverts-World-Talking/dp/0307352153) +by Susan Cain, a great book on the introversion/extrovesion subject, packed with +interesting stories and research data. + +## 2016 + +I plan to maintain the 12 books goal for next year. Pushing it to 15 or 20 would +be foolish and I doubt that I can upgrade my reading habits so much, but I hope +that I can hit the 12 books goal instead of getting so close like this year. diff --git a/content/posts/2016-02-29-experimenting-with-explicit-contracts-with-ruby.md b/content/posts/2016-02-29-experimenting-with-explicit-contracts-with-ruby.md new file mode 100644 index 0000000..e62c41c --- /dev/null +++ b/content/posts/2016-02-29-experimenting-with-explicit-contracts-with-ruby.md @@ -0,0 +1,179 @@ +--- +date: "2016-02-29" +summary: Bringing design ideas from Elixir projects into Ruby +title: Experimenting with explicit contracts with Ruby +--- + +A few months back, José Valim [started a conversation](http://blog.plataformatec.com.br/2015/10/mocks-and-explicit-contracts/) on overusing mocks and coupling between components. That made me interested on revisiting how I design my code and it has changed my approach to testing a bit in one of our current Ruby projects. + +## A Tale of Two Adapters + +Back in November, I worked on integrating a payment gateway from scratch into one of our client projects, through a gem that abstracts the HTTP interface of this external service. On this payment flow we had to first authorize the payment data with the gateway, which would return the transaction data for us to capture the payment in the background and go on with the business logic that depended on a successful payment flow. + +If you ever worked on something similar, you probably remember a few rough edges that we need to deal in cases like this: how to test the integration with the right credit card numbers for each possible outcome? Do we have a sandbox available for development and test environments? How can we control the performance and stability costs that this external dependency might bring to our application, and the coupling between the code that supports this core feature and this gem? + +Our attempt to handle the coupling and maintenance cost of this dependency was to push all the integration code behind an abstraction layer responsible for dealing with this payment flow logic under a `Payments` namespace. + +```ruby +require 'gateway-xyz-gem' + +module Payments + class GatewayXYZ + def authorize(order, credit_card) + # Uses the `Order` details and the user `CreditCard` data to authorize + # a new transaction on the XYZ Payment Gateway through the + # `gateway-xyz-gem` classes. + end + + def capture(payment_id) + # Capture the payment information for a transaction that was previously + # authorized. + end + end +end +``` + +Somewhere down our `orders#create` action (but not directly in the controller method itself) we call `GatewayXYZ#authorize` with the `order` record and a `credit_card` value object and our integration with the external service is done. + +We might have a nice set of well-defined methods on the `GatewayXYZ` class but our job on these abstractions is far from done. We might unit test it with something like [WebMock](https://github.com/bblimke/webmock) or [VCR](https://github.com/vcr/vcr) to handle the external service dependency, but every other piece of our system that interacts with this abstraction will also depend on the external API to work properly - the `OrdersController`, the background job that captures the payment and the `Order` model itself that might trigger the initial `authorize` call. Should we just sprinkle the existing stubs all over our test suite and call it a day? + +We added a gateway implementation that mimics the expected behavior of the `GatewayXYZ` (with the same method signatures as the real gateway) and doesn’t depend on external resources. It also has a predefined behavior for specific inputs so we can test different code paths of their collaborators based on the test input. + +```ruby +module Payments + class Memory + def authorize(order, credit_card) + if BAD_CREDIT_CARD_NUMBERS.include?(credit_card.number) + bad_response + else + ok_response + end + end + end +end +``` + +## Dealing with environment specific setups + +Now we need to make our `Payments::Memory` the go-to implementation for our test cases that depend on our payment abstractions. There are a few different ways we can do this on a Rails app. + +### `Rails.application.config` + +We can expose a configuration setting in app that says which implementation it should use, similar to how `Action Mailer` picks the delivery method for your emails or how `Active Job` might have different queue adapters for your background jobs. + +```ruby +# config/application.rb +Rails.application.config.x.payment_gateway = Payments::GatewayXYZ + +# config/environments/test.rb +Rails.application.config.x.payment_gateway = Payments::Memory + +# app/models/order.rb +class Order + def authorize(credit_card) + gateway = build_gateway + gateway.authorize(self, credit_card) + end + + private + + def build_gateway + klass = Rails.application.config.x.payment_gateway + klass.new + end +end +``` + +### `Module.mattr_accessor` macro + +You can set a class level macro on the classes that depend on a configurable value and change as you want in your code. This approach can be useful if you want to keep the configuration closer to the implementation that relies on it, instead of jumping between app code and configuration code if you want to debug something or be able to change it during runtime. + +```ruby +# app/models/order.rb +class Order + cattr_accessor :payment_gateway do + Payments::GatewayXYZ + end + + def authorize(credit_card) + gateway = payment_gateway.new + gateway.authorize(self, credit_card) + end +end + +# test/test_helper.rb +Order.payment_gateway = Payments::Memory +``` + +## Factory method + +This approach is useful when you want to hide away how to create an instance of a gateway implementation, so other classes that depend on it can have a way to just ask for a gateway object without worrying on how to create it. + +```ruby +# app/models/payments.rb +module Payments + matt_accessor :gateway do + Payments::GatewayXYZ + end + + def build_gateway + gateway.new + end + + module_function :build_gateway +end + +# test/test_helper.rb +Payments.gateway = Payments::Memory +``` + +I don’t believe that there is a Single Way to Do It™ this kind of dependency injection, so you should feel free to pick a strategy that suits the interfaces you are building and the coding style of your team - I’m personally a fan of the factory method and the `cattr_accessor` approaches as they feel more detached from the configuration and closer to the application code, although the configuration way feels more aligned with global APIs from 3rd party gems. + +## Skipping Hash driven development + +Our `GatewayXYZ` and `Memory` implementations have the same methods with the same arguments but there is a second piece of making a uniform API that we need to think about: what those methods should return? + +Our `authorize` needs to return more than a `truthy`/`falsy` value, as we need to gather more information about the payment transaction on our end, like the `payment_id` from the transaction, or a reason of why it might have failed (was the credit card denied? There is invalid data in the request), details for logging or instrumentation, etc. And if we think about implementing this API for multiple services (let's say we need a `Payments::PayPal` now, for instance), those services will return this data in different formats that we need to normalize so these differences don't leak to the rest of the system. + +One might say that a `Hash` with all this junk would do it, but going that path opens too many doors for inconsistency and bugs as the hash is a weak abstraction that can be mutated anywhere and won't enforce any specific format or requirements on the return values. + +For that, we can implement a `Payments::Result` struct/value object to represent the outcome of our `authorize` action, and return it from each gateway implementation in our system, enforcing the interface we want to have. + +```ruby +module Payments + class Result < Struct.new(:payment_id, :errors) + def ok? + errors.blank? + end + + def failed? + !ok? + end + end +end +``` + +Our `Result` class has the minimal information that our client code needs, and each gateway is responsible for constructing a `Result` from its own data. The `Memory` gateway can do something as straightforward as this: + +```ruby +module Payments + class Memory + def authorize(order, credit_card) + Result.new( + payment_id: SecureRandom.hex, + errors: SAMPLE_ERRORS[credit_card.number]) + end + end +end +``` + +This approach is useful not just for enforcing the interface we want, but also to improve other areas of our code that could use more specific abstractions than a bare `Hash` instance. + +## Going forward with contracts and macros + +This homemade approach for better contracts between our app and this external service can go a long way, but if you want, you can build strict checks on top of your APIs to ensure that your objects are collaborating as you expect. We haven't tried yet, but the [contracts](https://github.com/egonSchiele/contracts.ruby) gem looks very interesting if you want that kind of type constraints that are lacking on Ruby. + +You can even write your own checks by wrapping methods into type checking proxies, as [`refile`](https://github.com/refile/refile) does with its [`Refile::BackendMacros`](https://github.com/refile/refile/blob/v0.6.2/lib/refile/backend_macros.rb) module. When [extended by a backend implementation](https://github.com/refile/refile/blob/v0.6.2/lib/refile/backend/file_system.rb), it provides macros to validate the input for methods like `#upload(uploadable)` or `#delete(id)`, so custom implementations don't need to worry about validating these arguments on their own. + +> This post originally published at +> http://blog.plataformatec.com.br/2016/02/experimenting-with-explicit-contracts-with-ruby/ diff --git a/content/posts/2018-02-20-git-field-guide.md b/content/posts/2018-02-20-git-field-guide.md new file mode 100644 index 0000000..fa1b1c0 --- /dev/null +++ b/content/posts/2018-02-20-git-field-guide.md @@ -0,0 +1,126 @@ +--- +date: "2018-02-20" +description: Values, practices and configurations on how I use git +summary: A rundown on how I configure, use and see git as a day to day tool +title: Git Field Guide +--- + +Git has become an indispensable tool of software development, regardless of which +language or framework your team uses it. But in the other hand, it isn't a tool +that you can adopt, learn and be effective from day 1 - it takes time and guidance +to master it, both in the command line the integrations and practices most teams +have adopted. + +I've put up together a guide on how I see and use git on my day to day work, that +can be used as a starting both for both newcomers who are trying to grok or more +experienced professionals who want to make a more effective use of it on they +work. + +The guide describes [**values**](#values) to remember and strive for when using +git, day to day [**practices**](#practices) and [**configuration**](#configuration) +suggestions that I believe are a must have for your local setup. + +## Values + +1. Git is more of a tool to **document and communicate** changes rather than storing them. +As the number of people involved or time spent in a codebase grows, you will eventually +find yourself reading more about what (and why) have change rather than reverting +changes. +2. Git is **not trivial**. All its power and usefulness can come with more complexity +than your one might expect. Be humble enough to understand that you might not master +it as fully as you think, and trust it to be more powerful than you currently +expect it to be. +3. Failures are **usually recoverable**. Whenever some git operation does not goes +how you would expect (from commiting to a wrong branch to rebases with absurds conflicts) +do not panic as not all is broken or lost, and commands like `reflog`, `reset` or +`rebase` can be extremely useful to recover and fix whatever might have happened +to your git tree. [Oh shit, git!](http://ohshitgit.com) is a tiny but useful +resource on possible git screw ups and how to fix them. + +## Practices + +* **On commit messages**: care about writing good commit messages and read your git history often. Chris +Beams has probably the [best post on how to write commit messages](https://chris.beams.io/posts/git-commit/) +and I recommend reading it rather than trying to explain on this post. +* **When working with feature branches**, Always keep them up to date, with both `git pull` and `git fetch` + every now and then, rebasing it early and often with its base branch (the `master` + branch on your remote repository on most cases), and fixing conflicts as soon + as they happen. Fixing conflicts on larger rebases will be harder and merges + will add noisy commits to your branch's history. + ```sh + git checkout feature/add-new-stuff + # work work work... + # download the refs that are on your remote repository, and rebase your feature + # branch on top of whatever's is on your remote's master branch, so it will be + # up to date. Hopefully no conflicts will need to be fixed. + git fetch origin && \ + git rebase origin/master + + # if you want to make your local `master` branch is up to date as well, do + # the following: `git pull` will fetch and rebase the references from your + # remote repository, and then rebase the feature branch against the local + # master branch instead. + git checkout master && \ + git pull --rebase && \ + git checkout - && \ + git rebase master + ``` +* **Use [git commit --fixup](https://robots.thoughtbot.com/autosquashing-git-commits)** +and [interactive rebases](https://robots.thoughtbot.com/git-interactive-rebase-squash-amend-rewriting-history) +to rewrite the history on your feature branches to keep its commits in order and +organized. Intermediate changes are useful when rolling changes and trying fixes, but +once the dust has settled you can rework the history to represent the final changes +you want to introduce. + ```sh + # So, you added a few files and some commits on your branch + git commit -m 'Add README.md' + # [master (root-commit) f1a4ab4] Add README.md + # 1 file changed, 0 insertions(+), 0 deletions(-) + # create mode 100644 README.md + $ git commit -m 'Add CONTRIBUTING.md' + # [master e8644e4] Add CONTRIBUTING.md + # 1 file changed, 0 insertions(+), 0 deletions(-) + # create mode 100644 CONTRIBUTING.md + + # Now you need to update `README.md` and want to "merge" the new commit with + # these new changes to the original commit (f1a4ab4) using an interactive rebase + git add README.md + git commit --fixup f1a4ab4 + # [master 13168c2] fixup! Add README.md + # 1 file changed, 0 insertions(+), 0 deletions(-) + + # `--autosquash` will prepare the interactive rebase to squash 13168c2 on f1a4ab4 + # for you. + git rebase --interactive --autosquash HEAD~3 + ``` +* Not all branches/Pull Requests need to be **squashed into a single commit** when +doing interactive rebases. Squashing too many commits can make bisecting or +navigating through the history harder than you might want to. You can practice +this by avoiding shortcuts like the GitHub ["squash merge"](https://github.com/blog/2141-squash-your-commits) +button and favoring rebases through your editor where you have more control over +the operation and review your commits to decide how they should be squashed. + +## Configuration + +* Configure git to always `rebase` branches when doing `git pull` with `git config --global pull.rebase true` +and never use fast forward when doing merges with `git config --global merge.ff false`. These changes +are vital to maintain sane tree histories when working with remote repositories. +* Configure your identity with `git config --global user.name` and `git config --global user.email` +on every workstation you use. This helps to identify who's the real author of a changes +and is important for tools like GitHub to associate a commit with a particular person. +I also configure my local repositories with different email given the context - commits +to company related work is made using a business email while open source is commited +using my personal email - I have an alias `git work` that sets the "work" identity +to the current repository while my global config remains personal. +* Set up aliases to abstract common git operations, like: + * Undo the last commit (`git reset --soft HEAD^`) and keep it changes to be reviewed or + split among different commits. + * Add new changes to the latest commit while maintaining the same message (`git commit --amend --no-edit`). + Useful when applying small fixes like typos or styleschanges without having to do + a complete `rebase` operation - don't forget that you will need to push it using `--force` + when working with remote repositories. + * Run an "automatic" interactive rebase to apply your `--fixup` marked commits without going + through your editor to describe what the rebase should do with each commit (`!GIT_SEQUENCE_EDITOR=touch git rebase --interactive --autosquash`). + +*For more configuration settings and aliases that I use (and don't use), you +can check my [gitconfig on GitHub](https://github.com/lucasmazza/dotfiles/blob/master/symlinks/gitconfig).* diff --git a/content/talks/2012-07-02-design.md b/content/talks/2012-07-02-design.md new file mode 100644 index 0000000..83518f3 --- /dev/null +++ b/content/talks/2012-07-02-design.md @@ -0,0 +1,8 @@ +--- +layout: deck +title: "Design efetivo para desenvolvedores" +conference: ['RS on Rails 2012'] +expiryDate: 2020-09-19 +--- + + diff --git a/content/talks/2013-04-09-documentation.md b/content/talks/2013-04-09-documentation.md new file mode 100644 index 0000000..7259404 --- /dev/null +++ b/content/talks/2013-04-09-documentation.md @@ -0,0 +1,13 @@ +--- +layout: deck +title: "Documentation for fun and profit" +conference: ['NYC.rb'] +expiryDate: 2020-09-19 + +--- + +Good documentation will save you any day of the week, but yet a lot of developers dismiss the importance of writing it. Either documenting the source code of your gem or sharing the knowledge of how your dev team does its job can improve the communication among your coworkers or the ones looking forward to contribute to your code on GitHub. We are going to go through some examples of different well documented projects, what that brings to the table and stories of documentation in some projects from my last year at Plataformatec. + +
+ + diff --git a/content/talks/2013-04-11-plataformatecway.md b/content/talks/2013-04-11-plataformatecway.md new file mode 100644 index 0000000..a7d5db9 --- /dev/null +++ b/content/talks/2013-04-11-plataformatecway.md @@ -0,0 +1,15 @@ +--- +layout: deck +title: "The Plataformatec way: TEAMWORK edition" +conference: ['NYC on Rails'] +expiryDate: 2020-09-19 + +--- + +Scale a development team ain't an easy task, and it should be done by the team members themselves. I want to talk about how our team has grown over the last years and what we are doing to keep the company as the best workplace we can get, and how our routine exceeds the working hours and affect our lives. + +From our development workflow to the tools we use everyday, we are constantly revisiting our practices and adjusting them as we need, bringing new ideas and concepts to ensure that our team stays fresh and able to deliver great projects to our clients. + +
+ + diff --git a/content/talks/2013-06-22-boxen.md b/content/talks/2013-06-22-boxen.md new file mode 100644 index 0000000..d32ceeb --- /dev/null +++ b/content/talks/2013-06-22-boxen.md @@ -0,0 +1,17 @@ +--- +layout: deck +title: "Boxen: Configurando o seu ambiente de desenvolvimento" +conference: ['30º Guru-SP meetup'] +expiryDate: 2020-09-19 + +featured_slide: images/slides/boxen.jpg +--- + +Já teve problemas em configurar a sua máquina de desenvolvimento para um novo projeto? Eu também. O Boxen automatiza toda a chatice de deixar o OS X pronto para o seu trabalho - instalar Rubies, clonar repositórios e mais. Veremos o que o Boxen pode fazer por você, vantagens de adotar ele na sua equipe e detalhes do projeto que garantem a consistência e previsibilidade do seu ambiente de dev. + + + +
+ + diff --git a/content/talks/2013-08-29-rails-front-end.md b/content/talks/2013-08-29-rails-front-end.md new file mode 100644 index 0000000..3903b58 --- /dev/null +++ b/content/talks/2013-08-29-rails-front-end.md @@ -0,0 +1,14 @@ +--- +layout: deck +title: Rails ama seu Front-end +conference: ['RubyConf Brasil 2013'] +expiryDate: 2020-09-19 + +featured_slide: images/slides/rails-front-end.jpg +--- + + + +
+ + diff --git a/content/talks/2013-10-19-oss.md b/content/talks/2013-10-19-oss.md new file mode 100644 index 0000000..c671161 --- /dev/null +++ b/content/talks/2013-10-19-oss.md @@ -0,0 +1,10 @@ +--- +layout: deck +title: "Contribuindo com projetos OpenSource: a teoria na prática" +conference: ['RS on Rails 2012'] +expiryDate: 2020-09-19 + +featured_slide: images/slides/oss.jpg +--- + + diff --git a/content/talks/2013-11-23-manutencao-css.md b/content/talks/2013-11-23-manutencao-css.md new file mode 100644 index 0000000..65ec6cd --- /dev/null +++ b/content/talks/2013-11-23-manutencao-css.md @@ -0,0 +1,15 @@ +--- +layout: deck +title: Manutenção e Refatoração de CSS +conference: ['DevFest São Paulo 2013'] +expiryDate: 2020-09-19 + +featured_slide: images/slides/manutencao-css.jpg +--- + + + +
+ + diff --git a/content/talks/2014-05-20-sass.md b/content/talks/2014-05-20-sass.md new file mode 100644 index 0000000..ea1e9e6 --- /dev/null +++ b/content/talks/2014-05-20-sass.md @@ -0,0 +1,10 @@ +--- +layout: deck +title: O que eu aprendi com Sass +conference: ['DevFest São Paulo 2013'] +expiryDate: 2020-09-19 + +featured_slide: images/slides/sass.jpg +--- + + diff --git a/content/talks/2014-08-09-photoshop-meh.md b/content/talks/2014-08-09-photoshop-meh.md new file mode 100644 index 0000000..f28de40 --- /dev/null +++ b/content/talks/2014-08-09-photoshop-meh.md @@ -0,0 +1,15 @@ +--- +layout: deck +title: Photoshop? Meh. Repensando o processo de design para a web +conference: ['TDC 2014 São Paulo'] +expiryDate: 2020-09-19 + +featured_slide: images/slides/photoshop.jpg +--- + +O processo de desenvolvimento e design para a web não precisa se basear em algumas layers de um arquivo .psd e pode ser algo muito mais colaborativo e iterativo - igual ao softwares que construímos. Vamos falar sobre os problemas dessa abordagem tradicional de design e de métodos mais colaborativos que podem ajudar você a prototipar, desenhar e entregar interfaces melhores nos seus projetos. + + +
+ + diff --git a/content/talks/2014-09-04-devise-en.md b/content/talks/2014-09-04-devise-en.md new file mode 100644 index 0000000..c7f8c4b --- /dev/null +++ b/content/talks/2014-09-04-devise-en.md @@ -0,0 +1,16 @@ +--- +layout: deck +title: What Devise Does When You're Not Looking +conference: ['Windy City Rails 2014'] +selected: true +expiryDate: 2020-09-19 + +featured_slide: images/slides/devise.jpg +--- + + + +
+ + diff --git a/content/talks/2014-09-13-devise-pt.md b/content/talks/2014-09-13-devise-pt.md new file mode 100644 index 0000000..370378a --- /dev/null +++ b/content/talks/2014-09-13-devise-pt.md @@ -0,0 +1,17 @@ +--- +layout: deck +title: O que o Devise está fazendo enquanto você não está olhando +conference: ['34º Guru-SP meetup'] +expiryDate: 2020-09-19 + +featured_slide: images/slides/devise.jpg +--- + +O Devise é a gem mais usada para autenticação e você provavelmente já trabalhou com ela, mas você sabe como o Devise trabalha por debaixo dos panos? Esta palestra é sobre como o Devise funciona e quais são os pontos principais do projeto. Também vamos falar de como estender os controllers do Devise, quais métodos podem ser sobrescritos no seu model e outras coisas que você sempre quis fazer. + + + +
+ + diff --git a/content/talks/2014-11-08-front-end-rails.md b/content/talks/2014-11-08-front-end-rails.md new file mode 100644 index 0000000..cde4d70 --- /dev/null +++ b/content/talks/2014-11-08-front-end-rails.md @@ -0,0 +1,15 @@ +--- +layout: deck +title: O que o Front end pode aprender com o Rails +conference: ['Front in Porto Alegre 2014', 'Tableless Conf 2014'] +expiryDate: 2020-09-19 +--- + +O Rails completou 10 anos de vida e diversas lições desses 10 anos podem nos ajudar a construir as fundações para os próximos 10 anos do mundo de front end. Vamos refletir sobre alguns aspectos que ajudaram a stack do framework a evoluir durante os anos e como podemos aplicar isso no mundo de CSS e JS para melhorar as nossas aplicações. + + + +
+ + diff --git a/content/talks/2015-09-18-tools.md b/content/talks/2015-09-18-tools.md new file mode 100644 index 0000000..4c2e372 --- /dev/null +++ b/content/talks/2015-09-18-tools.md @@ -0,0 +1,9 @@ +--- +date: "2015-09-18" +title: "gems, executáveis e configurações" +slug: "tools" +--- + +**RubyConf Brasil 2015** + + diff --git a/content/talks/2015-10-17-10-coisas.md b/content/talks/2015-10-17-10-coisas.md new file mode 100644 index 0000000..186d410 --- /dev/null +++ b/content/talks/2015-10-17-10-coisas.md @@ -0,0 +1,14 @@ +--- +date: "2015-10-17" +title: "10 coisas que eu gostaria de ter aprendido mais cedo" +slug: "10-coisas" +--- + +**Front in Manaus 2015** + +> Amigos desenvolvedores, o que vocês gostariam de ter aprendido no passado quando +> começaram com desenvolvimento de software que vocês sabem agora? Abram seus corações. +> Nessa apresentação vou mostrar um compilado de aprendizado que eu e meus colegas +> de profissão compartilhamos durante a carreira. + + diff --git a/content/talks/2016-07-23-minitest.md b/content/talks/2016-07-23-minitest.md new file mode 100644 index 0000000..96ad67b --- /dev/null +++ b/content/talks/2016-07-23-minitest.md @@ -0,0 +1,14 @@ +--- +date: "2016-07-23" +title: "Minitest: voltando ao básico sobre testes" +slug: "minitest" +--- + +**Guru SP - 07/2016** + +> Minitest nasceu como uma alternativa ao test/unit do Ruby 1.8 e se tornou um +> framework de testes extremamente robusto e ao mesmo tempo simples, e está +> disponível em qualquer instalação de Ruby hoje em dia, para todos escrevem testes sem muita +> burocracia. + + diff --git a/content/talks/2016-09-24-zen-and-art-of-refactoring.md b/content/talks/2016-09-24-zen-and-art-of-refactoring.md new file mode 100644 index 0000000..1350f3d --- /dev/null +++ b/content/talks/2016-09-24-zen-and-art-of-refactoring.md @@ -0,0 +1,20 @@ +--- +date: "2016-09-24" +title: "The Zen and Art of Refactoring" +slug: "zen-and-art-of-refactoring" +--- + +**RubyConf Brazil 2016** + +> Refactoring is often seen as a process where we make bad code better by waving +> our wands and casting our secret spells while facing our editors, which usually +> happens when things are on fire and the pressure is on. +> Changing software should be easier and not scary, and one of the first steps +> to do it is not to try to write future-proof code, but we can adopt different +> steps to think about the changes we want to do and how we can do them. +> In this talk we will discuss how we can approach the code to-be-changed and +> see our refactoring tasks as a common transformation process instead of a +> rescue mission and different questions we should ask ourselves before picking +> Design Patterns or architectural jargon for the changes we want to do on our software. + + diff --git a/content/talks/2016-11-19-circuit-breakers.md b/content/talks/2016-11-19-circuit-breakers.md new file mode 100644 index 0000000..98b11e5 --- /dev/null +++ b/content/talks/2016-11-19-circuit-breakers.md @@ -0,0 +1,9 @@ +--- +date: "2016-11-19" +title: "Circuit Breakers em Ruby" +slug: "circuit-breakers" +--- + +**Guru SP - 11/2016** + + diff --git a/content/talks/2018-02-24-testes.md b/content/talks/2018-02-24-testes.md new file mode 100644 index 0000000..4ed6a27 --- /dev/null +++ b/content/talks/2018-02-24-testes.md @@ -0,0 +1,21 @@ +--- +date: "2018-02-24" +title: "Testes automatizados e a prática antes da teoria" +slug: "testes" + +conference: ['Guru SP - 02/2018'] +--- + +**Guru SP - 02/2018** + +> Escrever testes automáticos é uma prática bem estabelecida na comunidade Ruby, +> mas o quão bons são os testes que escrevemos? Na correria do dia a dia, estamos +> testando de forma efetiva ou só escrevendo mais código? Nesta palestra vamos ver +> alguns vícios e más práticas tradicionais de projetos Ruby, como podemos evitá-los +> e escrever testes melhores, e quais mudanças de pensando e práticas podemos adotar +> para aprimorar a nossa escrita de testes de software. + + + + diff --git a/content/talks/2018-08-25-feature-toggles.md b/content/talks/2018-08-25-feature-toggles.md new file mode 100644 index 0000000..3ddf3d2 --- /dev/null +++ b/content/talks/2018-08-25-feature-toggles.md @@ -0,0 +1,21 @@ +--- +date: "2018-08-25" +title: "Feature Toggles" +slug: "feature-toggles" +--- + +**Guru SP - 08/2018, Elug SP - 08/2018** + +> Feature toggles são uma técnica muito versátil para ajudar o trabalho de disponibilizar novas +> funcionalidades em produção sem quebrar a experiência de clientes e fazer entregas graduais, +> mas acabamos aprendendo sobre toggles de uma forma superficial no dia a dia. +> +> Vamos ver um pouco do passado e presente do uso de features toggles, a sua facilidade de +> uso graças a ferramentas open source e considerações a serem feitas sobre como e quando usar toggles na sua aplicação + + + + + + diff --git a/content/talks/2019-07-06-ecto-sem-sql.md b/content/talks/2019-07-06-ecto-sem-sql.md new file mode 100644 index 0000000..b134c32 --- /dev/null +++ b/content/talks/2019-07-06-ecto-sem-sql.md @@ -0,0 +1,11 @@ +--- +date: "2019-07-06" +title: "Ecto sem SQL" +slug: "ecto-sem-sql" +--- + +**Elug SP - 07/2019** + +> Um dos objetivos do design do ecto é ser um "toolkit para mapeamento de dados" independente do uso de > um banco de dados por de trás dos panos, e nesta palestra vamos ver alguns casos de uso de schemas e > changesets em situações diferentes de aplicações onde um banco de dados não está presente mas o ecto > nos ajuda a resolver problemas no dia a dia. + + diff --git a/static/CNAME b/static/CNAME new file mode 100644 index 0000000..1946162 --- /dev/null +++ b/static/CNAME @@ -0,0 +1 @@ +afterhours.io diff --git a/static/favicons/apple-touch-icon-precomposed.png b/static/favicons/apple-touch-icon-precomposed.png new file mode 100644 index 0000000000000000000000000000000000000000..6cb41a8e552c6150fe56b3e7dec516fb20093793 GIT binary patch literal 831 zcmeAS@N?(olHy`uVBq!ia0vp^GeDSw2}n*~u)PdONtU=qlmzFem6RtIr7}3C&;z9@5zNS2R@25`Asfh;AKnX+Na7u<97pKfq@h3WR^mA`88 z?UHTy&$mDSZ(}bLt#tR^R^N;HyMq~m6j*~49J!V_aH)7Sih$4rCd~;tYEVtKwv^Ph03*mqU=WF?`)+l_csf7$lbVq?eg8ZCriHZf0dPmchuUsuf3nV1IIRN=fxMh6GLk=k zZMu23Znx5OYaSz`-ky294+9(jy#Dy{%!v)95ooLJGzi`&*fMKaA}@awOyN0x{Ma$D%Ixgb7d1FHF+EN3U!RoRfdo7Gf15=v@yE0Bi`VYm+j?lDea(>@8y@Wa|LNPOtgI}ipL>obxb$mz>>h)i?~)gFJvr>RGNdW-kATMnuF%es z>gk&wbfKpkRv}<|f(1S}JwXE>EPm?sYzAfquV*D64qq{42j&O{Pgg&ebxsLQ0K4yS AE&u=k literal 0 HcmV?d00001 diff --git a/static/favicons/favicon.ico b/static/favicons/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..2cd56085afa9abeff1bef566ed1fd9fcdeb4b03f GIT binary patch literal 340 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1SJ1Ryj={WI14-?i-EKU7`vU!wgU;46*#5? zX$3HD|21bWka5`4#WBR=cyh?)3#kiK6Bey}xmb*ci#wvg^T&?e-~3)2)e4OX*pvD^ zPf0gHOib{&*2gC=H{UkT+puwymX_ur*5_yE?N0f4sg|Ap|G&@e9^4WipELW0KINT# z?eNZ5v#OS`UA)l$B#_%pSAtROgs1nf9lI}GVAAL3k4aS$)p_vffrgIek@am#+-G`t z6?uF^Q)fjyc=pUKfcG3%dw28UllQJ2zb+lQVeLk_nbI<1KKoexzHOVa(Y>cLqoHui zL({B-54Hn?;k<@f;Hq6NK<_A3g+!DD=ckpFCl;kLFjU+s_BrYA75d?fua7^km#@!C a76$z}tXJ0Ytn>w{X7F_Nb6Mw<&;$TXFM{*{ literal 0 HcmV?d00001 diff --git a/static/images/companies/cdc.jpg b/static/images/companies/cdc.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e979eaf0f10d8f93bf7bc5fc2c7a8c432572b5a5 GIT binary patch literal 4128 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 literal 0 HcmV?d00001 diff --git a/static/images/companies/magnetis.jpg b/static/images/companies/magnetis.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bbad9782787aca44ab008031f842893b795be6cc GIT binary patch literal 1996 zcmb7FX;f3^7QHtENeG0Skf2Yd0AjEfUV=nGnZZ1P1ri2RFo;p4g31&q3dmT7GF5N_ zH6nyk6>7>LGLK~t1QZaoC?b;#B10|8Q1Wh29>3qYXRTzdbI)G;oc-qCW06_Qw#Djn(fJ7i92?q*JG!~6Uq0rJ8j1*QzT1EyhjmOIpNRTXnNWkME1&An5 zrcfv{a@)2mkhhb_6tV;aM8Z8NG!Bi%k!A6+^J{7;3Bvl(-8D<`mBZE$#UgWhCiUdij1Ny*MxK|py~nw zA2t;I<8NoT6fbh43}}@DxNFCL&9>aTyKPtKLjAa#4|^a~rSy?ePjL)@?2djj9Z+(q zKk5rJB+QitQ$ZsUQZTQtfq<7S1%MbTlSEP2rmIKZ=Rk*y0no;aHB$`MYs?oU*4wsCrOepZVTA7OCOqH(fBt+mto zUX}m7+pBB8MJWD-cIL(EdBnn#st^GXh1i-?a@LS2B7zFh8KjK?ksxRa&Llnw&qBA? z>~>oSyEB}Vqepgit$x?VJyweO{woT6AUBr<|AO$sh*UZQAgOJjAS5U)jfz_Li<4c3 zX_shKnnTI?A{^3^2KSpm00KlHP*MaO`U?o$51@!7w7eQ0B2yXcKy?k>y?W*jj!pqV zMa7Mjoph!pFFoT~^yM63&sQO&Oc9IZ4vk_@V2Sx=LJTOCkEERV(BK>qoTf0mT-o{X z#^SRc(?c~G>$$mQQC>HWvVIWhw&$%aZRFvznxiY>&0&`^Z6=!x*7&+L4UWYelcdh~xb_ z1|cqdqy77b40BTjO1qv@&oUo`W!><-$m6G43q{-xy)(BBj|#50$l8&LQUzF!(sVfM zVYL^}z<7v%^Y44-9t;{kuT?JTcB_kyr#ZWZHk}^#_H*`NdVElQYlN?ez*SC&E@n?q z_*H%(du&5L^^|^wd=V31s_(8SWU;||2@addQlZr)Y|3&OQ;3GPC%fMNc5&>Kq8=K&gKQo zLsSMmI>#ZssNvbdre{pmRv>;#+2Ra$ZnSpJ{?L^MC&Jlv_Fo)Ez?pI6P^`Bc=vEqc zy>UTRuQ!4h_~Kjp%iPgVlZBW$4E6CI)Q+D9chw~Xexu<_*JTNct!tUf24`27663se zUaOv*wXCRl4E5R6`IP@!-FZAY+=`fFeQ_~w-RckgjueyU2gb~+KiOG%7fOG2w@L_% z@@o2dOzt4%))9e$(h9G^>m%E>*}FHoJ6}n`cdWP}+mx1iMb7s}or)@tiD`dTV&;F6 zJ~G@d6E1((5j({`dDZ-MNV;=KIrp|G5gV({<0^h~e8fne^ni!mxY_`TGaxKAMv{B~ z!BPbSw-Hz>WhE*``n#McYK$#?qeP9tZGLhi2k3t(3)meQ=oaKQ4o@V2hgZen``};M6a;78V$>*uGVN?dapK{W@HXpL|q8f zNX@Jp;igsWjJG}+H~qtuPTTkdvytqmY59{U$JV#gM<2NJS-)A|uSoBF-S>Wdtg@%KoYb|4<>Y0tGxKRp4lY+Ic7T1n z>;vsW(-rj?8&pAKp8Khz(%#w_gTkd_5kmvnB6X9hY%}Ane*-O#`H#F%^6JCVcVb?f zXeKLj<1&B8_;htsIQbb)ES0YF2^O!6^4bsb3ezef&1i3t)i&YV-UB1{FS{|iAY?`8l1 literal 0 HcmV?d00001 diff --git a/static/images/companies/plataformatec.jpg b/static/images/companies/plataformatec.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8ae20749a3d940c095568a0fcf4995cbb78bcd31 GIT binary patch literal 7618 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 literal 0 HcmV?d00001 diff --git a/static/images/companies/podium.jpg b/static/images/companies/podium.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f758d4cd355fe07f813a3808d4273e72d9bafc1e GIT binary patch literal 1357 zcmex=``2_j6xdp@o1cgOJMMZh|#U;coyG6VInuyV4pa*FVB^NNrR z{vTox*0zJ^W-%~0tbEPX=fEJwA1}sNa)E(~)jwi| zYl7^mps5cN{`Fq@#lXPE^JsVF+urMyFE>l=nwioGG>SRm=CP??zClc7V2}s8K^bTd zD+{s{fg#Ao&cLK##wa3g;20QE#ET7F38@(Th_Slf@$uZ_+vr) z-u7fKN!5OL>M0xL{8-&+N+zj-XxgxWA$HZ4wH#`Fk{{-=>Zx0q~|NWl<6jp-BVF(JA0I|4;u+E>rmfhcI%n;< zgnXr_MIWXWZMSUP)0x$MDDu>;;7Ko*OjYpVdwcZPr7x}O8g~xuk~*{U`iYfWZEO~= zn)NY0;?=S};n$?6PR*4}+}|R+>2}X9j>m4ZmS}Gb;_VBXT0HM?_buz)mtD3zHt&&= zau)Vkn`^_7d}pulq@@A-Y`(?(_P!)Ly+(BVEL9=VH?jPIed2qj#wHxtf8VZW{>;To z=T~gok-KQs@et2{D*d_Y3P(0?&3e5>R5#uM7<_61z$j*7V`OH9gbgtD2{IT8C^{xK zew=6!P^jQ=@ZkqoQm|M2ef`NU!FAhX^LE`W-SxV}q(5cyy$?ADH?y6QR?3+>FJ_;$ zp82t&z6Z~a$)-FO(eRk$->G%K^w*6k=cfwvN^f^XZ%hhGS17&-wdZ>1vt8>=uU4*GeKu9_g8!1A+xE`-mVI-5_SuXJ z496xkF1FZZuy@N+CZU<@&eU$SscikIaa1UJ(Yt*+J@^vauDEL3EHp~{b=3DvgM~w^ z%Yl>i6E&`c?wKUUAv-D2#N}hGQR|M`lRn(uJF~MvIP}6#`DLkd&X~{ItFpM}-N7G+ dYCG1da3(NXF}AqONwX4dSm|*m_k;ZZn*h9K*J=O& literal 0 HcmV?d00001 diff --git a/static/images/headshot.jpg b/static/images/headshot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..30cc4e03ceacc4ac2caad16f6c1e3a7488dbc3fa GIT binary patch literal 103380 zcmeFYc|4Tw`!{@z!5~YDvJ5k!Y}vON%-FJKUrVwJ5e8YtPEpcWD~Umjr9z5OSxO9* zb%ZF%$TTL|#=hOt=llJ9e!tiA`aQ4bx$l4P?>Voz=D5x|&ht8slV6g<{107~!}1T$(;Ucu$&kbTZ~8C*g2Dhi3YB**`S+ztPP9JgcLe^}pq_{Wtn= z*%+0UbNoC1&jbFI7!(tYLH_Agp#P~A{--sJOp!{Yxccfd%0$}_%y(x2bI>SK_; z4BGqOd7!^@0cNH@{~!75p3!1VbBsH{$=FT~q57xabD;df!$UL`6oSI!J-mZGedN7@ zuP8)$geWljlLDZv6BXj&72p#N_w@1g4?>A8zG@eP`+K9roYX87EkX=@{QOO@p+0t4 zOM5SDfEUtROa~3uj?#>}5^}{S+yfqUB`_#VGYTd4SLK=v`cJlk82m4m@Boz9ISXsJ zL2#%KTuok8UQvuuI@J4;rtKM{f0t$4p~U_zWMpKde58teaHy|>5)z42P*he>R+eLM z$c04*g?mKF1%-+KUBellFt1SmkZ}LtAo!meJv@W2hNHw7PyUxkS3>@&_J7pZvSGk2=?~B6#f6f z^jA&6q4vSSfhe*6qwy{V|3^a2KM(ttY>Wo{p9E82SYP4a=Kn+f(~fBPf6{*}@E;5O z#{&Pcz<(_89}E27XMz7hf<8eE^bpCwdBDK}5M}*0Jc6spD*_08Qw!!lZVdqFKtav` zSoowdlmS4Q046At4#29UtfHc%3}r$CY=7{FlH#8mjsJe5{WsIU>N@#XU56*zr`bei z&40o0n+iuyY}*`k0K9BqN5%&v1~Bo0z`US?cL0omf>}U+rN4?XE)3s;nS~X?#?Enw z!O+O?<3M0A6Em2F<&T)4xIexLGcU`L6H0olM{PVHVi-QrmlfNY8sp|G%_|ZHM6sKaCAC%-r39B=aR3V|K+gos}Ye= z(b$x0*HhDO+)U5O&AW5=UjF@phh^o2ipr|$N6(%&G`?tRZh85(^Icarv8VU_Flpq| z=-Bw@iSIMy*&lP1pVax~l~wxM`o`wg_8+|%4$8mOVqE{F+5bZ?UWQ&w%*iQhAHh~t=q>i3h&e^mQRv;TjJ zCI263_K#x!rPm~20I;#LvazwUu(GnU{7GzoT?JX$SlC2_V4@;IP$*nN0uC2bJkFp_ z!zHAoq*PU5a4p@_Qi>8%s!|7xN|BSq{-jgNK=48KtQU;^L-GyEoA zFfX73e4d55j+E`LTJGYkD$Vo@$*q1&l+3W*>e85mZR%vqK5G`Ye`37rNb3Q>;~a#f zktXs)jq8RJdE4O$&Oz+38k0_u=I!B#j+w+0Lg zd0l3Vd6&-aj@^X}ujLYERK1l5k~UfZsX=0k%{>!&Uv86=rIo(5LaMjZLst)gF;##= zzhxIm*tW&(&m_XH5*(hh0=hMARw6XH$Ef5!0)C-M^$-aZU!)gmLSP03??qqF-igJ3pD z(^z`wqhej-Si2i!d|pzV)*w?>8Qe3==)MHbxU@p4+n@J2zEc&1a7EkdLL>{kSZxK* zt%>}EG&P; zrLI$$1>GaJ?nttnI}$crOd%E?9TVBMKbZtebG}BFY*kcXw~u7zPR%nb_ktJK$~?== z!`hwKrNC|jF7o-bP2W}x?DX_L|C!lH%$?xUE%;|k<5_!HcL3D6Q1?y7*FsYtql91o$ zd+5Hdgs*7c0npfsvnveoPl^<*(D}Nt?{GfYq<_g6nB~sPjHpBez22JuA`;{qUOlRt zP`0XEC9Fo#QmDGe*mtQi{P&7S%a8C_ClCN_4r`SEEjT&biWxg7hVa1a$YeZ*T7k?)_lnGaQ^l;iJy&{yDWk$tFwx?{NT;L^uvoCnLbw1A^rqM6=vo z84Xp?A&x8DUzSa{{RA3H_M}kK(m->$&a92eg<@yG+;)(yOOCNU0Nh5hCg>2<3yX|& zpo3zmgi9`}^`N;EQ`JpgE3r@ou8or}3tCB79|ie7xst@NfwU7Y`3RkFHe3)fNa1%aLt z?nB)X`rqtVUl&ztt%_~bMpx)t+Kn%}-me|6eO$41<5guEi5!W^ED4JW<>Q*jM!t-(x>*$p1Mhxgg|-OMIRhF3xa z_$9QnHxij6tFMs#FFEvo@>l;YiB#pJzLqUlotb`lowpVQSq!hex6eC7I{-2r7PG@QJXZPo6rwmrZlmTLiK*^QSp z4yh2N2=z(3%krmykECv)0-m)Sv!WXE(}s*n*+)woeye#>t42OPeYmUWBhxcTnxaPfwf*>l+K zKw+(GH$F4VMm(GjKLAEEu^ny#{)>e@Rhq}bGVGT(i!D9D7cV4!d*>$ba5_M-w}dAU z<}#YFzL&&I_$aRhI%)Zm@Zi@9C4;gU`<3fB(>D<+kE@JA!&|H4hnGJ^&SqOpRk8>Q z#JpfR4jNgja@4hC7wkt+Z7C!?lBnv!?$qASfAp&OQ`I#|=EOJ*&O(1+HJd~;?1=oK zx2tJq0LF*SV}|jH(Z8Yu81v8#9CCncj=Fpvv5l7zUo`AKxdjxMU-8sq_2Z5PNh zDNXPBf9L>D6uiR>u9{uob72-gmBrogE8RTv-4KR@)&ChMN31U{&L6sj=pC?`xRsb5 zqEktb53}e8D5&br(L~rp?zW93(b*jijgxNgnxtASWLprCzonQAwG-B;rZXAt90uEi zCvK0emDo0UO(jYJr>@hAN0X(%TZ3TYN+o%0t)kL^W?8`;7$UHL6?Q+T41d{_RZryQ z-sO|fO!IUgZ+e|EwCzNUG&!=3!uC}&5G5QR+tcVJ3g9M!N#|CWi7_A0R}zCKsty!K zcgD7*wVuTp!uf#dz9vaEnOypsi2wa96Ld?ZLa;ON^m%q-^el&C^Bb77=xch_y#t`m z^u+WaxNU?RL9F#VUVp@Cju{%>^C(aycawBD_KR0tr87V}TB;Mpk?mtpT*zZS8UjQJ zR$8;nW$Sg@uds$$pM?)V5@SBawW1&>KXGkQIxu#xKu;qmg=*3})~;>Gbd-TPBvHmS-6P{5`0(xAK9U-~%);HlclUYVQM z-I`vU>tHLjR3t(hEycklq7BnZ<`AhpM5TtFNqeT7v)!UD8_!B52}0YgHZ5W4Q#}C8 z%!e3Dn!!NbcjJ<|dr6Get)R5e`T^pr+x9BNHVuQ^?DS$ZeN+%4ux-uC^}3>ey5j&? zUR1fFPds7a9@W$-X0T4vyG@k0_f`8e@A&ZCl5!26O@yW?Ja;?37prpItMF1{{f{H1 zrmm6~GX*Dmy5}w0KCh!_q(&>Q2{+06V529NyWz;%i@PU7a9$Zf!cWU1Dvlv(hz%3| zXm=}-=NH?rX=~j(K4w#OCPC2{{@7XPy4(V%-Iv!n?QYTu*IQ{-M?7?X6e@NjK_LJk z9!_x*!?EYJHS*ul_psiZ6Y8oi>#i!q|ts`ZcJ zTKGN12DIIQ82j}2@)`UINF8hx&&OSy7Hil1VM6u7Z&P<&8TA(k)>g22lc3%prIeaJ zLqF_%X*%Q!=hZrWQWlFH?wqfPe^R5rsJgqmg4vM6Vp6e-!`XN~0I~0YvDB>)L#FlU zE{?uF0EqQ0&yu>0w{=C|IhD4tAt^6puWhDWAHH%^^3*g_Yc+`Spcx`wd0E5TKB|Md zCncF_$#sh9c|u~jAQ_Ku=!iz{a%t`E*b2OAfz^rlf8UfySr~B6)XrRy^6F+lDAV@4 zYuba{x{^%^&S~*laniBn(gM%I~NGb6C=7q9muDq`1UY zNd%vuu*_L?rJ*Q(7fWSh^Wm)zw5de-lkaY=N<6F9`5J3?05k-peZ|in{aVW{b0a%c z8ABZ~vlGjH17Y-z^nkHm;-n;T!&pr@>gB%nOhh+Ap;s;4m^LTf1vo>cefyebxOWyb4 z33=0O{gF=K&3%Ic{76u?6GCE1w_Ih=__k-(?;R8o8cuceSibl?N4t6jIr;ol%VRFB z82M;$(nW{VT+yLs&Sa!sZwZSTSV+?&uh0R{<6uy`Ehvlo5!-`fIFQ6Vm_{=mcpvPAyKuOk@Q8YeoZnJ zf2T83coux}Ng~cvptpKvxdAd4HEXjs{Ce(I(q}NyQp+}y%-?5BmgOOPHLo~42%2bw zrPDWpg2Zme9Qk4sqVXzbCTr9?UhL^5oAvyVC}xez_jYVQ-B|g30*-Y5aAAqLQr+NwNuQAdYf@FmS2{M@$`I{el)F1ksktc4iLp`lE!xDvZ@aN)K4b3 za$Fi8PKlJB#~JUE9#BPe*45>ilO89W+aeb@0@h%jtr>#rH!}}d5z<0YRAoPgM%~GF@9LG<`)!KtlM?7?P|0>r@ZA>P+LIec$0kn8>e^?=E<3 z>xHv7*#zOBT>Sk87D`mx}sRB=wH6s_NsxF>CUE0LdGMzn9wC@rN2hn87N z)2d%DQDli!4yP1`%BF5!GZ`-V?fmP??rk9YdALa2a|_gSEAb|)V60a{@#R!zuSM7g zzFj&6x!$G7`MkKKPm4B&^5z{(x!=g_yJg4LQNaY>ju}2m%F?MZvXTfdA8>Qs z9cHp*tSio%Jo~L@EFrGNHK$f-=ImM&0wSBF#wLmK|60Fq0U!!gwjwIr*9U%B*?Srp zGbJ9cCU4oM476L-XdA^XFIb)1!}_+u#VI)CzJ0UgJC$H? zML>C@&2^O4Aj{7&0Wxf~aGqm&-~I;?X68iQw1)63b3xXXkcZN2_15Z6gT-~Gz@ne# z4*=e@T@#l?_EkQoJf4?r@1=l&__*uxR+jfG=I-gt7BCAU$eDU)a~DbJK?(iR{)xZ# z<42BdEMz2&mYv4V`cloO!ji*ukNif?8)*q)f|R3BxAi5EYrB35n=#hRZ+7rx=510+ z;gv5KqTr+N`}vi@BF1FhBZ7q?!rRLhI|kfNQd?UsG>a)l6PHP%cmz<@AdEuA{PX_G z43@kkyHk&&TDm@#WgK}f8i2IaT;IEFIn}bJ`YxdIMqO@Z5CUe*G&}l zW65P$YZj%Mb7Ns=nTNBs z1BZM;Au76}$!+4KZ@<63BV+=-U1k$~)iAkta`*?{{jxp$d?J%Zy3|F}95hXnvQu-r z!G*`?mUWYCF@h(-InU+Y_(W$Awz@B>1CPnL=#n(fj;Qu(d#O(dmS<%@0Pf}!LQsic zjJUs&#oNv7oAq^>!$^hcD`!TpvP`>~bQETN?Q+h1H<9kn?&;17`1CxS#y*WtX&+P7 z;=VRb-f5guikh@GXSzGZ~0mcHZQL7OB2GzIxkU3fBkpZ~2P zxt#6DStn*pRy4n=t9m2XOB>~S1WbXiV-bu~4AXlYiv>qn%zR!Mqhh04#%WDh;{6{4_Q@ls+VDrYDa0)_596E87A`?N?Cry+vBlW?;^Yx}$swJ~x|-yPdkg-1^G`e>q~)?+*snqH z1Ja7s>TsTeQi9-b9U1I5!>?N?R+)E<)dxv{-IW1Fv+v8tH!N#HGZImg1pxK6LZ-S$ zZZ_OgWuldP;Hd~t-R0?637d)UWUZvP;Xeaf8@BX0cRLp&AL$0X3sEXQ036IJA;hkyE_FRS&LywOhqYxiY!7Q2~38 zCuWFR#*nNmi?gb{#O*%B`H%OjOckJ4Lv;JJ#M2FUNUGgbE1msEiYO2|4`lihUxcAr zpyKaDy<{Weq@RQ};;pat2b;9L`KQ04@Ts*`bBaA==u*L_QAE zVE0vK+o*9Oy0JjkPS0&K-{{+~EGfaCSa)Ij!y&*ft@MQ}u(l_A+|u>1S1n8M1v($- ziXms%VtNQ)213W`eIlaxCPe5MyLfnqH^)liH<{(!hO2cBn|V4j`gnX)U$jxwuCf&9 zwzLRNTKhXLuUnfuMz4Uzq0;!+9t=R2{Ep(b__>V-VOVn#)0;c~udbhA`?CwwTCdB) z923t6bJne-S{@o`S}kGqT`DO&I$Hd^n1DD57iZqXOcjDq)!&s4fceUB>b@$_QCT%} z4_{oPEo7hzQ0aUAR_(!NRx477ZYf>orw;ykpyGUvUk#haf+Dhah6V+(-oGLEPm})j zlw{p6;}EDrQj7m#GKZ|=Nq}>o-|~~9R z4oIRE&DCj{?ErW;GrlIxdpgb#j;z^TBa29f@-(&A7``g>g%;??QI&G;f(z5lcUIS` zL|Uyxq)Rge7QPYSa;$X8)w0O;IVFeA@VR@@8{#zGV>)%Msu`hLJ0n_|!IuJzL)=cJ(&*4Jy6ye1tz6sAH=uMsbri7!F&<`aQc%n|Ms z|9*e6b7NSer2g0VO#%KnEhDyWNTbx2@%w0$Wr*Q%@W?&un>ToSg+U{C$!eG&GKZ4b zbKV^5S&o&HcMYkh6Y~44!%*LM(_@b>TUG+)Oh|Z~Cx*Hzp(ZIvL+MOMC1p ztrb-1AgN_Ad#TcjcdBB#Ne+j&qmg3RLEj=km}5J^5WcQl1oazOjdE+|Refh*Y^VU& z!^+IACZO7HIxHgylFi`d4_x9#h)~aER>l_0crE8-1Sj1$9e)RP|8!&5E$9N}Yoa28 zu{St>meN9>woM^I)cP~|&Z89<1tnpM9gi^qqt_B8ZQ~%$z$a{`0Bt0`k!jv>arNdy z4kS3{B{A*@EC6tJ+E1iFAv$8DNUVG=a~Eywvy!7rmxZr#Vh(Tz2a6z z-(ij3j&UGbhnB2n%sP0%wEy@-s@>4KQ3A2fO;<)Ekhhx=f?L621`%!RY*aJZMN}K> zWh{5c`GJ^3P3cvIK!S6zb~t5xgd4fr&H-Spf8&)sX{nk(ljeb~E~$axbd@dN${MiNVj6Kzh>kb8uRpt9XWA%&AP$Zd z#-en7HoXQvxNhT`9mw+`3C9{XXa}}Le?p)hNu^l@t*J{L{*0z>@KX}_e)u)Cs+GZy zM(GI*2&nz6MZ0wpqT9Pt4uB&?s!+ym%DRzOh#&Z)#ctwk2|Qe4CUZgZcNxAj!@*X% zd3X8E!wwgrB+3t(nHn$NE(51Wvro_B5g7Px0UIThK2UVIiDlAp`ILy{FRDm@l_06k z`PD+)Q=7E&O>Q*fCjKg82(>>z{U;Y0pfFs5Cy-Ubw%uKolsy(?narcG5h%tm^)!se z=j}~DRm znqz{Gry6&)4uBKPk|hR%-eZbtC!txoMDt5871+MibXPq}OoB!S;u=!1@p#3f5UptD z(OGb1jn_FG0&pCGy^SdzPL$`)!=arWsB84{__Qx!x=@XGPq>a~(_`+~tkp?_XI*)| z3i8hvALZFKmFte$IfpK~9UY3(qC>BiaP+YwWfNuC*&Qda8LKpB35s%+N}*tgHa#z~bkr5l(@F;*}skdhHPuYEKl93I~QS8K2~Z-Khw0$NBU;W%X; zvWsI%vC_*U0HSuj!<$<($uaTE3+mz)#~_5MYLe4^ooLW^0it8(DJ+fHPG1SWar*!` zTE!awO9W+zeO;UeM&GZK*u2p}8_M|J)|$l3}UnWv)(xFb=Tk$qC@KQ%{^7>Cv5TFBs~EZ&R)^$By{P7Lm&||aaG`6M}vCA!bG72xghC+OnJDt zc%uT%G^6+bd!?x{u) za=#JVul(*XqDKHVpNKyc4f7LTF?PUCJ{yt@F>Su%1O~ZPSBLMo1opT_Blt%?U%)A= zlUXn%Rgg1LPYV=tzn|5to@(*wG^MG@f8jTD>ulET?trq}5p}eV#q$MoEZ3?1>SqR$ zOnA_@x->cpw?cV45LCypZe>8bXA;$|Xc3wo)en(aLzc^J#&|Neyoh9GPmNCH*k-v` z+9MxkVj{Xtdv-qacSbC3LT#G2v$T>J6Z*MWJ-_b>!{V;LglcP_U$(!}aywO-sbHnU zq@O1!1XB>&lW^@0N?Dk3xP*P{_6}1&2n8pPe3mae4Y@BUF-;zQ-E1W_Z2^bmXk4u} zDpRK4bw6I1#&A_e$XS8?y1>dg(z~|%@C^EbtLMwFGkId66y%An3vNfIm^92XAR_8R zAt){aSiobkOR{KxaQAU)W>+LwtMoR})4P)4{#?-5-RU|25~P}82cMQSZ45>4)Qc5B zg1shEMsp`CRa3FB&TpH`uh91l_^IlZC!*HtG&keRcGSI+R=-T|j6Iyle3ki~tlB}k zK|cTx)k$krVhlJ$qHPa?1(tEI-Ny=codT&?=Z%2wI@2sp(X!Fkq?vBk2W3fP3z@o^ zGDOKb7svi250Q5nD;_U)U-1~6BTh6l#F?Cb@31^;t}6+xF5zx$IO}waRbc2TR^4oj zt7`IA%;W=1ay^F@SyYTXxIgl|2*bywJYpgovyiltS~(hWsB z$MIn}T5eu*+4<`xb)qyc1sZ?#K4Nd{m&w3zqW~0E`Q!ZaEP2bA5^>f71765`(AudS zmq6F@_43u@*<%@Ym%>&;FgQge%T8H~;YXkDx44pN4pk?w^I7{HwlU;mlh$J_S$y2& zB$Squ)3nakA#-CrpjYiZcgX>edoehX_3GK=cxoE+y0fDo?XGwRCwXi1qyDqgSgC%@ z;CjssEa!T;@_TxD7}1<`w_r~SJg_gdTz(EzT(B9@7u}{A&rfwbGVR~6heizO1WHm} zLzlE;5#rF<4DUhab7cCX+`aji5Wz*NgCtB1a16@p5=87>)<>w0EHW@|g{^_vTE(sG z;{w&^ykoduf6~fc1vEEG1Owd^ki^t}-~0HVN?;DU?f=iqbkUI##2 zyJpB8;&RibwMu|$N%6;R&-&{hQ#O0i4L@Gx?sQ~qJnV>=5*5fX(*A8-)*9(3yHfXp zC3-Q1pe)y^aqdfq*4V?(;nrHK!_{n`lcGeh7)N6|Ilb;!h>oR9&zfpSdeH4j+#31Y z;gwkZ76IAIn%u1cNzG~UZ$WY|I#Fq`{aT~XuAV9Kd1vy{N z`YDz~RN8?vI3j)*W>5+TFG>H3lTOfin@iHB3}>u*;Of#2gXBqh9Tsadq zylmIspAo&ovpQgAwYqSYHc^nE2?XFZr|rRYc75k$v(q!W^+faF5^0N7BIgtNzxw;d zHmAiyYNEH5Ry`TWqQ=@pM0O~=VN3is!0hg&<{thcV5M$a)A1u4FkpbgH{SDZ=3w8b zxsl4k1nnf@KJ{$U$$BlsBLY%2_aeM`+Y5hxdsIvmyD|3?B@+6WG#5Bmz~5hNky&Bv{Byxe z08&ac>#BE=$s`hjC+Yy0nY%L>yfjlEYlIt||tPTdP-j4oZ+!RV5i z&2F`H=kCl42_xF3Ee}a7Z>_|)*xYxyTxB>O#bN z`t9Qi*8v^Zt%{3EXlF8u5kjE)_~k-hK}6qiiNpCP^10g@I{J%$$8jSbeYza`YhytB zlNr0av;~}?dgLUZjV=qHZ8{LT26KD=iYM*Eeo@>vUYslrQXJH7cd@Q>XumiC$CFbj z5@wp0dG5K}D_mMJA>f^|j!^IOeO@XN%wKnWty<7W(@tXFKy`Vl-~gyJAA|^!BbelL zinoGHn4Q2?FSoq+<}P*g&N^LOmUqN)!NsAClR((*#y3g|A9DI|bkJcJsr5%HD;)_k z!{R>>(;$3nfM#&(?@;4LK=&&fS#?B|NJ=S);nv}}91{{(eUH~fKzsj=enNXTExpb3 zXVfDN7X-L|uITznPY`vtiqF>iQrE+D1Ks32TibMZzC0l*fd-zj3>!04t0554#_mE4 zedoLJzSzb!)3Z2)eh8;B`kK~3-V>e8J^&OBr4-O(PE4j;XU6AsjNgKW@5%&yVn(r8 zGB!|zmvLK&uBfrh{#a8PN?wwV(E52~$HJ@h05nNqFR|cv{CzfcvkzIpU?X} z6#~=CgVH7^@@$`$vqUXPrXjb=1=iK5LY{X__-2brlC8{Et5So+1jz~LPgG66f!xgR zhU5{45=|`?#@TqlnJE5yfe6vPR#`Lo;u|Gr>ITPzmzl|Dz);natF>J(_w)NgzVZIx z{h1xSb<5>Cz?}!0YfVLzZC`!#c0q~g5^w)K{F?6wy`1>~DB?d{#Iww~1~0IYTH|}7 zG?y_9vHRjXoRMj5=?9=c9Ze}5DZ!15{xoDeBdEhTmSc>@1xVGvXr2@ucE=$xXkH`C ziUTG6p4EyGsOhc>vn(HTD4l(CNVI&3=Tu80Se$mzHMPAtEt&mfJw7=}#OKDA6S{D& z3H}q6Ak+2CmMJ5tJM2OT-HtYqbT@{(6(Lz#8`<@Q^>!6!__Z7>^D)E8@pYz_1cCbf zt`TI1IHYafoadB5o@ldRNnrsW*UiZcdRe1Mx03ccu@xSqIjrLrXcwlNc1$%$HF5Al z69ZMFUfH}Ft5MA^-ftC2=uQ;nk~gMTjkWVl^Mnul_Y}4msuC|uo0qWL%@JOiyal|*jwwB%)l&K@HvEHbFgcDCxUC0XpTa1LrjPh zdPubk%-LIZ%!bG<9ic~;zrOzt5m{b)ly~@T-WsfiDPeMD< zHDT0=TSqs%TtF_iSLa@3rXAYPt=8C65kz4aQ;bss_=h;6=3IT3k2Co)U~Hc2oE;7$ z+bZ|$=k;P?1O&`1u$U2lr3tJS-(1*f6=4OAJ}=B9giuh%UkIGMs`TZ>J{kJ)VI)qbF${vPV!9Ofi+01NA&7>1kadaU@2<~v5 z%_KD4%w~iK3;f>YR=T3%tM%LX!`_f=vBuk>CKxyI|dbz*Yt*ff@x zV2&m~Bw}rG_>sd0bY;7EBPSOieStBmY#4~IJh-yCT>0!Fj6`XE78sN?)q2R>Mdk<( z-2LdFQ!(}V^%fv|Dm*|{h^}}W|G*Ps5-jqcPBqHw*F_XzkEU-uU z+bYjqhuvJTyQRVLF&ey70Y1ELfus{YZ3&~ae8*ttkphNsb_qc$eKQP2*rX;0k7+WT~n z;n)IZ4Uab^MwniTYMVQw?ePtzZ&14HC9GTV4Q=P%%oSzhyOZOS6M3CPw-zn=zP+=1 zPMx|1d>_L%6K1jwBgK(3e;`ZvkVo;s;F5t^Lw+U4cviW1O48(L9wUM(h*f8MBo$kn zm>O=D7hJyT(h+P7Zj#FPBg=WFPkN^)|i4_<`u&0YFeC4IsA*JW5!H zaB)>-q%mz>Sc6XBpVVMwi>| zHKdwS4VbDS{jOvvnGqrGSjt?Jpuu`*g z#sH-;bTR?&$E=nH!D)`3?C9!_rl8keiS4G1@u!9DzasGoNf@5!pK4+3(14rFf-%L; z`GAqqz)Hm}lg#Q3^c@3hSewAF_8Qk&4RAa9lhFaN7cz@i$~C`vC$VE~u>e%QV5)aZ z;%k@Uu+1OzVq*>r8IKI@{uF5cZoG*(n?h`rsT0@Epmzb0`w-Z&d>&pWAu;UYTB(+? zW$WXVCC_W5As6z;<{*=uidT=%GhL??77mtN3EeQUvpv~L@-A# z6g=pMinjdJok^64R{RnHk>FT50FFU7)9iG<=0fq~b(dFJT@IUo@d4ehje`cB%;$!5 z4#2tRQUkz;+H182JAdey#hfA~^FVERvoPE11TWJ-U&SA74HG$rNXenF0tGrqlLCoVcM z7p!q(S)9 zM6d`=FlsJ!KtK{)kE{R>44g6+&gbomc&XU++B-Y<`gCNij7pD0xOlPI@9^-wcW~e5 z(kLz_%^0=ss8n=g&0#p`C*le1#M=zV0!DD%I+aKrWyEo$2??k6Yp=0id>l^01>D%o z`nG&Bv*c?i*C|MzLh$=q;$WQ24Ja-izZQ>9p;GPK`94WA;zGRyX6j(XR_o$D4;rZz zP!yFmfZ3VqJ?uarcctflVVS-m^|HDx$U0bhPjFz_?y2Crr*Ga6A9LEWFOMyC zU7p7nWrZq!9CwX=!U)0emt14s!P@OE?~%4X=`H@$vR&RcWbC~UE!h;uE{jIN&eH+#F`+zR=6X7zq3*FSzCNd?fkfx z=m=b)Qg3UmT5o{0)GW)6N!kQrS8S#xvs9GEnRi%6{y|X;dUwn~O7sFxha=aZ zs6RM&WYGV}GkMbimrvI%Wq98#44kU8dTII-R4O!nz2i%Omi1h`mefq+Ip30glRlq$ zZI`D9fH%e=Oz65c#-ehYCAnYjb5LgHzg5YrT5(Vwp&qKncgq3YkZX+S&L*Qdh>=@ux6# zo|^NkdSy|n9R;H+en)-U#_wqrhX$XjxqXRNX7;PH6ecgL%{#zUsMJHH=?aw>u11I5^F_3hL3e zmHuE*=%;J~r_e?pTO8|GFLwUPQnB<)eKz#+>(Qh;t-2lSC8_QZ= zXP`h6zrzo6@@$1z`Agk3m%oHR*&ZgPCLCem%Sjg5u{A+keseZB zF}yXhu!=j?jS3*0HvU4i7+_CXH)DGzcvX#*Y{-RBh+j` zE1B_)7)=i5(LRbLW8wUApCWkoA#Cc?lnsQ@GT z8cT}U83e!XhqOu|1rLBz_nS&Ks`qL8Lmzfy8>cNVt?adYg@vIOH$y9mYge%dK?VTB^n zGJyS#KB=*5CijZ9*+qITOVqI}dmrP>%X4oeBa&v%muOtaPdF^B2X2H58!NxZJEX``=;XBq-GwlBSDKKbe>z0Ns5 zwr!K<;+qZxj2nod#k9`K`>R8434Gz4PH9f&DDc1eEGkInbDd=rImr1?1bOozgm2*a zn-S;9;zzd4Lvu00JB$|r^x57ZnehNcjVk9G$ar1g%!@b3lU}nURu$)SOrPuJ(lTrV zFBzu+>ca=Xp}1*a@xo;!^lAn13ZL#1-WypfMqvec3RWL&g-$fXP7q_gL;~1?6tMQJ zA-WP7(@uJbEhW;_Q!nAR35^^1FZd{T9~p|v?XO<#K~+(A^yuLg?Q<^ z=}yzEhC~Fp&;hnO`jT~6bm_M-@7CFVV`u-Rh66zUvu9}3p{Y9`36B+1b$ZLupIR6# z&^k@6zcG7V_1mVA!j923(R}2?+3~J2(o~~WTClO`nHEScPC8A$4FdDcTHTd3eA^u) zt-G-&L#Aq6Hc?-h<&HPY{B<0dej~Nk(IIJ|layo+%@9xJet6xoHyEYFIsw#Ru>yr~;pl z|JYu3*&EK5*X@r|8+wmsyuSLDq31cQ7p8|^GFl)VxsB;VF|elvW&mn;FEOswPhG;O zJBoQvR@gf5OOLTRm|k-gikqun)YIVkhNcf)drz#05~U{|VZ`}|P7U@LLyxBXl+`_V z+Cbi+m8ntXs2D=9K9NXu`u-Hmb;|w-YCht=^>;ogYL-g6M{$HwM!Y>69`*R0J15i| z=l=tT)XsHaE{}kcUJqjzrkB%MO(ixvAlVj2jv!E*YV5s|RRdTD=7d6P=JzJ^Ur~>2 z;Gz_oL&pYsm((#EDe}|&(4kZDEnSxEM3j})<+{TTvzZS@Ms91kD;ukJ&wmPtM)#T5*P_@Muj+(C%)OTjfN)(Y$lKKD7-`CQjsLJ{sZB>i%z*emM& z*JK7OvqBd_(jQ$aDkY4HxQW;7Wvd||MLjeH@9Fv7L(VwdMcV^K zVtJ^%S+QovrL5Vx+fVMadEW8+a%MHx&!-3m;#)&`#BHazX#( zQx&F$oexURyviR37Csdu)QJm!*)kwtg-w@2bfn-V;1Y@HHjQ%Z?1l_jp!kSrYR6{K zBWpsP!Lo)N=4Gp#*Wzr^Lx5Zfw$HN|Y`l?kE!N`K+aTKvsjc z(8&+^eDqNh*t&A+Gc(BfdLoTkw$d{rNbhevOQpJg(DqTqTT;W;?&(ZU+AA_s3+BZE zNIxoh^oew}uN1T^?n;&@XIcb8zm( zS9N_w;m$X4qAd!x2Oqcs%2X58i=@8Z78Y{HX1UgjTV8z-))jG;;hS&x^=nAh~R5W5f!YPm!FH{bwW>8 zgCari<_Mt@(=R1566J-^oDf_xeW zuq)fx;RX{Mptv?_N~YIjK1#y*fGNcD92|}=D0RPwmA4JxXFB^I;9J?{^RbdSf-{c# zB1Di)u%z%$FsQi4(Z2q-IX=+^mQ>p~1>ro?O4luK8~>tAD7*JSX@BKen# zYhQAn)K~BSijX5Oh*GoVd6}Wa1Um_9C}&d4!ix+y zA5)x~PYy?Rf0TNzB^XaM!Oqe~t8WjHtxlH53&6I^>)k94$$3aqaM;N%TqQ7FB&t~BS1?>_6 z_xM8c)vKhMeXJh;yM)w|3UIu)j*aSEK2RPQE~S-WToxef0q$RN#ECxV-lQfZ#p{c( zjeTcppntu3sAuqoEB<}sdXXU6cFK%F4Te&Z?dM{5y%}68#kgIur`}IPQ!Z5sazK7u zQN^#+sZJ4W)ELdMrGXxgdz{N@LGu`iL1HJYD1g~jEY*elW>vZpzrTV=S7S{dX)PGf z(tmz9C=x$T0x4bjp8u*>;$yH8S`Gr7?>`}6;BY~5I=ZkGdq(KR49T>t{$*1t(;v2L z6ObF}#R{W@G-n*iiIwm6o|FO6qRYXrT32xDJHaLzdcQU$dCDrT5w8#yvm-N8|;WXai&#J88JDOtPogQ*V<+cuV}M&NR5|As`@wkn87Y zIxU?>U7TG419z(#H(S-VCsRXOg?xLAS-k~gnIUFxPB#o_ z#{ThWrbXh>-_q0;*rR}%G|f#UGYGlb(gn?7)!PDU={3&7U$LhvZA`i`B&w`y{mi%U zIB6~gIGmCKR%jEk;Xc6pD4zOie?i<)b$_Cu6lX?8y%hEDf(D;`<(_RZ_o9=%_qf6> z;dm^>xsh@7fAz8;FZ>Q^(S-wYo?jRY7ZbJ0v7d;#Ga(Ecq^0LXXSbNd<>6Dze}Ip5 zf-Ls;;v^P}wfq&cz&Uger0RoKQwDuae}PCqZ_~E4?=TEro)`7z()IOo?Iok??nhD` z#T%F(TZp(r|MO$K>#E;xuZgSWH8BRQt##r&(JH#;KL97L@oHug(M{_-z)Ly@I^9~T z(h1jXPgQtDwzXdv-F?BiF_ze?LBzY7Fs~?H`IadTw*9&2 z-SS(&>Kj=_U;Z+Kv!1C)J>@x&bIcHosC=9Jv%nDge&FlTN^Uaf`C_^Sc&ErN7ZX%| zko8S>q`cvNV@aLRjp&8kU-vX*eN}WY^xe4oVWSCEnJ5caMQmtYcEQHqejopj?jdg4 z^v8S}fZ^renIH>q2m|VDJUmAQIbN)L^jYskMv7M*IETvPcuQ@RxX4j^X}A*3izni> zW=H=m0V9L92VZWV5C`2{0Fl4wHMWQdcA0hrTy`qnKEn6`9=OPcqi&`Fgvn3%JT5kf z8rJ#<;lwFl-a;ZEpg08&tE65=Ku9^Km%+q^?gEm?(5_O!#*1_ONR$6#xb-hHo~6=@IqPV&i=z z7ia^d`%6VwydbTwY2TQhg=_+HoB}-cSa=K;1Y zuSm-2Qs~oGLWe$&_1SrZX3Ej9{1`1k00&o7mwp6jJDlD!box?2Bh*254J$;>m_QQ7 zDtZc=X^)s^UP#)O5PS5mNMI&F zA9~DI?(d(h!$m_64^icrxPkL{Cw{%ZG0jqa2iryW1BkO4uU)-B38_3G-Dm8>{^Pu5Uy*<*gEjzAM)R3bIL z1?GD#!J8_*x@=g2eS@}RJ|!i~QnD;qdV`A5HIfCRwLW4?1GNoSMv_SR`zdZ7wiMyZ z;oG{#guSE6lx~ZgvkRX_LYK3VwhDU{%&Shx@DOK7=Xd?!HDgS%NapyflEZ9a(qF_` zaD}}Quac&&nEH}(XsOcM$&EC~QkdBgCzrqvj#at$7O|X%8q@RyyL`Y$Py@lx)g;}x zA;Frp%Fc0sZ+RiSojcC{p(}ZpToCxQ$E7B!hP|0ERWz@i{RX}#JC0D#=VEp1(S(Ax zY@!^fSSJ7?k)zj^Ga*5p$CW1o_2|l$Bb6`0H$^5KJmFiB`#}#%5Y%kuk~i1|8#x@NP(H6p(O9hs$2ro?0GgFGv#){s zg#0<^90qJOu?tzzi}w5|=|Ka8Xc#9rasD0@P84|7hMj#KHw}i%>I67SwS%C6=fvGS z4Tmfx^fXU@X@FjRXE=!%d@|?pZAlr*TSO@mU*$+Oig&;Jim-QDE<)1-cs^aHf}C*T z<4~lbGEA!9{zC@GTR5)6U?7aRtVxXVy#U&Cngkjc#J&M%&KTn<>8+6E(%IM1*9S*+ zTVj4aGbWHl2NmPKib+DZrb@u|6lZvtJEc4}ZJxO3qo^!pl~&mM}e*X*-= z>$tb$MEa9}iq~jp8dBCoE;J6>%ic0M386te(oNr;|J^#UV$bkc_xZ|M<4KiH3IpK>z5!r6gwHHR2K-?|M~p%-x^OJ#2w65(LETDhI9;*aZ9A0Vd0A!Jg0kcqMv zQ_OhDzU%$Ui0R#6avcv(akS}Qd5-+pA*b`7oL|1(sC{)35$(P{5QB( zZH+&hOZVqU&V&Ic_6L3M5P0`1=%79Ys07`~5rl#XZ<{`={U1tr%eXx|gRanDC~Q4~ z#c_$_I@3&~Vq<&pWDqszXSlH`k~Z1nwYmgg40afy9_r>U#$JZ{{y1At5%dHVO2lX* zuUz$PqKc$+JhPysY;4Ts_@k4;Q#^B-q&h_sg5_cRWJ>(9E^=Z@CiZH)9US-UDO0fN z+S2zv{2pW6YTl>(+tjn+sb8B@8vTks<(Y{+6*a`)W0iPg-*{nc)^IE6ma1oGlxE9^ zH8)wCMp9E?WD>v_56pC^QquXFEbGB}E&oEHMzeuv;R;=^Ir8ht_M~2wyQQ=#qNBeAK<|JqVoJmmxAtIKVR!o3v?)Y<4 zyQ+<2oX*4c>LvOKva!w)THkF8Mqid}z*6w!zjJ+xqTIxjQdc(F^>C;j6T`oZdZ~nm zDH;6+!{f)e=ePa?^jhe~oCflpRCIHS1KY#20MV z#~W2`G7HH;L~XqLxa2Kt8?4Z1xQ-u&UlQshHRb&3oLb&IpW@IFq-&Uq1(kt?9`rNF zU;8onvE+K((Ez6OAg3Zn^Ibr_`2bWr&8VfJ@hz&wQ}kq(>#gm8on_y=G-YJ5>dJQ}#;KKZ zSj>rbC4a`~DL%N7Yn5^++Wr_QGS%kpGD5fqf?y=#6l?5d+kZn(3}~ySLP5vn)C*2+MxcZ$tt6}S zqiv-Jbd&C5=R@Y~CJR-)T|RYdW>XK{P<)brGK`7DkScmKRPm!se_+1uA)}`~Li}l? z(%7f?JS2Gd;M~w-dwZ%#q_5*jLbKucN>I|l7O9~w!w)Z|&Ux}AEJ^2}@6Th74!_d4 zy`CkOCI7C@E;0D;QrwXqOpK&O zi1qxw7nnt=$19B0bn@zcV4izflIy-~7qat_uE~rWXwMWsmX2i0fVuZcT-vl|mQIxX39Prylq0g`6R31)-|Ar;=u$ghKz^R(c%^9R1p$j^TmQ(p!MxW#l}hR* z8SNF0JUI2f7tE^(k=?L4>ai)Ft6`^dZVA3(URfvU`k;WKDDil|MK zT>Ojc_Vyo_Z%-X;9UM>@8AjoaM@thh#fN<13w9MZdy4_K@eEdDnJ?78&RF8Enp2_8JJ9FICT9kn{)h>24U{|`W~u{)OjbHGF{_C<%ymT7&0Drv}e zQ>N6%Qx}V*U|oAamxm-9oZ^2|`z(iuGf&TtL>cH)Z^=75q`l^4T*HY^SW|*y;f2t! zUXf*?o1Ler<>$$v`K{{tt03uO{dORyXXDG~pIt(Ao?VFe&LD^7n#V0h5`WlpWHD%o zN=?3!?ILENU=R3`s64LRO6spU4>Q(%DS36qCL3RPN*z^ZEaniH$%5b^!DyrTLP;q+ zK}(PGy|_r z%(0`n-DeoY(r=-B3m7g5sEk~Uo&KE`_vG{=>>1e~UMR5K>_O)08ydE^_%;vg4;+pR z12vJscL(Z?of0*Z-kia~V~?V{)wJs+l?Ir{!?E=4iA7fC zoi9J&UC3TYsg)0c; z4BNcS_lOxSHJ9(2(>vC`#GoWB)%nY?3AmR%cz=++=JML&pcCcW$aAvC(WR>0P-K*lbo}EZ#YJQE|lo&*3M->Oveh#W+$GQa2 zk$QAHOwVH8bzP`bN15q=0MwS*?YVIN51 zbdVxWW#!7|sYj?A(rf+U?C9&KUoy;RBlu(CytilAux3jx> zuAHKMis3^@^HXc7h1Ga{7gmRt*6lxif1b!d)s7UPjN`t!Ih5DMcma_X=2iO25HK2 zj@Fl;SSK4wJWwI!`eZ0w`*9WE&j#;E@#3qv{3>Hqlg3rs-#&dfw{9*eTPhQEh5Tox zw0seetviuKMdb0ta*sHe6i~&ydoV^vL!Ix!6@4R5lUCsC(V|Z;{eJrkvoy$4!sV6I=9&#V&EGt*?>N*&8edL0J3KFm%^SZiGL7C;ru* z>x?47BoBy*S!8*s%FmsQ1t;jbMejeBP2V)@??H73cs30M8cJAk#>QM~r(?c7=fen* zrGnOlkXo$!$Hn%=Rf_KckC|DvwhZmFzh|iH6#~@M701%mZDKZs4HeU*F@kJVFnN=E zxg-KFm{%qrv-n=W`QjgVYh+wQ%p^nA@N?p~B@k$5X|6d7j;vXrS?99)ikXi%pEfAoV@{Uz77q~y->YUw3(mAFHen;#U)I#0d%F6S zG~N(X#%9t^16O=>&W{GTZR-;DtPWa5hi&GC7X4o@NP9@}MU z0UCw9P9ieyGCM@L258^6Q3c}d9}!iM=VnP1o=mrku;RZi|`r1eIyg>k$fBQaW=%0&Tw1j_Dm%x1OYMc(eW-bOq0-#dlAy(Nc#V8%}YJ z2?F+hlvGCVbhYIg)2&0qK(5K7zyGLQ0rffs{F){Bn>A!szAVNcI?6ey4Wq0f zz=(5w$_b(tnuggHJ+hdvjF4>oBv7S7v{5HmZ*)DD(?v8GrHspLeZ57Kf*)Kg40`^S z=TPQKBT*CZuzt=VvxXJ;&xc-NTf7xpI)0HQ@(ia=n4inP5D+Ns*xEwGS4o^_i_-dQ zRnhK@mr3YgZP{)Py6L$5^ZO$^rSmn(`^F|eSMZp#W3N0ddI@6Mbu%`fZ`J;=A`u}n zKUbf}$wRLP+$()qWYn(M{Hf{8zVD>MJe!OYE{n2kxY4Tn`W72KeCw0sivs-?Wtde; z=2&%sL-IuZH0|G~PLi$Mw zFqh(1$5?Z+Ptc%r$u7RBta@l>Wi&YAsNfd^*uN*#y^@mK26`ze6e%^#sU<3syc<(= zm~CC_sJIKvHZXYIqaGHD)U3tALn!aC_l5Ze(dQg>vUPJY+O9u2A{zXK#G@AUjS^b$ zq=3N4)fW5t_r%7dKB7(eQWxh;{cGFs!QNdPHM4O4NF}`1@h)Y_UG@(Wkzh`H!vS@B zGN{3|s*NtTPHl0g5`9u$K4P4zsox%kdupJGMG~=DB*IhPxoKZ?n@B?*Mw82`biHk} zAH2~O5XW%;RtTlhd)+RD#X|CXyta@dpp2>J9gPNHG#lQvM)neiC2(r}6u8-t(2D4m ztg@F~jr6_UrCGD)?$S_lL3YlEo$!W$GtZ@ zC^d+I7?M9>4{a=`4o?irLg1#ijCxRURF+nh0Dq$1+W?IM+U01n664Hpsbut2eKyrf z4u)Dlp(sTrQu^rM5G%$l?`srLR8nK5)Z7BVlJ5Jw&|U2jp@EGVlb+`dWxEtK>MJ72 zq-45ADN3dSYNzEAnO9OKw;U$Zdm+B(aTEi>E~Klu=+p%~z=+v^c0ZY`5N7^p6Ld~P ziPF()gZ6@u-L{Ic+>nSC&MwYE)394lG&^C#56051h}wh$$mn{M)dG6K=N4lFXQ+g! z;g#ma0+x#2nXMk;fI2=Y-UT=u9anTUfl49XI-(yD4}Wteu;tKkbMYCyCDgmo%k41; zaAn)1O~v{QfRwvkH%_=MQArlF_UsWgTtvP6bj>o(Pi zaq`vk0naV`C7kj?@@_Y{mvnsL6b)Z#c}SsPra$vtr;OQlBV+%j!+`e~u#@63`dBZT ze)KZ1rdZYs_5tnrYqHnaZOvPYcjr|SAcUQ3)>aD3E7;wqI) zzF<&l)IIm!vw)?zSj%iFG#>2NbCZ3he3eyJlt)+{;$8fa`BjChM3T9%giH^V;|25x z7kPi-M)HG#<#73^XAio@=^K3*+MM_d1H^iKa;{lq(VS!DPXb8=u%dM7Zp1r*UmJVt zjSqsal~eA3?gQB5X?7e0z?+&?g8P`}ljh4WdS%j!c!-;LU|ipq$GuYcUmMb^Qx71C0<(XK@fj{;0g!8!Y@ha4P?L<0T>2ty zF&8#`-`FwD;zcAhq_Ir7NitLL7|5(X-M*ntVi|<(<4tmz!rrKb?p z;zCWFPv}o%T=|@U)5OdUg-}ZGp9L_Jv9X7?l@^4y2^&o$;HAIkle9`^>iC53>4?kF zGzs8*Mm#2r9-9jIu6Sjf{>NMB-|_zz6ynevhm(BDVbrid-Lp$Yi*o9X#_y!g>+IUN zIgo~fw`FQ8&cvPMxwb6#5?ajBwq%Uza#VC) z2q<%$7Ua&w+9!4U{AuyDOxDP1 z?DjW|M{ne;G#(3VOL}WQe(*aY15~y|)yFPprowc+DXIQbJ#_L7xR3pF{DtXxSb02l zt6TF41BVh2P;VxKPaPPXIjfKjs2no6&&OM06z^YYWByiDDq2(%n#(k6{sgh9xs~CN z9TapPZ_*mZfTj>w|5aDhI|nVVW)-0x3Q72NZuAT)zz*Fgv|vp7VIMVtREqro1G;Q) zsYb3LVt_5;#Byy}GD3H&V637*$>%cEV^Z3PE0cmp@IkE={_zc6C(#tX=JqVZ_ z`aVgiNyRPVMN`)-mL+TX@lECH%N)71^pfz>M#iAc*}+n z;9L*x>$DB6TN|VzEvN1yD0V<>Rfc=vJxPw)zc%&I(axB9`X80BbCXG;@iIhcL!n@D z=ITmS15bm|&ChhIbT!%(W?hTfLU1Upv~n^&ecw<^wO7-eJ+7>%}xp6C61;_BQ8A!GJrPvB(FmidD^$z zm{B!VVa1Snai~u(NJh=xO&%>ju5N+Q5JLMha}Da2UQ3fR$-p+g2~RwYAd&t_YG@Kp z&Nw`BlvAMN#TI024}_z}ny-Whu51vBVx${&-S?8pRNjYdrNsmGae%FZj~+FZR7=P5 z|1X*K0J`OUx5mm_Bh38&CQZMe1iJd~mr4%Pz6j!1?{T?T*S+s8Kz&SXPQavw}qH(SH0W?pAX<1D`5-QUp6;}7Dq{sTO6rnl!VOpH`Ayq6i( z%W`*^tJ4JpiCCC^a`+?W>L-n58jq-5sbb<8B`;rQB-Nu4xip?Ot|EHa#(KB=>~nJE z!}f;3x$3prHxss!kISqT=}$lW!+>-9Fb zBl=KWFR~HYZ8cH%^tmXwP>o-nlC#VCc9PbXvEXX7t+%f6dYRJ7jWO*YT-0cSzMHJu z8z*;hwyhymzDEiC){K!!onEPTouh|(espt3;*m{Jv`qH^q^?`=gSF|pv(l~JwYS5+ zWlAz${Rdcl<1JZSTKG;o$TJ^f7Q35d^k9TEgRjp0s*VJ0XiMBuhxk|Sc46;b4_C9k zz^##m&%BL~Tlv|)P^$wTX5SOa=YQ&Q%b4WYXi4_-rkNKI!2VgwlmND1hODl-K-bCD0G_o3V+}H86 zjy)-l4cs89hsG<{&kHS#I`CsT_5wZXP*@eq{tuyjx}g=aTRC)?y1xevB3qfhRgC-9 z!?9IuYQNi}1%a%jCX08%X%VNAvgzW?D8R8egb`Lqb-K&|WZWN!C&QyG7{3GVO>m$& zj&-{njj(~2BKq{|8`^4V84-+Df&$rv#;CV?Mf-8pj0*b48zk2)@?t#m7OW_IRNI5& zbLb0Wn|0%qHJb7k8gnNYfYK+Az6jtn$k^c!oh)WF4bo5Cb5 z1x440#OB9^&GIZfRyKBOXD(xTPNQJZ0We~D_u)(|s+eoq=;bNmgk@kJDp?7|+sREE zyzDQPcS_RlSLc zg^&%I$9R@C4pGE!uGH-1H^GKLg?n4kB3%v+RM4Kec1VR;GCivIxXeHhi1}Vo{Og>C zLMfo^W`MDSzx|N$o-o7qOe~uw{9?Uyv-Rg|EHYyl9tbb_a&K`y5t|c{y>n7{JzcNZ zHOu+iil&2^5nF3cA9JC#uyNWeHDdVgkKSdya)^}GAK-}L{tVesUWc#UCTU6k;8v*g zvb+Vl6>Sx=$<~f+Z;fXUxbeP6%!63 znBNU{poMJAHRKUk_}|pQicg9jD(OmhDKC)F^gtjn?vUN(^EH!Yd<&m}RXBM)%Nw+P zJp}E^R(aESTxIiPO^eg*@SIG2p7*oqVjh#v#R6_m(BKc978_gN{2(|=C0X+&N=3%? zNVc(2{WYN+H(Jb<3o1+f8L^Ke z|3MG1L*lJY3V;z2iD<|~vLJ*p9A6|mQiAMQ3iCDaW{XHW7GNIv!AE|>Y89Aiyc36T z1PQ9q?8m+3R=q!}vDnwQrP>7s|H88e_6QY(QRAzoik(lzsG*9{uAn#1CZjli9nUQo z3eivn+KS83997W}F2v^L{RGBZ*YqDDxHUUSBW1!e^1bAUy`m7`@t}%h$!4y+n5=(! z(n(n&hIOox3&xSg%i$_;toRY9J;}IAsJ|giM!@oT{ljjmXP$+l=89uOiHg72PD*5! z?paR!2WWn|WyL7>DYbtLxtTDm=)gv)k!kzl~t7_Gkn9-=`*<58G2eB;$oarSYA zOL!k9Nb!vcZ>CApx1Hb!6K`}fbXPOHXP1;3joj5@t^rV?cBkr(78$Iq!uuG#KJo%( z9*c>)52$vWPsXw$JGU(wIPSJY+?3ZwfIGmj3eDN=A-o|jxe>0JNAPxT;f?J8#!qkr zQeZ*#uBpiy8)EdJz33tj9}TWUylySi;FF0dh53lTMFku}O{%jLt`e7qkc^%Kt3Bq6 zc*jah7pB24W!azEbp;)ho_yV!i(foA7>Slo50qi{pJwITaanhSxi|cl8F}{4JAWO~ z-N^O$7kPv2xH1J9$pBO<@M)Dyb;v}xe_bwQlKXGvyDV^i}#<)V!VB- zuxgTmjZIJIv|B_cnBH>eJ|@wH%~=`tuR0PHZ0p{eK{2*8I@_A_-BjF&ikjCGoNp<7`Cj#?-H#-Fg{gS)3Q0Ws8-qYG zz64)8e-qFLPYE;IUm<0hof5TJi%2MWTfmdODXge{v~xi3XtbmK$oOsbw?xg0ONH(E zCNtQ2bBP1r(guw{@@QreBGcKyEWFAIJNx);&w`f}}PUsM_7kfHggytLE8`7JyC?eSBk z!eJK_lJ)a&+6_fHn#14-W@NbdV0;;eu85J|9&V>-041LsJ9{dBkei6J8@LsHuru)? z#+skgl_o!(F-Z7y9}7_Hl)*oH5<0Sx zV}Pxj{^z>;clxm3B>kQ#^x31kV-k%`XS!u_FcX$LGK5GrNu7r$exr(;6Tsm+?N{gs znWpu4Xl$7TlxZ2FVWsz4hnrKiOV#iI6`^oi)pi88{dZ zHy~dPsPy;HU9)qtd?)`#4q-Jl^hrKtZeEX@a#b(0q+{@<@T=ZpD+v z!4`(|oFD=z&8X}EV;;W|K}xg}<2DFag6vP_I-kLP^gJgzzPGkyIoW>wV&ws#wJX0l zAC5YC8v*e?x_V-_V{kRzZJb9Cy{cb2Zc0DIK9|mR%_M=`UG00U-Aah-S}V2P=z^qU z4JOT(N%WfPDO?%HH@Wd#4DK5&YuC(dlX-*!ca%-Ovp6ddKnfsBb)7%CPILAz8}Tpa z{T5W(c&k4U)(3_Grqlk#f0(X94Rx7VkwS)jqFR8{M^(c6pv#zJ?x-Kf@NR&S(lJ}< zevd4DPc9G)Y%J$i>xS$}Ol7^c-6XIA6&Ehcq z0IRWRqD~HJH9HjbBk7LYhs{T}VWI@KWzC?tsxL({ySTjz zy1TnAQKRYUt;Dof%fs!$A*uPI?k&-5Y79D3_Tk_&9{^=yIq)Vwg7KsU@~Y*lTgjSs z9Cf{rRkBrP=1OVo&@r9pZ|7{Gi=R#zlg{et&jLjebHT=Rp6_IJFTPfkvC7lCKFfof zJ=Om*CrFol|K{zjxIbK{TOB-Kj&jp+XQX7_8*vNo5~^^#Po6zTTaByhtvwwIDPf~+ z4?%1--rdh;UbNwFuc!zxs^E?=CwSz`{2i<3v*M7OeivA3zSaCrjQT>8ZrDJHwl~3S z0?gi!oI9*MDFx#5bNY10#=zi%+%f<2$WcvvXpQ*1TO8e;ZnG1 z%eON1XKsIuV(tjPp-gsEX#<@Nc-g@8*GI=s;$_rP&v>F+7Vv}D$&9H_+WQw2z1LnR z-g2i!6do4?O&i=&-RAfbSb@l}md)tLzxtg?SlJ05PdWdrMi?HaOZw)Y&!wwt{|7k# zb5a41WA;&SPlgt(ikU^F49Y=5nR5g4=Olue)p7_-kn=d?&4g5M81n%gKQw=?`hr>I zn+mVz94~%gNVAwyA55T(DTLyr|CgD_F&a~?;gFojVjRX4fhTW!_#^PHM_J?z-kfVj z8;^)YhDt=0*4_-~?1z~it#}$&GpST}-@SSh68pqJUTT@G4=qp1w#a+NEgz!u1i#Mt z9-eU4t-L`Ia-)d1*Doo{$>{iyz$FLr%r%()Mn4593MK2@mKq(l8KtA^Ie z*9kJswHVYpr2W1Hb3B*Uuka|Idli$`)v%cAu+K|RDFLLdIw<=I4`ipay5?vqtAqjK zFFTCC=2VW3{IgVL4d8J9aeAvNowF=sN4Mdn;}h}N=pjY_#(DD$cgJ~EyVty0xPE%1 zz6D8rbxvcB`I#-%!cq6xsT5q0G*Q{$;T;o@meMmO=_X(_;$GSLL3(CpGoNeH@=B_A z#`ci8*eXEAO|MbGv`4^Sd_Km)jNhQC@7JGl&l!`AdUcE8gZgBe13CZ7^>uDRF3hLy z7YoD~bZubgP^i^P)=&@vU;kPy`-+2;I^y>GJswC5c<|s!`#R=%Z3*q!EuV9JN?TIrAj;7QJ|As-|m!ZMYg-!ZeLa zHUz$@#E6HV)2N8AeK8uz$N#O#W@%4x`qcT1qJNe+T%3fNgbacrZ?;=I~X5 z>Hwo_XnCvRUg~Q1BNWKKxq24?7Gujq4!h2&+!6-%$okN`T9Hz{+_4H)`gf#E2lW$k z$i@}wK3BG<*o#z-ZC_Ml^BTkoFfu-4TraH>Ey0zhXLHxiTn!AO%G%#LTcjytFL{e< zhSxnDJDEK3G$Ip!GsCGucbFagD}$d_Ti)}Fbqap*8C2*ouK^`xUhdp^=<0tX%yF;P zg_ly{84~N(d+Z@B5?oxLEFOdGp`vn|S@{?r&!H&0_R6|I)jMxZioO4R_sO2nf)0nb z?-xX1@0qSQm6XMl4d(|h;lEu&NlXis$`dE(;ArI`euG|-Zr}Ptcw3{1bJ9~EzE?Dj znRQulrn0LV3Il@Xu_W8o{Ghi*Pd3l*-!`wi%$Qo7##$~0o?3pcZB7o>@E3kx&V_Ij z=wY4u4=`Ij|Ko&3=K_>Gzb2EX#@f_lQ3+03pxqzza&CGoSs4`UZ!oOYQ>$-~?tKG1 zY+#AyG@N_w40EL5y51|toHO$IO(}3@lRr+LHSc2g@nI@X`LP2~$4(rM+CIz}t7~!q z{Ppn<3VxNjG_m7pPId8M=yz@x0%-}WQ840XCl_i^k$dxAlh%;#b(}{554gLT$?nZh zmy`*UL%x2MzgfnQ)odx1xrJgpnv#BIn#!;b+P;%u`1rdB&jPW>z+H{LPw~GA*hI~6 z{HwaT|KdNu+v{Rd5fq-Wu0FF0PY| zxO><63`3=PCGzYxV1weEQ0VBwdw+j|W(LpsQM#iEd^HyWJuUjWe=JX^d&+uVZ~`Xk z;Nhsb2uO5J*w~KT<-f8z$NvD=iee#!G8U0jB9eSm`H4I{WHcM;E+ro)>awjF7_I^tSY$Afxa+MS~(_w8gXxZ9!`Fn$t4m zKB1v<)8+law8&wtgAl6?i%I&x!*t(bTP_>e*7lZZ>Z|;3!s$bS@^)2fi1$GoY|_*l zGMQIjQhwjBxHOHfMZLNTH(^nM=#!JI1aTDPaYCx%OliTRr0u@EzO?T*Fq9Q^l?as? z^*WIm{%7se00Y=AarQSqh?+|r{%`!yp5m=DkC~Y9SCP{m*TTz#`KxH@SP3rA)c76g z4F6Iuh?ke|q57q!XtDR8%baM%FmGMkuZr+{YUbC(%6#mUNb3{r%C6kx`~7}2uD8C5 zEcE`lEA4P_(6rzh^x^}X;nSEyzUEJ92IwckPa`C2^=`dirl;r)vaOAK`{&$}jHL&)OMPKO?yl zdvzsUl7HS`U*qW<77ZK{c~Xf^@T3whL5MM9?m-3SD%)uhtEN7WA}HP-B+cWLIDeD) z^*82e;f9(UEH*dDY#)>Vs2A4P7_a4Q)s=|u-N3oZCU2?*o>sINUG!clt<+5%4Odwi z@uflI?5}3}h*Q-p=%jFPO1OwK=dT6q0PBYNk7J5!miH=oA397UTa9YQkBe#|CRS={ zWNu-EK8Ls>I^u!ZIR%Poz*`tP!BwX^%4kIzjSG5wF*?tyWT|#cF-ub;WYgW?ju6=R zG3&_pW%iTmYlsthk-C|FzlsQLq|giy;#5Svdc^YQHwP(b#jk`AkKD5H`6V$fs(AOv zgJNZ9!~q4~{avRfHJNq4{T22Xd~-DfS|;9j%yBt6;U2Mw(Xozy#(kXz^y?%|t`ptS zirVYtHQ`GfON6)f$sBHr949?4iFR{PDFuJY?WMys{SnE2 z+8e(vXs&Pr#8LOC^6%f#sJa4=f~ZWI!G^j6b4c>HrqvPt!SsoyB^0J{>q(OR9tc)G z=fL@A-7e??+iKt&@ z>E;-jfjJ3dSg_OY!~tRCzj)(;@frU?Q&2I|DBpoGlSJW6pbVp;@DRU}>0%52-JXcI z()n&wH@OHxf(vx^*5(%9p7$MOr6=3TskvEq@Frzz;RN;Xg@*(Z5s--!GD*W{cvz>q zt*J*xmeOpHcMjHjvL#qtABky=Kd$hnQo@qK2z5ZI4O^2;46TeU0xRJRu0x}U5#E%Q?qQ^}o*l2ESb;>(_ zp|1yVcMc=y%u=lUI}U*WJg<|LPTdm|yc$jXo-9`zga>-6V@WN#^J~%}) zp(lHf+dujIaLSP$k#?k$Jz#YvNa!+O@2<~jP3qYEKI}cbU*~565=(ZltB+rKX7R-H zUU8ijbq!+bpz;VAF7+EHg)I;Z5}H~Cx&9C)2&+IMo*gdqNrhaGLg*)jNEQBBb(%Tq&^}k;chE1au4h8&A-ZIMbKP+e3et$Y$$TZ*G%ZR1^SjWE^^dqE3iy z<816(V>pa*Fo!c+A*T{4057bMsErV3sFPpWlQ5T=oah7VC)wN9`XLJo)ok$c zsdR^>lMRKm)#eZMxY94A0;35ffSJj_kT8o{)>Hdw7IVKNb`ZK1)Sq7j!jZ#5o?k1j za{d)6GYK}^&`(cR*dzc;$`lI$+{^|Uq;#{?Fcno{3@NvETbK7Tj+DSLtOeL?75-$2 zQRjsTRA~`k=S%!$hs-BbY!ftNrN8N}WV2q6tJVP+oyM9sI z^OzOW_M}-_`Sc!x>Cw(he1u_ju8f|C+7w5Gi)4-B#GImhZ}mwDI&!N8R%ZP8f&Td? z`9(#Z{c9ulXW=<76My3swcHwtDMDpJ=fB_m+I-fKBrmGFy|)~W<6gee%a*v2HP~>k zbVmKbgMR!EamvZaQUbC{d`f`Rwf!wbo$J+3cd+VdgeTVR_U#&q)U&Qi{|9!zUkSN5 zHKr~o?sBg2%)_pnzkFJG@3)q?oNQ)uFVnHOzD@FjsS3yBuY|UYW43ELkvm>>;e*qs zlt`2N|J32FKAJ2Cw@SLxyUfUQyT&9n4&ScvN#-p4lJzY+`O=##!n)9PIe<<3Ma0s! zHO3iuk;CW>3eyiJrvCYr{t!yS72Jyo!sy+2nhHsZ@c3E15lyRjcM2qrEtm?P({b_t zV%4<|O-bIWHBBa~g4tlyigdWF_PHOyeLA*2!z3>1rZw=Bv8@0LFJ2}BBo)oEL)SB8es>N7f zzDoZ`E^h9f!TT4FcW}(kkxKU-t%Q^jJEfg0Jm9qH4=NvU$J+G99k%cxkL`rjz4HY) zim^fu=AOOGHk)AV((SniuAVTltV`At6HJOv`Nkw3)GeTAm~U{fkTEIt&`|@Im)PAd z*;~B>Fm09P$Q7~s-5+4$PBj}5_xEqz_QTF*wQRQ%mw?9>Z{|dkHR2dNQ%Q|mvmIS^ zAo`GEL*&h%bEybhuvu_^R>Jp;8sK#lx4=~9E6(y8CU>Wd>4x?sC9DN5#agsIy>4zQ zOZ0jyql|Y$A6i;bUuFpy)acLJQ5{TN#WA=K**uTAn|atLpV)gl`4O$rb}Mh0a4M#M ziOZ+tnGdCx`o6T*3e=o4~lzan_1 zAv*xtBx~J|`HMfiyw)uTQ>~yPzi~?YD9tYqy~>`s4*OFDzE-a_`S(pa(3$Y4In}b+ z6ERb!|D^f-Yt!-9)_uZ>urt|7xi}>PuW@r&#y%yN617yG z7}*SEn*0&wbY}LEZ^wJEas8uUQ~Us2S7ZQ*bc1Hdzv`eX)KQh$`QBB%P^RVh_1Ic% zSaZ_0-qOFm{u{T0uVM=(+qeH&^n@a4!(ezm_#O5g@iEa5W zCv#F?*gd3z30YnCWElDZTK)_mL8vk0mrzh1f~xq1i)!+W46U?kaDMMv8qk=#GgrX6 zrv4B1;GIqh0DuY?@+to8u5 zee<7Mvu`K_2K=dr(%(v_EIF#)VE+L1b52+0ftmrZJ^g7_{{a1USz9CDr_z+aN(Nl> zhB4FW%{0x9bDE}QBBE)JKK&>H>)h~ptoysn1|;AC#yHJIEa6p|jz>TNn3f7bBP6iR0do`WbL5tngTdRzDrl}|U5p=gI3>Br zs|QG%y8NW`k%5YNuyCbz9QO2}E>`~5kT;g9*(YctoK}nzOPJl=ut@59)=OEkN%L-9 z&FhR-!ja@6^>j>bBQyog`wOgv=acEux9#Q|bL)%`O5$|ekKt_PTO9YUlHOy5=aE#H znmJF27OUo2-L3}qD8vkNTrSLDahz~*(!B@b3xi{3I48~=`WoQ^lZ~o!NaHPe2LBO1oz%islJW0%Mp-&00oD*zENZ z_qPyR0MW-}#iVs5L;F;VV=-JTag-ba*4xcOJXiv-`#j|1<}vM$C-SIl{AAY`cNT)q z>@*PxH%onu-<1|Lb$VFpw8waDe$6l?M>$w_Q>WO@n-^*;bSLi`$4_sYi=92eUG#$Cm)80p3;anm(UDHMV84m)~Pq;$tFqti4DYaaON+PsrcKk+ow&;2|R^siQ);SdwJ zbHMql$~6L~RMd)Kui6hIxu8Q-@(KJntpsExBPByNGIPyPUW2dW+MNW66~oOt0K0Ix z?$iN=s}J~?Pm_`kF;sfhy+%#ZGLsm@CF869h-$o}yBtDW$f+ix>qvb!C*>?@=5NB1cX z=l|969XZ5r8xiumg>pSBcIM>TT){MI8Wm-9&pE4J4)E=+rKa7@bkq5(J0vDH;0ls! zLuoO#xQFdg+qqq(d2w5%scxm?V|oo&dRtAAjhqR!s(=m!((5*u4Sa6s?+8mkx^3FD1;2=tv9A+)!Q zv`hADaMI2A_3KedsCdR}xGdiDSbMvM0yuuuRH*s`S=v46w7NSEHlgHm&34`dlTe#k zyVTX~4Dlh788sLAR8=G(-rxbIs@Q zZ;LJM(&8;g#2}Bq8fxW=AAV{nm&X=BJ58+!lmqf#88KeHr(Lvy`U&r#lIq<;q5-+4 zrfQnJb~ijd}>pgbHX)K^NGs3^Wuw=u=Ys>sg@h0kBMq6DhE}b2;?*!B8F?oU59CoeWhKv_l zzKSv)H!_pP+^&E6_2-^2u}gh_S6G8>H?o-*Zgw2hvr&ix&}T|x+a zqZq45sL`yjxRwVQM^l`N>B^%q{{T|en=KtZ z;_b4#W*i7heFby+bEJ_mQGuREy>z$9n>)DQfg~YVk4ookZNw1yYC#T56O3Z9n>wj% zNj3tV${W;r)AY5D@=2lDm|y{qG-aT*kVz|b8*3&jsjs4$lGb%-cDooP0yoR{sFSS3)d(n@NZ4NEmUrXEn>i5i-PF4S<44 zT-RUX?*;01I<}=eu*obJ_p(VG+cFB1SXZHw5eW91c*2}6Gg~7D#kjo;yD)(jaJWu! zR29QG9Bm|H0-D5Qt7G5gp%(;Tg~uSXb*3Y0PGN0(Z+@}IA+{mbHW?BcHLK}$4Mtml zk7$n`Hd{W$2k@-(I{>O3LWSxdik8yh{P@*WOS^_$yNIM3k$s$&%z@mtH$10%8o3N{ zD@T~2Cw4iHIjtM0*<)8_0|SBO^{lrH517O*SmY6oX@Pp`(jy3y$%hS-^2dRiv+&aK zZ2V#NR|+A%UnHU9ZB|)J+AKg8V!2(XHKX9)3*X)Nt4_Iw+Ej))RoX&0N=#>4@k2}! zSQ~`}Uea$hO7&q_nl<;@w2NsZ=2-s#a_)MN1$tkN^uaBy)uGs3td;V4AlHw0Wch2W zSjm-T%f-0VGLcGAnWo1CO2@8y)RMj<1EAZ|pe{Vwc^MNp9Ou1DFV3I>03CtNV@n!B&+kk6+ZIpArUV0JqU2srCWq$91PCN?Xuf4kO`Qng9oaL3Eq zjmoY|S2C!tW7nP=nhBf?x^&R)dn<_yM2+4=n@OfxLm`pcV=KNeUPj5qOSzzyR9Tw} zYg(!BowPPt(km2w6_1b+>0 zTWajQNXpz}IqOn&Mco_MBPe<4j8{K!z%yXvf=AM=O{yS9V(Id(?mL>qitElZF~|DC zMmx|;Ci4k9axv{sSL9%fk7}o!NO|wm6)H*2JCT|RE(seweSK^2h zyX6E7o@<)7yk@{iw<_vMvYS9chJ*ks93q-y&}M^{1Um(OV43>6QT2 zNA^Y03+6w~y8*Uj3bvjbnYNa6IUExn+)x%QHPx(~2Tz-j3h_+>-#E%13ED;}Tf-L! zrGd)rEIwWhLNrUFt+X&;56z5<0^VXzV{I`7c4whAlXq$&BmzufPI$*OPbAiIFPWc1 z*aJ?xyAoTL#^M(nk7@*F+c8U#hT!0jdg*PXI3I>hx!6a~`mn!EaD|p1>o7Cd8?}M;&INik zzrss6)kEH>lW5P&isgK5@XF@O2=8?H&E2qU-1%IU6{7!uwX9hy-80KaYBD(8dFZ{}7zhnKxUJ?SwT7SsKfS<1R) zrD+`-s5P%|;+T-9+7XV^g^?SAYn{AcZmxmA0^!#S#}#_dOR>6zLhln`mL^UV&?}wY zhOcdOpusGAg8<6Uf-6Pb5y8fK9>iCfCx>Q?Z@0P&BDnw~9M#KT5b7FfNHrLqdsaI{ zk`6-qRJCxq*WHj3M#%?j7Uw)ynCUhiexZ4HDu;$Uhbj;8oY#9Escn4}t#2SWjFBI4 zT$Z1uyjOBaw}@l&*t|$HipFb0vkhj^w`ZqY1}16v4K7hUAyK7u z<#+e2WFIi#o_gZ87e$c+e*V+%5`TM>ihNoql6z%&?c-OJERCFbW7p|j9Jfc486_mn z+rqvcg>>j{ZZ{cjS9(P8;H_-l_Z{?|BkVz0`AweJ=-*kJL zpT$7%uFbRBaJ5NJ5d9CxyTjFU(F(dI6F-G#Qax$K{=Yw_xCrQ2t$hacfn_V(%YsG{h-s$F1n{&}|7`qgt*Z*bR_PuZU*9gSBb(w%^BTzzp)1J~A-6rO`Eo)jLn*mz&S z8lJZzHNCus1J9YaYOmI*L`|HE0gwv;lj~CiQaC5SQC{n({1LZ}6yIIK(rp=z1>98D zvV0=b0UtD&0|&XqUnvep&R$6em2d|+139jfLeSR!dpkiMX1i~cvuz41+y}y4DD%2! z2LowbW|RI99XiVT)*Cmtiuzs>MP0%L^`n$r#~)?k?J~kYvn9pT%9-;?hby0Iv;CiA z{{TI%Kky#AcJKs5o!9d*-IB&Ul4(ETUqk-@KhuBTvHmo2hcW-w=6n}3TiLCsLA9|f zI*c9EzBafJHH_doy!Q;df9IjaQ_ywT;I?))GPsA5>TpeC_>;v^>X){AE#$YivU4a| zPU9qJsRy#OZaL5|izcrb6<4fCXp$zu6DvW=3FWFBu>_XPdCpuk#IpcI&O=n4M zq`mUnK9i@&$1Dn_N}6IkxBe57q%jsq!&}v&Wj3q6ialZ`o ztC+8KTj}kmjs&*}6s|UhKj#(0{7AK$-^DtCSljH{gh?*tJSneRzW9}+#cUEgTeP-S z8=fdcY7gg8SYPQrBC~Bm8)$CTK1NHJfsq!FoFyI6;5Syq64K>Ee2fEQoQjTHWVy7u zc=))o0_8TGmstb^(l5ed3U~JRZ3twPzDa zGgrfx9$nMI$IFWL-^!8HZrD24RcrA_PP2tAZFH?kVYZRs6X1OQ;;3jE0}Ufo*CdZ> zL1g|z2IY-Z&}OiYO+>w0FFHw?q1-a)c&@l!$2*FZ&rI;okL>(G9G22qdC6?QGTg_P z#a_Jd&xdabc`U9Vl%34coa9%Xd^}VAt>PyJKP*Umvk=-gSECr+)QFrTV}>HMvCQ;l zWBfbt+nk4)al(fiwu-57@UKL3n65}ta?7)&Xh~_R4gOWlxdV(eRe^u2YSz~#*xXqL zU;1Kch)?)c+DDkmx`M77BuKa+Yg#{s`dX@(Z|$SX?JlTEHO|Sa>Uj<(wcJ}Q!V)Uw zuDz;(@|!m}&+4Ya8-=IVCrN8Jk^aZIzj)-EFRKhQ$^ zF5K1Yc{L2}xcfH1c_=bXFPIZp_$$Mgqyq#f*aa=mjUra z)~yCR2qb5rJvgrwO*Y$5@m|07*xAt-g>d*-X*69p^L0H@yj!5(Wm8nOmr$38;*qdr zuRYf^p<}K^eQ)Lcmr#(#%B{FYeQOr~08Y2I)^vo^;VBYa#$Isw6LVgR;!6)E%k7M@ z`EW$Cg5!1#0M(h}lEdZQ-9;q98|@M^fcOY1slNzV2Rl^obN7W>)ojFi-Vt( zY~r%!vt=9t{A1R$X3_3$X`1V-=#x($lEf@ye%+$CroXmjkQw6Icmzr-&wk9r6SQ&P z9Eyl04oGf08t0V+-!b0|bd-4+HlVBayP}PhGZL()tz3>(ONgX%f#k=MdXrg_94Q00 zAXS^ZA1A;1I`ipPqH?;HmCb!h<_Y2+Q4CN8Ad16YBwoNAQ=uehCp^-!{K38RNufF2 zolcZ@M1#`{T8$6O$6j;W6_KGiXvsZ~%Uu9m{{T@?(Yz#PG(_ZXe@=M@tl7o0ApZat zPAcJyW2Gj{bpCxQ8WiW@vyKN}YK1#rMm|Mspf$fRzse=Vywq6PJ4`s z&PNq0ONPdHpe}1h{rh@mo=$PkdZ!$N{Ayn_J^uh2MGlZ)llapkY_Q3|&lLT^y8S9J zxO0w%ftL(>wvsz>f!3qBvX13K%Bht5tjnAlw+GCMoMbNJgkN<_tg z-gj_E7!_nHL3slL-cvu_BcZDx;~t0GtuEDU?odcP9=M<^Ueq-USXSOw5ym%TEO;iZ zKDVccV|gxNOkQxlJw-bJZeJ+cub zWnBiuW!tz_TU(oP=Ao88rCU7lTqAf!=m4>56D(+Opw50;d_ESvLPB52>z+g0aheI_ z^C$6zoIhl^dvdJ#`FrHn1(um1vy9B+B|#%?bpHU^Qww!T-Z>ct7@wH6A%_a84;TOp zbfBf7k6~c3mvsc~JAPrw6|ZS)YcAx}Zlkfa>h}_G5Kur>=mt4GjbE~|7j{=L8!7IZ zWh#h$oTPj36{}lQyJoU25RTs4<#)l(>a!-! z6Iu9EsomaPU)n;#-tt2%QL6#~sun&8)pT2xyS=lKZMKzZi2H)Qr%ctq;$3dB&7Fs4 z<$c%{L&Z9S%c0#wWZVuzZsg*VC9}Y0CR@A4UPIimTpmqHZkJI?3{bcP=Q+k|gpBb? za8%*e;r1MNtCqJCw$mh~ivhqm0MZrB__Y~?8>O~&l}`$eITY!&C}x60y0x8D0fQmQ zswm9Se8(&^%~|lYP~7XjMes6O1tp_tcI40(Ir+B1ID1)VhBM0Td{(!H;<>uiUOQBh z>RXUPDEYG0>Dq^dG)XMgW3sqeSws2CcMR3P2l!&cO`bc%np1R{@{kRRv^ZS2R&aMm zBQ}S0A)HBM?=zi&wh@ZRZ8fcQyM?*8DI*L5%hcDB;DDkqFXGs*77qdkucyVFI_aY@v@x9 z7}y30UwZS)J$`$57C53pQd}#u_N%dYp6*CBLg^ZdYhA#HCnq({$oZ~%u*AYJaYapL z;lH)zSjk1VxY`vC16Gyj4H1-J5`eHPf(>)1?QwM!lD7FSE(19Ot!rLt*2(sZf8I2T zn?O;+Gfg@!>W5J-Dkl4m@NGFj@A9;H6a3~Qtke#5h<+=B* zizr&|%J$wkcgYy@19Zh!^%?PRb|5dlM_?(9&E05}-$KpKcRAFgU&ryLy9QZuw?pL%g#{W2&6 zF8Q#t{{XWYJv!H%Mn{=GIvJSySEOGj?x!OoQB#fIoU_IHNK+L>bTC zBxES{saYCpxt297(n@j0Ko#lUAMoX-foBG>tt59E)aV;X(VcVi_GTa5tz!}->{jsC zf~~BQ*HQ5zx;@bcPSO7C_r8SsFM9L~jdm+-I2%oB&dJeCX=$b?jxv2c{U!`!X;}T^`W|st%89!+$Bg_$q!X=36-gv{S*c?2uZXv98nPE78|1YF zd@et$tRw8@m(=`78_)fe<{{TT)fA9{tz}%fJ5tm%_@=Y9oWS=D^QvST(Ek91cdrIMU98OH557R$ zKNDVu;9Dsh!83P7!Ye zjGjzkw;kWDb=O)LxkkH!`uYX?@+5PW2x_{#&Onwj26-&`=C9k_G%DyeyizXKL*A_; znab|xolN)Z_SputsKpdB6^VY(cN&ICwG{h3=+!Q_POLHxT}65d*lEF;+RdHa_b`%d z3UId5+01RFIaFVkPqc6aFSo&y3Z{Tg`3Cr4RrW3+HVi+`{p~-p{65+G%lIO0&w#eI##^6Y#G- zm&1CGkg9E^g`L1*wC;@2XT;s!iKJN)5S^($sRp<;k)5w zEKP4O%y%PW_=RYEIf8o|jat$C*cNL|`($5~oY$$!@+iy66E7#{U~8V#FCz+Ay|T!D zRS|%#OP0jd#5t`<=9RrhTe;&kN=u9|4U^9!H9hQ+$7ck>NZLYjK$9l1q@A4P?Hput z(w&ZU%attF3~%M{DPk80|!r^T_|gRxEztwP#r zUU+)!9ql4S*9ZZ}%~3d9(i5@9`JsMXV1v)KRlB)T(8m7&H<==*UwWq{>~WD0QmzSC z&qOswTafn_ugfY-t$=;&7}M0~l|<3>g_Wc!q-pjhJlV-=hFHfN@+v5N51>v9n52$O zle9^VwI!6EW}m0ZIA5|v06n-BGO-+nBc8_h3uvAU!tcGyvgmCz!cM^1;df0BX65pN2_ue}8#zd-hhmJLOOc z@m)9e%%_F&!6%QCwMMt|F(-LboD3eKfu`2SKW*^p&d%!I>hAmPQrkFap;%j+w@0hmVH8v7YBbrtkcW0bl=}A7BeRmRK zXd-EqgM7Pdm9vx2e<&vD3vIw0S97PZJ|DO&O9!+lH*t~vO=QItydN|Wta32o5EJ^3q^C}y94sOZpB?$@QpcwZw6zj!Fsxt0}$;m#|l=%&kcpbae z^s#4xIIQcdJgIJ19Aq9%A(c_Mz&$EJaB@yfR8Ummk3-wNOS_M6PV@nGJAv5rs|hx9 z)7r8_42&L6rC3JboS$Az14gPgeziKUf6l1ECr_vcJu2$9an}?Ta{a3UeuIjdRR^8D zs+3G##d<1 z%USwm5n`7;+ys(xu4EL=cozNgJP^cX>jK``Do=AGBi9k zzFv@oo@JT7Q_00x)Q{od8;;s_KSu%X}TnW+{yxWp(i!65}4j4qEk zg3ev43~o!D91LxzY4(>E+PqS{W;o=OF8ubdND4YCMi)8ZF;PzfN&>i#*z6e;as|<_ z)BLc5$Pl0noa9u|%oh!~42*-fHO~Ev@)qi3CxP?i14z(aEOz-jn?MW6M$rkDi7gN_|ncDdrM75&svcx_h+6B%`m7MFC;pf)Q&b7Xi@y7C+Seij*Rlb8I2-BHoHp7N4-xA zV$)jS1LZ0)#dgwZRx=Dp(FTmO#A9A_T;0Z$@M+qN#BP@M;KgqMKQk!rSu*!B^zLsh zRQ3W+y{a3vIfl^VB7bF3U zl_xa8)qQjMRhXkW9CA?Sii^r1slhz<6oxPZ@@FUK{HpW^b&dZ30Pb}I)YWkdw%xJ2 zWS&6jR-$ul1d0BEXE9sy8Rrph1N~ilwv*r;1ldF{ZeH&0 zSe8l3w%jkJc$I_`NpjIz!tCO311Do%*Wo`8>Y-!1)nsU(3%M=S{_(&1)oBpjj#BqW z(6k+9_g6@oc&(3>q3LoQz4gHUChfPM=UnCPsV(I5US3MFU0ii2epnOGdJk&$dAtp# zUds0xhuWu={{ZKtzbX%EQSk3U=Mc@Dbuwo)qINTSo*X5QsddJF@i?f>)I{xB6|j2y z*Sa5vdKNGtlPA^lNIo0rSQ}xG9AUi;Qkgubhb*d345aoMz^Oppj1}p~&sz4A@XJFz z5_AOQ^NI(RkN_sSkUJbI zEIj`JTIVnIhn8lv(l<^Ou_XI)vHt*{N=t1y!!ymgX`AM0W*7wf3eiN(vG-mgxp^5h z%SC&9;U>CGp}p#%n_8L4n(EfxEO4;Lo-0{&`B-CeqJy5h1z1fXPclvhe}~MfNOITbL{^zcSy-Nty3l4#`)V+Eo{ z#`$JoJ!d(nj-P5+F>A0$!3%bJes$8Vo}QrXR&4#;jo73xSq=m;6aC>1aYra~9OCJ= z*x@c+K*8N~PxYj2GRFio5;lEgIn8v1EeA-X3P0(dDc@(aY!*pVx{|pWqQP^NI$e

$smW3@&p6FaWjOnS`S`XqgAJi!rRb-5zUOhmUNsMa!$MNCJ>p)L$9vy#D~D zY3H^DsWm73Ci><^XVXSH@3bPbtt>6uNYySUGmGd!@(@M4Jk~&Lb;vykC#4{<*GJ=x zXN~h|WDiSYlUE?|)}R0q#bil5Fa>d3HsC*q^VbHEnTH^sQOyBk(1(vMe~R8V!Rs61 zx{VvgdUezhr1Pbnz!_wj@s_U?7Y;k%6ZeU(pToWveM?W0`|Xyt2Ahc_Eb*NDRPpiqV%&wtpk+yP@*O&SmPxy$kGc{HMu?{{RvBC~G)2l3<6gPcNl& z$l50vq(o7rQ^*W3MQ=uV9nX46;zhY{Edm0gDhCxJCpCR*Wr@aAk@;@V- z9N<=r667d2Hq{2-_n6x&$PAOB6S?~CyKRvSb1trJAKA{U zk1T~=PaREgzwnz%j08|z6bENB5lx%M*Y1pwMA3uB^81Od_{8$1E3>nb+sn%|Zlkdy zf@!-~&~iBMiu0*;o9RyJE-nWhJmM79cGRx-WL?~kK(Bx*tWD2M5wC7@$>S9Apm0%m z@;|?lC_1g!82fd=4nK+Tb47%DfKh?+0(~}OlmWoly!0C@%vV{y zTz{rc`*~lRpr`);ZfYPgTj_^z7<3fC^xcE|fqtvOpa2Q^6miMhUT8J#L?4#yzZ?fl z;-p^@>OkktQrO@!U{D963=`9X$18!F0w!^^ag+CJ&)3Dep!>~i{@zyVka)vVQa)Qo zTy!zuiY$QdJebaK6dt(7DbdENNyZx-9=NU|KO5cyhPAVEpTE#mi2QLk{Isxv`w)_C z%@#m*ndhk|r(ERLl+YxyY4$Si^0phRh}3No4?|vgCykWFDy4(Pa8UVg=WY?VuhP1I z4BgKygxac{O9Sz5Bg6{y`KkCknfyx#9!w=&9*M?L(5 z8?I!R_h9=|{AaC5^4waZ;qPZ_sn~E@Jn{UilD0T-IQh8Ea><=3Xm2jFGdW)=P%bv@ zY-X;-ti>=`X9hM8(EZ_D`y4QCnCGo41(rR)?U7H+dK!zAY3s3XFuW%u{86!6Dk}J$~@c#g92^?=L$s+_v#z}0~qh3t!1;WIR z@;VT_aBCmJ+8bJG$$folWw(Wl-e32d(yby}JqN&=W|^f$72c@volfDi8p#$C1^4%_ zPKrq8RFVl2Sjz5G8NkJPtKUtk{I+%}YZNL0jzAk~)~ZDI170ZjDhv7D{m6p%bZ)yE;`8s!PgWq8(vr* zzfftx2mb)9)=T)3&16V+T>0)d2=EC4tPNT%s>Tbzt?348brFBd9WW_Ef!Kakn)>Vu z($?gHalT0w75zj zzv_f`{#N1ZlT~FfyQlVsrE_eOADTmYApm|9`B)thmNns|h#x~B;+yt}zvrw!_w-jI zE~TVJE2X$=v{SRsmVY$0H~V8x{{WwK{HfRv|IxA$a1R6VrwG@NT=q4lWzs?B+WAjH z3xaA`*G!etIBc~Cc{p5723oq5Ze-n#3stdQV_J_)ir!m?v>}06JhYEKzmcZh&u69y zw9gO6=3Ir_sA}%p_Iic%!Ou0PuIkW3J>HAq<;~UPhAmf9-?*y(0CXOs9<_xaiq6=> zANtduHdgtIS4<ziTCWCaK7 zjx)|_nZ|enw@#D=&VoN2_r~>tpzpbA@U2$Qbet%%*>xPY;S;#5cN5l^v0`2K^?uZQFw&t}#mE z7&z#2sjeiGgM-`FpJ?w5 zz_^8olnjCm12;7tV^-5zYdy9`&gqyW-)GM3*E8m^EK9Q&a`_`^HQ&efeP>N&a+`#B zE7hQuxcRhcV4g_!$s#94RnFl^3SMh}c>D7~ow)gl9gb?}_C&bINrvNqzF#Jqbc=v+ z22b}{O5%{xDjAz2B=B-FcolLDUj8VW2ya>l2*Hj%^u*C`q+qc?(y?v3P-d<_g|&o* z=W7=c#D&|QaX`vGVI`f|ySd!#Pu?{oa)yyX!P(9T$Tgf8obJk;kXO>Dh~PdB4$?&f zH!Z^5T}Kdi3coWd%0OD^j+N)AwzVzi>;OEcfn0u*Ax3MEequJ9dRKMf$CBzvW{CrA zhyYmQZ6x(A$3uoF_V;%-^C)M6QXG!;r)Ml+D0c{qa(5h6pBLDeHFc0-65$lN#~J3S z+u9<4NG=anKQOJLV$F!;fq?R)LPu4ru>v-_oE(Goth7V`VO2&s#~G~~XAiYifKlpc zvQDbs_mIT+1eE~yshSW$`fw{ROm>cA5OPt#!jq9(WMi+U1}h1x8$sOWE>QidL5yS2 zQ)RG=Rg_H zF2U$WObV>`?UA(coE)5Dt=z&$Y<0muO2)WSqoznWC(@Xh>95;(!v-Y$-%7D-sckrB zUAf@;Rx9vwN$*gs+gKc)IvnIxBR00G`2$hf&_N6p!r(z55(OR0@t=6sGgrdr6%gt1@`O~<8nQHkf`YIH7vkZ?aSP6#;R zcY5NYM&qw<&ZOQklaEU4Jo}AfjyOL-OgPU$O=skhNE`g-m=i_hiDNelBSIVZqB%CP zUuxGk`XJklH&k%EZ}S5ZD+ssv(YqXR_>AU&G_R+zm&$7!E8A_Pmy+s0Ll2;;ih$#i zbJrCH{{Zp^F-{WTU~~FVBEXGt_j&XqGzA>-_*6pR_vm}mgy8hZ_cQ?W81A?~o++g< z(}C^9A(clYlkZ2Er@20Z+JTK_1JfVYofzyJ8SR>gzDOK!YR$A|-4~Kwu%dtxRU$pb zupcps^(dki-V6tF`LbCulZGwN4tPVJb4W74TF2mJ9*nYY|sNuR$vkx_%ww>*zZ<80|J0t$PP)|ne^ za0xt|Vu(&x2L}g(Nc=Y(btAnYmf|5_IpaROS5x7gMa{!$^0;J>W(OnvU2*ZaW#~f= zmC|@!fxJT8O5@6nvA{Ia3!V3pGma0b0~w>qUv9bfrd!NQyb=Ji#lgt?!mVT5Bi@FF znFx$y0B{d}X!5wg`F@710mncoG0uA9sq~~WA1|JypMKPNU$3dDcKdxeqaC^YC;|fz z&jYVsb4nu3P7}}^XPOTfAW0mMJhPE%a+UVyzdQET8k($g!sW|6QrX-`&|BYId7zK2Vojv&kUZKA(|~s~=^BrgtbUbl zOPQSvsdUhYgEyEt3tUJ1Bwi>NaN9?BVn?x5v=IxY?;MQfpk`IE!9A;S%?t?OoS`DVHeKT3GkPqam%TJHH%`#(?I zIA)+UyB4if%U0%O;7$2?L8rnW!H)IBqKn&C3~e8>VR|d0Wh6 z&#%5~(Tq+h$W)0eVIa2anG~CuH)WXCJhQZ{%zkhICq?Xpj5!CLOI3` zGRG8#R}Oogy{c$jZtKA0impc|k$`zQ=qp1_(7;DVc^d^rn!FJqAgm)B%Ne zK`2(a3&4ze*Q056!e}0Oe{%*-)>!kr)^3U6b%x)4+=4jU4fcHENq-+o=>E{6F%qgI zQH(5U#sxbF=Da}#)Nu*)$)K6x4DKa|etj#3J}}h-GMKCjsoKQa_pe0MCkyi^RROcp zC99N=!f@(8XubeLx>nx1w&c{bQf5ScG}RRG9e^XLTVl0kd~d5d>}9o8bY%O709KLk z6eRq&45JwXJZ6{v5L5xS-0nMgR$eno#T*+sGD^?4b4XdXt_EsI++n((l!NbGoSzS} zcO}N$jFrzBsr3H<1q*3J(@2*c!Z!*jSPoN82V(rCa!yIFO7KiUW4V#=sL%nDI-2FY zMQQe1n_#Mui6bZXNq`M>dMpyfVF}#oCChxh#Y#1s(Hed(($?ommSj-Z7UO>Hy+wJg ztkSv#M#2Jeoz&N$-8|;rb(UFVkIN$ku%@_Vwsa?CYypw5p!TkqBc4p2Bx1{-&o!-V zssLlhrZ~-K#S?-zaB?%pO5Cxqg@*fyTphSoMCn&z6TXG0CJ52E>lT!(5}6+(`C(t-ya>R&JU(@JCO{OJK7(~3jy)}$-=Q%K^0 zk+<@wSaqu#c&OcZ_Mi%kKf|8YQe2kfw|sT0(kFk?s=D>&ffc10Q_`|8Pyl`THL)U} zbCXnVAr7nw!5#f*C8L?0PI$>4qN=k00Gw8p)MPOjAY}Kf`8r^At42~pStJikbf7T@ z_2Q5YwB;S?knTNXAb*}I%W%t))E=PssGIWR@TiIBxb(#|g>vb>AbMla^rp4THzPme zRQ_!ACq9EXtt%@Ql&d$~+&3PWtziqZIn=jN_HjI}8Mk0{=C;Cx3IOOSB8n(ZA{ZQX z?@I0SAAi!jp&KKHq^`%AFa|!IYBJ>Kx7VdK;B)%pG**UI4D|!2){Ode{&b(tfO++x z2kxMs^XW`IN3|Z_v;evP0QFE0{{Uawkn!KY=Sh?F#Q;A){c34E_x$NI>&|})a>h?1 z)AFDN2Ru{1K0iv8Ezhd{bTkEWaD9HX0UDoDGur~MS_ASiY+&a-2&$2xcM1U{kT3>F ztr($nRZ@;Q?;bHpur#b9H#*jlY{lPo!g5Y?&31nhrZH(OfQ8r?W4BH#o$#b0UlVDL zHjg3qoSbutzwut={fc3WH9QaXtsM;;n&zWqJi~tWo@V=>Goz>6EZrSHibpUtmoZ^;1K+j&F@rw27{tL(s z=q^<@@WG=b=DFQ-;ijQuAD#nA1Z0PloGOZZqPfAs-#XwHEI`Mtbh;h8Lwgm&hbSFe zWM?~Rbln&(S=27Z$+(e!cHco;YvjbGV?qH3aqjfe70!!VjBl~NwJz+sXip#==6Mtu#wUq_H$HdD5h&IMJE5r#0pJzmD~1x{+*ryGvMPXpvqG(m&R^ zh<-0y08(pak|rBkIU^axK>jQ6UD0Q`({5sw`H`VwqcrX$j!k@j;s}yR{QG7}6sr?y zoKI({hG|8=W{T@uDx`B1{MsO-qr1qw2B9XyeQkY z_=*(-?!!V_oxKNT;chA3A}wJR9FVJZ2l&A-KKfg*YOVr&Nw}Ea z?nOK8*Prw5zxUm1zN@53mN#~G`8nG6A!)zb8bAF6wEqD73=|5-|I_B|l3Uw}_1#sP zTZviCyl!#_(yHn=MW4$By8PsJ9+f5UiL~!3HMg8RaG*pHt_V1;bn1~iv%Kq^&N4Igrio~jumb>& zeS6b0kWO*m+K`W8dGz2?9swP*(;aGsVFCXD3J!RncK-l4r-l4G&=w;jo->+4KPr%p z3C3~hL5z%WdEjJFB0j%|N>DvG9Z$VjHp~Dd3^z#|9h8O4B z0jP76>+71H2n(Y=oNTiWf(;=8E1Usvvx3ou8iWnHIQTASEqax zPIcK&7`GVr=Dfy2Q3)q$!N9Lq_&|c+OV(#%aV%?1tpCUE;(pE3UYj=HO!bHP~q1?wf;=L=vzYy%Kd^e+7eTwng z-rPkaMS?e06HlSKX2|$K;q9e-nSlQQdb2eTf|^XRxV4#}W6$qn+@tcVQ+!#pRR%3O z=4RYOD>z&V%((c+fOcsh7FG+o<2+O)Fl_S;OX0-2e!BW}u+4cOZT9JGaFQ)_c6vk> z0esO7#nLV|M!&j*)$1=8%d6@dmZNhN5Gufl98jiPKDn&DM^GMYuOR?4lAuS{R*LP**G-a+95oUy4ic+c9ea7v#me$mpV#U^X* z9C7*6v5XPNZj^wYdHUyoD9Oe-IOe66h5rB|nnz6FfGIM1{#mC7KB>F?p^-=t&-jMM zORK14i9uLl=LdjmYS53eTY>U~j0Yb5>myNlR$g2t>xJh#L0ZjsFE*}2NL*y8-O{1BndfDB8w7K; zeo!g`-9fCURP?D~6l~hmLp-KWHKZm|;N{LiuCGMaqnSh!pWi310=Wkr#YP>Fhel*{ zAfX-2a>=%IxFgk-K~Q>wL5y?9>0HK(;&hb9Z+1jds*m0=!o78B>d35&8*tr`+*WLd z5(baZR7H5f>Nu;rdeknwnnV>!(+bswN{osCgoQPWcK!|(nsH* ztrDD65-)6UMF3^UoK}3p8OC~=+LAAB392)}&U$C10CU$!4tN;{ImKhk0o-`?#dT6z z=XV@;suNj`xa4p+rb|aZ6(fc1SA=^; z(7QtMj8&~p!t&DgX?&>?+IQT$dMKr}({JwBeVtNOEwppiyD7;WwWzyXtAma~&Ul~( z?l{jF9M-w;&aaRKu_Sg2#Wr6LYYC7n-H06FbDHW-=M#yQu$<%6af&vcf2CS&Ct6Yz z>9T-14dnHxTTjts*k5?$VTWVAanCB0jVN=Nj_ODC43x>k@lkC;!Y6Y z{HKG(9#a#*>PKEF!sg>7HHFIHfXpKY6=5bV%Ok1CA39?c$*~GRbMs)IZq;ET1E(L> zq!#kFb}GI)0NjyH@~%eV_E}p8sP8}vv#%dYazxBP89e&ap@!~9L|Zw4Ck5DWqOU!j z+)AQ5S!6D7Hjb1CuV^8T_RX$$M{buW*DjnCO6=f@8`NixIUdfJ_FN| z_r!XAyy_k>=;cdeBEGANXszvFf<2JO3<`%}+A)gxQJ{}Yx?78T=C-+y{#mTsWRLQx zr11sp=nHC^-M}N1isimhP|OiP$Wl+$& zbLF`Kk2O(?O*E1*01<@apr=5}s{VtYp`^xohMjb&V`>bTW