From 5f84f5d6123a76963a88c760400aef420fdde7e7 Mon Sep 17 00:00:00 2001 From: Brandon Rothweiler Date: Mon, 18 Apr 2022 14:22:59 -0400 Subject: [PATCH] Remove mentions of the retired term "Lovelace" (#1292) --- ...2-internet-of-things-and-the-modern-web.md | 2 +- blog/2021-05-19-lit-2.0.md | 2 +- .../custom-ui/creating-custom-panels.md | 2 +- ...lovelace-custom-card.md => custom-card.md} | 36 +++++++++--------- ...-custom-strategy.md => custom-strategy.md} | 26 ++++++------- ...lovelace-custom-view.md => custom-view.md} | 6 +-- .../custom-ui/registering-resources.md | 10 ++--- sidebars.js | 6 +-- static/_redirects | 5 +++ ...g => dashboard-custom-card-screenshot.png} | Bin ...s-tab.png => dashboards-resources-tab.png} | Bin ...png => frontend-profile-advanced-mode.png} | Bin .../en/frontend/lovelace-ui-comparison.png | Bin 11136 -> 0 bytes 13 files changed, 50 insertions(+), 45 deletions(-) rename docs/frontend/custom-ui/{lovelace-custom-card.md => custom-card.md} (81%) rename docs/frontend/custom-ui/{lovelace-custom-strategy.md => custom-strategy.md} (76%) rename docs/frontend/custom-ui/{lovelace-custom-view.md => custom-view.md} (91%) rename static/img/en/frontend/{lovelace-ui-custom-card-screenshot.png => dashboard-custom-card-screenshot.png} (100%) rename static/img/en/frontend/{lovelace-ui-resources-tab.png => dashboards-resources-tab.png} (100%) rename static/img/en/frontend/{lovelace-ui-profile-advanced-mode.png => frontend-profile-advanced-mode.png} (100%) delete mode 100644 static/img/en/frontend/lovelace-ui-comparison.png diff --git a/blog/2019-05-22-internet-of-things-and-the-modern-web.md b/blog/2019-05-22-internet-of-things-and-the-modern-web.md index 5024b822..8b982b26 100644 --- a/blog/2019-05-22-internet-of-things-and-the-modern-web.md +++ b/blog/2019-05-22-internet-of-things-and-the-modern-web.md @@ -75,7 +75,7 @@ In case you are wondering how an open source project got such an extensive list * **Easy state management.** To be able to share our state with any component, internal or external, we decided to roll our own state management. It’s a simple object that contains the current state of the house and it is passed down our component tree. Whenever the state changes, we make a copy and update the changed parts and then pass it down again to all the components. Components will then re-render and show the latest state. All state updates are managed by Home Assistant JS Websocket, and are all generated on the server. They are pushed to the frontend using web sockets, allowing all open UIs to stay in sync because they all receive the latest changes as soon as possible. [Home Assistant JS Websocket](https://github.com/home-assistant/home-assistant-js-websocket/) is our 4KB WebSocket + Auth library that can be added to any site to integrate it with Home Assistant instances. For a standalone Home Assistant UI built using 50 lines of JavaScript, see [this glitch](https://hass-auth-demo.glitch.me/). -* **Easy extension development using modules and unpkg.** Developers are able to develop their own cards without running any tooling. All you need is to create a JavaScript file, reference it in the resource section of your config and you can start using it ([example in the docs](/docs/frontend/custom-ui/lovelace-custom-card#advanced-example)). We default to importing resources as type=module, so that developers can import their dependencies straight from http://unpkg.com during development. +* **Easy extension development using modules and unpkg.** Developers are able to develop their own cards without running any tooling. All you need is to create a JavaScript file, reference it in the resource section of your config and you can start using it ([example in the docs](/docs/frontend/custom-ui/custom-card#advanced-example)). We default to importing resources as type=module, so that developers can import their dependencies straight from http://unpkg.com during development. * **Make it easy to find bloat in bundles.** If we can make it easier to find things that we ship unnecessarily, developers are more likely to find it and spend time on removing the bloat. For that reason, we include scripts in our repository that allows anyone to quickly run a bundle analysis using the [webpack-bundle-analyzer](https://github.com/webpack-contrib/webpack-bundle-analyzer) and see what packages add to our bundle size. These analysis look [like this](https://s3.amazonaws.com/home-assistant-demos/bundle-analysis/report-20190522.html). * **Code split translations.** We use [lokalise.co](https://lokalise.co/) to manage our translations. All translation strings in our code base are automatically uploaded to lokalise.co where volunteers are translating the available strings. We have build tooling to split our translations based on the different panels in our UI. This allows us to only load the translations on the fly that we need. * **Decentralized routing.** The top level of the application only knows how to route the first part of the url. It knows which code to load and which web component to instantiate. It will pass the rest of the url to the panel and further routing can be done from there. This will avoid the initial bundle to keep growing as more parts are splitter out. We have also created a simple to use router for web components with support for code splitting and loading screens, making it easy for our developers to do the right thing. diff --git a/blog/2021-05-19-lit-2.0.md b/blog/2021-05-19-lit-2.0.md index da4b2f75..bc3a4fa2 100644 --- a/blog/2021-05-19-lit-2.0.md +++ b/blog/2021-05-19-lit-2.0.md @@ -17,7 +17,7 @@ const html = LitElement.prototype.html; const css = LitElement.prototype.css; ``` -This is not a recommended practice, we advise you to bundle Lit into your component, or import it from `unpkg.com` or another source like in this [example](https://developers.home-assistant.io/docs/frontend/custom-ui/lovelace-custom-card#advanced-example). This way your card is not depending on the Lit version that is shipped with Home Assistant. +This is not a recommended practice, we advise you to bundle Lit into your component, or import it from `unpkg.com` or another source like in this [example](https://developers.home-assistant.io/docs/frontend/custom-ui/custom-card#advanced-example). This way your card is not depending on the Lit version that is shipped with Home Assistant. One of the things that changed, is that the creation of the `shadowRoot` is no longer done in the constructor, but just before the first update. This means that if you directly interact with the DOM, like with a query selector, you can no longer assume `shadowRoot` will always be available. diff --git a/docs/frontend/custom-ui/creating-custom-panels.md b/docs/frontend/custom-ui/creating-custom-panels.md index 4e4e4a31..00f8f807 100644 --- a/docs/frontend/custom-ui/creating-custom-panels.md +++ b/docs/frontend/custom-ui/creating-custom-panels.md @@ -2,7 +2,7 @@ title: "Creating custom panels" --- -Panels are pages that show information within Home Assistant and can allow controlling it. Panels are linked from the sidebar and rendered full screen. They have real-time access to the Home Assistant object via JavaScript. Examples of panels in the app are Lovelace, Map, Logbook and History. +Panels are pages that show information within Home Assistant and can allow controlling it. Panels are linked from the sidebar and rendered full screen. They have real-time access to the Home Assistant object via JavaScript. Examples of panels in the app are dashboards, Map, Logbook and History. Besides components registering panels, users can also register panels using the `panel_custom` component. This allows users to quickly build their own custom interfaces for Home Assistant. diff --git a/docs/frontend/custom-ui/lovelace-custom-card.md b/docs/frontend/custom-ui/custom-card.md similarity index 81% rename from docs/frontend/custom-ui/lovelace-custom-card.md rename to docs/frontend/custom-ui/custom-card.md index 400054ad..129184b7 100644 --- a/docs/frontend/custom-ui/lovelace-custom-card.md +++ b/docs/frontend/custom-ui/custom-card.md @@ -1,8 +1,8 @@ --- -title: "Lovelace: Custom Cards" +title: "Custom Cards" --- -[Lovelace](https://www.home-assistant.io/lovelace/) is our approach to defining your user interface for Home Assistant. We offer a lot of built-in cards, but you're not just limited to the ones that we decided to include in the Lovelace UI. You can build and use your own! +[Dashboards](https://www.home-assistant.io/dashboards/) are our approach to defining your user interface for Home Assistant. We offer a lot of built-in cards, but you're not just limited to the ones that we decided to include in Home Assistant. You can build and use your own! ## Defining your card @@ -36,8 +36,8 @@ class ContentCardExample extends HTMLElement { `; } - // The user supplied configuration. Throw an exception and Lovelace will - // render an error card. + // The user supplied configuration. Throw an exception and Home Assistant + // will render an error card. setConfig(config) { if (!config.entity) { throw new Error('You need to define an entity'); @@ -59,12 +59,12 @@ customElements.define('content-card-example', ContentCardExample); In our example card we defined a card with the tag `content-card-example` (see last line), so our card type will be `custom:content-card-example`. And because you created the file in your `/www` directory, it will be accessible in your browser via the url `/local/` (if you have recently added the www folder you will need to re-start Home Assistant for files to be picked up). -Add a resource to your Lovelace configuration with URL `/local/content-card-example.js` and type `module` ([resource docs](/docs/frontend/custom-ui/registering-resources)). +Add a resource to your dashboard configuration with URL `/local/content-card-example.js` and type `module` ([resource docs](/docs/frontend/custom-ui/registering-resources)). -You can then use your card in your Lovelace configuration: +You can then use your card in your dashboard configuration: ```yaml -# Example Lovelace configuration +# Example dashboard configuration views: - name: Example cards: @@ -76,7 +76,7 @@ views: Custom cards are defined as a [custom element](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements). It's up to you to decide how to render your DOM inside your element. You can use Polymer, Angular, Preact or any other popular framework (except for React – [more info on React here](https://custom-elements-everywhere.com/#react)). -Home Assistant will call `setConfig(config)` when the configuration changes (rare). If you throw an exception if the configuration is invalid, Lovelace will render an error card to notify the user. +Home Assistant will call `setConfig(config)` when the configuration changes (rare). If you throw an exception if the configuration is invalid, Home Assistant will render an error card to notify the user. Home Assistant will set the `hass` property when the state of Home Assistant changes (frequent). Whenever the state changes, the component will have to update itself to represent the latest state. @@ -90,13 +90,13 @@ Since some elements can be lazy loaded, if you want to get the card size of anot .then(() => element.getCardSize()); ``` -Your card can define a `getConfigElement` method that returns a custom element for editing the user configuration. Home Assistant will display this element in the card editor in Lovelace. +Your card can define a `getConfigElement` method that returns a custom element for editing the user configuration. Home Assistant will display this element in the card editor in the dashboard. ## Advanced example -Resources to load in Lovelace are imported as a JS module import. Below is an example of a custom card using JS modules that does all the fancy things. +Resources to load in dashboards are imported as a JS module import. Below is an example of a custom card using JS modules that does all the fancy things. -![Screenshot of the wired card](/img/en/frontend/lovelace-ui-custom-card-screenshot.png) +![Screenshot of the wired card](/img/en/frontend/dashboard-custom-card-screenshot.png) Create a new file in your Home Assistant config dir as `/www/wired-cards.js` and put in the following contents: @@ -201,12 +201,12 @@ class WiredToggleCard extends LitElement { customElements.define("wired-toggle-card", WiredToggleCard); ``` -Add a resource to your Lovelace config with URL `/local/wired-cards.js` and type `module`. +Add a resource to your dashboard config with URL `/local/wired-cards.js` and type `module`. And for your configuration: ```yaml -# Example Lovelace configuration +# Example dashboard configuration views: - name: Example cards: @@ -219,16 +219,16 @@ views: ## Graphical card configuration -Your card can define a `getConfigElement` method that returns a custom element for editing the user configuration. Home Assistant will display this element in the card editor in Lovelace. +Your card can define a `getConfigElement` method that returns a custom element for editing the user configuration. Home Assistant will display this element in the card editor in the dashboard. -Your card can also define a `getStubConfig` method that returns a default card configuration (without the `type:` parameter) in json form for use by the card type picker in Lovelace. +Your card can also define a `getStubConfig` method that returns a default card configuration (without the `type:` parameter) in json form for use by the card type picker in the dashboard. Home Assistant will call the `setConfig` method of the config element on setup. -Home Assistant will update the `hass` property of the config element on state changes, and the `lovelace` element, which contains information about the lovelace configuration. +Home Assistant will update the `hass` property of the config element on state changes, and the `lovelace` element, which contains information about the dashboard configuration. -Changes to the configuration are communicated back to lovelace by dispatching a `config-changed` event with the new configuration in its detail. +Changes to the configuration are communicated back to the dashboard by dispatching a `config-changed` event with the new configuration in its detail. -To have your card displayed in the card picker dialog in Lovelace, add an object describing it to the array `window.customCards`. Required properties of the object are `type` and `name` (see example below). +To have your card displayed in the card picker dialog in the dashboard, add an object describing it to the array `window.customCards`. Required properties of the object are `type` and `name` (see example below). ```js class ContentCardExample extends HTMLElement { diff --git a/docs/frontend/custom-ui/lovelace-custom-strategy.md b/docs/frontend/custom-ui/custom-strategy.md similarity index 76% rename from docs/frontend/custom-ui/lovelace-custom-strategy.md rename to docs/frontend/custom-ui/custom-strategy.md index eff03b35..693cca22 100644 --- a/docs/frontend/custom-ui/lovelace-custom-strategy.md +++ b/docs/frontend/custom-ui/custom-strategy.md @@ -1,26 +1,26 @@ --- -title: "Lovelace: Custom Strategies" +title: "Custom Strategies" --- _Introduced in Home Assistant 2021.5._ -Strategies are JavaScript functions that generate Lovelace configurations. When a user has not created a Lovelace configuration yet, an auto-generated dashboard is shown. That configuration is generated using a built-in strategy. +Strategies are JavaScript functions that generate dashboard configurations. When a user has not created a dashboard configuration yet, an auto-generated dashboard is shown. That configuration is generated using a built-in strategy. -It's possible for developers to create their own strategies to generate dashboards. Strategies can use all of Home Assistant's data and the user's Lovelace configuration to create something new. +It's possible for developers to create their own strategies to generate dashboards. Strategies can use all of Home Assistant's data and the user's dashboard configuration to create something new. A strategy can be applied to the whole configuration or to a specific view. -Strategies are defined as a custom element in a JavaScript file, and included [via Lovelace resources](./registering-resources.md). Home Assistant will call static functions on the class instead of rendering it as a custom element. +Strategies are defined as a custom element in a JavaScript file, and included [via dashboard resources](./registering-resources.md). Home Assistant will call static functions on the class instead of rendering it as a custom element. ## Dashboard Strategies -A dashboard strategy is responsible for generating a full Lovelace configuration. This can either be from scratch, or based on an existing Lovelace configuration that is passed in. +A dashboard strategy is responsible for generating a full dashboard configuration. This can either be from scratch, or based on an existing dashboard configuration that is passed in. An info object is passed to the strategy with information: | Key | Description | -- | -- -| `config` | User supplied Lovelace configuration, if any. +| `config` | User supplied dashboard configuration, if any. | `hass` | The Home Assistant object. | `narrow` | If the current user interface is rendered in narrow mode or not. @@ -30,7 +30,7 @@ class StrategyDemo { static async generateDashboard(info) { return { - title: "Generated Lovelace", + title: "Generated Dashboard", views: [ { "cards": [ @@ -50,7 +50,7 @@ class StrategyDemo { customElements.define("ll-strategy-my-demo", StrategyDemo); ``` -Use the following Lovelace configuration to use this strategy: +Use the following dashboard configuration to use this strategy: ```yaml strategy: @@ -60,14 +60,14 @@ views: [] ## View Strategies -A view strategy is responsible for generating the configuration of a specific Lovelace view. The strategy is invoked when the user opens the specific view. +A view strategy is responsible for generating the configuration of a specific dashboard view. The strategy is invoked when the user opens the specific view. An info object is passed to the strategy with information: | Key | Description | -- | -- | `view` | View configuration. -| `config` | Lovelace configuration. +| `config` | Dashboard configuration. | `hass` | The Home Assistant object. | `narrow` | If the current user interface is rendered in narrow mode or not. @@ -92,7 +92,7 @@ class StrategyDemo { customElements.define("ll-strategy-my-demo", StrategyDemo); ``` -Use the following Lovelace configuration to use this strategy: +Use the following dashboard configuration to use this strategy: ```yaml views: @@ -104,7 +104,7 @@ views: Strategies are structured such that a single class can provide both a dashboard and view strategy implementations. -It's recommended for a dashboard strategy to leave as much work to be done to the view strategies. That way the dashboard will show up for the user as fast as possible. This can be done by having the dashboard generate a Lovelace configuration with views that rely on it's own strategy. +It's recommended for a dashboard strategy to leave as much work to be done to the view strategies. That way the dashboard will show up for the user as fast as possible. This can be done by having the dashboard generate a configuration with views that rely on its own strategy. Below example will create a view per area, with each view showing all entities in that area in a grid. @@ -175,7 +175,7 @@ class StrategyDemo { customElements.define("ll-strategy-my-demo", StrategyDemo); ``` -Use the following Lovelace configuration to use this strategy: +Use the following dashboard configuration to use this strategy: ```yaml strategy: diff --git a/docs/frontend/custom-ui/lovelace-custom-view.md b/docs/frontend/custom-ui/custom-view.md similarity index 91% rename from docs/frontend/custom-ui/lovelace-custom-view.md rename to docs/frontend/custom-ui/custom-view.md index bbb72ff6..4fc0c651 100644 --- a/docs/frontend/custom-ui/lovelace-custom-view.md +++ b/docs/frontend/custom-ui/custom-view.md @@ -1,5 +1,5 @@ --- -title: "Lovelace: Custom View Layout" +title: "Custom View Layout" --- By default Home Assistant will try to show the cards in a masonry layout (like Pinterest). A Custom View Layout allows developers to override this and define the layout mechanism (like a grid). @@ -52,7 +52,7 @@ And you can define this element in the Custom Element Registry just as you would customElements.define("my-new-view", MyNewView); ``` -A custom view can be used by adding the following to the definition of your Lovelace view: +A custom view can be used by adding the following to the definition of your view: ```yaml - title: Home View @@ -61,7 +61,7 @@ A custom view can be used by adding the following to the definition of your Love cards: [...] ``` -The Lovelace default masonry view is an example of a layout element. ([source](https://github.com/home-assistant/frontend/blob/master/src/panels/lovelace/views/hui-masonry-view.ts)). +The default masonry view is an example of a layout element. ([source](https://github.com/home-assistant/frontend/blob/master/src/panels/lovelace/views/hui-masonry-view.ts)). ## Store Custom Data diff --git a/docs/frontend/custom-ui/registering-resources.md b/docs/frontend/custom-ui/registering-resources.md index 58c4fe6e..c490dd5e 100644 --- a/docs/frontend/custom-ui/registering-resources.md +++ b/docs/frontend/custom-ui/registering-resources.md @@ -2,15 +2,15 @@ title: "Registering Resources" --- -If you want to extend the Home Assistant Lovelace interface with custom cards, strategies or views you need to load external resources. +If you want to extend the Home Assistant interface with custom cards, strategies or views you need to load external resources. The first step is to make it accessible for the Home Assistant frontend. This is done by creating a new directory in your config folder called `www`. Create this directory and restart Home Assistant. Once restarted, you can put files in this directory. Each file will be accessible without authentication via the UI at `/local`. -The next step is to register these resources with the Lovelace interface. This is done by navigating to the Lovelace resources page by following below link: +The next step is to register these resources with the Home Assistant interface. This is done by navigating to the Resources page by following below link: -[![Open your Home Assistant instance and show your Lovelace resources.](https://my.home-assistant.io/badges/lovelace_resources.svg)](https://my.home-assistant.io/redirect/lovelace_resources/) +[![Open your Home Assistant instance and show your resources.](https://my.home-assistant.io/badges/lovelace_resources.svg)](https://my.home-assistant.io/redirect/lovelace_resources/) :::note @@ -18,6 +18,6 @@ This tab is only available when the active user's profile has "advanced mode" en ::: -![Screenshot of the Resources tab, found at the top of the Lovelace Configuration UI](/img/en/frontend/lovelace-ui-resources-tab.png) +![Screenshot of the Resources tab, found at the top of the Dashboards configuration UI](/img/en/frontend/dashboards-resources-tab.png) -![Screenshot of the Advanced Mode selector found on the Profile page](/img/en/frontend/lovelace-ui-profile-advanced-mode.png) +![Screenshot of the Advanced Mode selector found on the Profile page](/img/en/frontend/frontend-profile-advanced-mode.png) diff --git a/sidebars.js b/sidebars.js index 8e2729e2..0b462c03 100644 --- a/sidebars.js +++ b/sidebars.js @@ -68,9 +68,9 @@ module.exports = { type: "category", label: "Custom UI", items: [ - "frontend/custom-ui/lovelace-custom-card", - "frontend/custom-ui/lovelace-custom-strategy", - "frontend/custom-ui/lovelace-custom-view", + "frontend/custom-ui/custom-card", + "frontend/custom-ui/custom-strategy", + "frontend/custom-ui/custom-view", "frontend/custom-ui/creating-custom-panels", "frontend/custom-ui/registering-resources", ], diff --git a/static/_redirects b/static/_redirects index 07c2c375..74127d33 100644 --- a/static/_redirects +++ b/static/_redirects @@ -70,3 +70,8 @@ /docs/creating_platform_example_sensor https://github.com/home-assistant/example-custom-config/tree/master/custom_components/example_sensor /docs/creating_platform_example_light https://github.com/home-assistant/example-custom-config/tree/master/custom_components/example_light /docs/creating_component_deps_and_reqs /docs/creating_integration_manifest + +# Retiring "Lovelace" terminology +/docs/frontend/custom-ui/lovelace-custom-card /docs/frontend/custom-ui/custom-card +/docs/frontend/custom-ui/lovelace-custom-strategy /docs/frontend/custom-ui/custom-strategy +/docs/frontend/custom-ui/lovelace-custom-view /docs/frontend/custom-ui/custom-view diff --git a/static/img/en/frontend/lovelace-ui-custom-card-screenshot.png b/static/img/en/frontend/dashboard-custom-card-screenshot.png similarity index 100% rename from static/img/en/frontend/lovelace-ui-custom-card-screenshot.png rename to static/img/en/frontend/dashboard-custom-card-screenshot.png diff --git a/static/img/en/frontend/lovelace-ui-resources-tab.png b/static/img/en/frontend/dashboards-resources-tab.png similarity index 100% rename from static/img/en/frontend/lovelace-ui-resources-tab.png rename to static/img/en/frontend/dashboards-resources-tab.png diff --git a/static/img/en/frontend/lovelace-ui-profile-advanced-mode.png b/static/img/en/frontend/frontend-profile-advanced-mode.png similarity index 100% rename from static/img/en/frontend/lovelace-ui-profile-advanced-mode.png rename to static/img/en/frontend/frontend-profile-advanced-mode.png diff --git a/static/img/en/frontend/lovelace-ui-comparison.png b/static/img/en/frontend/lovelace-ui-comparison.png deleted file mode 100644 index 1d79d98716ba67749c5f9d14dfd28bcffbc5656c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11136 zcmcI~XIN9w)@CTudlBi42}l#^MWh!60@9>+ zLK6s~3h3aSneUmI@7}rJ{Fw9O?6uy#*53Q9ecorCXYCXBL|==NjD-vU08nZ_Qa1nq z@R0xjUOWlG4U$e=Q*#5zJ<&DNxKU|nXb1@Y;-sXctgNgI3=9+$6gTSsj|&eE@4q-K z3kwSlheNO8UiWS>vvJ&bF|n|-b8s*)vo|y}pMj#NBRMbO@2Mml%Hcno5xp@;RzGc3xdZ2AAA|@V? zS=BZ?|L~Fi!NI}c-0l;5U%q<+x$R3R6smW6E3@f`fRKp1k{T-~_tw^yteSq;#Cl=Z zdPhe`RaKR!gp9GVvA#Z7N=hmqB2iOQlbVj<%jj}xWAEFK?bTm~V`5@nE)m0x^BM1+}p_)B+xEqxMk^X5%KL4lEDpuN4lUs}16p1FjKLTG%Ji(d!?0&&9M zrMlS?X66O-OtMVn(n)CJ1_HCN`rWAxEmuEA;G_4PYG0=qJZrvII-fCM5vzw$$1x=2aYaiI(;l2f<9>;0)bA8CE!H?D*nh^$^*j ze$eW5F8@|Y!>)!9pVG00mUlscJ|^h?iXfSKzxwq|zI^RnqP7(DdsGrS3wFNlR~oL; zUjzj9QqW@1w`nz{6z{ME-FX_RS(=hCG580Cq@9|xaV0!t)}0L2He0|1p~1W9@koG`NVj7mY|&L1JQ|KCVOs zTuo>Ld10Qe>rjW3Nf2|=W=el!%lbVztqm^JpPYu^E4}x!D z^yR2s%2u6I_ohaEy@t;snB65&K5_OHSO)A|@$S9>MG?!JV!hs03jNnbI)65u#*nT$osGCIf@H)cRg3ALaJ((yvYtAY9{my_+G)~QXHfwVs|J7Vc;$3 zAR-4)e!G*s-Lf!mh6XV4gmhj%1J9dfGsQoOxf7r9DY#47EO+fG#BH!hZzbhst!HeO zLpqebM|%@7+LD-PNX;njb`q&q-`70($oS$jm;OJkNS`|U*qw>m??d=3P7krGTtwge z=7tMTEcjfn@Rzo7MMYioU!}J!p4olK;9DIlL5wtlG2NfD(1n={iefZgf zID=0~_Q>T2nhSaaiAbumYm*$a zMp*K9nQ|z-=eY_PX9cbcy`C7RE_b*pLESU2Cx&a%tD^)%CdXYd>m%0Bz;&%ZofGbf z5J@1moFi&UPzkT>KbvhiMv(E&+Jjzx^@jEZRiGpQ4riL+1ihwvTYFRiaQ|)>@hMyc zdDDyunP?yM>ZB3V@i`axWqRB#?6C3aC7W?m&^r{@^R>G1+U?`E)zsgE2PgBZM6o3N z)@JBqLfzrcDpqm98N}K(lMXSho=U>f+MQUN`W~{7B7YUnp6k!Z8J5_wsYVHWyT}V3 z5Wl>0D0@TT;@k1s9_JGWpD%j*1y&zWS0Y^^mi_c_%`zJQB<1RXXj{M4h23VFgRQ^` zot39;{%czB5%paLGjyJhk0PiZkLEHE#B-5Mzls&!h0%?{1|R+~5y`B6LgC${|42elLC!xlJm`>85eR zkKl~(^CN!FH~IG%ffMxEGIlMPdLl7ymJEG#Wn|tif~uF5TTK1nJiaVphOYfBk}khk zjgmcg{oy^9nKng# zvm``jTeCTVdIfbMGF&GE#adY;NH;&Ycxwrn-R*MnqQbLjDME!h><3b9>3fmAv=Vi9 zR;JlmNId(u&voCdc^`1L8dEzOnIPu=*dx%KYYDk0vU|k%qXNe6 zBVB|Ey0X5uj&E)s^-7RBpK|q*n?Bp`h(Y3pk1hC4jHoTABMb?h zLR&f-`)j$kl$Z3-XalBRxk*E8+!MGEJn_5Xn0+QPo}>8K==jci)Z705BYpoflPjBp zeKY!3T>{B!H9yY;e0SilhzIZDiN`A{lF-qx8Mt~%nn@d(2vbo}Df)SN?Gd|rs0FKP z@IK)jy3mVxFu!uNB#z_lMeqyu0ktJIwc{ng28poWgyLJOPU`aa5P`Rv5T$~{OD;=aD~LGR%>;!{~n8a8$I2Z3KRQWZ?8%=zQ)M4 zZXUDr!Oej|eom8W=+eA3Vl~slFMuz8=eE4gfJ(H*VFGe%;g@E8RN+3LNP2tk5dYvEs#2ZCRR_V#_{KDCK4x@A@@l5y#Xyfz+>-;1PI;uZ zvl-#CJ(!AxlPExJo8oe1mY6MKn z5rQKp2tpoqx`f|K1fK7Nj^~}}pMimWVS^5>NJkgbS?A*0d1s^J`WZd;_-u&2xmUzM zOyRM#yfdBP(EPe+UzSr4TXKQp2T2pAM`j*t1zd!dE>_<2KeAIWL3p62c`Qy4ITflif%_T-0^UvE%2JB`V|ut* zBo?TJza$A5YXL~BOlYY2iRNm;~=~~>WzzaG&9rYnPFPE@UczY$R*4FiU znqELzHyQ|j0OCtyp@4(Llf~{3r<(TUadtG(KJ}J%T>h&5!Ydc=ZbCNvww;t-6mUy4 zpQ#nb36jv;A#GOvI;D8EqyB6MW>eZY4~tT%Q?x7$>tm#4f4ORE`f~UZVt46gw zp7!ZPa#^ig9y4U>AUWY7>ts&K$I^n^&-R{!DuecR#U6S9V+e*LzT!tLok)l8w{PtY zV!1<&!8~gHx({@!OYB93yP{9jz$RHLcC>aa(}B#&TVmBUv)j$l%RV4Ek%{D6R%@VR z3Li_NgwMz&`7#gOuo{})!?~X#qWziQFpSA>PJ&!!);ty#w(bKmtS{~|Y>z++3X_yX zTEH2SrmeSE@Y< zDWAGF|0(yPqcFqHcCPP4`i|5??S7%_f@bXS?~Pu%uvhM!IY1BpHB#2)$7sibH&;er z-dRT{sPtiGz;}9={9>G$?MJ{vA;Eh<%H6bnn!`Gs2+D;P<2srMD{$7tOWm#8`9bxZ z1m=+X3Ie@r3vlqe!oIuSb`c24bL>-iTGk zo2~sL8yb!LBfm8B-u`dRBTV)8)cB956x(GO1QMS7ZyM9RS&476PZ;{J;K_cJAL+bc zT0mN=20k8X`1ekbeRk?oIf?GPTX~tm#>h*7-in+8BPU`#3LhQgdy^) zq32ga7@0my2;3W>cJX1Nl32d46^p+lis%bQB8<;$SPD`&T$|?tP{IcKi2XI0A5}A#_fp%q z2!$dq)TcA3H!hgaw`!4ZIW-c#`91~Ah@p2+Lx7`8_@zOHkkrCqpw!~%vvX?KGYhtG z+^WqLnSj4^Lh0w}X7S*!DP2;_N8#;#Lt-U8NjiV-`*1XgH>afaSX}D3b1CM-UNHsG zzZJI{o5y;Zcm>WDS@<}!xE7YZmeRl5{1j@Z6~fj40bF~&ejpK+iM>C6P&l-{J+PSW zx*1peE!XS?>3xc`4I%ul_YWw}x)h?q_^)UssK5+pdhHAFrN4jERMJ=J-16EMr|dl(^jrRMZn!=leJ^U->MM9li$=FIJ9Xy$L> z{9XMH5C?JOtB~o;)Oi75!f`#f8!@uJJ0+-w1v=6!`Qv>=&{4#usl!0(#9!UM-*Ih(tic!X}KF7s1`!cIYB>PpR7NBKRZ@XgG~cQ8jz; zjRt|_7%prioJrqJ#)ztEXK*jYHB+SLdDeOFM=QJ8h}e&|M~U3^hGZ5PcfOJeLywsP&Q^2d62lrqYMq5T%FO?# zJh;eU4}?5rBkPv`UB+=F-5h>bm5xW1F5<2xf?MOzxHKt=$(1*I*3tGQk1l2}XRaq> z$bo5rTqHs4!h|2P=_aW>!W_K%7|Dm`uUa=d3i|ir?_1#V=e-A;#*hKleyz*p)kb01 z??jZL<#Ir|ekz7z&mP!!aOMqU|K52vXg&{i(4T3!UwIqv@F!(FC1}2E{em9pAv1ff zB=f{ed1pXz0#RZPkd=)WJw5BQPC-p0ULOVJX8?V0HD|X4?w;)J1T1AXUbW)#EPGiX2LQhCs82#EfX^cd z{TP`7OK!#uKdHzGpMW0NPZl-ORdecmralhPE8DG1pjlF2;PDE4S6iO4tYxB2mOapi zb!dF|cpC2+xqxqD*=z!|l0;76GCWJQ8$LnG2MkyI1j8JFmww~MVlv&sQ2oT_ z&n`|>M}H@4_lXkiUsb2bDxNxwu8z-q9pz!UR?0@HCVH4DxWTC}g$(yM-cu}0M9r1D zWrfKq1xg@Y_QM!a0B%jdNWp^G89w^11hGZwZRm4FGxDEYsYMG?pSRYCAD0}Eu;i{EGI)1wp6pBL5G~CRgw`PWp%gD&kf(^8(#Z~ z0kDw`k6aW$gSeeuKmI!nV|RBkP2{da(od?vyI+nj<;tka?Hsxo-7VPHvw)n~f|9LK z$yt>lE`Uqf?*YTMC7CR4aMRQGnvdyY7fzQ&C-p6dOf|!Jvt&P6C89j?9vgr(graG# z2k7@#pn0_ehR3p$cev-=JY1`L3m{oZj}2moWB*2nD9D6?Zyj%RTkV(td_I1BeH#`Z z1S`*VZ*Wog+HCd>_MyV$`xe)3FVx*MCw;TdFf#yZ#b@(;T=DYUU|pd+xo5Q}?T00L z<}mY|6>Qne$5Xw25r%mv^!>FfS**~yC?q@yY!^#u8T|RyG+>xMD%(m9Xypdy`v0cmx09==Ovt&+uAhU08h9-&I1@xCfo4F?)cRgl#rrNS{&Ibnnoeq(^)C?JvdQk;P zbR29kg$|d#wG*eyF!5YakCg7FIeQD~TsYm-Le@-dGqN@opEDyOSw}{L zwTP~e$*!fYUF?Tc_xQN~qLFFt6X4x$4zoYRZ+tjq+(M|kGq@wUUe!T=l%<`N+33gJ zUwdzGe1HPb|Bko<{?6b1W}9F+DEUiuS^GLP%ZwR;a}HfarRF}*2hVEWNGwp~FluM= z(J2FY$7A~!h1#-g=))CRM|}Or7xG;Y@m^g2yeg+tw)1=N8r!spHKR)kznJ>9ud4)< zfNX8b^>D#x5GNcM5F2@)Cd&5MC|{^5Ok-+gj(p-H{@epkFuu%t()4xCBc*y_&0(C+ z^2Phz`9>|yr7uoj3hXf(b#;|k8QI~SDgU*~C1sQlu40@MS3!@262$p_yG<^n07*QFv<-bC5xlDv(* zD|B+VZbF$jBO#|DA?MR+322M!GgJ`j66_P)_haIDYs0sP{l6|bR`+x_Pi=Whhaz!% zjAHFfOy6*8wSOvd&L_5%e@$$KQUN;+*E;BdGXF}z9YK{sd}Tm*=!CVn8$)r)Lqc#8 z0r+r2{(lNhQb3OaXIWE`PdZj-n(P*TkRj%yg06DpzsBR$3Hb5B$4o#sF^9;9wxKgj zUpA4S1$^dE<9zcUc~B~$#*L7DeK8{NF#xFL4igYRVIlTa%+OMg#{1_c~^{&<=Im!g!?mL9Bb z`)g-2@lHaO%b@pygbh#hXZU0KC0(WdG5N*sRE#+?&8X1;ufYgF4NF$IyFEz@#`HfJ zUgQGjxAG3d9_#1wvI47bA`bzAdVK`AafzQNBZ|Y=aYH2nimOf;6Z6K8hxWO^G1>-= zUmXtHPDc)u2MR%Zw>{Otz^+=m5p-bE*8Kr<6gbH@dzX44c_F2zV!j- z^G&DbIHwf9hTgU`(erfy@_#U^Nt|XYT-9!1j8o5{lxXKZ8ZUtKggNif*F=qxhdLv*zx$qx zDz}PqWE{XoY#JXdPX%pcYc0o(;ND?B7?3d0mPLdeeegliOf9B;;4~sDYkB#ie+O({ zvNRL?HeW^1Vz&Ipdbr3COXZs~MjMKLEpgVI!Pcsz_>&=rCE8l=GhmR+T(7Qh= z(8P`|sdcMj3ykegVt$jNA76-$jk=8&hV%d82d<@0Zh6WVJs#Fb}J+!Po|Hz?7n(BAFfCgi$tzO%t|^R1uXE~w??n$Lb^bAlV& zqRyjdh74E!)(z!12Z4-#%ZbtU$Ug;`e3PVY8Qj$Y^hk$1_oll@dE??@fn3-IN#;k4 zF6jaO2_DLT39;c`Aj$fHxu`A)@Mf9kzl5%;VfW(NMs&5Pa!y}Uahv`us%oC$bo5)Ym$!{cE^6(>%l$sUG6YRYJRv+qKPgno}1pnG`g)rK)wkPI|E+%I812y~?wv z#$I!Mzlc#?rz(XYPkA4YVkqe5koDDvn?Z(fQ7l1dbweMu`LT+H1xMCk7j*riN9hz$T-)K>m3!rlh9yf3o>|~1oEmhcSopUXsW)1zuMmC`McrzwHu~j^66je3|M^Q~ z+Lg&{CqKUId$U)w0mugy1dJ9~Uc{##8s$B;F9*L|hEr9CJr*sEhfVbXU%!7eLq^&B z@{H03H8h@CzR3t?65t^nOOn(GuxCygPTHV&MP#+bW-`3$boqnqGr*7dF;I}&yq$Rmu8E_F8Pgxl z7D6s>l`+*d^!UU%rN8SY2Q$T(ZKCGFWNnv(_4_%G4L4V8yMPDfPl26EN@UnhbAtMh zik^em=&eBV0UtH4cv05!ruwa#MtlSl@oluN9h-W)Cr#u~{bn!Kjvx)EF)oQQvXDXq zrl|kQj%EhaeStCR1G>1-pp{4D^}~0f-`EY|8Z@yM#oB8`JWnJxVdllqE&}&TrC+k8 zcW`Z$W!TGA5hr&HaN>3`A;Z!1O3j#^f!u&yoL!eeEAh-9sK4WbecEu|B2Xm zdWT~99MyserefkUX^nagB5G3)?5dHUW^P9SH`*_mjCXHP{xsc=sQouQx4^eE;{eTA>pSEZv9(0>d zQyXW=aMH4;@-xwXei--6D>f>G!ghf3_xTo$SB}f#8G8#Y*23TCNJOs16y`g_Axr7q z?K3)K=aY6(m26Y0(kMvvhSeR7Uv7HOdLPyXGHi@pCHuDhv-zw6kGDP_V6$|X?v9R@ z<41FG-ZfEVG@y_{`<%Uhy;JxK#>ThploY!=eyh&|ZLU~KndtQB(4nW24ZfmOVX#Xof3aMak<)N7h)aI?2EJ1d<$9oba5P^i1bpZFwpes*^F-!<4j3-Fs88S6$JuvA@k@?gl$I!A zEkZa~25ZD{(58bHpJ+vxQj)F9NFTwB5P+dPZNiC-^@{^$eQne(naV69(J*&K3 z^8`wH8zAV<_PmCR?^r8%WDuctq zmcwt~+OCq=|C)geDL-DD34LrPyXPC*b$i+3!nw`J>A9ti2o=GTdOM(cbs%F-M2#Up zk%JE1tFBzi^Z&$?f3OL6IMn{7I%2{>vRc2119G|_KdH_@?-1dSG9qn$xu3Q z!heF$oO=s;39~A9IzHgk z=B~Yi`<#Ni-E)lhq?JPNCrTw-h1}zgVELPX`~D_iubTwy{5L26FHp`V3_|35zwkqM z`*MiVPIt8q1Q(*tx@bL@mWxHG19^=~bjN#N6LNumt` zWRSvpBgAJq=x-}Qud%hTv$lvc84ZHF0S`CLcB*=DtPS{Y2>n-rh<*lz-eb9%slBpH zfOLZ=m&+Il2#cdF4|HB?3f(^4W#9HaoB_xc56aid6*(bN$0_g15Q-*@TJ_PqZ1_xt zcLecGoRIc@&dGY}AojDh_IT1NYN!@y83*Cyw6)$_?tcdX0Z1&&7pUd6JIidQi+EHf zI`$JzBJeF3l);$@)2)7uNu6|#1?pB)FYa)$j)CfXdRLFS3SUTi0k67%I^$W;5l_-f z+4N_#_1>#9tbjX+vV_ZQlw0)rl=4cP+5IpFaqfA_gZ_8x3a9zJH^rCP#9hGK=Si^a z5@D>b_IOpp>r$zmh_Fc~X-#{yRD-dKs6Ny`EH7okh3!z^= zVSlU8O?+YW04X)ZyGukAh|Gm6OJ5^k+0{C@C??lvhnnN^FxW^s+ z);MY8s9?=LO_>W@@I1+jM&BPujHu&UxSK~~%RTEIpjbv4J8eq*ckU6X$4{o3V|b7> z9u+^YXi8h6L3<3I+59h_^=#6UDa34r&S9e<$3n(-1AN31^ZWY&ADzv1!(iDTb#U+c ze5OSwJ_^`aOM6?=mSTP1y(){{`f>XnGoxErP-{_PiuR_dQqF_d5f+TWsT)-f!b}m~ zXc2=}0xnMVvf@0XBgg5`im^^Y;;o1HoC#16MznRYR7KOBh z?=YAAv*xrFQ-gwj0HHyBpU(|`lENj!kWt&(i2u0#sJ}VV`Nw5v1^hF;?=w;R`LC+2 Mp|4)`&?e%)0n1N>oB#j-