From e546488aebaa7cf8b2571ca2eaaf8f61f9ef58d8 Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Thu, 26 Dec 2024 13:20:03 +0000 Subject: [PATCH 001/237] Fix broken reddit video & nsfw post thumbnails --- internal/feed/reddit.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/feed/reddit.go b/internal/feed/reddit.go index 297020c..77a6e89 100644 --- a/internal/feed/reddit.go +++ b/internal/feed/reddit.go @@ -111,8 +111,8 @@ func FetchSubredditPosts(subreddit, sort, topPeriod, search, commentsUrlTemplate TimePosted: time.Unix(int64(post.Time), 0), } - if post.Thumbnail != "" && post.Thumbnail != "self" && post.Thumbnail != "default" { - forumPost.ThumbnailUrl = post.Thumbnail + if post.Thumbnail != "" && post.Thumbnail != "self" && post.Thumbnail != "default" && post.Thumbnail != "nsfw" { + forumPost.ThumbnailUrl = html.UnescapeString(post.Thumbnail) } if !post.IsSelf { From 85b8ee493e01a767eb0c5ae15c98a9bbbbe810a1 Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Thu, 26 Dec 2024 13:24:40 +0000 Subject: [PATCH 002/237] Update dependencies --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 17aa4d4..7034fe5 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.22.5 require ( github.com/mmcdole/gofeed v1.3.0 - golang.org/x/text v0.16.0 + golang.org/x/text v0.21.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -15,5 +15,5 @@ require ( github.com/mmcdole/goxpp v1.1.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - golang.org/x/net v0.27.0 // indirect + golang.org/x/net v0.33.0 // indirect ) diff --git a/go.sum b/go.sum index 28cb1ae..1f81f1c 100644 --- a/go.sum +++ b/go.sum @@ -33,8 +33,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= -golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= -golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -54,8 +54,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= From 108c83588c2ec170786349ce515ffe07eb85d58e Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:40:46 +0000 Subject: [PATCH 003/237] Allow using a standard HTTP proxy in reddit widget --- docs/configuration.md | 26 ++++++++++++++++- internal/glance/config-fields.go | 50 ++++++++++++++++++++++++++++++++ internal/glance/widget-reddit.go | 45 ++++++++++++++++++---------- 3 files changed, 105 insertions(+), 16 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 6bd1bc6..8508165 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -746,6 +746,7 @@ Example: | collapse-after | integer | no | 5 | | comments-url-template | string | no | https://www.reddit.com/{POST-PATH} | | request-url-template | string | no | | +| proxy | string or multiple parameters | no | | | sort-by | string | no | hot | | top-period | string | no | day | | search | string | no | | @@ -807,7 +808,7 @@ r/selfhosted/comments/bsp01i/welcome_to_rselfhosted_please_read_this_first/ `{SUBREDDIT}` - the subreddit name ##### `request-url-template` -A custom request url that will be used to fetch the data instead. This is useful when you're hosting Glance on a VPS and Reddit is blocking the requests, and you want to route it through an HTTP proxy. +A custom request URL that will be used to fetch the data. This is useful when you're hosting Glance on a VPS where Reddit is blocking the requests and you want to route them through a proxy that accepts the URL as either a part of the path or a query parameter. Placeholders: @@ -818,6 +819,29 @@ https://proxy/{REQUEST-URL} https://your.proxy/?url={REQUEST-URL} ``` +##### `proxy` +A custom HTTP/HTTPS proxy URL that will be used to fetch the data. This is useful when you're hosting Glance on a VPS where Reddit is blocking the requests and you want to bypass the restriction by routing the requests through a proxy. Example: + +``` +proxy: http://user:pass@proxy.com:8080 +proxy: https://user:pass@proxy.com:443 +``` + +Alternatively, you can specify the proxy URL as well as additional options by using multiple parameters: + +```yaml +proxy: + url: http://proxy.com:8080 + allow-insecure: true + timeout: 10s +``` + +###### `allow-insecure` +When set to `true`, allows the use of insecure connections such as when the proxy has a self-signed certificate. + +###### `timeout` +The maximum time to wait for a response from the proxy. The value is a string and must be a number followed by one of s, m, h, d. Example: `10s` for 10 seconds, `1m` for 1 minute, etc + ##### `sort-by` Can be used to specify the order in which the posts should get returned. Possible values are `hot`, `new`, `top` and `rising`. diff --git a/internal/glance/config-fields.go b/internal/glance/config-fields.go index 6c6f0c5..8aaac85 100644 --- a/internal/glance/config-fields.go +++ b/internal/glance/config-fields.go @@ -1,7 +1,10 @@ package glance import ( + "crypto/tls" "fmt" + "net/http" + "net/url" "regexp" "strconv" "strings" @@ -169,3 +172,50 @@ func (i *customIconField) UnmarshalYAML(node *yaml.Node) error { *i = newCustomIconField(value) return nil } + +type proxyOptionsField struct { + URL string `yaml:"url"` + AllowInsecure bool `yaml:"allow-insecure"` + Timeout durationField `yaml:"timeout"` + client *http.Client `yaml:"-"` +} + +func (p *proxyOptionsField) UnmarshalYAML(node *yaml.Node) error { + type proxyOptionsFieldAlias proxyOptionsField + alias := (*proxyOptionsFieldAlias)(p) + var proxyURL string + + if err := node.Decode(&proxyURL); err != nil { + if err := node.Decode(alias); err != nil { + return err + } + } + + if proxyURL == "" && p.URL == "" { + return nil + } + + if p.URL != "" { + proxyURL = p.URL + } + + parsedUrl, err := url.Parse(proxyURL) + if err != nil { + return fmt.Errorf("parsing proxy URL: %v", err) + } + + var timeout = defaultClientTimeout + if p.Timeout > 0 { + timeout = time.Duration(p.Timeout) + } + + p.client = &http.Client{ + Timeout: timeout, + Transport: &http.Transport{ + Proxy: http.ProxyURL(parsedUrl), + TLSClientConfig: &tls.Config{InsecureSkipVerify: p.AllowInsecure}, + }, + } + + return nil +} diff --git a/internal/glance/widget-reddit.go b/internal/glance/widget-reddit.go index 1ef1147..5025772 100644 --- a/internal/glance/widget-reddit.go +++ b/internal/glance/widget-reddit.go @@ -19,19 +19,20 @@ var ( type redditWidget struct { widgetBase `yaml:",inline"` - Posts forumPostList `yaml:"-"` - Subreddit string `yaml:"subreddit"` - Style string `yaml:"style"` - ShowThumbnails bool `yaml:"show-thumbnails"` - ShowFlairs bool `yaml:"show-flairs"` - SortBy string `yaml:"sort-by"` - TopPeriod string `yaml:"top-period"` - Search string `yaml:"search"` - ExtraSortBy string `yaml:"extra-sort-by"` - CommentsUrlTemplate string `yaml:"comments-url-template"` - Limit int `yaml:"limit"` - CollapseAfter int `yaml:"collapse-after"` - RequestUrlTemplate string `yaml:"request-url-template"` + Posts forumPostList `yaml:"-"` + Subreddit string `yaml:"subreddit"` + Proxy proxyOptionsField `yaml:"proxy"` + Style string `yaml:"style"` + ShowThumbnails bool `yaml:"show-thumbnails"` + ShowFlairs bool `yaml:"show-flairs"` + SortBy string `yaml:"sort-by"` + TopPeriod string `yaml:"top-period"` + Search string `yaml:"search"` + ExtraSortBy string `yaml:"extra-sort-by"` + CommentsUrlTemplate string `yaml:"comments-url-template"` + Limit int `yaml:"limit"` + CollapseAfter int `yaml:"collapse-after"` + RequestUrlTemplate string `yaml:"request-url-template"` } func (widget *redditWidget) initialize() error { @@ -94,6 +95,7 @@ func (widget *redditWidget) update(ctx context.Context) { widget.Search, widget.CommentsUrlTemplate, widget.RequestUrlTemplate, + widget.Proxy.client, widget.ShowFlairs, ) @@ -161,7 +163,16 @@ func templateRedditCommentsURL(template, subreddit, postId, postPath string) str return template } -func fetchSubredditPosts(subreddit, sort, topPeriod, search, commentsUrlTemplate, requestUrlTemplate string, showFlairs bool) (forumPostList, error) { +func fetchSubredditPosts( + subreddit, + sort, + topPeriod, + search, + commentsUrlTemplate, + requestUrlTemplate string, + proxyClient *http.Client, + showFlairs bool, +) (forumPostList, error) { query := url.Values{} var requestUrl string @@ -180,8 +191,12 @@ func fetchSubredditPosts(subreddit, sort, topPeriod, search, commentsUrlTemplate requestUrl = fmt.Sprintf("https://www.reddit.com/r/%s/%s.json?%s", subreddit, sort, query.Encode()) } + var client requestDoer = defaultHTTPClient + if requestUrlTemplate != "" { requestUrl = strings.ReplaceAll(requestUrlTemplate, "{REQUEST-URL}", requestUrl) + } else if proxyClient != nil { + client = proxyClient } request, err := http.NewRequest("GET", requestUrl, nil) @@ -191,7 +206,7 @@ func fetchSubredditPosts(subreddit, sort, topPeriod, search, commentsUrlTemplate // Required to increase rate limit, otherwise Reddit randomly returns 429 even after just 2 requests setBrowserUserAgentHeader(request) - responseJson, err := decodeJsonFromRequest[subredditResponseJson](defaultHTTPClient, request) + responseJson, err := decodeJsonFromRequest[subredditResponseJson](client, request) if err != nil { return nil, err } From 94ec286de64b37a730b6651af54cd1e2315ac3f3 Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Mon, 6 Jan 2025 21:28:53 +0000 Subject: [PATCH 004/237] Add codeblock highlighting --- docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index 8508165..f4f96f5 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -822,7 +822,7 @@ https://your.proxy/?url={REQUEST-URL} ##### `proxy` A custom HTTP/HTTPS proxy URL that will be used to fetch the data. This is useful when you're hosting Glance on a VPS where Reddit is blocking the requests and you want to bypass the restriction by routing the requests through a proxy. Example: -``` +```yaml proxy: http://user:pass@proxy.com:8080 proxy: https://user:pass@proxy.com:443 ``` From 491bc65a38f771cea366b1ffab0c74c9bcda6386 Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Tue, 7 Jan 2025 10:45:54 +0000 Subject: [PATCH 005/237] Add target property on bookmarks widget --- docs/configuration.md | 8 +++++++- internal/glance/templates/bookmarks.html | 2 +- internal/glance/widget-bookmarks.go | 22 ++++++++++++++++++---- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index f4f96f5..949452a 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1520,10 +1520,11 @@ An array of groups which can optionally have a title and a custom color. | links | array | yes | | | same-tab | boolean | no | false | | hide-arrow | boolean | no | false | +| target | string | no | | > [!TIP] > -> You can set `same-tab` and `hide-arrow` either on the group which will apply them to all links in that group, or on each individual link which will override the value set on the group. +> You can set `same-tab`, `hide-arrow` and `target` either on the group which will apply them to all links in that group, or on each individual link which will override the value set on the group. ###### Properties for each link | Name | Type | Required | Default | @@ -1533,6 +1534,7 @@ An array of groups which can optionally have a title and a custom color. | icon | string | no | | | same-tab | boolean | no | false | | hide-arrow | boolean | no | false | +| target | string | no | | `icon` @@ -1556,6 +1558,10 @@ Whether to open the link in the same tab or a new one. Whether to hide the colored arrow on each link. +`target` + +Set a custom value for the link's `target` attribute. Possible values are `_blank`, `_self`, `_parent` and `_top`, you can read more about what they do [here](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#target). This property has precedence over `same-tab`. + ### ChangeDetection.io Display a list watches from changedetection.io. diff --git a/internal/glance/templates/bookmarks.html b/internal/glance/templates/bookmarks.html index 1e8bfc7..f247bdb 100644 --- a/internal/glance/templates/bookmarks.html +++ b/internal/glance/templates/bookmarks.html @@ -13,7 +13,7 @@ {{ end }} - {{ .Title }} + {{ .Title }} {{ end }} diff --git a/internal/glance/widget-bookmarks.go b/internal/glance/widget-bookmarks.go index d55b818..4f3d26e 100644 --- a/internal/glance/widget-bookmarks.go +++ b/internal/glance/widget-bookmarks.go @@ -14,6 +14,7 @@ type bookmarksWidget struct { Color *hslColorField `yaml:"color"` SameTab bool `yaml:"same-tab"` HideArrow bool `yaml:"hide-arrow"` + Target string `yaml:"target"` Links []struct { Title string `yaml:"title"` URL string `yaml:"url"` @@ -23,10 +24,11 @@ type bookmarksWidget struct { // {{ if not .SameTab }} would return true for any non-nil pointer // which leaves us with no way of checking if the value is true or // false, hence the duplicated fields below - SameTabRaw *bool `yaml:"same-tab"` - SameTab bool `yaml:"-"` - HideArrowRaw *bool `yaml:"hide-arrow"` - HideArrow bool `yaml:"-"` + SameTabRaw *bool `yaml:"same-tab"` + SameTab bool `yaml:"-"` + HideArrowRaw *bool `yaml:"hide-arrow"` + HideArrow bool `yaml:"-"` + Target string `yaml:"target"` } `yaml:"links"` } `yaml:"groups"` } @@ -49,6 +51,18 @@ func (widget *bookmarksWidget) initialize() error { } else { link.HideArrow = *link.HideArrowRaw } + + if link.Target == "" { + if group.Target != "" { + link.Target = group.Target + } else { + if link.SameTab { + link.Target = "" + } else { + link.Target = "_blank" + } + } + } } } From db512419ea8b52269a9b2f5f6c33fcbca35b05f9 Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Tue, 7 Jan 2025 15:34:58 +0000 Subject: [PATCH 006/237] Add new text color class --- internal/glance/static/main.css | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/glance/static/main.css b/internal/glance/static/main.css index 1d5c19a..a4b7591 100644 --- a/internal/glance/static/main.css +++ b/internal/glance/static/main.css @@ -41,9 +41,10 @@ --color-graph-gridlines: hsl(var(--bghs), calc(var(--scheme) ((var(--scheme) var(--bgl)) + 6% * var(--cm)))); --ths: var(--bgh), calc(var(--bgs) * var(--tsm)); + --color-text-highlight: hsl(var(--ths), calc(var(--scheme) var(--cm) * 85%)); + --color-text-paragraph: hsl(var(--ths), calc(var(--scheme) var(--cm) * 73%)); --color-text-base: hsl(var(--ths), calc(var(--scheme) var(--cm) * 58%)); --color-text-base-muted: hsl(var(--ths), calc(var(--scheme) var(--cm) * 52%)); - --color-text-highlight: hsl(var(--ths), calc(var(--scheme) var(--cm) * 85%)); --color-text-subdue: hsl(var(--ths), calc(var(--scheme) var(--cm) * 35%)); --font-size-h1: 1.7rem; @@ -1793,6 +1794,7 @@ details[open] .summary::after { .size-h6 { font-size: var(--font-size-h6); } .color-highlight { color: var(--color-text-highlight); } +.color-paragraph { color: var(--color-text-paragraph); } .color-base { color: var(--color-text-base); } .color-subdue { color: var(--color-text-subdue); } .color-negative { color: var(--color-negative); } From 8b878149d41419575ea13e2be6f1423f6648368e Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Thu, 9 Jan 2025 17:17:56 +0000 Subject: [PATCH 007/237] Update docs --- docs/configuration.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 949452a..6fa0660 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1302,7 +1302,7 @@ repositories: - codeberg:redict/redict ``` -Official images on Docker Hub can be specified by ommiting the owner: +Official images on Docker Hub can be specified by omitting the owner: ```yaml repositories: @@ -1311,7 +1311,7 @@ repositories: - dockerhub:alpine ``` -You can also specify specific tags for Docker Hub images: +You can also specify exact tags for Docker Hub images: ```yaml repositories: From ed477e8cc6281c0764df5573057013b3896e928e Mon Sep 17 00:00:00 2001 From: Mystically <100186990+Mystically11@users.noreply.github.com> Date: Thu, 9 Jan 2025 21:19:13 +0100 Subject: [PATCH 008/237] add option to include github prereleases --- internal/feed/github.go | 37 +++++++++++++++++++++++++++++-------- internal/feed/releases.go | 7 ++++--- internal/glance/config.go | 2 +- internal/widget/releases.go | 24 +++++++++++++----------- 4 files changed, 47 insertions(+), 23 deletions(-) diff --git a/internal/feed/github.go b/internal/feed/github.go index 18487f0..9ec3733 100644 --- a/internal/feed/github.go +++ b/internal/feed/github.go @@ -18,11 +18,23 @@ type githubReleaseLatestResponseJson struct { } func fetchLatestGithubRelease(request *ReleaseRequest) (*AppRelease, error) { - httpRequest, err := http.NewRequest( - "GET", - fmt.Sprintf("https://api.github.com/repos/%s/releases/latest", request.Repository), - nil, - ) + var httpRequest *http.Request + var err error + var response githubReleaseLatestResponseJson + + if request.IncludeGithubPreReleases { + httpRequest, err = http.NewRequest( + "GET", + fmt.Sprintf("https://api.github.com/repos/%s/releases", request.Repository), + nil, + ) + } else { + httpRequest, err = http.NewRequest( + "GET", + fmt.Sprintf("https://api.github.com/repos/%s/releases/latest", request.Repository), + nil, + ) + } if err != nil { return nil, err @@ -32,10 +44,19 @@ func fetchLatestGithubRelease(request *ReleaseRequest) (*AppRelease, error) { httpRequest.Header.Add("Authorization", "Bearer "+(*request.Token)) } - response, err := decodeJsonFromRequest[githubReleaseLatestResponseJson](defaultClient, httpRequest) + if request.IncludeGithubPreReleases { + releases, err := decodeJsonFromRequest[[]githubReleaseLatestResponseJson](defaultClient, httpRequest) - if err != nil { - return nil, err + if err != nil { + return nil, err + } + response = releases[0] + } else { + response, err = decodeJsonFromRequest[githubReleaseLatestResponseJson](defaultClient, httpRequest) + + if err != nil { + return nil, err + } } return &AppRelease{ diff --git a/internal/feed/releases.go b/internal/feed/releases.go index b0cdc25..a27f7b0 100644 --- a/internal/feed/releases.go +++ b/internal/feed/releases.go @@ -16,9 +16,10 @@ const ( ) type ReleaseRequest struct { - Source ReleaseSource - Repository string - Token *string + Source ReleaseSource + Repository string + Token *string + IncludeGithubPreReleases bool } func FetchLatestReleases(requests []*ReleaseRequest) (AppReleases, error) { diff --git a/internal/glance/config.go b/internal/glance/config.go index 131ef7f..5b798e6 100644 --- a/internal/glance/config.go +++ b/internal/glance/config.go @@ -49,7 +49,7 @@ func NewConfigFromYml(contents io.Reader) (*Config, error) { func NewConfig() *Config { config := &Config{} - config.Server.Host = "" + config.Server.Host = "127.0.0.1" config.Server.Port = 8080 return config diff --git a/internal/widget/releases.go b/internal/widget/releases.go index 74b5af7..46aa21a 100644 --- a/internal/widget/releases.go +++ b/internal/widget/releases.go @@ -12,15 +12,16 @@ import ( ) type Releases struct { - widgetBase `yaml:",inline"` - Releases feed.AppReleases `yaml:"-"` - releaseRequests []*feed.ReleaseRequest `yaml:"-"` - Repositories []string `yaml:"repositories"` - Token OptionalEnvString `yaml:"token"` - GitLabToken OptionalEnvString `yaml:"gitlab-token"` - Limit int `yaml:"limit"` - CollapseAfter int `yaml:"collapse-after"` - ShowSourceIcon bool `yaml:"show-source-icon"` + widgetBase `yaml:",inline"` + Releases feed.AppReleases `yaml:"-"` + releaseRequests []*feed.ReleaseRequest `yaml:"-"` + Repositories []string `yaml:"repositories"` + Token OptionalEnvString `yaml:"token"` + GitLabToken OptionalEnvString `yaml:"gitlab-token"` + Limit int `yaml:"limit"` + CollapseAfter int `yaml:"collapse-after"` + ShowSourceIcon bool `yaml:"show-source-icon"` + IncludeGithubPreReleases bool `yaml:"include-github-prereleases"` } func (widget *Releases) Initialize() error { @@ -42,8 +43,9 @@ func (widget *Releases) Initialize() error { var request *feed.ReleaseRequest if len(parts) == 1 { request = &feed.ReleaseRequest{ - Source: feed.ReleaseSourceGithub, - Repository: repository, + Source: feed.ReleaseSourceGithub, + Repository: repository, + IncludeGithubPreReleases: widget.IncludeGithubPreReleases, } if widget.Token != "" { From 46bc36ad4ae0659288f63b71ba2904b450d04838 Mon Sep 17 00:00:00 2001 From: Mystically <100186990+Mystically11@users.noreply.github.com> Date: Thu, 9 Jan 2025 21:20:11 +0100 Subject: [PATCH 009/237] oops --- internal/glance/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/glance/config.go b/internal/glance/config.go index 5b798e6..131ef7f 100644 --- a/internal/glance/config.go +++ b/internal/glance/config.go @@ -49,7 +49,7 @@ func NewConfigFromYml(contents io.Reader) (*Config, error) { func NewConfig() *Config { config := &Config{} - config.Server.Host = "127.0.0.1" + config.Server.Host = "" config.Server.Port = 8080 return config From 086fac4120a6d4fe6deba15ef304ccd1e6fde98c Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Sat, 11 Jan 2025 17:59:07 +0000 Subject: [PATCH 010/237] Fix monitor widget showing incorrect status icon --- internal/glance/widget-monitor.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/internal/glance/widget-monitor.go b/internal/glance/widget-monitor.go index e5f7919..0890902 100644 --- a/internal/glance/widget-monitor.go +++ b/internal/glance/widget-monitor.go @@ -62,10 +62,8 @@ func (widget *monitorWidget) update(ctx context.Context) { widget.HasFailing = true } - if !status.TimedOut { - site.StatusText = statusCodeToText(status.Code, site.AltStatusCodes) - site.StatusStyle = statusCodeToStyle(status.Code, site.AltStatusCodes) - } + site.StatusText = statusCodeToText(status.Code, site.AltStatusCodes) + site.StatusStyle = statusCodeToStyle(status.Code, site.AltStatusCodes) } } From 59bfe3e8357b6bcab0f3f351c7113c32d57f7821 Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Sat, 11 Jan 2025 19:48:06 +0000 Subject: [PATCH 011/237] Add vertical-list style for videos widget --- docs/configuration.md | 10 +++++++- .../videos-widget-vertical-list-preview.png | Bin 0 -> 79163 bytes internal/glance/static/main.css | 7 ++++++ .../templates/videos-vertical-list.html | 20 +++++++++++++++ internal/glance/widget-videos.go | 23 ++++++++++++++---- 5 files changed, 54 insertions(+), 6 deletions(-) create mode 100644 docs/images/videos-widget-vertical-list-preview.png create mode 100644 internal/glance/templates/videos-vertical-list.html diff --git a/docs/configuration.md b/docs/configuration.md index 6fa0660..92c5d8c 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -583,6 +583,7 @@ Preview: | channels | array | yes | | | limit | integer | no | 25 | | style | string | no | horizontal-cards | +| collapse-after | integer | no | 7 | | collapse-after-rows | integer | no | 4 | | include-shorts | boolean | no | false | | video-url-template | string | no | https://www.youtube.com/watch?v={VIDEO-ID} | @@ -607,11 +608,18 @@ Then scroll down and click on "Share channel", then "Copy channel ID": ##### `limit` The maximum number of videos to show. +##### `collapse-after` +Specify the number of videos to show when using the `vertical-list` style before the "SHOW MORE" button appears. + ##### `collapse-after-rows` Specify the number of rows to show when using the `grid-cards` style before the "SHOW MORE" button appears. ##### `style` -Used to change the appearance of the widget. Possible values are `horizontal-cards` and `grid-cards`. +Used to change the appearance of the widget. Possible values are `horizontal-cards`, `vertical-list` and `grid-cards`. + +Preview of `vertical-list`: + +![](images/videos-widget-vertical-list-preview.png) Preview of `grid-cards`: diff --git a/docs/images/videos-widget-vertical-list-preview.png b/docs/images/videos-widget-vertical-list-preview.png new file mode 100644 index 0000000000000000000000000000000000000000..e33ce8679df732acee3c2c1c181e324e12e2e54e GIT binary patch literal 79163 zcmcG#V|1oH^fy}Dwr$()6w^*U_0;C{uJ5{2+s4$kIkkD$wr!j~|Mz`Aob&aZleKbX zCwpH>RYxb_>e=1=~p72tF*SOnuED3z}VRgOvTvB z-jzjJTAhrWg`I`twF9#0OQy+8Ti#q=o&gN*D*_Eh01gcX{zZNJ@`V4J{;CZa9XRCw zq(gqu?BEb!XkX#aFK-nJ^*`y>U-W;jAOQ^Q=u7DTg#V91!M<3ruwYPMl58BDY~Z>7 zE7$)@gwFk6IVFD4|2c@Sd?Efv@&`ZP7xlmYVrOIfkNfoP($Z+ya}^Biqg!4|T;1K^ zEDP3%XkhuVdDEafL3y?mpc9{A+d7J^mG18ckJghHgdyiHFM&W_NK54~{7M~!21kwt zM{Ohkqd3&EwXxs@I`&-cdKIn*@X!oL;n`-sTm4SYva2um`nVOUudjF4)MPO?GBUby z`g3Op2?-e}$yV6g(_@5$WW~nDh6gE0fP{oJ*b@u$#bW>ei>2%jzI8L%c^w}Aj=J$G zPRH$#_Iv+)PBP~GI7t&J!)fGE6RWuHcfR1K=Vyiwo@UG4;At`69aAu>Tlf18B55?k zi|zWtrmkjDG0ODq&F6;=;+t7`vd{CHjsc+(U0AO$YuA&x8dD=gni{az%te7isgMF{ z71aH-_i)#Rg!JJ>Ua9FN;8FL-c%u}#weLXqJzhlA>Y=XeDcXWimP~kMuEhlu9n{># z)bxS+`SW!>>`L+3Nf3f08OK$8BJZakKpNQ%EQ&XSgAR< z@1zVD-jBhjFSw3%hbEfZ@b0{R=5>K3HUy;a-vxwdV8X-@6 zO;e!NPjSK)Xm_vhn(w*Nv(=rdCPC1WjMCj&Lj@b3Jo^@DX{gY)ysh@5>CCJ9$-whv za<;?uV*5zvbspvSidNVCZbntt!5KgHWTMPh*#H;owLG}SJ88}v1!g?W>{Iy%z}??l zQR>c9(zpJ=A1xva;jWezYhjJmu(Z6h)!OgVk=X;~t1$%>9BUT|B(Zk4y%c z+y>Xk)Z3GC=ePA&6srJJ+Y80!RS9D}Gk>X~!1v)6HU5iye%whW9M1=03c5sSyWd82 z>~z(|c47=wqBilMtm8_3{sI-^v$f*twVBJ}(L)3FPB_iUa^c5J>$zd0?yi6T)2@eE zDIO73pD$cm?uVkl&jTZYQBL(?l2$&KYvDowh8d? zBK^@d2>%Pnkzrt9OpN3L{r!9K@MgbeIvY#~7vBF{mg5fTXc1jHm3#o(pcWU~laPuA zbnO1Tjh-?dtu}$>3RE507y=e=mf4qP(ScZCla33|{}vxRDS)0i>?iSv3#W>Otk1^w zvldL)3fCQrHG2eChS7N7dHzQ9ktE+)$Uk5cgnVq zIZmN{|KDmTzPMfP)Co=TtvSvicnxi(BxS1gRz7JPydo>UXp>mEK$D;{V}fX7gmFtt zb|&gA$pLt-g6fEmT&|zsl40{jHN0FA1*QVD_gVvV4XBDCK5S4jm<&qcOe`4)4)t9?$iOM=gs}Y< zDbEAZgTz=E>pt%?PZ}9wcY8$)b{&4pRVz6*lbWHxC%BaKb?rV)V^O7lLPQIcB)iZNquy2DewWmtX5$&no=u+hE8kt_Zia$&{qi2?BKJ( zlpxr9<_uC;kdOY*kvCr^K32}TAR&o}D)U;AAr8*WO)*^Ew^D%rNXF#ijMvAy-6PBR zuFKZ~u@{-Wj@@CJk=bl-Rc}>YSQ~`cJXp>ZVqTy~UMuABJk&NM9OO4N4bx^ehFgp@xf@}~ zz-@P-IJu|5kC|Li0(cldBftDocZ#BzoIp&f0fm-L)+f)mnJN~6>9~T2ecfLyv|*g; zKg`G``BY$@Sas$%WQ5I(uK2}O=i!OSZ}xa4F?660EdTM?w4E~=qF1^pyeEclew<*i zYHW7=Ev$a;i(=KQxo(B86qJt0D$6GGbT)Mm(GXPq=eVj>{ewdYdOZr)R=d*_lz~G2 z5%*3?l>~|Jm|tSH)kA@iAYJQVR0A*~Oa9}c$AO1L(?Z4irw-~Q1QSZJlsGRY@m4&p zWm&OSle0R_^CjqRmJK}b7E)rJM?5VX@3ed*5FomE$VZNry2wIZYqRH0-|*RK z3$kfflFlaVHAZf*F^Z^`#)jNKdh@z@o z*ibLKJk`>hP<}V-%|`oeRrj3&uYOzIs4A!p*`#s{GuMUUw?A1}Vn!~b#81LI$&+9H zz1j18L$v(9EoL96a1;zV|t*VJKDbjNCnM=(-t>Y8JhDAMzrO(0ud!%b)csPr$q3EBNy^ZPHaH zop({^MRz#jU)Lu5 zi_5afk4k-y?~StS?pL4**?W{|n%{Z=d_KcZ#3YSwUXR)qAHvD>^CUBmW*^#`ZhnEi zvDSCD0PZ|D*>x$Wa7DP;3(+-)4DJkl&x7exhakWO{y6=>^py+!E-Z=?Q9KRY6IcqE z9&7PjcFOsT4@49Ny($K@0hk52UJ%vP-^>t5CEU+wm=XeiE2OAerb<=YA4ObOGSe@x zr~s^g?k%;<9cB|Np-p4l31hRZ&#XORBQsG23M z&86V$7_=uz3lFNE`=z11$0MnQq02~cb#>Q%sl!n)=)K^zD*J9IwD3T3amyu-rW$3goJ z!`ybC`|8-jDV)R)T?j5$3R#pU>!ZQES{na@I*#h5BPgs9wD>bToC@gY*v<|8ZWFgp z@7zp%o5zm}3ph`DIG-?Ro&Bl5i;PUZEv5-io5Z2~q)3gD3Rp4kMHGwpb={IbiX<5r z*PnkU0byb}`paC^pDju;EUrsYL*wpnSFE=;smJJtX}TYFE)pyXU|fnnOi_@aO4nXj zbM|@h(E+%3(A`*Pp?6hp=J^oT>%FgKk%H_HkhS?V*7!=yY2UIV=Y%A)U6@a7DSYxi zpalH9Zl^QjKRqL5X*}~d3nO#@+AHPnoqnq2@KEv2UH7Qj1YjQ~oqax-5Jx|AvdZn7 zXzwRhpng0ZMRjiqoe8^7uU&e(_-6YS@qRS+vjd(dN;#pm_Ft^+vM$Oh`VR{AlMXh? zJ}uQ4aST7noOA6veC`cVH&g4)_A*Z4zI!X5OsbBgL>8}OagCZgO(pr#PSNZ-c@7s18 z&^JA{po(K`w&^|8#yiUH{jtJ6ED?uQi5c#h=kmtxEF9IXfval?q_m~ZK-&M(WUtrB zxYlBITOha-OfBuXG0ke%h&L-^n~dYQ%t_f@UjXkF&QwT)0(!OeO{BBOTpT;T{>||ZgE}-5@6mf zCh6!HVV)|!0bC$x3z6C|Q5>SXlbXLkBXusTOZf@vE(7}J-{WM$D+&64wa2b_S<11-wo(3ls z=Ab)Yg@=gcoXyZk)Ow1l&S2+%OX+U#_(nD@=0nos`a41?Fp>N(A}kbyGJyo9Vz6P& zi#8X+1=!RrmAt>@6%nd=H3I_l0$)XbC^jtBJ{rHDyM)qTa!i_}rVReH1ubRbUA5iL zv#!J`?^Dp=-+E=VE-g2xZ(4e{CzOWouTxX4w|zthOOkQ@N37U{{u=bv!f5g&bwlzc3!4= z<+OlgtFt{WR*nzf794!%F|=etx`U7nOMQrLa8T{>DFs&Jo4tbkNRTe#MZYKH~c9489jN1z67SSGZ&(u-nrG zwBBg*jKI!~MSpv`ZZ~}Dhdss@7I5DgakJZbD}`N!i@xOWEwXq?bGrEp9?5K7CoFo~ z0p!tp`*#*$nC7+pab2&%N-Mv_UAsNfYUpb^7;Ix+;chd#Lrciw>omB`swnta>ydK7 zNHm2xFL-YuB4D#GYGK%6asvS!i8Be4CRDf4V0H2kDffz8YD=^RInO1=sac++pkc`; z6GwHDp2tu})q4^^7oh8x4AypDkaZLd`O}cqBmA!Rhiu5yE(kg_Eo8UIf~|Z#{wA%T z{`3By_(9@|lK;oT_w%>)_43aaZ0}cf%pGH}7(XFAEUa~pO>R+9O5s~{EV`W;It&r1D!FnbjO0h!4y+y zN!{596bX_upcj>j>(=X-s2d87Qme1Ab>MDC$43=uIrEO}ID!Rj zc#Xtm1dD1ZcX5%K%yNB`i>>n`u>m{%L8UG%xh;i~0PT3;L@xhFUUA1!yk~|shLNHo z;1*sY4ql_Lm8wqO$D))lxvlf$S6sRgOemW~pnS7Ys+xy57L>m^o;HFnc$EoEp2Si0>fFOjSHO2_kENmg-OWs|olw=;Xd)V>dxVn5a_~1cVrRxNr#dG7m z`rL)O-R$a`Lk@6YJeUr6odX0sD{#>;Aov)6K2ADY-mLkkLb0`*o3`qO7_2`I33I zG8&+(8SUbB-%(oa3x!b3TT$V%Fqz$IT~=A$j%#*KaN(k^m%Q@45P@rUdhlFD+qu9G%rf0^B#NI6Bg-+1r@VX)OsnW?>L zK0CwZpUaCkKXxHFIc9@IhV8arb1}O~3u&6x$)aDE`lSh65u95Ig|3tf0m_3Mno;tw zqH$?{ksxD%Gy{{|!Y!TbfDz8SStWr@KV3)<)*m>!5^l#kY6^J>2`Dy4xdO;zJLJ-d zZA|Q7FjX-t6i! z*Wm^4gFw;yURC);S6!yzuJnq}}uisrS>L&Q_mQ;In13&vkIkD(TeB;`{Fj$kMHYsK#zz zPX6Q3>NOxJ_)xq3^JeH=mb>^CZnAQdmRHl2g zBI@_)fxvfUm~s95B7SH>h(dxj^HO~Hayu2WEAgC?lQKz!X$YLQEeM9wQ#X__J(8kW z2z)9Si(q-psD3l=%=U3j1d(oRY-c&&Qa2Uo4T3g&Dwub7NQrMm1;*3DIiM;K7O_c^ z^70X1^Q|ee?Z^4B`JSg#Y8V|LrzQsnQqH_>@`+t=u!m=~=ZyBQtq$om5z7*!(IJQY z#Q~Uc1L7#!tRrNH5(iE%eyA`U1gi&)EMAEw z_ib7=7S9ipa$K9IaoH=nXQU)Cd{p%Fb^hh^esANshq~3_W4mbK*duW2&)fxmIJ}Fc zM(3~H6KPx~rl%DUQ}A>2HTT-0-9%7jnF+uEC^)3;7)}DJT|FmdIkKBXikbD!Z}VWJ z^aEHCf@+7(Nk{Qd=*}FXme&wW80^;dmupwC@xoWv>xBDBt{2WWlLhBh*J}?M6T9v0 ziC;&@gt56|a?Y%~Xry4-TJ5(-we^SVV4~ zFyu3fuP$)j%@|W4x<}enNoOyhtAFZm9&A2uv-F;fwAw9F9a$qLoHyO6tC~=-h|b{e zqHAs*cy2sZoU>@%CHLBG`at4YA|w+ECP5VD2oU-;4Y7``^0jQD2K2zE=Sz#vQxXbW z%lj9SXTj8p$wPps_?tO^^FPA`B##u3t@!-Nk#jIoUyoP^1S)-!Ivo7nJ3l8dv=#glJdG8eOM^7Dl5eg_2Tp4VKz@f&mX&BlXWb$sq2 z^LWR-uC;R2@tF&aL33Fjh_WVGh3ucf^@6+wi(c#P{R*j1N;ao#)R0raKkBqCj{q~d z_XkQz&WcQ==XXB!S1UnT%_!eI?UD=G?^Z=%7G#}R!XH`Iu>6kA5RIDoFk$mZHv}m5 z=6(Wicr*WSV-i@AOSOp?8o12jr6sUB-}N_E5Z3ljUi&+RfiH;mjqz$l<+XU-E{DUc zz*72eZ}*K|?H7IQ68EOYdOuE%t={`deLkOPIct^gOtvVw+ z<)U^+Yh2?lUT(&5R}U78Ri%c?qe2604OqC+=u+aU>N=WYfIPBTBRrTik+&Xf3GP`RiYoMi6UQ^tvV$<*Pp-v?_B3ax#IpE*ZTdxKd8o)v(8$-R2t{hpTI!8 zv9dV2)H)aMb1Z5-IvKXb{N*zpdxZhVlpxhq2AxWr&^h>EFe-T{Ad(yW3>2Q=333>V z%INf*XsNGlo1C9IS*sX;;qE~$lPb=>un$$84Kk3G?Q1l%`P&fk{ytr#`4~97tuo*~ z)dDDY-NHU?2=@s(BmqC0ZdSXPJ8qlm97v^&OgXF;)dRkBP)s2Rkt3ktmY`8;Gi!9e z|2}x*uLTN~U2Fsf2L^)->_*1fj0qY6te+dJ1H9gL#{dT=KO-Qx!#R`n3 zqFQ88S$@zSSSu@>oOmi&TIe0%8@((8G8$d<^k;x|&x#zIN;sLSRwx!MCJcT*egE99wZ%+|c2v>)iCdxj zD}at5HWM>59hBgHqhrr0>c}GcVO6ZOJj;yrNhcyWaO+IPd(C-5d~#&b7d4IaA|r$r z9126=$D975bUMXxU+(qycTG{zFMDg)oSm(l+dg21G{7&`KRQ(Dx^OsMs+f=&;U(|a zK_&^CTzG`ImDyq+&90E-E}uO5zrKlT1Lp_z*=^6`-i7KcC;X{8qisc|KY^~P%t1^M zny~7ZwtRnVe#~z7Dlrj0*f0zp{A66ovD+kU;_pSDk&%%xI^<2Bh3Jptg;P+t%S@x3`5as>U20XPKCVkjpyt-r+umy>9WtG2f2DL<%p8kzR zVICq>r0p0pDjQXHP)Zij#c?OZ`^gg>I#TJA5NW}YPYRv|^efpwobX8Jc1=0Dzso>6 zqloFCjQ^sN&sUChjJjI_Urz#~1sARg%ZC;(wma z)g@TMt@?pf^rwX?V41$n3cU`BTa;>=S*ql3?_bzcjlD$v9f-~IkDq}VTc}7&OC(fF z>eb3@<%r?t%fxcG^I~27jKml^@lA=JsJG=}4Eyz!$u%oz^k^E zD#KX=GpJH32uFvEEm}4!pCRuY-6R!&VIvXq^TY|w+J{PB1xf`TJO4|?>(t{5MFc`} z9u@o}1A&`@hhdINk>=v&m+b8=W9lsAm)HcC*RJtFPd^w4X)C__q#vNLV}S)6`w~Q z2|^K*^*+x%p)ro{qX&noB-aN-g;}e8ye!lWP1$&gbyH{y5xLAFA}4V}EIxN&>+Rc} zHdHXl5u3D^u<_iUL+iX&ajH^S4+m$QH8@& z$@PAM`YQ$?-_rVoEH5w$q_Rpxl>kR$h?n+>Iifq-{iA&{*-;a+a=#-9^gK$tAKAe+ zO!v83?#G1D@!5X9U%UX3xF6*Wxfv&DR#-lrk-n_I6J(+*5_;A?U8LOI*~o|vvy#zn z+89||Skbs>oMs0nC^W2unaYH$ETh|kBFRf~o{!7R8lfvxmxCv^n zIG2`b}&^=WMlkjF|mG_KfpC7$(NnrG(I32p;<4j}h zV5*ui4~DRP`lM$mSRCZPnejl-v5R|fEBM2pUmF%WWiS0DKFuP#kxe0%wzA`5Jk0ho z+pS@b&BF7ibDIZpdH}&Yql8bB4rkw#P}*7(bG`9kVbcV@8cp*1TQRg2aKUTUu6|P2 z`?x9P1n3xHvYdwBxWLo?cPo0e6Q${B?Ju?HlQ;<}OjH?y3j z4DRs|c&MAy{Z@OplZ3DOq)F8Z8o9xa>%1!7M`1yDs<{6Slf9Gvapx~tX zRvG$vw`5Z(wa^-YBI4!q7WoudR$R!zUDLl6l476@DyA);Z1qNH+Q%=MB?WRO0((;k zQ1A=ss+YRXXF^FmOy&+o!WD)C$(Fd24L-Uv^M(bHf*icuwjqWFS6BvFcMmL-birKm3h& z$|IlQ?NiJs)l@GHPhM+xxV-#aQ`asiWhlyRM{JwfA*jmT*16M$(0JvmnlgU&fab}F zl4<&$`wCd(pOU!9`c*d{*2Q?GoJVrP;9~8 zYB9GGtzuMYHF04~!^q2;^?tc@OUrDTT5tK&V{kjV^vv^v*l;=AVa;h*i`9^$a;+4w z8zRs&T<&V?+0BXt7iGJ;hBGlK3t3-;zxE2HJ>{8%0Jo<5A+?1QK6l9SxD+~P||W|uAn3Amc5RC zcW6geQb2(N)70JyyYz4{0nl;HH$3!<+sK=}(iRf;-hssiF6f(!MirD^K%Id#XS2U>=0(5`NULIj9QwfW{^|mzPjijH` zw|{E^I?WH<|4>%oL@Wesq{B*p*-KEMJ6u{u$^6=47i;YqCMTt#f|SEj={Nm`ZiLf^ zoEXIwPzZ;>1<_BBMlc@_Ug#Zf;?MNcdE}K z8;T=;af;`Rwa}wF?1XJl)sDQAjkPhrdn(v^-sFNpaEXo^YJTfaCd8~?DR&nMD1N~CJLpyP_5ESv5c1+-c zIQqm^g_^5!(_xtgo)Wr{Y{@s|Dm0S+#XdWcQH3`_E6eul+9juTHAg7 z7aC#`A5z*UN9ufu8iRLf@B0}%L;@83Ay7`z3f?2D8CnEF5nu|PexIzbzJxoLuWIbi zQPtTUWQafv%6=F2r1`a#72|d@O?iqM-RJF1RK-??h3cmOfeBbs(uU;^;pE1P_&SZX zF!9qfKinwzdtG_~E}mDvoyY*M5se>NN^566Lq(t+7nzR3{WbtI$od|Vne63d~qe;Rxde5>uR_w9PyUz-esQt`+ zKIKDniG_5y=cmYVJN&%=vZbr=e;Dq&T<&#>PE=ghnK=wszMyN|E9BqsLf`rlOgx>R zDFBbN-&{6cS4(l<8**L-vY)E!EbK~Cuic*ma;Q5#b!+cX6Q(}R=5L#Cpdl|hV2kyx zPD@^S+xr3X&p_Lj9o~`5_S=Iyj~nhdkf5lQ8o?vm6w+Szis$4aNIgNpq_AfLp~c`}IY z(a~rYO^i8IN#DjA zl@c;;VwAb5I9gs?uQ z21Xiv&lz~invdF)jH_$hHOKQt5HssHTaSy@`KzKz8(b?`>NscB-GnaQ<>xz-dyiYTc!h5cDx%c|;_iT|13Hov)k zh*-wud8Qj^I0#h*P9J8pgy6p|G!$68HFA^t1QB%^5&*4V11H_z%O7hR3ll~o6{<0E zy@gG^IQllq@Lf|MN0@*01pQsf>#=ZZ`U?>T-c?ImGdA~i;3=9)^% z)I!Zx(*sMi`MBN>Wh(b@9&%)f?hc)aa9q>UL(m~A+6lj!F_ha! z%$k?Zc^3C5EHk85q=g{wgJ#Fx-|DB%*G=RCdk;sCc?=*OXGSBES#&B0eZHaHwMaC3 zrb+^5NK+LU13xlm5v8mru*e8u6DcdPQkCi^BKe6M`i<+CiEtK`IC&x)M$+Zg;9^OzEYJu> z(w&fmvl^ZHLmI2Am6C?OT5Fdp5yogTbJ-%Zwj@74)A%Tnr;v$+i=q)?$$hlg?<|n9 z5I67Mbw? z{{s(y#(tSCXg?4BegP5b|NQ?2ODq#g%-SCz%i>C~s+D3(nH!l^6eM-!U%&U*ZwNE! zz6eZi;=vfw2{%$g8cVm;te+ScID1h1uIc8Rr#Nkwr7s!y4i$|W6A2?Jo?f(j-4Y_> zEJn$jYv_{-n>afJ@P{J!7ENO*7*UHgIh#25?dLd6!pN`MeUC3=uS0Ni3utrh^byu0 zJAaz@mL1^tk;o`k7o2nufcJQAxwsbX+zP|DrC;8VfX_*kdnK9R9y_TiVO)zlG0p}QgK zsiqeZDO>m^H}f%yvi7SbX2}+4fl69Jq=TQvUN>f@%WePImKX4G0=0k&^5!)3v-;pb z?ZjVr$|fz)b4)a&ld0zwm0nt>RRG@8Q0}M9lIPjk{SV&HD{;?Q1QrF39PhV5@mB#d44p|{TMW#SOT@<)CT+iFuSMTuV<&%>egP9_ zaYCrvcXBTtp?MKXGcH!l>cNZK=2_Z^^n@0t$ zY4LUS;c9C7Q%@%vNt?2mO*YcSe|tXTFR}<~Su(SbWgReu7LZNtOwf%oX0sdL1cc2Ueoy6T zZK?RTi)|``hwOi3Z@mg##LD2D%~;M=?#I2nDibQRE3S&oFReT}!j>{z@44lOk}zQc zFkc$SqY)s7>9q=75FtVypbq=TR@^_+)K2dc0+Yj@T+y*VW?g1?9hdCr@B@JQ$;iJh zlgPq!`;(c+ucsEZ+5R`bz8Q6}3&DZ?X2*NyZ_<_u^H><|s64smxvEkI&xp)0@H9U~ zAQ=|Y5TATahEB$Ep8|%Y<=AAm<*Ct7_Jeu)U!8XB0=a~N9j?_(obowi66Bc4@@&<; z5mcJK{%!OtS`4A$?!VEQKRHCmZ{YoR_e_CHhcO|c65FaG7d(Q_nK<%lwvoZ)aLGLW zf)w<1VN~QUIn|s)>2VfQ=Ik_sE)XSn@-hi=_o!X@Ih#urFAJ3}4{ygIz~yeADGf#n zhis?Aj}YCeXOxE(=||J`X3v#recn!p`YjF=qp&2dXL@e9>;?uF;Xf!#PKMr2lPwr3zG%-@H8f0he-t$?9hsR?aHZ1GP zwv+q9OG#=DW**;R9bkD18w9X-E_B>KXI;L#-0DtUXg9Z7Y+BCdoH}ZF-7s==Zc+Lj za-_o{ga*1_x$@B z$d>>0fV10sD{Ck8ukYaVu1WO=hJHRFu--{a;PGyIPXSUKGd$!T73pH7lNRSYl}GQk zqy74malkHn{6DUVzFB+5U2}X|>1F&;h&(8z8LGbw90Umls?s|C0+i`njz}i>Zn;1e z~|%-aJXzV z0|D=Xk&3&Z$5>iUl=+>p1M@Akg8v(W2M;C8znQ6F4N(dsS~ z&3tU{KKbktW#-2uzEwZmQwXG!6ZYv0pn`$?kYh?t$+@iK2iR>ITj(%K3NoAjoLfWU z@9Jqc`f=ZJy?YXVgJ73zO2#$~!bFiJt24z*$1ODC5+RC|;U6IllL{0s9?(1+g?G^l znUIbT8nPZzPg5~_g8$cg*yO`T5aC|WaZ`VDsHxmpX#8B}ahPq`Z7H+-glNIs>bcFY zKs%Mr>-*3*a*Ly!%~|if(r`onTe>l2p4E`Y*g#r&WG|i|M!25!0JKj=MSv3Xex@-1RUntB~&a8lLWL~!=&gj!R_P9sr&_hQ`Sud-+xpSGf&w29isXt2J{ z?8{aX4fQx*N-&gwSL=M7h^Zxd-zv6K;Nga<6EDllofp+Tl`yh{LJgnTCD_F z3h{k^PsurZ`KQ1K=muVoE&vaIa7KppslN{l*mFj~_xZ=dGl12PC1m3VCgD~=?#j++ z&Vb0k=O7~prUNMTHzJ)jxybjrH_pzq z`63ye4U}bm%YR7UT2!R!01W!?TqaX_ZC>U}69z#bP1cf}hF_Bn(wNp|^_)zFgBUFo z2-i}2v8K_7{k1_5>~KZgF%LXZ4d*1b2+pd8LK~zp%`knE@L|-%)Kvj5b{zuzkg+&i$0LY#zUy3{goU@G5%!%J_Nr5@4XV{TtfGw8tMMH*Ue1mU zB~q#jsMu+-HiirD+l{BP$qzPzOBh{ByE`V1M#~|)R*Xryjgi4utjKCa1-lG{A@3 zLY6F2qe#Bd?D{5Nb(PoYC(8P(Lbd+=J8->SP#B<{5054FL=Bxl={bI{D&_?D>EFDZ+=CyQGcuU+j@N?qm zwV3YQ;NM$Jl%;bv;=5F>uBO2avPU)OR;a*9$HB+vT4hq15rO*Tqt&Dc6_#`$yw(5M zL%z)rgabll^d|+H`SEu{C{h_?%o5(v-wt;Bap83`cM;duj7*w0Ro$~`he(%_4ctam z*l$Dj(>hs&{jJwyc-=(WD{;&50dcL)&Q9(_uS1R+`IPOUg$E0do9&w&mS*cS4z1XU zpD)qDI=WiG`wd|GImJV?*&Zzp*1eExVo`~jzgmyY@WT&t9z1y2f|&{=)SzQkiE&m& zOlUJMyob<&GA7iA*N1aEE1TmW51n}VbZACosrZZxUBl%DCxEQ1jcohWWd?iKpw!kD zx2tQzkSA=Gypt(V4d`OShnB9V`?-&uQuWjKL+kV~)8P@zZW-O6ez148gk4Rwr^5_~ z)b_ElqrLdJbN#Zjsf!V>#*+w39v&V&dO$WvB@$?J`VwmJc1ZdCy`a5)$h7HC0NrqS zAw8C!415G4$5eT*oX}u7B$^Qs^rzg?PksNGJL7hleEwa9x_~_9V`>6dlXVu7FLIp4G}maRL#b<-IQ@gGic9m4aTAnKX4w2 z!u4yUq-Sa3+EO4KFGD|Y{o=%?ilwA-+`wZju}u53i1N4h)$iBi4%>;%7&{^)TpUyB zH*#U1<@ajsdiUp10j=}1wDO{#KM7aw-X=SRi;fR@m?~T+o<{S{JZ27vNj*Bc=u%YG z1qx<05YbSkGRhS%`s_}Jh_lVp1tb1m)+O$lmI^hdYg8IsF zS-;)q%FVUa!e@w-3$3j9&V!;XuojuJ55=+&+03PrWW!`syclH;5>KF;RIh*&62Z+U z*PV6?F)Z4{cAx77oyn4uC00W{mLqqDg)EnkxRXVpZa(SR7oqJPCcCc7oJ8goRYsYs z2mk796wX`ui&Y5!jikWH$5Bh8o59nB8x!G-T^-e!Qb&}RC3H~9A=q(X@0srNt?hpM zW=g*dS||;FtJwt2FJzs&x+6w3yZ*ksB!wGniBko>Kb?4gFOt{%V>)YFZ=5PK)6jp6 zgn}w7^Dgx}>ZAq}hw(VZQj$_-CLzdb<1P3goI^*wSh0lfai<T|xQ9XO5@WEn&B}P|}p})ev`vqMENWNTXXAw0twJ&@C$Uh1`65 zw~Mv{Z2n$&XIocC<{#18@Nneic`rA7zMVSQ^74!x=(V&#VtvWccm!G$0o=zRKj(iJ z``kj>KyK_aUUu6oFngSn-kqKjgZ)APkGNQIO!d_yoq2s6%3vO=eqPqoy&om)7Pi0J z7PSX8k92*&diqaI^y_hNiU%9|l8mxua7X7w6nzT)7J!|ETmAT8&B32$z0|TVQ|@{> z1m%dBHy^8@xcpzVy=73NLA$>>xVsJR5MlG z-g8dvo~_z%Tl+1QRHc&cC!K!o`}$q&J}i->=Hy$*z)# z!rO4J1#v97v$`{DHcWqera^i!_!)+|@|9)xZjxs|N&$Ae*0epJeleMY;gq1^NQcF~ zgFx1xOlIVCB&g5XgxYWa&SYwhb!JhJprh92XVV~40JhYeE|+gyO=bmx0Djb(9en}+ za{39PwM|MNt8_1W2MnH8$8F>HE89!U1ADc3I|c=5wxLnBaFu)t`s-NV0v_*>&x`+! z-##0XKi$e^rwMutv%0VX>rJ;E27@UTw;rYTkY>7`((T(GLa=cVXb@;LQh=*NYZX!W z%hwrJrd6AN9eAKw=`73ovrbsjZ~5`54}+67)qp;8APsi)l-kkoa1uDCAXE7&kdlf7 zJC$twPUR8y0d)(s0>)SA5Q;qLDs${WB*-Zi?r{TbQFNebqsfn=k0o4=uTAP^I#Mw) z$Z!&pn4@2Z9czLQSn9DN@>t^Ey>Fx#@j6l?ypog1FmY6Qh8$^}zM$+ya3?@rS8#}9 z*=rSqCHm@jkEBhPk0V^#@-9^k6OsN^W&O~tM4|<$kmsW3WduwA5EsUkXS6gW`$5}@ zJKhk1iSlbavJ-~0axG>WFxB{5Baw3q0zj$bcJ$t6?9&8omJjQYEwCb`wXr`NlZqtEfu8p=%Y7zy504iE{cpISj zUjx>NJ~}P--5|B3O{PqvKdH-dx~=yhhAA!k_g~d*_X){7F5`7=?)5UKAa2?HG=yRv zgv19)b_620X-aPo*qng#wUfcO4`Rt^8Ucg-@4kXe)dM>vpf_4(OH=uP-%mY-evVAH zMB?m;b$5+Yak6s0$A zY-HD+{(3)>%kk?O=zik_yJnUnMVOi#QMGxhNxQgh{4AG7h;75JtuO-3$J5ay646SR zNhFp91C9DkDOj!(?65G;tnP-$Qf1`vf7SM+G@OiqjdT#e|Eu^iM3 zn9389^X8I}e_-7r^_p2JUJ3outtpPyvy1906w`ts-b>8;uxYF|FIsn8?6@N=D{@oM z=miM>gqGKr?i}6d*+CiyH-^fJ7X2FO0eZiL@PH^2KT*Wqqc$~Cb}wwKUHB@nt$WQ= za?R8$sIeLbWmv7;>;SmY<|2It^+Jpk4rT+zdLYv9flUn_d+;7{lc{`XC9ug1xj%}z zJpPeG`DOBl_*_XFs1L!0-bAH9t9Bl|apUlvlZIcV!CEFHlW!4Ul!+KGTAm!abF?w3^7RXqjS*0U8q`k7x@o`igm^T zf)s6)BZgb-Adx3?7aEExA2ni|qD4exfb0xpEc&gHLPiG}eUk5QZ{y+me!R0ITiw07 zvB2h|#Um9sLF*PHOZ8k>_EIpq(KcGyMWWloY`!C;hyKS;XhC(cM%(+J*;f;zs9d=v zJ$2;J7Ip5q^>s-q_e2>^uEs%6Z=3e0pV})|cZa{aNfmXIEVO4JEFD*PjK>km$1T~J9pwG)>7+i&yG6xW?`P24A1S2GZ!f` zqMw|2qTy)TsLgbtb$on0$O>3PfC;OnZ}tNtVY1U3L4z~>q%PveFP9<;JIHB-e2Ni^ zG%PLg=gPqEtO8YfX09x|5xV#;b%Lnh4!f7k2DP)Aw#w8)qf08)@}wFpTahF4W% zZ+jUTqpz=?xFtX^7{g}QEn{A;eS&?f$*w6ul zxGXJO9dc`|M__(fFb9S>%t4`j6T68CE)HF_ZT^0pBOoI^jwpyOk=2t(VNu+Iv65=< z2R{`|C=QbZ8#1g-Gys#zdVInGH-)>SwJh%3%=~ZfxAtOfR^u$c# z#&TBSy@jcd-l@FZ!mtphlZRo0gws-h)#aJgSboSpf$EFhS2cScP%?h2fo$mAneJf9 zq+yXF3m%?Dofz`VViiREetrY)NE50_?fWyQZdZM4eYy3O4mk<_$vOV<2?FwKLSEe0 zNCQMEsF*!cjky-LmhM=CZ}|bi{rcklZ=#(%j}s9Y(pQ}y3a8L0$O5Eb@x-+P;3u%N za@UWEEWHP)9Ir$O5p(2z`!5e8bQ0O5tNV|&n_ENA-^UfU4V&2EL~BkAXwlmpCo=-t z((jZIznYel_AN-y<9iWiHSu=<84}F^sE+&hJglNYUd)i9z|h&7kr2)zPqG5T2ai zpA$Q@fS##?K>%oQRhc$K@}>M1QOD;jZ~=k9%O;Ih$Kztq(Hd&qBjz9f*vVLUa!BH~ zvd7q;JJb$p5jba4NZ}r`+%Kan>_sPF+eZv}we+}M9pB^S^z_8Uq}{9NsE)24H&F}? zmO^>7F}}`E!;XzDt`@!LIV0G5pDR=naa5&vOXxMycw?02_}sKpZTpn=fm7P9d9VfhpntI4TRJ@(CvkohV(P*GkS{d8n_;lQx>g|%=_ zth2gw1P1i%Ud<0G*dMqt)FSagn|*F~9nJ5%qxbm4sGbiAI1Dt08VG8L&D}2(8Cmg) z$o)#LH;Se~ACJq;0v~?8#RWEt*6fgqZ_bl?9v^lqXG|UT%IP?pOEEU@X5MwjQEI;w zMhlgFrZd`eRx`#(kl1`L7mua^HRxqTq#KX7{bz77Y+VDj39eHQy6M>-Gwf}aQR92r z-tUX`o8PM6T;wfzkGdnU)|FolJW;Yw1Dx2Y$`0n^VQxu)*VH}sN(dp3Eer)^YQ!k!EUvJ==g{dl(Xua{}9}Yj7P2#v9Af8av+9#Q82`| ztQ}Jnve}G^B21@BK%C#o>xdkGhqhc_el!tlM{BlcKHfLEAU~L_Xp2{YQsfC+;so*U z@5sCRs1b;04 zyRAU|QLUuTc9ZeZR#Pt7A8_~PnPJ?!TJU9|Elbm->HhYZHNKX-oLQrBX7gdKfZ4mo zaDdf#cLLOFJsE%B_Zf8{q`4oX&DU(l!|s@1sD%q|yA;V2u0fuxesU@_`%xHbWmiGB zQ5}O5GVu4MQfvhE;@E=`bGLd|*F7^zROHZovwaTg^_&nA*n=V#YH&@se*wImgTHHX2 z5oL@FWB>BU*w&03>spg>mL{w~g;>J66I_6yzOn)8esY0$CleDR92{t`0`SrXO#~C3 zF@yvuzNg>{TQa*AElKjtY!Aea1gqoYl^MHV@LkySeWK!cNJ3RK@i~&I{Wjtd33tK0 z^^0=yyM`2$2Jorw>=)C2K>PF43Nz2~5y{wywenM1wk%tpl}X1pVeKz^cN-&1DD9Hu zpVw_)4wk;9=X?E|e#%Jn+SnGv#_9LZ`{I#*Z3p*VPQXp>D0%+bRI6(*DwutUN8)4j`kISxLQf5t3^@5(^FGgpX zzhlO~eBR%vO(%#!5=A@*U?BA$n6!PP${yYcgz6ainR197 z%P_$(KFKgKHDKEXswUosGHa@JPK$B3MjniDt{gMlrd0YE%Bzo?YF zB;;RcFrW9gWoc2kD=UqWmlyq-!tuEmDJyC#@O*wIZ!uYs!Ov#5_b1O{P~I^eEywdE zc`{n~Y62%Qy|ewbrNLQ#f=mCB&BzdmkVd_|xp_5p!=pdglryQ7Rpnzq)yHQKKEw!o zJ2|`1PTm+mgfD;6w~OlW&+9sE=+LsV`t2?{3+i!gP=)=asj=8IK6+OUhA-pMdb^c9 zo}GiM^(hy~4W`&r_zE&}eE)Wu)Vi&`$v8|`=``H!{aI#mYU+BNVAq67W-l^XP23Ct zz7ZDp?5ow$7dHrtXQkzB#YAcWNJtR=z1Nl$3Kki0W;)!}{asuPqMXgs>nJtlPQ!*m zumKQ}B8$Cv3F`u6Fbe1U=<~&P(uO7E8C*L*bdC(GAG^C28|pU+WfcIAjOzUEqpK=} zML&~_*R1qT(BidO{$XK>t30bz5EMwY!7z_P35DwyONy5(HPavsX_s?FcYNwq{M{my zObHSH_)WsKSZtoP|BIi7EjhYTQaVuMF6OQF6W!N5hZ&8p6TXu9 zUOi6LEV=}dAF;|sh3cV^UnZ)l=v|$)OG4&#xpFp8vpf9Q@5WQb{SD{Zu>!>WYVJ`x z8>{1LbZz?|I1^i3^`HYo$lMpWETk_+!ws|3ik>z&Fj9w$3j|StC*_8A-7}xC8SYm%*1zS~ zx$H+Rc2@7%AZmtU=GGFQsoS;D2Wn%TP%LDEWjk@T#Qd+=30Ifz*Wur6ozuS=DVSRg z;E|q3p*@s;jaSo3(AC)`C5V6xSYP84aC_<$30)k>Fw1C4lXqzkCaW=mB+4`-(U1GT zv1#8qS+t>8G88Z_ofRT$^k29%F<;7BG1>oout^(D5{y<ePCXxI?dX=(WIzK^a)->&!b@=ojD zCvNF=qEVvh-w3KOkkyoQc-i<@>P?pi@;BDjezT7k>404x5G3eg{kf(v$tfW#eY5DS2Hm)F(=As^hWVocg!;sE&L{S^^Cl zsVYV1GZa$!Qp!3a2Q#et2g2J7t2KC(rdwD-clGdzm!Pi3*tmnh4Ig+Vn2;u(&2-M; ze|>vMCXDH6f=`uC3Dcc(oTq5YCbY4$C4p34(}0bsAFcQ?2sqR#Wel`GlT>k!Ok1;< z%D)LR%eGM57M7uBr66i~3@Yh$T&By;VlU&75Xsw(%>$Ij>}6bu`|_uHVM z#6-Abr5><+JppMarcQBiCnfrZ29!?Z%Hy*4r#Wr$BiaQZ1@cNp z>dl=ddHr637oP=u7gNHX5R3nbHL29VSdKe`gr_P1KkFeYwf>-K?M8 z=zwE>u0qN+f6C}+%26IE?ZUx*3i}&3?hdd%%kuLJbGiRO{CdQlDN}l)<#ZW{&GA&# zyUeI<<|5FjI~Gu$$>sU?UdC(L=TflMJ^lOw-kp{?o2xjli&OE`!~G#syHp}T$dj4J zW~;B&@ys%^Hv8Al?oDzcC;pj9+3}vC&Hj^TC?dmV_?EhlA_#}Kir`3-CB-qd-^&8c zE>eQ0;Q#QJH_H1Hc(mcV(^RGm4kT@^_afWNKEiH~$AD55S>iN0PolQ$WV!W6g^CKF zGWVTMiFc!!N-W15A6gMY;+;DaMlF`3sPz4tE`c@KKeyd0Ae&Bd?Z~k^ZG5cA@r$Aa zV)?h2A-^&EAbd3#J@2oi{j4|^uShgXM+)}i6wsuQ>TZm5;8Y9MXr4Mhks|jbvXrRY z%$612({t{Y-F}q(AYA~fTF9yy~?-hjd|jdM7EkwiTZhds^_-^JupE<7UwNdY=k{Gkg@08v*?Zhyov|%(HIZ6i+XUg`AgPo89BCq{c44@@=UK{$ry` zN->JHwT@-3P=rdlU{_xl9(avvw?a4viB3c$f{YG7@?{vpr7|p+sAVeXb(~UVBa9FooVID z98*)RH{F7&24HE46P&qw-wi>|jz`h^nM>!y{Q3_UqkB$gw^Xu^)}rE-S^DB?0K~=P zk)T;j$Oq3pYyedWjOz7!!CuIvSh?aO^+I8oc%n$yvV?(5fuei2?8?HVW7?omQwel= zJa8(_9yBC{_)DoB@~hxEwvUn!gg>MM^vopd47A+hJLCaz96>lLRk)0$qQUHe14u3^ zh?36PF5|+ntf&n;JW|pwV9#BEg?DXjqt@GZ+>DU~4?5;34|F5;7RCOnZM>M*@f=pwpJB!4T;Y;G2ak+@?e z%w{BV#Tq_jB~nCh*iuo-w!*5;oyIRN+|pxURWzh-HwKM0QE;IeoO^EuSt(vphb-cM z4>t;N+EqeFbYK_}G>eP8hsuho58pziz~Hi4cOGpGZd#o~d>Y6|U&tfJ+NG+}%Mi=e6QZ9XeZRj7S}}KdrlSPw_;S)&}7@j5Tk$ zk8t!Pz2qAO^L75$$U!fEaJ3bW8lMjJI5{NP5G1ntc)6T;0IvAxDo9p?mD4+df1Nx% zlmGw3!~aKv3!>lWP@kX~8mM6uRd(Vhi4~(v$X8?JbG`X@8jYa?_7w>-x&Zf|gPqvY z)1wOF*Jh-YN_W-oZ}w*5lul~%RDs8oFVJL2C{H2!;cofu#eD0T`we_l(jjs%ohgJ% zLi;txw(CL3D*J*b(o!cq7BATbtrn<{|THRGZ(+Qgcn0N+`EF$0wDTR?xQFe}pE>~D+naFRI8J2`LokAlDn2LA_MWGl* zgt`&^;|oo&tiej*6a#saLPc-BnJrldW$I| zmpgNkNO8toa<`_(K}O9D6sAc;5yPN&$DayLBdFt|K*0%``Eetnz(~dev9nC%fKW9% zU4=9w26_lE3~|_hV(~(^O#O$7MB962kDXq)9c#3<@%?qq%FWFDenX0#n27^fxbr|Z zlrrnqxHZD6aK+~uzEIy)Z@-FrmRU@S5ILI4#zcLj;DQw&wq10<)1U&P*~=Lb4b=4w zr@_p`j*!ub_oHA{?0#w!A!mv_vTOtus&(fAefgx4r#+- z1R=N|aXMV#Y3`0`?2uwK%1YNoS<*6bhtxm>Z2 zm@i@|oaK`ywPO*Gp}}de9N&5*%e+NGkKEKF3K50@n4QK)*Z-@9XjZhFV(F7uZ~Z~+ zc`r^I0LJMw2|oUdSe_M~WHN#DPQ@5RL3E?k%U7vt1^_V>i-UjrUf;~6iL~= zd`tUj!KJ41FMxmg5Br(T%iMFb*Lz6yw#PiovM%3Y2U3ShG1it>Fj=p?k}-awn#`aX zHg#@`ux~UBBKAEc#IcIv84sKvPnZ$_5r+PRF_8I7SNF%?c(9rBUluDZ4uumkElKVGi^Oui81Bavy+*x{= zt*bnU7L{*+A|)0StJI|fZUx6dHIm|WVzg1MA2sS^N++a5c_UvIE@@I4*Dq)i=`axZ z7=IEBJIWW);bSKzuJhQ-u#C}itmcF@xjs2P-M@Ig4$NZUfROK-7_Mmmn~L1%g1KBL zWYfD!?q8(+VRDfW9f;=UZp;BCADdZ`#l~}KX~$l!lU$@ka;M3sB8{}wMKjHh7fq#+ zcp5JxUHi|Hulm*wAI=Qj&D_hvrJ(BfJl*aW;21wY%%SVY^d7s+wSxu67p^ zH%~$3+MSy#Ii^DF?aOA{S2agh-d8v7iK+P1_~koDmDc>QMFa28mu*whnQdIF^wsNP z!eX_x+T)L>Eg}3J(WUR#>Z`EV!c)I*{x&Wh*?62Xw<2Y?hQIlayw_H?9D)c5X3`P; zvuQu?$F`sH&b(T(4F7i6e!guu=CRaqH#}usk)A{)#aCU!zd1`G(nzlLMVDF)q@_O9 zkZkKC-N77ShlS1}{ZTDh#?J`h_TP8AJ|wrGC^ULyn0^uIy>C)P;-FCZ2n&OeT*wnH7p$ck|CnSyz3Mm_BHea>bryV^-8<`6u07YXToj9*-R>=A zfU&(gKW`Yq%=?U=HpRKzQ4Y$$;sMwVfsI6U)kyR-i`YJ#;Tk3 zSZ6m}#W4Qsg$%u$2&6jY%eq5BP;BRoWXW;1hgadwS@UGs>@NZ2gR<%zcDVI-$C9tU zouj`vKQ&WZ=VV##8l>j}1>NtPd>bqi@qF(poGx$dg0c+NrTxz?j%>QTAI2fB{wyz? z30nVhjbWPzwP3r?X&>bs++ZlmeP8z0u$Dk|oj z%zwNwbaTEJuoD{|tvqjc>1mX)bZZEz)}9|N6a7dt9CBD%71Xj=y<5TJ+WOeY5F1_o zr0u+;Wc{h%6$UQF`0@V478i$N*1;enALmv*&u64@XFVP^{uY^6es-2fg<^u@=Y9Ge z4G8%$k|5ao3^ZuStuR>vg&?=%UL({HR2h^7c(5NIg<`b?8+Tqt&1u>C{4C-mV9{V) zLT+9)p=CqD%yyW&m?|HeEO)wYA&`|3<4=gRG{yF)&Juiu(``Mc73}CV`%AQmBGrnV zi|8?bNPZE2EgJ~RGa_)>DPY~5(_F5Un794QH>aU4EUx3#uadcKiDavBw`7@>a-%Z8 zUDdUeGKBZqMp>}#^33TXuABz7sM`2zv-vPveisa#7gRUEA>9@gFOd))&hlOI+_jq> zMYp@~H&SY-XXNMvjCyWwxb5URNgvL3&F$mSVuJucTL*G;Q!t=&UzwT+vaAb0$}bUXrJl&bQ%jAHmq z=ADPrwFo~rRFJlYh^oEYkQN_{;VA7pclR*uDD05ZefU>WK2g_T{h8Nw=lQc)OeQk5 zD3vIi74a_k0Q;JtXC!Y6<~4W>kK=Ycft|2CtEhz^T68pRh}vC%sFzy!CwT(*aZ$N2 zQDm}eGPBl?_P6tT6S-2?x_EVLTEKgwb4d=wIYDOwqD#b<#vkFJfEPvpz3d)pN@Ffx zQqrmz7Gr<;zY)8ZZstPndigELCH;9hCr|DLRu*&u;xQ#LNt&{J@}Mu7lKKPwW)RZY zV`2fpT5v?auz5PCSZ7`$NcOfqMy{HN<~2y6rns_rA)8K)eEVe3WdA49u<+6iG7OZ> z*71|pdU^Oa?4(rTs8V*|;g$XOnlH4o3>}wTBE+TfS)}w{GU)xJz)`zE-6Wv`)Svx)l|M)D{Mdgz(F0?TaMvDo3?3iRC0voeo-M0KAH$6iUv3O>F`9sx{Wf_Jgw zVDELTv=XQ_;#D>3aFUjC8Vxo!*y*SEr#ZdzxY*e-kx|f4W(m|eR){g-Sez87O9CQF zP0qwpt*f{KkwcrW*6tf0Udic`*jhwN&|VzpA-u8KHcHDh8^4lsIvKAGD*)bpb^yO+ci(vU!oQNtqH9N z7huf^7rOulxEK7*2o43>h#fkho2#TX=`xnOlBP%!%WQrAh^)WJSRD2r&(@OLmnLw% zkP9fy^nr&+hI# zIuRmj*guFGbT?_GTVYs`_To-`OAC(jYbcZdO_P-xDt#@Emew>E^i9&Cet@B#xF$q% zE?UB?5q(m~oF~?bImtD&E6gIrNj(yJ$|#y`X|I_WhjYC`jrJHTG7frGg3`6IhSx4J4sP$y(Qy|H2q2&d&M*1uncK*)Y>xX+@y@H~|D7(S>YP^b z2ag)#_)69kr~`7zpa38d6$~e!MY_>mX?(#jnynzom|yoZ`$!FE51}))4lp41m(f<( ztHqTiH}&0KRZbQ5l2!T7*Sfj%M#e zh%7~Fh=(aoiVDVGWRr+BgvvZoS{Wz|sVfn(0~LWt@deBQLh*{70_g7lm`DGcKDNGW zo@{mc+b6Re<(L9eOWEk&mvUX^;zUE*H+lPS@#&dQ!>R2j`$IuoMqxd@cH_xtJk)mE z#rtNy>+16Gq!6EOR~>I>J}QU3dB1<4%%=6Quk5E3A8F!8mA>SQ9CKN)OS#Eb*0au_N+(S`k~u4^k>lZ{oRm}{m6)F5|3QG} z6jk1{?}76_{R3;0jNy69(}Bh^b#knX*7Yh0ENg2NyWF(5X%zXUWIg}XV4g3jtZCqd z(SwaJt&~%YuPBpKPKtwJ!rt~8UYIBq8#pZTfb?GKv zScCK9J<1E@hZ27_wh=lRa+$9DtXYOZC9an5B~nBLr6koiXu54NK_ZGQ_mQJwYOm={ z+jD2R*HP_X?~k|n$Nv$EdVBP)bksgB+tSc#KPSIlwOx;Ae{{e3>`QhQficO}v$EIu z`LQ!g^702o#fJUF)NSwOvK+=3>kUV>-DVKVN{=dt3jIpn?jrXUvo_bU$58K!y+<$o&ICRUF@#h@A56CRvir^6Q-*E3?W&db9mecvIaPAG z`=h%&_BV(Xy%!~fy8+B-GEm??iZ6=2&7U8EC*mmtSet}E?;U|CK~c6EN_gRu_#!p@38Vw=4BRn1O3uy>kra_@jy*Vr9yDLcWfXu1 z8NU*?9cx1(v>99Kk~x`~W!=24#zcZ9xtEKqkoOl3Vulh)Ee=LLIoAQMUk?0k zc<3c3%GHbUwTV>J(rh4r8!2TM20WAA^E>^fRQtzkUugwu#xCJ{ujh#|VS-{`^GU z&&+-+lU&`CLmGxV9N1zV_$iLOZRaBftaT z0pbDseaCsy&>mm4y1l>r@FQ(egeWiIk!R1GWWp1JTB@sK3uA_lsHmi8rl+46oeJ^7 zYV-9EufvWI3w{6S%G>?hmDlSA$`g*gFK#eK=tE!V#uP$9DghnCOC`j`{fWpLTNFe= z?z#qVjla+mA)~_}dB7k$&Z+~6qVM==uR+O0n+kl=Ds>TSczRh2EVAf7dO})!M6nh( zq?qCe(4pz5c>HApDo^=>I9N0ER6EsFd{Na!KLE0dqsp3Wa#h;(f## z62OB6N)$|zZCm<&9BO&YL^EwqkrM}`Xm0@FitDmS4Ty3N=KdxS@knttIchcPwQd&Y znX;-yhsJ~?`o0__0v`Z9N@*5Sx6Y^#8mK?fPf59>iHwR|ME2}A~ zXgl3Q7KHiz9qJ-$^Fq5bt3U8tEue}mI2{*&tlvzXFp8nDQg04ba1zK$h6W)`KL;&E z$wfg8SCYzw4Z&ed7A>k1<==Y*tExw92S^1^uhQq4^QC06wM7d@0;}$8nfL34)|2-n zmKC*%@+`Zy$jzACd}Xi|8C7w%bnPvEtW;=CIe3b3KQ4bx82vBh;{EKWyoLs5 znTvZh8d+1w$_bka!!2d>0eQhfH5MZB(&FYm3N9hz>8YtmD$2qnL4?olts1Lf^?yYN zWAX6Nn$^!fD+QWhKeEe}7XOeQ+Cz@xq1a1BFCuM%nQ!Rdt^Z3y5}piuPc5J}BZ_#C zSB}ViGGhKKIc|G-c{`Q}DMcA);k)!Q`ocB50oe$}>2yp6i4w^{iN`PF6|6Ptp&f7u?P3b#2xTJP zIpBn-Dd&hgrIIbS!@s$PJv^8}qb#MB4XAK5c6B#koO$>oKr)A8_Ro~41(1p3P|^W| zoSJCIv(ok1G|Gn6CUcfq9G52W9ZeLod81h~vv3LB06R84Q?o%BCHSh_&0YIIGDK{P zJ)ujHQ+}s(7H)EEM)ikI!l@h&#P81cy5ML5;2Q(x3TIim3NFkgY*nYCX{JQG{mqQ%4Cmb<$8$VhrX zgpr0L6)p@{4(WsQ<3l8Ha1hHYVP71Bhq!GR;_xei7%n5o^Y2FbjS^soki)YxTr8g> zqvNx=n{}{{O+krj#pm=94iX04V^o;iKr2DmyKB}kL-GQk4TkJeiEfjWrZok^}24gH{g@WfwV>$A&J*Mb3De{G|iP_;iwT(i??g0#iFhF zLmfz*)j$yt;0LFFXQXn2PAjwXw*X@2p-FfFF`QSrpwn+RAXcxo#wBuafAp`hH2R=_ zFF6WjMcvz*BlG#$2?^2HuQ$=KqU28PK+H($!~n8^{cy(W<_>`FJ~ufghpD@pe=Pj% zUoDES_BW=cSSe~1n5jZ%1 z=i6uEb-sd==l%Ze^#)6>bI^EJ#_ao?;dF)IgmR3;$G;E?pR3TUli8mNfZmuQ@AcjL zR!};=x1!+VEgzrjCE)>D%ItR2Ay_WtAu!24{pk&|nT(4lvxU@w{7T?;j5hsu5^;0_b59(r$9JFd) zw=!8e8SztsE)-3nLMI6=Jh$0UIo@TB297;Ls(`R;KIFq+*MuhMPxS_Ns; zm)GZCe4{k0@lMKNe~{H}Kd7kxJC&`H$?({SN)>M#R46Qe!2H{N6hAHp$6U4&4d=uC zFz9I_`6!3SbLgPL%y8Vyg3IV*!?Ie-{lAp7<&Jw7(I@Au{%ohg_X~^@vQ}#|+M9Ik^{CembYqP?dEhBNM7#2AqAD3}ji}v;al9_DxYxYi*~NJld9Vgq0jtJ;)9NHT zq^k3I2&UcyI>29@yUuaFDZ6Sa`?Bh3%d^{kI%GBbTjGi7Sg>R!mq1H>ZT&<4YdxlK zj*Z9dp2rO2VOhO(cSrAgd8W4Mw1I|J+k5#G7}a?{J&UPkYNk%4D1m}Pg*QtUxF3%< z_qtF-`(CKXe5oYMtj@ZbZ<=ak8kEUtMSuV!;bLnh_~XEAI;SC5e=6Vn5dWo-&jm4} zLuR<>=~cvkW~6D-diMP7R@KKi&)IG`Ql2ud`)Tt*)4T3nsFVE3>i0T?xW(^!&$Q98 zNxrzv+LO%`C9{%~%8Py{g(`s|X9fS|h31>ZqCBM%&;8fe1b3YMd*@iJ;8<9ZJRz+Y z*Q@dEX0C?raXivX5_}6%D^B;d^1XQ`e0^2NI(F# z3*n0QUXf}y+iX^8x9hmwJb%+{78*#%%*jbjrM)3?gU-^<^0y1y=ZR?Y*jxypvoI#% z`IC_Gi?7Z1Dub?dl6p00I7GWGppw*-$1$ZcKMF84+~v__{X5!N1fL^sBPnsv$Xy5t zc+j4kf+==-5aah%Qr8>kT;bgv{ejKRA2-wCVcU+5L8MWz)7qNLcx_;``dD=IV7( zmIL+)Z+Bm4Za?SPzU{Pc^L(DyxBXsc(z5>`-u~P|1J5lCO1)Q?{t8i_ddbb@ox+a@8jN29|w|x;3%E*O|Wj;N!yvt=hP$;uJ-+0O2D$F z2^uOE4VJQUVJ+@nrS`caDKCf2w-E~8XS&r}^xBl1P75|wL za0ut$`EvtssEHAV{<_q{L5rb_$0glQuws%D#7LuWz*BnrJ1x~>ZGO%{_z%mo5DBXYkNrQ9eWIc#@8BBs62z$o^2iMV-?)oet=QoQe*F?86Dk2estaGB#BQ z65gBJ@Wn6;fWb8zgFUy~=IyB#`#(t0@~*k1FoGV-AqeBuT|Tq^{zUS~fg*XnwEZUX z#X}UFHAnB!gj=gi82n|Z-jJDtNsk)&8^bZ4c0q2A4;pyiDqj@|^Y71Wuf-1zKKF%C z#e}1V_mx&f;;)pA! z{K?N3SqU68u;D$;uSMAq_jeM9yP-J2{nIlcIFAbjP%hGD!f|^*PFic zWv*pV%YEqen{fW?;Dhtkucw-CBigcv>nM**X^NFS0;9KZF?zoB-2A+Y&zX-Xyas6^<1Ul3gr7^s`GvsKTWJTtMkan;h(G>?&Qa(p0V>i5?HvNT!mI>xdrkUa2 zl7H#++Dqq5!!3S2XK_wiAb}=dWoJPT8@#)%hfyx8yU^GYdbr=o3ko-pON%gGg~7w= z16a*4D>8Cv`&4}cGG1O_^DB(u#kn@$k%;<<27Cxf&x8|)A1tNjY$g7;Z`1u} zW6S4BYID(+6&v^rzcxS159;MDC*^0mGt)bTr6rD7+gUX4i@`_`6th4(Nhb;7vHSk) z6F6hd{Q0*Le6SCmR{KkIjOxeD?8}CuCMLD%CfM!yYpMRCy1U~>B|4b*xx%vB{i1Q3 z-?js4To*drvbqx;#mn;A-Tu~7^j3su!{;5&)a>t-?L8x3*KRQ0NB8H` z=Z4Lb+AnPwo8UE09-_e`gMjLSO1?1quPv0fKc8+#&RfAhyscscy_&+%`4 z5Y#65YLnXAWC3{qxI4ay1`*8?5)HQV@oajCCSXgSWks6552}D+mBvQr=`HYb0R9+P z+ugq4qQef79nsUr>y_Z=+no|CTJ%2x&Gol}g3V3s*USu&-RmvyR}VPY49(x}{%{zp z;DmC|jvht2nT^fK`T0tnyW?k%5`VncS!FX%wxzYzshQ=w-PxlQcZ1F53)m}{B3{~D zTwPFL>a?)UM|E+U_w<w+XfTI}_ zvS<&*f};wA`qiiqpAhhmod^|fnp$k^2hciWl#8s4paoMa0m>Vq`-?%46jcR%*`P(E z`UL;9sV9HBf~C3i^GAw;c=EFm1tnkk#9xo+bW=EU{DWshlg2;IsjPcOc~jWiMW~Z^~CQ`7!JkE_CLSj3K439#A16Yh+fO_h7gM*HE73 z+FJ}C5*J)S5cs9QRSn@BFTrdt^gT|0Y9M3AM>SaDs!;M08V~@3ylJJt!Qi($n~t9y zU{Fl2d4X!jN#w!@f?46LxN>MEC()l|gr-Z!$JeoSacQDm&LmW%u}3jwv@$o>=o;T# zpQYx@QV8u&Pe+J{Qs+8l{nM=RTWcvGA0*B3r@l<~?fbh^$hZNuxYl~RZ!G40J?@Y} z(S*sI6(o5-K5P=wpT-4t?EEk>6qF~UVxoZ!!5m0m2YlaN6VNWST% zzxg|L19S*hOHntOv;<{Y$#wXaBzSBrR*n`FbdjB_V9!J{>U;lFHBwd;~Oav)Zp2QKFZ8c8t;BW<%{lt$;0j};710DmS#Hi8xm^8k8;ghKjse6aRtD<=3| zN{))W--Z^x!_Y3s*+exuM*y4p_0=1?sCVfk3xIhXP=r7&4ue}Sod6S3M8Nv>+hcwRT_7XD6Gd;p zLi%rnE|j&A=6#x(!M7}^CmwGC0hO|_EjVyAY5p3(G(x$AfOX=gp{%Q`wZ_PS(z-Vg z(iD&5>aFqoS#gV1%H!15W!2-D{bKL`VeOovBMY}R8e1LPwr$%^I=1a}Y}=iR?R0G0 z>ZD`a)~$2LeLRo%v39-G7`tlK+Ux(;oDd6;h=UlP-MRIq?EHD9EcCVwnIxdHp$5L7 z(1EIb#`8HHN!ca;3l!cRibwRmE7{FXGn}5d5eA!rZAXOOgMz^(W&{Do`B1;83t`+@ zam{dJm9#)_)|0@Bg&sYJc8pq$UdA-tos~&CggZfGgk@5p?$b%0=F&t*V6sUKd_Ti( zOT4Rk+*bC6;qNABv8yo5$_uL@Oyc8f3BxJZVoeO0p|a{3c;WC-Pk;1Nq*Q0I+NjPve%cmu=KHqz#`SUP=GxJ9C$j*65TW z!5Inx9iDZ~71~8+ou3cQZ^&WRO(FT+H$V2!0V9kb*af;4K^>HzuZoFp0%?$_9=s%M z0;q(R2!e(7rC`rhcb4s^&Mm}{pLFAy`8lU-U{GrfK@_u}XxnmA$lm1O=f4RdE0fwG zGhwGC4K(E-N)?UmkpuhGO4O4;i2fK-#RV&N-8o7G6Z}i@P4tYdo5$?1xJq}EOnXlzUC%pmg zQYD#jhpmj(fctCJu#6)6xEVWW4G^ZBlfleOD_xd@zI>~_RCiGwu>1N5O>G03x`}kw z=ps4n3!&g(f%;I9s`8X6!xqaFS0}*Z`u5u=sf9&H&MR5Ve3P!* zbsoc><4UQ4)4ym@>TyWMM`9MFV24VVQH9(WvcORz%yUlS;dD(({(fL{3NI9A&ufp(u|PumBKz$VSE*CB61&hsxY^@0pc zSizQNgN~;~uHS*>p4;^mv4BwvnomGzh$Gc*1 zDL>y9g*HDJQ*V^uYhPDL9xshyJ)SHS4Us6`u}yPNr-qqMBqXp7h$d%4bK!d)u6{fd z5ejQ@kd`pHoLfz#h<(l1)x8g85isXu&mj6) zdfWbc9TByBiQYCqMj>bz$Xlvxk(cN*zMHZyX#RoOLpE$I+6%s;qLSt8m3^nq%9O5x z(Q=ZL-QtM7QFdP5X6N%o1g>5(WC9gik~|Uu5=AnsgxDn!_plMWm@2~32fA&EHr}AF zbMVB}IM+s=KN*=`>!sI2z7i+r9|bGzwg1spS_Lw<{T=NpIIH8+iIr!YB zBi2wRNNbo>GO@(U`_$q%Z=DSKI4Hh}jigyMr&_;=n8rCS71Rwr2bOZZciX0d{NJC2 z8%&C48KPrIH%7^buvzfP%yL+`N;yW9BzF!`rWJ15_biKbC@c^g}>%FGjrf0#i zOM5Y;7{&_IO0LS^brM(ObRpVpr_bM4m6=qU6yF}lWUZe?@cE4|IhLp1ad?hWRW&-_ zG6@CE+@6E3T-!Zwhk?hzla{6GR^w@MSjv|HUx!7WT{E2Wg^yiiri2$)bh-SyrafPo zmK{{gdmh1%D?SY>TR*eomd*YKlbyD{5K@`uo!*KVxNShv*$F&<-X-CEw+U!=Ur1#T zDRcc7U%7Dme|4k3O_Xs0m3tugQ}F(U6Iyiv&iZ71JeCaf83!MiU*$rg$;DBu(4YMa zcMCX87PQf!L@>f3;57+VjL1Blft z_@hcn$5bo z?`9k0J3YR?!v-F{d$rd0w{mHy={!BsN*=pgHLrv7y8bxaWUf;#<<-33S29&e&ytSt zt1+VP$j{ihwxpcnnKjA*Q*o1HJIX#O`=-@w0${*w-M18w)GTXhzKY4L;8+*NX8*7G zb)I0na(&_d}B;vRIJ7cu``e*1sobgD*;L$*D17;3vv zlN2+wrORYdYF3gW2k=Y)i>{KCr<833*DSnjL!EQout{{dY2xbNjdtsMi-<`c);(JX zdlKx%iV_NRSZCB;-)+L=QoRnJ?2Qc`l^qGe#p!HoBn5O!4rh;;on|MUmbQ(lmg|9lmGiXvz zNhod-?D3OUmHAH%4e%&p_!zh;OuEtA25mp5lgyq!5iJ}aM{(+e&kKZxni`NV6X~zR zhf!Y&8)~mRmb0%~x>A@5(v~I4hYz-AgEevfc|TIu?=^i54PJGOTwLj>7W{Lz7c+=p zqhd->^+f~O_)y63kwm2Pjpg?ipaP}4jS;?D5{4d!<`aR-`P^r-P9>IVvCgG~{zWYp zs*WUhws48w6lN`AIHz(8*-Wa_(Fk3!xL`I(%Tb;Vr9X&tj6zpWlPd=Q zwj%hTH+e+;?fV~SJqI7wCFC+}+s4J&fM?Lxwc992(4Fs4BD^f+%!u00k6;fMg{&cq^Zgly`VX;uy*_p}awKZ*4!hO?zuhi90D|&}CeV0&} z5i$gsIqvbQV(b_u-t+1nr@iUcE!BRRZqR3Y@Zkj)S zfE}09q^a4!ji$)RY94s8l7ws&mMg}14>aqXdvHwRp5FR=xOBC5TPvCBvC}~9MFs!E z=OLtY7EN|u+D{^PX%t`=D>6v;k?z-({}Og`vI+%Y|72pnSUba7u&WAVlUFFY2ns*H ziMX6!&|#xH-HNL#X{rYj9<%oAdOH9utiFe>jNT`f@L0uI`01sdd~bI)SY8nxU7xoL z_+WUlHxDdv-pjd^UVVH$b9OOI(~L~lmDO;?@)z3$UWG2r&2DrG`I@~kP+ zzj^L|Sx*w;bR7SPMu4%(t=RuW`H1509Yi5}+UWh0t~)NoJ@UP7zYV;24E)ga2fr&? zxq5FWM-%)ScYUvZnbw)ED_wP*UC~Xxx-)%0V34nno>i6^{oGa2`O#3%R7trv>O3!K ztN69A@$Gl9TN6Um@n@>ztYVOC5Qoui@^YHMw!4KtVbaui8vN_aiCr~WZ-TXyn&>e? z(o!+|b8E$uwHha@mcA+L68p@E+DF#?la8p%%2``h|FA*ZPXDmYiGGc3jn98CmaC=9 z;DV->hTwa>lw;B&@9*-)p8z+{Uy{z4d2$Wv-03^Jy~RnpPFA0Ibq_6^jny(JX83BZ ztksjVnQXN_!GA|2lRwDn>{vQo(4mU+2F$I!yr^*!bagtKx)oF?a)*Rdm<2`6vs1an zCi8Q!0=T1peceF*<_PGqehfe%BjS=*p&+oAn|k{~+&13&`3CK!^ zV?N&|ye5Q7=x}Loj$JyZ1A*knn&igEhL1^AkOaommt|>rP~Hd!T0?1zV2_$CS~{6> zItD{Ez#XnslRa`{=PlE|493XJome5&B%Lie4ZibgiVh`3GtM;r2UC1Ms@7O2exD~R z>q}d7!EC^+tfj`*2zGnQspk*~bI1`i+?v@9Bp+yKr`7>IU;&p1dV2Tp=J z|Cs7JT$V9R|5?%g#?Hi+UaTO`hY2y0#h2Xk$ob=0UM93|*`%vr;YylkMPQfY%z_%_ z0_Vt#;|zC>cZnQjJOzl0j~xewwD1#3_A5&t;~$DqfBc3HBg<8WR5=(Oku;aYNl>5; zHe1nE4HSp;Z9?yB*g)u~ElNAN~ z5Jv-m1+8FgsBLVtKb9KdK(BfwssUC5lS3s@5&}O`8nsc$E5811U85>3ov4fXZcFmV zEZm3TTY_FseUI~IGRVruS?>q^i->&f%&t0j=VaAPx5#bp_h)7-T{0;vc~NU;X1Vl@ z)O_>p61M|6b~dJ3;jmd8rD=0k5P1c=Wz#xZ1+`4Db3z4nT&ZRizesYTmzP(pMa?|A zr#P5|$o<}_j-r_8&cHl-Mk*w7z%*aiaSn?-8gcXtT^xK)o+eCr{-w)>xW^` zYEFhFhn_r?simH;xkTFH5&aD`L{N;p_z^p2Bg8*xi9r@9(*bMeI*UA~v>59G?VUju zVxr_@^50rPf-gOqQX(u4tQ&TOMdRtRLmm!)Z~ryTQliNuY-*nTNyj==a?CtJe%Xh6 zT&n6!woamSiUva!CIXwat`r5i2jD1i*H%=xO_&++d;c!jB3uwgGeRoR*ylO8+1(Y@ zOO3-+2CQJUE6)*B1CqccQt&+@R9GMIFQVl`<0QeU$~L{PfXL>n8N!Ig-SJ60Tm(X% z1$w&1B$34uk}7S|`OU=;{!W_c*}f?ZN|>x77*S&Crb+YW4SH`uOA(Uu2NumH+MVbI zJJRH}_Qz?gucwdS0`Kxx3>idh+By-v^@R&NQ@+lY?23FiKZX53PRDkaMOB2!cD zQVNd7*&Qd_f64p{mz*2)^pna4Wy6Qe6wsYh9`8Z5Jz9o-EJ=}galkzeu(QB^D~KzC zm|`EQ1*wkkcd0=D)d?B~vk_?YQl2<9+>(l<+CF=jyCIr zntD8e%Zsvefi)tr(Wp6$HfT-f5PL9jvOe#4Df}dS5WF3u9&4U7d2-Oe$3UUq@8i+Y zQQ3*;`#b(ZdS89bX!V`$V%73dhH2OPBd(cTgDhEbjCFt&tsFVE!VUM$I;*WlLrtIQ z<9nCA6jFE3D`L*3#UGxz4*FaWOe35T2aZGUf6687OzYK{sG>K?>~W>S3c_2I{h@R0 zX~tH{PU12(qPD=sP2e}JlBpqeoM}TR)`snb6BR9ub^X~c{|)xx2TNK z!PHT#3TlnzB`Gw)qO4r}{GzG|*x#bGpmzu|Uh&B25b_psN=n~jb8X{hJLHPWskh|U z8E6#M?6?Y|V%KgwsAx$AWbe_mRq7I(tAgV7P~lLJkl9}NU#eEQDImYVE(1$pA-S>t z@{O&MSwWAfl$6pmf=uo!t|@Bd>&rb6}OP4+ItcX@Gg^7s?( zs)V>&(|P0-kvD@f1_1Fk!wy%a(H~)f&466C_=BrZie3(Z@5r2`fIuKqY7kRCuD(tl z1=kM&{XQzDpR8t0@gpIeC1(73l1>4M54FFcjh9f44o=~=BI@@He=A?!Q68sj!8FQ` zC2?JlAgLt)8ia6?_|GL7j>Xl;6WJo=RZsB@F7%_rC4Bcb}mzm z-e!R&d;ta{);HQ>2VG4=M=gI}-dAEVal*@byo#cK9XfB@><`r_G_etj&RzpI_+J#s zVGVrPcLmR))79O8bwAfmD;))e@6d$-(1Aw~1HMWFqEL57X z0d*3eF2+_5IURt0$b>}&9T6cWh!->z?4zKfj|p(pCJ_I1wWt8myi&XMa$CjN?sXeH z{P?;j{I0AUaFsIeb;(r=<92l^*g|{%S$Ny>?$GWtUwAkgFR6ANe}ydea%AAU?H<&c zrqT9R%fvzBh>vJ7yNzT!+(l9HL^Mi>RlhvZ(5UUKr=lA^g2BK!?a7+TmOu2%HqlStSbSg+>x zJ@DeJO34~sh1-c?B*bj10m?=QZAvKOBB-xR)?t6yJwM$SGglN6J`Z-wT8iNr^?DC7 zixQh+4*GiqKT;x^M#=Ofo92&k1~!P^p8~!fvYG^Hva5mmaZ0s}uVhbS_tl#G_oSO{ z4}+a9>;hu!Sb+2rf5=HlyrP(a&oTMJc2eXSK^mDhl zq6qc7KgGnQI;y5PsDm;(C3EST`uZ}k#Lb)$f696-?~e%l!Nt1C_M_ZrX>HNq#Ml6! z#P^_Ch}gK{02$m%b21VN&}tYj#yODMm>n>{A0>|`ido%tyQ0Ua(^5S@8y0E9)O$Vk z2kLuDBIsbN271&xUJ4o+Ap&w`%l#SGbn@zJ>Y;fZugB^BVdyv6zEc#vfy@3+JQcjo zdQPUTznt0Drb&0IB3RXJ-k;Hj_cnG#_LnMI)xB?DIcFxmx>ECcefn|^-)Aa=qS)H?3i^ ziIa;8PQ$A+Y;bb+H>lp%HrIC*db-7{HE40F%`XBTsQ64^b^@IL@;g6&n;AA9-K);8 z^i%tQb1~BAxgVOxbOrNU?oVsUTlykDj?BT2LX!02_4#^(?p!tKsl-04v9e zk)D>eWKxP?g~1*9+;*R`rfq#XQ>Fv{m^EScj~eosgf4>YL<9e z7OF;%8QRS%d_R^)3BO+1etw-H4{Y4s^k22LHuG-$N>9Tw{hYRclZ`q1!!SnVkjSW@h?7nU#dv6kO?QYx3B71+4CvJ!%!R5f1h?!l?)GqR2xXS&v} zAT98hKXf?f`%O`ULivpMVQH4|YrE#QtHc)5f=#GHMychGkgE@>JjL+1R=|78DCZxv z<#SDo6+c|8pFS$Y9s5ZU0q^SdZMSZ9mS&`dKG8O8bmI}8La!N@Ss4hkgHYd3bHBYd z^}oNi9c|dAbTt!9;I;JqqikR50s`OoH*B()2?&FecZ=U(DvJKV}A_$0*$M)?Dj_R)itX}8sV@G-%pSLImU;wzpK&#pO{Apg= z>S1SPrlPc47l<*_YxX+Kg~L)mO0A#nKJ9V*m%&q;S0#n$fl%Bvyy#X?Th73O@XUTb zrL29S)zQ++g90ld`FwE^=?g!HNrF?nVX(moavSmNAvKLjzAUTfDx|4d;w!5EhUx|G_A+Cz-YLF+>|K;<=KVivi+3Nu_MsT zAHY0za0soeuV7B>e=u#|og{tTB9K>ROPU7GUU*Qm( z;>SlsAWLQYj=(hQfOKU6WivH~y-wH$zlzVp{0FOBg_+Pv{yup=SV-!%c#ckE9<=#Z zQVC$lYFhTj}k^e{!kSA`Pqj~9eN}IW+)6Yims?Zh=<|pH6?G- zSeh;U5vO7tn_`IQBJ)s03V{ID9jJ%1NcC7l7G z$3bRr`aI)bgY%=kR$ZIv{&0TR)t%C2^Ap-?wQj4lV`yox^_zw#J5A>ogvHIbLwu@T zm$`)T(*$g2ikfl=#kOOKbF7iS#FgEW8Fzb~@nXNczM*XfO1U`VFF?x}_fpP04vPFE z9_9CCp`s4KKP#o#`Yo+;e4Eo@SzFwl+VJQPr`g@b_!T%&%`8;$+XqD)7NcExVg{Iw z-E`1Q@2tL?HQ?YGtuz1i^!eB0R805j0MDx5S>>r3a5WB6PVn}W$$YC1oDN=z7X1^2 zE$G22VDu)d77uSd`;+l&-LF(~FCy$d7*}{fd6dXc)kj;B45bh4ge#Dj2%zHx>8(uy0()1faczbN*qv26$c@5Ni`N?`t0;MJ(==;$ITNb4 z(b2FFuIr*(A++RvFs0uc0E3bOF17XVVN&PRJ? z7vDgH;m6>LsmJ(x*pzv1OmS+-`aR|`I0x}32zY0|aIz%OiV#?eWfiT68Cf~6Y_8lV zybEoBq5%d0CdD57!K?}abvBR&8P2rCy8<0sJ{V}SkeEkbWkuzWNDq=R*iSJsuwR6J zw;re|4k|_OSlRAz8q1nb03D``o^tC&N*DoxPkWO@UZN(O#4&?K#)5g6ZK>oijpTsoM-5neKj-SWJk(^jZ1+mW7#_TAgs1{BM~96LZzV16 zjo;nK_}1scaFdqm89r1#IZ7@JW-JYVw;lXYk?*fX&yx(QyN>pvg_}RebO_z~Id<@- zAaYkK43Gz==mcG78%;Syvawhsi41r#WZ?uV((`;JAGrD|$~0_e;414n-or~2r~cf8 zGZ|>cCH=v>+N$62bNb6kMQAxfy2_^NrK1$v2FrB zY!YmCb4K{~f3z2og;+DjX@d^wX*{$L9pH~c)rUm497(-z6c)&;NRRBDqHEJxxqkKR zHi(msm#LBFr%TMK0U%BV9#N%`JQWXSJAHJL7BA^_y_SPjt?PeYN1hYF^PQy^d2LS( zrIsbSe{FAj?wR*HzpX(Ehx?^{sPgw5-cT zjWhu|9$Y@JGZXrvlE>9D>#%s;d*Q9?PuF4?#QXpoozz5R`~nQ4+dbB5 zG0~3b=o>pW)halNFlWGPK-WP~-9UbV_66b3SuFK|!L4tBnxP7E5JM5estkik-c54U z`c~OFM60VKOd&DVe5%znaZvtxmwpLT`AsoL`AptO<(0K>9%SjnPZ;A=fsTTdy@arU zv`{zJUyyY5W!%Y?7)uo-`{0bIES_kpoeD0(iohU?ie9sbVZof)_b@~g%@OD$R$#3Z zy}|}W_KEwN!Sb)0$PwM4&){Xo8@&r%rT$~RhodI-{ns;;5vPgNim=8%V`lg)^W^h>AF!5I+jgO;PVqk1 zG;8K7Sq8R-j*59H$eSrJyEk^k<@;0aY6ZUAV&YfE2L;!OyPm#ZbtM%o53Fd8;re8n zq0cqe_4^sF-HsbLSXRbAFAVv z-`zr|G{glA|IF>kQMLLI;)YOZ^LdH%#ee&1G0uKm!6L3cWXW5d1sB4nfh`4E5RzOa zv!o5&N`<$B!~R)`4k(x~28;>0jT#W9eEsP+uqbU+EG9Zv*ySD%+zCkzvTf>U(Mcwm zi%hZuSAdCHA@l7PM6Q@EHN#0a#|b-5Zi}kt9g&noBIGyn^o30p%?=V|0Tt}O0Wl8( z5Qhts6`ll>O0L`Z~OQbtNZX85hi(p#~0?yOhs5nT}E4q=c96Vda1)073>Rd1Z@ zdt7D#ng6nUZ|NHNKMu#0ykvB3z%GSh7R(e24Nie;NU+*JgKo^92)&|gyPaS9J%6b#PhY{aFHGJMiBd= zspj}eP}w1n9HOpFiC|zBP|Nc|=(xxg$p}eSM&Q%)AWi%Dz5(y`MmFWN(jG(~%-*1; z^qgcexC9t-7QSkO;5-H|Mow211>I8H4l>IOu!($mm~)Y!<)6fjk?8C%=o-0NDp+Df z3E%eG9|}r)rL0;7S)abz=`e5yIzv`b0Q2B+(%h(?sPH3*v}!rN8ibt$Pk{y;whU*)idBVt7#{2faS&TLO&Fdfh)`LG5;hB! z9Cl>bik=4rzswr5vKFpzOQZq`l4=wDGB~86VPY21t!ps*B~T?mVMMT_k@nAdUBLO| z$dOaJ^A(kBNRXiA6~5KEhSemGPE!93boN~1Wt*U?2(hym9o`4~5yc^xW=si1Qp`Jz zGj}p6#0+Jbyy(AyVFl5JENpj)h$J@39dzYuig~-n*f^-c0;lNxfr1lpc01+`uQ-Hw zrE&=KKfGRZgWNM#%$E91a|jB)E*=={%39+s6LK9ee z7Cy9J+k*W2YS^gl^6RE0MXt9p3KmW&nwKY=o1TXWqYMGSqn6U3gQ}B)d4pIZ#6>Kg zrY_o~i97q*smoJnfZ9Q-gf^2y<|iZ7L-k=Yvo1X`I4Yx?x_00*BAYTlJt0OGrpi;u z$;pux+{}&DFYg9tOybJ-As~P|;wXfdTC1Y$y4ym5!#_#0CW-riSL6t1qasPk-OB^@ zl&gAs8}8>>zR%HVzb9Hn5)VE&zP2ADu+B=kHf2{z}4UMGZjiToSDL!SCVERz+;G-PME)(!~ zcezFhfQvnuU!>WQ`AWVhhc^MxSd<(GiDF3K#Ei{9qVZkEcKOBQab3npB4iSa!hx@i zQ4h*VBJf=@A$V+nSMe!D{$Jj9>Y<}HB0 z=6$fyq_+(PphVjGFC8(O6am4eC7-MvJ|6mFOC2E!YtUbQuKN8V^$P%99(_S6{eZxIEnHISa;=j4w(H0d_$FpVVWHY z*5Q;ig=s_*RT{?F>|4-4X<&RN_Cd$M8AXiIl=aTlj3(FQ@-3P0UlQIOx0pF{5 z-w#%t`X4phwa?uzot@uYS#d8YPPgW>0fjanVN#9(W{nCJDq#e(zsq;u2McGnZw0o0 zmlz7A3J76v8r-iS4rlEoQGLBHDp>}v0R;@tXdGEPlT888x9{7Ej(@Z`-*BhU_xckw?9i|uz4LWSNvT$XeZgr!^?Gv1cN}K{vr1 zcTFC3>hAu#iyx3IkK1=zPVyaOXpsLc`vl#3lKy8^6}tCj3}C&9F}oEi;C5`7zob)m zmD2jKdFZ7dT+ssM(zU{eVbyL&Y z#(qMXkd7m-Oc+ml%?R_PyJ7EB3fpBWzR%&`-BR029h=Mt8MeAs?}!R(gLa&l=Zn{` zUI*WpMH%A?#GgX(Ez`VGiA}YJ&yRF+T?iypk_O*{_uIc7+oB&@9M2%O6qMYtK5sY7 z-wC}QptIsQnDo9UYF=*Z?!@}SjyN&bolq!$mi7nECE{B~fra5Sa#=kAE~HH6o#-i~ zqZa(~NoC0fP2Z6@5@N#_SnpWsNH)Z<-m4$Zc=914LuW5Ex>3Rlu;Ip_zmn8T$tnc(Njw(7MQjYutW{(KdY zd3mYrGAVYlAn+{oSygm0kY?C%W^%F9N_^z2CrQinwL*~P!aOzZ_IVd|Jea1H${BFl zz__vSswHyJUqdu`2ZpZBH_3mu(xk)jYo01&>JP@&*Y>l+*X1K}b&DCP66jrvQq9j? znupGf(TR*-w@&!Lor zhL(atSD>k`rLLi6YoewwbEEIIBOd&5ll4RQQ@uA7bqAMO)`AJnO$0Oq^5A!{oYgU0 znz+6Mwzg(~$O&V&sx-s=y+{!TZf(B?28(WsvU;+C)sdSlb;8#yoI5ie`}>P`S^X zc|h+vG&IuV(??lz#C`!5@e#D_27lSwZL6wf?C#F zdooY53H7hjd(gf2^Z0m__$bWq!jbE(bXt7=8f`ZtJ{11U_FNfARY&D(J|^o@oA(w* z#AV<6YeO8gAb~LqsE51k>^I9*G3c?7{6x%PGMs1E8-(#xQBly?4Gz2KhYXs?&h~!f z$SyuRRiS)?21}l;eoC@mV9S3);yw{dEqGQG=2d6yD2ASY%7K`fb5l~f-kBqg8j)%2 z#*p3?wpK9#JEf&AL*qIRYK%v8llMVey%B-zg5KWfy1uCTsDGk z<+6M_sOogF&^Ue~>gq3JaXxn3UdJ8J4;a5)@j*?k?ff_$70Rc1*v8b8-lU%*HjM|B z7&U{J#M_Fo{^!_vOo>gxC`mzJkRQST)X2n zo3g0uV#4?N<4UaTtV2O!+FBHvVz4x$|H?CZKelkD5OOjjoqv%AnLQW7&98h!X2H>Bkik8GP`av61 zVKq?_O=%!{+945SBW#mdT?z4#Dveq}$__3>OMZL8OD=qd@D^c=jsp47G56T!g2(lQ+vQ96P z-m*MS7W2-*O@+#Lh?K*ZtlEvStn|4F|9a?m5_>k!~Cx2ZT60TPBnzNbz}gSX@85+14H>meUe$7YbmjPFT7 zOx@5JqG9KK*=m0HwU9ip_=3nxWxn%b5$}egp~Eg9LMu*0AKkQ#NYpqQjoGn=4mc}< z3aH18?oUf0@z!X@EYjJqN-p4H&qNaK6wKvDBCLWaZ|T&CWS9&QTG2yfLc2km2@9hl zT1hJ*h|J-lkeDSILxcQ7BBoZxLPmMr2e@*{~eP*2Aq);W4uf{7p6q;u4E(E%=9 zHXIqILoa-OZZu}pTRuIQvYj7OLbY1Fb%4fb3BC~F3H8pY7#?PNs+sdpmMC5*O}iF0 zIAvooE^B2yTKFF*_wrvR%W;Yx!CQXcynFK3|2iWSCvbO7PY>Vr*&RZ^R`7ib%cch?JEEE&A2@351sZm1uzZZO??W3}yZge$oi z9BI!-JiYH|TFhk~s|O#WjSeFALvvCYv|^pzEr)N@+<0P!^<#f<^uz-- zbRF`U!uIH=|M*nc)m8?deq8D9wu5ArJJAW5<#hXJHl)^1b(@ooyP9ts_(H0*=axP^ zZLjx{cC9Jb2+y7e$6i7)f!gy`A=m3h_o}KG#LQ0I-{sCfy}|C1)+0jCtk0RUI)7!A zz1Q@2S%Z!3Wp}APbD2)Ccj!GS;r5HSWFJh9r;bez-L?+O-6DUFSdN?}AD6g>mA! z_=s_2BS!Ip^u^CUJp~aI%&J4t5wR<#kvbcw*xco2C@|q6gnM2HlqY8btijfYb?FII z?iQj$OHypCd9|eIDyqlF=K;!bX~PsU%YZQk`UYgRBaWFyZF;I{ z|GpNxzd_M_Y+gCPJ{Pn6zi*MJOeS`73tsekyC?2HW(7YVteeA|;^7?(z-=Ou782Gi ztm54PEn2IWkJS3)(xL-*aTZf%w{QCJ*%poHgHp)_x3EISF0QCzJI&EJ;(y1YEcJ=e&`a3y4fS)-$mXivIRQ34-;!P`f@K55)8n7E}lI4?3`sJ9MA2wiAx zw5-KgZ_p0OQh2m(K_e_?>bas58wp7co>Hq^oV!(ZO>rN?$=d;`A66z~JMlF1bqO#t z0vx#r#TDn_LVHp2$RO-*5DuwBS-Yve_epF04&fGXvfwdC)3h}3>gwp75QrCGI*Zh~ z;we9z;9?;Z6Dhe#@MH9Jp=mu^p`k{tzDict87bHHKQ@XNs>e@o*g zffa#!fez@{%>4zesS_nnq5x|X2tlYb2g}N23%-q(G;Hj?_gV#JBT1@%8`_+n`yLkY zb0+lzhnP1$n_0i15-A_B9=}5(gZnC36jF^|e3lFeb8M@Tl;iLUU5y^>T}So(nj zfeoX7fow*R%n+FbziL+fM3+Ey5r9=zdO@xpF1LZCTFmB@RT0srxp@teRxAw< z3L<&%vIO(KrsMl=`xNIg1%7Zh$L;q{ElI)Vq>U6%g;kvkTkdCFaQ2nC%pwpJun&oS zRNM+{R+$wFHQV5E2^L1fCGK!!4RPp_+?IpcBcy*w*&>}C zml`t(Lee<1cpO$9#&m(0QPx!Cdn=un?Cyh9#tH?vWTS6MehJ}FsDow8X@s8qtGN;$ z92`viGqV;Xd%!tFw3V8g-J;+e&W9_imJ|Ot4Bw><$=GP75vXE7DouM&bpZJUb8`Bm!TPbt2Xfy$%u1 zL$)eLn@(9eNAe^-ahKxe$pwBRC4dddTqo`i8UUeiclWYWtfmH}}W3 zE!YC1nT9Gx8nKlIS_+K}icV3`O?#At>-eN*xndP4^Q1 zHa(+BqH#2ZnevahWI6m(thtkvEN^cgChACzHN-x60NKd}NOPb(teIgSgS2BH+niQ> zclVThWlCyT${=uvsxk!ZG_6YJgQ!6if~TmF5wZmX;X6{nc2d+rBk3mqJb+&?S;W|X zy86_U6P8!0Gw2Ies);u-MR#IdvC8|%NNqkulI14oWRIsU&TSS-N(flF2!Ge(F;tl8 zVshjHe$WAKp_Y6D?ZBGZb3ouhZ3>kF#WxWFl_+8_5HBVju=I6j&BD!5C>s4AsAH0T2}MX{Sc;znH%Pc2T!~$?ZcyJwW7q3JEF) zz$c>`%l6J>kSC{BRV9u~XV51pe1g${;r^2_`fcu+SVCK?<3)Sh8u7n?v? zL^6R97fP(l`~tlXNCu(TKjF^&!Z>F+QAi0d2_$2RsKbwnw&kWNWwixdI}>PW!NL1Y zV6A{mt^hQ+o3cbHa_o34$+*8VI54MMU~GQdCchL^tm-u>B?C`MLh9hJq4S`hQ5sd4 zBM+YAIZ;HW$G7)dPN&Ad$%5m8FX#`Sl=K2z_NdcS$eDQWCbrg|XWcA|YA4^`He17& z_^sW*yRXg_0(=hhATF=XOG#@E!wV;JhrheoPgQ+{aQEfto9vqDwbmM*4~l2IT7Ff1 zSbuc5j)nCYUpzE3x;$FB-&gx=aag1`dUn~m%Ac*IcK`i;%Gq|+^QoI*+r`8?YPkdR zWV7|@lZXQbnq(OV(yi^IwwPa)Km4 zi&v&e&|VNKh+df-Y4A`-=7J0~Kk78C^Ju{IdnxDX!&?Nu<}pc#$f*+tIk&_3poza( zT)XzJkMM{d-Z{;0m+LQ6TzxF0>k<-QA*|pZxuK^Pr7&o??Nv7G)LCifXCt63Y@+z% zkL*%%Y&N3NG9Xyq?Pgl%YsxQ!S^k-GDth}%)X6hUd;|ryo<+RY`LNA7ke!AD_7YWY zM$7H}C1#l>FNYXCFbD)v1Rf$~mrW}VkVlpJ|Io0%d&L?*T38laTg}g-5IEsED)qoI z@|SZOU&xVV(3%IHZp>sJboVW|c$JQZvFUoR4N51oCn@!dd(`1a)}HQa^Zz+G#k#YM zG~8@UPfw(M$ccge0kF7kA(F_3$t11ECTQH`6tzIY;v<)hODVhMfvs#EQ3iC9DQH^V zaGOVf$FCMG4TOmA!lW(SD7X#_+Ux(^+M1M)l%T8H23)WmFj-i29LDzv*_u6pr8&xu zP<}UK{d)>WO*zI8NS%{O4GRz3*O%vp0Kbe`CxcdyGx8~rJ7|ao3BIo**akX($Q91y zN!JLgOhQ77G9U%ZF-63nm2Dj?BEgH;UMs|U0%_Wdo-id?f)GsI3!9oq{eI}zSRpUG zo%(rCLF~IsR4O&1&whW8MC)$Q}mJA8$_lI&}T3lFr=cK z)5!nymi&aGd8R(;jC6hydHhSZNG7OVEBbt+oBtp^Gn>yd1K;XEwx0g{Cez3JG)k@3 z_}?tu?X;hFqT6U1ck{JZg=@3$fu&Bjsw30VSf27hPr@g$U z_`kubPSw)lU-#Gj{BF}>~Vn47CHlqjEU7~QmcJHIU^Iv+tC zY)JGP{>%w2Jg*6lP}@bL^*2->S6i2Pt5J80EJ8z8h+iTtE*!GC{Y>9M`?=8UwigoZ zo`vo@zg6ShT({~O^K)mC%wptl??(tX|Jz@o1td#K-JwIyLcm}96XGNquvWr_#~xxT z&a0rB$Vf?_h|uB5+tDgc+sO>c=yews&GO~1vQ*B_DwtQ&Ix+znTAf<>zfvFQa>^{5>cUmm5iH~vTATEDljzg^!-i}&?|6i%?I|teY)yj#ZnTA zRHqvmIx27<=N;f{C_w@vEBfYaL>FX)=@<7pdqw*@&3l1JcC3n@_c0;l%f+$4c#n~O z^Wu{sBf}q`;l-OCsqwd$XdCt66O{5taOAr8UeS-}*IqQByf&7F!0ub2B2WdwK9CQ-lvV&$!dg(e@8JZK4tc_t zkT>Uo+80^^kSi#hhFmoV6|F-?K%3VqJ^8q22RKN$gP4E!H~Kd%4|U{URJZ&oTkVt& zZT+V2e7|yf^w*@ilY>IsA5OAg<+s!J2ZC(JOSSvk7hi+#6GEmq>I~s_MQDSSIE5>bIz{g(D5a#{pkRSRjFgOxU~0dIvB^_%(8X(C5BUTzO#+=RtUIDwSK z>3Gswo8#&PUcM?X_RhBDO4^duL(m{)>11H`rlK}lQ>J3`Q(WlA<^0J`P2js_=FEQ0 z9;a$9v7L#W-`<~w)EKv+$sG#N|BP)c7DhNpKj~W@YS?(PfDSGO=<*<31m~vjeDO_( ziU+Dq=079f0mT&We!}XKcm}3&B#rauv7L#s3BBR95Ui$#FuF)38W33D;<9>*bqSD|>=PeuOEE ze_5J;QJ7iseBUfjKYv9sgUJsNB(2$wZ}Tj!cbch#p0hI}2lOqp8Yk(SDL!`C}artfRs)Hz_e__Nt+g0;}L)3yb;|(o5;t2B$n@3KN zK9T~dv48qni($xjD^H8JpBB)ip`~c@hjW6xeB;DnzxCor@y3B&%QnY0dn%)I@f-xC z0dp@47aAT?aBdLscVwg(@kx!bBU6}wo9vGlgK^xh1BIu!rrcT2w{lJl>{FvFp@LlM~jvbBSV zfrp=Qz0x#fyVe`s|Avm5TsN%K+k$6*FpdIe5=SdKP{Z@^=FAlHJRMeXjI9tw6oIWqS#O2G|d-O#gdTT8;gpN zCJD*@H0hSokibq)30>UBW3Q+x6fl8+0;^nAP&Pl1Sljliip}$X6dHtVEUW6ZX}p0z zvGC6W#`l2BhUP_fOqAXNg;Qg|KqpopgQI?P1=r7Xu+01{ALHM+xNYV9vopj6 z66g0nm{ zNxb|KCDIiVP>GN8GH_i?9r~6=g~b?E(8gzd-96{$PkGXiJB*<6t5=bHq%LpT)tBb4 zkF(r4e5oUT(Dj4qus2(+M0!$eOYF`l(ZxE)+AB=4AWm{ZI8VPo2+J)A+>%J~lc0r` zUCOdz1VEz-^a||3k9FtK-}MrwHT!3m<9M^=w&_4#W_aPVGFD@GoL+$Rz}8krtLq2g7q= zNV!agY7G>w1tOHmRKR~JBDNv8>H2ZQ!INuX4M(YIi%R;c{US_2ie(Efq@+wm$4!t` z3)`6qvjapYj3`Iyp*t+)eJRF%xp~3psCW(qAvn+lDfNWtrRcHU6Dwow2kLDNNy%q} z622e*s=9+6udKc+Y_sZiwoL!dHI$^CGEX#a1#Bs*UuK0CCP?aS9YVIc_Ql3xRY|`=6iIm9`r|hz~qhpHv;qHMbRT{;vB>1x+ zM5{{dGO6th2;SZ7@Qm2VlAws4(jbI|e2MJ0x7KQvSDSYg%F$4kRTZr%ro=){fW(uh zilorgPEl7@i!2B3@kC3DQ;8wG^9=#sjH}{XhM}>i}LY&ACQ0#;38oi1zj^1&MF_KO$6I7tevM z{5_N+Fr}Vl4KfD^<42KvR`?Y%QjrVKK?n50QX^Ue@bNf{@tzALp2?<>u~wpPBzVxI zdA|B0n7Z!cOG+pN(N;Fp963?qzW%~gYv8Wlp4hVKOW5!*0RsF7Rg2>oo2KIjq7(tT zsJKV7(BWf_c=5FwQh#ne)0D__<~_W;yQc`G2xuKsW8uf@)U2s>6FK8$0zCbpW7s>W zamQkh6cZ%lVy@%IiNF#_i6V3WmG5OH^~nG>R|Eu>dfA1}1sp7>?X1sjSDw^9)q}aG zb^Dn-P;z_{_4BNFX=z?vT`lo1CJqiZq^H~Wt#aT z6feu_g~WN@3uk1l>#jB1vyHF&qGwB9f0A}v-^EBbh`s5hFgMI<0yE_XH01wxx%#!p zKSXx*@sP#xuWHfmQk({uG{}sE2qjBN5ue74uLKDArtfAql(Wb+r>924NLNx#Co>#& zqc~I&Zo?K$n^ItrNT-;FSlLiCnnHyG$x!I#M9JQpjs!92`@D-75NDja)oJRSIkf|} zM?w^Fw=+F3GIBg3K|yF~RYHs4`o76S`WKfF7gK~KDRgkx7YIO$qTCHLCX17yoI3%8 zIPWJKYtHm&2O;-+IkyeKh4^gPi%Tl||! zqe=LyFe@Zj+4BF$lFsNU1~u}#8Y~cUM1_@JE@gkM3%l=Q0_nATiEylD3nk1pTqf=I z>H9sb5}$~xBX$T5{soZfQ2`dwhXN^oB^girj-WPVX2m?-Q1{RMRwWJ_xOcNdQVXUr5`f!G#3+F6d+rC#BqAuf zS0#X{Y_#95|FK5wvAIC}n*&!s!57DA;Mb_3M+`P`y@h#Ly~{S^$Nm_T?jIKCYwa9a zPup>cgTbw~{#4nCq|mj9^!21&OPz=gkj9s|H#YotWPh$ zb-OLqGe$4|uV(Q}H#^(B$6cS+7mc+`<2LV?fx8{h94fv0UL)E1V(;!rS7-Hu zPUY}tw+%-{%V|2!S(tp(yL)wc@zsoQf9-CcbiI87|4ixLu=fM+z3=gF`Js4Gmr1jx z4|v_zL({68A}j(0tFx!+wdKud%4VK|?xeTuPps9d*p3TjOB^%3E0^Y&zf2#yQK=K4 za!#W3ud^8s?*_Aq?enfp6ar8zft#iV%OeOc+kz|~W6x~+mHIRT`&VIhX= z+XmM+)LD4pL!N);qSy(dB`-bs&FgR(lJJn&Dh3C*tRR7i61oCkl97oft+s?7p7dYq z(F09M17~mj-5xggPt_vBhOAL-1WqqYE8u8hUDp+Km^|_3D^Dl=wze)h4@%ai zyPoBytbIH6wHY%QcQ_q&wO%gVwf8l4mDEYwuKE7NCAkf9xvJ6!-T+BB9?~y?gSa3rR#y8T3oyN65I;k zKVD;)J{%4oELA)$!lhfNfPoS<`BZd6ky;z%YQzz=rb-4F4d%-wyO1c>9JxCUYTFX47jy?EaFKa{ zS>GbA-z}1Z7aCeW@z!55Dpn^=^G8R1J8>p9yxf^FXtMeoz?XNUnpKdDlnsmnq_r9F zF=HYjV_nFy;)TtJtk`w<(mw~dmM)U9*1M|C7aPHw*IEiOh+|4eY&fBr8GY$`b`_@e zG=??yChYIOKIX{vpEp`m4GeHW2sKb;pKLaKc0al$_) zbmm}~D4{5J&wF|)U}C!>Kkd4GYyW!R9wOf2@R7w!TC9v$&UM;2kmvt=k(vCmt`*%f zXG6#u--N^88oeR@1&X93?j&O!9H*^uf7S=an<+9P+6CJ5oz0;Lwwh5#-iMA3N&JZL z6)tBmik}(Nz9SM_>4zt6REX8l7y%;I7d4pvbVMdMOM)Y}l`15wC=LW@wfXPOxH{Mf zYi9jjaOLCUt140+?d7BWu4WuoP^!S3A`=FTrv#(sR2)RaE)J_vv`<$2OF=m)$-{&X ze3(t0H~9%%HIRk_hFl`@9{;Ri9+8Sy2=HA#AQpC_nG@)Q0o}>okgoRjcB>)TpFeAd z|7_Emp6X5{RK;jFA-}AM1V>EBJ@BD8)k}eJpy{nzcnWLf3Eh?ERblzTBAI zdDrB@q1WJDB?FI7CH%%{=nyF#bTDADr03rMI-UUX9-CKJ+19L7h$UHET)w?keehJ- zthAdAZ+eM)xKj=J?}Wux(2Sr88j&0PRuD_uRkq&%{Q7Z36MLf311ls`jGLxn58r@W zU;#$d^9P`+O&uKh$bz-qd{$EJFt1G$S#U?9U?S$FmdRU5`t?^otGi>2#rA^IgTQA#Cu=QRj9R5Et-C5o@8$%z8KL$OU&SYTr?jcPeu&((viwA-6y8JgN4&83X-@>>c6c zN#EI&F$@=|$jC?c{14*#B(mEX(3$tOE59IccuizoF-gIVwE5wFfm}XrI)IO0nSsrH zSjkj>_$KFMmgSi7Mk_xk8l?ZW$PqzLXN4THU}4{)ixl;9mX&{X6HDp&!DVxm(U_YDvZ4ok*nw919g3n z%8M*yvd!e}v9;c;_3nK`9ND3E#DM11S;Mnpe;9LF_` zIR#40_8t zUt_DKYBe117Q50$rhzgnV>HaoK8b_zQ>ty!iFm6fz`Di#_S;mbnjo$OM3R-CE!m$6oL23P~ebmC`GA6T!S@4d{mRu8)bOxcY#e^kB8 z?w0shW(b#l_SO9FBqmQ`RwR5QqM6whglz8!aWiy&0mf9&`F0|Ib(~yBp1XG>lD)!%1*NjE{J(bFbHE znwz>lt7C5a(*d%2KJ6WQ#rPtJM!O47%<{{Ht$E#&cC(e9?&-C1i1iuvY)H0^TGHer z%GJl+CvDfo+_q3Ujqa%nlfIX|ZhwP1M-V)W2QcsgTHP;`SNM^UOGl3F z>*{*7$dJ!LIQmX*A3seejoHpYLQM{2*=vo0^*xPE&P>3J7=8Vb-I@TWVBR0i`5^-K z_(y+0GCTKOpbFw2$-G12IDZH(sB4-$FcMfm7hD`>zhR=FgqV4_FXuGQtGhdg3y8Urw)+Y#If`~JL`GR$LkA*yUBW`_Tq|A>D^8b-6KD@?F1>U3_iZ) zWRx1E-5tU!EW)E-y?#8DBYc#2MSC1Hfl&zb+0ojHd&pXPl_ z(*~_-O7b-O`Mjr!-}RUT(QSFZgi>kTb$-P5h_Gt*NJ|67B1Ht$B>jD#(bYF21q5ZY zY=^@CvLPWs3ZAdGCKL($>iK|zGVrB9AC;}{;Hl5ens3Df=pjY$v)~Ua8e)k<0oFH+-v#Eo~MXzENOrlwx|fsbPP{$`cGg% zjCds)N^~I-dK*J%^dC^bSqy}G71&?;^wnd!sl_uzQt{uE%2#W3;dvDyREaV?pi&uqY2-2 zXsgm{zP#=w|AFE4cG~)6)iGhf8jMaW7bgjAOT$D%k6dH=vv5bQIbw8*V3&;F+UE?1 zXl<>P`JaMm+Mp{bRv0A)T*3$zt;ZnsAIwGW=Sj2{-oy>H`?J0swM6cTzPZipchVL?$G5hKspXY47wfNb0 z2*qKm;eMc{iY`c#%UGSww{d#+bdPfFPeOmYy^U(%3OKe~?j@9PJlSY>Hs@5--#rj> z@A%|tp6Yx95{%DMdaLW&d)xn~lvE0Q44L^PnnAT@MTNwZ5qFOKbCr#YzrAa(S_Guq z9<2v6DTT%C_qQiUpaoDWXFr1lqD2K_s-EspQMGwUo_KYGUV~@x9D)v<*yQ40$Zz-D zHfA*Nh%o*XoqoRkSB`IzS`^E>msuDSx^RBkJ+J)Veuv7&#kqOA_}Am6zzYThg$G93r1XZ15;q^<2) z@U2FVmQ9(DJN|+!xA$PZACS;5PAp;+Yluak+ZNq}j8l2;RXGM41J#Y~u3S;5uL~b} zl#DRrvEt$20Z0WR$MShQJ9ZLD`@G!F)MC^lI`YQS6RXKf>a(~!ySJtBn&3%}Fo?utA)1iz(Zpi23YnWJyPXgCzf1i^*!CH^h7h=ik&BUoLtyQKzQn zFtVrT1Rp%2bb~k;kYwTc+RhnK!6517=R0m05`%Dt%f+|m{y0$b=Fs9!E=Rq z$)z;LIwdcw!!Y7kZ=Mxo$;&f_X82=4!nLa9M*1LUf+%p)@Ip#S-nPTG%T{S+lZEfJ7fP6;h8*1MV##yo z4tNT4&WaJu-0x^gRRQ1ib znj~e97eofST7VAF3n^lH2o?B#Wj!4g5!q3STZau8(TY!JYA-Fe&*jBRrm^TK7|M!v z9Vl5abL5o8l^(^lanz(Q58sk%h>`fcYDERRt<)f*{ZrwwHkKFnUo{O*P~fPAG#q?{ zIUIx~no{CSU;>aDK^1Cc*bkCs8%oxGnuHF{8 z3ePD}F^R5N`zl;cFO@{~*sY?MmPm3ieiu>nwf=P$0Xmj(8G2@JVf?XIX{yTKDRyn4 z*KosUaN%WDje#SmPGDwI*zGXu-YDa^0~DbB%eXSbz8gkQA>l`eTP7uoM~U$DeFpY8 zr%cA~%}b8$0Rtz(Nn==P~z{*{7e$Gx_>dW$VoUoT!SA&5P z^TBx4*FdoJ54{cpo6=wFYrOVJndLIK1;m{H^IhPEloOf%4H97zape2RDvX*yc1~4( z=I=*+XYHkPN~^RzKx9H~U^rS?l3J)NR6Po9ktnpT`Sg+=Op(MG)HzQ*|uR2k~zothF;-rB`Ez{RAh*wc~IC2K7<$|)1=0o9TWYs;K~=PQ(JDe#npR6efllOi%d2d zKR{&*+K>0WBrEUx{U~1)9y~X%FvmyF#6shD{2z-xe2;1r9_~#7i+avp38j{EMj#Nb zR99o;&)L!8VQvS;QTrm;th7Vvqg#0lgZ6ll5=GdsNX4>D(?CIJg<4u|i_in}cjYIv zn6P^s9OCG}tgBz)j_B(l#zYg};-^D+ndyd-B`kRG<3uVO>e47^Br);QRPsKCHHnQ5?EH z4`Y<{*Z{S(e4>rtoeK9u*zKWi$+kM(PCM&Dt(|V1QLL%&lKgf$zR;rVPOMIP0`p*t zfebDay5Ao#eJP}Au+y*dxDy=W;@%AdJeYf*q#7)(3`$-M>;QFactjkAfdw?QS&)*@ zp{)Dhzu<4?8CLt^T>){<+OlfN+6wk+acv1V-eJ`Cg!2$m{p5yiOe}IciI8o6Wj&R7 zB!x_4<#4Ft{@)Y=6UIp}%=>*dwD`dDsvJ7(;}O65t5FQe1^Vn|T$U7Z`Y>N4mV z^*eb&ZcDkO_jh#ZE^e|GZ$oh%#~See+sBMY&J}w zc(%uD>xZEBhbV%M@EVuVNrClh9(E`(g321_K`>izfGt|-@SbP=Fl zjjYuMMxeC@CpGG(8{`G0V%_7=LDi*f%%}B}>q-ZdjirSForT287*iQb%y)}y-|C+% z>yfVDV5#cYYu~qmr!;i|*UR<2yC!oNnQvUme&e>9>VW%QBcG4ANALa&69ms(UGW)& z8Z{2t>c&C6k8#K9#&DB6?1d7TN0gY%)BiqxAoQS$?@}0~45hK^z;)xx&>1{Zc-c*v zn#Dk}8&WkQm4`B`H2TH2d>G_Em)Sk-$}DVIL+98TJ^RL5dys!9$SCKeI2GyU;wvyQ zp&_8WCFAyHXuzrb8Riv+EIdBrJ8to!{dod{C_@`YxFx6zY7(_{<7wQG)JTvgCj5KB z5_6QXL0T;ULj^oHwAPlVOF-ShUiPxb8e-F7+G9gfQMEw zelA(3s-xNuy@m=>A3DmF#pkfM%QvyZmL?Vqj%AkETWt9`aWy&%X~cfs$xztZa0uJ$ z>$4DX@?41}X_#P5pBwua$5OuiSX{H;omCf3cIs{oE1qB-_^7GK z?YL9?=>mml2<6XG$pewQUF`svc*`A)pe z4x<}&lILd%+Y4Q>;Cp|nf4yuY#JW+;H@Xco6VPz(OuHC-jUP`UTJbW=Xk1*+EAyR* z!yeJI8FOL-p3n8MBK_gXyT)v9>w$+ee}jsa{7bis4C(Sm!~%K`dms@6wIWmU z;`Lxo8406lAe%-M9kw#YkEl}Y0JP(23}vS6A@VnQ6L1(|r~E_=az;VlyH)csCB?XP z!Xe6coL2+O@dMBTX5iK>gqq-@cv$_S0)jaNi3ODl*x0sI)RfNcTNvD4B1c8cC8G%X z{l@q>MbMQM1KLr4O%Iy4^ZUTN7*ap6SVuD98g_-xKU<$GyZaLK4=rV?=#S6V?$81>85X)yt zx(gPJQ84@|;7e3Ph9O!hnPn9LKdr+H@0^>XtT#k&9U_z8po8;oFf9$R^d!FAI2Jdy zo{Nc~$Z6X*ylJp1oN<;l9YMz>vU~=?2YE<0SvARdWq1K-D6VKp$mn94h2t7QZNVsF z(?ra~DhEXx4#y8d5&$PvNeb1VKe_U|f+}q^KHx**`%!JyqhLiv8N6ds^77DXOh!w$ z&)E&%c!Bgn!rYv*zy3dt&{02fTbtJdV&}lI zH0)!ofBSYnbeem3Ul)x)qFEl0XcnfeneXm=r+!1<9ofE1NjM1yj1KUxYTMV542Tfb z)bwz{H+vEu9rJ*=Lf$W9=bMIW8tkzToZfe!m_&^Bq~A%Yu&6_vD$>$)k)m}wjB5J& z$X8TM{TEmJ8JFdEL$vlZ+!{E`O7nm;hMCTRTj%vPlSbX_m6seZHjG{>k|;e>*Jhd1 zIi?Ku3ci}BJ!+F5V-ZZHMDBargAuq=xpG`ED6k47oyvn+hpzqz$bdg-NUP5s&58VT zzS8k$EnQqp?kMaJ`v2W6YlvO$_wQEXloz)??r;%K{=z?%a_I9AB?d3L-MLv){>bak zAy#&)nI?%x{Gn(hi=4f*WEaOmtqDpB&o#8`g_G9go5+Kz%T~>NSS$AC_276JOPzE7 z1_5>k%BInjk;TX-sFG0IW&5Eq#?x#vfxqLG>FdB}ABMa8?W>6QPQRSv!+2+$U-SM{ z{;2b%{8y8cWTlTk_%{@BWfTD?6IB*`%rp%z*N(ts*dZ%wN%p}R@sI<~Zfl>rDvn2y zO|DSqVI{0-Lsim?wK*%F*M(P@uewWtd869L>zPZt8cRtU)3g zWlid|tv$#En_lawSUQ)=?>Kev>+KUx_^8qrp$T8al!HMh2A_~gjMo1z4(P~MlDEp)1 zG^XT47mLO<1WI{*6!_jMu^GU`YRD_;I2d>y8VC*DG*IPb-oi5c2sOovvCv?^ER`HH z*AW)+FNI9Imho#*u2aF3QAfH#`fcJLs~W=AH)x-xLaB*C(J2KKmu}#~xD-s+Ee-4o z)Eef38AfN#j4zQ$!^MaT^ZUM^NTcytE3eyS_jzu}J@jm8I+e}4mMxHZS`VrQVWc;m zs=ld9skCArP-o%w;6~Tk!d2Yh^f{p--r)cPVcX@6v1{ z+_k%;e3&o^%n#Xt(9co{)nJDtjC9+%PgxmO(E|N-%`v-BSX9lB3DvI@4NnJ zWU_<0D&GvQ@MLbd+Q~7GyxkUXCZPefI~OAQ3u-*dqn4~N+uev=Imp#aY=u|@L-E<+e9Qj=TMo77GpVVOM(eqV@7 zN!x}^>zS-zB4r+(XC}kW2oV9Mds)dOB!puRvqS{{rJ+Ds1Vh%zr($MG85ofFXp8LAhMD;bxby#g9{K5Em<^aZX510 zf4Hj5C*#9#J$j{d2;dW%;^$AkI3CW|?0tBx925RSJ^JMER7m=xIrTl2SqYbwOW0JY z067t?7TWVT016l&v+~;!6~SVy1~LqzU`+@Yw*|z~NX6}?kr`@fee)Y0!u*A_VxEH5 zkA)6^v?x!yRKb$$mk6Di$0STi8&Z**+f7THpQcj5Kn#wArNPj|s2c;ltz|sbxBhfO zk)gYLl9Fg_2nh2AO&UB|JR^ks?0FA9n3QwUTkMZ7zk8bZAGxpI*E3zb9l|>A2D`1> zeS^`akU%|S;2QrF9H&78%2-lJig8ZBUYlU9pCDPnIis+H7KQ!Q3TBf#V3kLJe$aprU0@Y(*!5b8COIXRN{h*!5qUe zMB~|$712TZB^%D?N5Hp_>tag!U--6hu`Z0YM2S%a`%3~J8>D^@hMVjcc7Bri*xUD3 zWxmCStuy@$K_LLOi9rigL%epFlETva%|U`DCn&G;kg&!&Y-h@m(<0;$!qUa|gcqfi zw2$usKDE{|hroEDewdPcuqBGPZ4*B-M9ERK17nDgiD4CMM0Ih%-+n+1)h=SL1t)cw zpelSn_kx`m6ErQA02e2=qDg9A+F1v!45=hK47re^Vl{c4VU8+CIE=V|?J`~@{$XrCe>g%V0V^myxJCxdlU7ZxJXs19*imATg3RfYc{F2nR?N6gOz>rw zA8-M4EI#x0`oRCT0?nHlfTd&aq8!~n`+}updt&NQ-GUdLJ zg9(C>qrQqMVTuxAs6~;PBnzi(7~>HeiTUfrY;{|nA*c6mJEil;)elc{Z6t>MwWlKu z6XIf|+SOqoE!?$WtqkX(3T>eCpX_y$y#jSMU^D!HGi z7ceo_q#Q+YAO_{|DTp{}$<(58zMzuY{J9gE;$NbeM{Ft^4ucl4yn6juQ3{fDu~+Q% zPG(c6m5zRc7IV6QTY&5tJcLE>{8zv|-7mrz^yi zIqm#rM$#Ao18Wrpev~xuFNvaMkgI3Jg7Fk2R1L+OEXhg#wbgA4-Q7}z6OJUUT{ySu z>`17@1rA2BvAb+az@7&~iV_Hdx(Qj*jQe+B-YT&X6ar{Q1L^RIkTHxX><2A4{FsXbqXmy*2I10}{U)@m1mKN~jB==Yphh4E z&>_^yvHIEmkJipAD30ju)3{3@=%B%aySux)6Kn<@APMfl-GdWclHl&{?he6qaF?C` z_toxJ?OyKoP50e7Ro!*!^m(86`9-RWI9co~&jP2uAAXpuas_$rjV-%1Ih<>^7C11#el(?uui|{`?u#Xl< zjof9oiNV-OKLMjY#GFhp-I_RkjTEO0FLTcy^505ZtaLe%&;i&lKV?J6mi!GpJ0EHe z#58!`dI}oF@*%>lml=&t3=3@LaybtWHL+~ej*n5I{)6{E-l=}C>UX4WK6hfyt6S#} zkT^##UJ^H5_MHPY=86a&G4TDq;{dVP`}#=e(634fe(zfmcyc?Ho23{ozqgyL1gOce z@xFuF2ZO#n(DLy8c0f!d(xTD#U_))rssLuk`4tjM5ofN#l>2zaZM2xF2OSR3b3Zv` zzv}Zco<~?e=X!WA_I7HCc@4GHN-kmHrkVa{+Ozp)dFp9{}InyKblHRH*pUFB))z5)sL)!r;(|4 zNYH_yi^{zSRjd*+(tyOi>eGP`sllzi2HM)B5waMvAAxX*r9_x?!QJ5vy|@yv)QGVp z=tweC1JV+yG(#0NEpW||v;nL{GBvliMU9Zdqmz$DtJ2X7TMq%#`jT7(iLrE=Xrx}q zG{Ts3DAn*!!D{V%`QMhGkgTt%&EC%f53nL?SvwAK{Wp_@)Eax;^bU5^&R#|XEnkF| zI^71h4@^m1$I5uWLL*3*LKh+8(=P@UEWMrU!Wkli4<>A9FY9K4t2HII=pFTZyBb*r z_9Audpbau7j`89Ku|=-<_NN>Tv-?Z5xB1hUj`~H!M5DXTkh@J00UwNIK5zh&^BBbE zElO^?7ylT5GUh+vaBh z*@`Lti+a!=oKpbafsC18A~l>+u_j$@bxREczS`;1CNwns^|d>mfk~>s()nEAWq)J8 z8d%rxd(Mg%wFW~4>J>;(h;tGn2tbC5f@{>5*XUwMl<7DKBvE(6B9KE{l16N%RZ!=9 zd3>a$-J|WdHmx+n+mq%@iFS)XNKC4?NngvcwAwhe1P@9nwY;neh((8BKl`PQKo8&DXl)*&!@~Wmqmm4x9=0n!O)8 z_*RdV(NqHQRTA^-(C9=8FPS{X_7es$f; zcOZqqe_B^Fy(^(V_dOY&6n?#3nQ;*2-Py;Sl-T{~E&{dM4dV+T=8vBZgoX@Yx?Op% z4%E2($H05E+F_g~(#s0f@9yXsyEoi}YUh(c_E$ki^5EefgJCmA{Nw6R zqD%3pRuUtTbF-_N%Jhgi_XmWW(dje>t-V_M+Q-+=RxD(wA)hR3b-0KU+`Pz$gTw>G zL+Lh{9Qy5#nX~__FV8Btd|iFL7lT@TC!L31F4W+!T7>k*HH`eh?*(QLT)ZWBec)j; zf2?$2*GXtTT+lRsyWr~yGI=w^UF6}nPHwAm+%>Q7o1)o8Q3=FzE9CFW(~b`ZqTv1A z-aKozo~X;kA;+JxB2Tj^9`AG}w+0JUj)j@0-R8Aosg>^xrd424yq_+V7lI~EUhfR+QWZ$4(-k94cKBr7)}vqY+nHaK|x_M|3xkSBN1o zl#?bs1z$c=LguTa_#AjF!$Yk_su$A>{wjHL% z>1a4FFqmXbU_6WkWIpv+~AWA6k$XITx4oL)3T zqvp*s*Pjlu#SLvkXH@|*&ODi<-$~ex5CZneekJrobHi~^Mo52&V1|12nRTPaEy7wU zF^3)>mh`E}<9_rO^mcCtb_aG$be!KcG%Q?3#0Syw1up%Hxq-n|kHX-vvz3zrGyhbk zLqbN*Ql(#kBXlf7l!0L)VhEbkR%z6~S&hY!-oLH``l~wk`qw$uy(L1{d{%t#CqGbE z-&4)urmbIOD4`B9k7k*ptuWzPK>ED7l3PuEE8gc>$mp4t!c5OdQM8S9BP^84i)Z15 zHirgsxxO}Zw6&hp|Dks`B(fzi5;SZH5RStd{>C*@GhHIn){ zZ7@F(ype&9fv!Q>zn_CAh)C+vu!`b4+2%#&NJHTk;2_Bxgpgp7;E@G6j#~%SU`t=j z=Z>o@;B8{DCEd9kV5B(g?P^`cnZ976z&mVRg^4uEh7ho_k}H(9AdR%W`MULJmL)tB zn4-o+2XJ~IErod(UIcy~65HT&Wz1Sz1h>KelkD-7z+~iZ1K4n7a44{%c|^harOn6Z z9&mHusl$bPcO7ud{usAnWn$*6mE}GRKlQ{1G-6O&aluiJ!*ccpfZ9wcrr^MVG^4V? z(@wS5Z68QO{3X;Wg1W1vnML?NSQ)^Na?&L|N^7B-wdMbyw#W-eEntBU4n_+81c*x? zw=pMGXH!o@TG@$}zC-y_f%asq5W6$2jGBX-KWuZeArarQft`WoI2H>K5Z1+T9m~q% zxH@|mFQM>s@RBX+&q2*X&CkRNi!7dO{XMhPcJGMRzsql0n#NE%Nm;g{XPk-u><7sdiq(n*fUZ!>;Iy3#a39 z$M6E^B|lbQNHdUA0I(^Jj@R9qZXw=Sb>A`RJvne=`gSxl_q0cZ1<55v5b+Q>QFG&i zS#yXBD87ks(g<(}ep09rl@F}O+p7|~f)7CoMx;WNfc|CF{08V-awc#CSeSc*zJbT| zDG?MniJ@%))xYaJbftoa+^{NAtbq~)JWZ;JHRVHqznWcI{6%RMpe`4n|Jj&ZJ0UxP zoNvniRLKShLj(Wrw?)67x5$iEkX}0(db&_e4kv7^4z|zw32hdVZXaK+x4T zDWC^yA9QO)*JCPut6*JTIxID7cF@^&S*G%}erhK`qdpQ&-q_Flx40xMx?9@xgqDeF zscVvPG{7svx6ifxKgcHHkDoXUv3U>#V!j= zeiXnIRnHQE>aut*+d>1Ztqzx?3BY-+LS9ejp~?-*1!LwTvblh|OX(-ZTKL}6|AqOA zxBi#)6+3^DFzYZ+P!A>$DFXM$&EEnM+Q)O@k04%k=X3jR?Vg@0QMPgPE1<`zxUGZB z4tJCm%0T`&d<0Ms)r@BieVi{skc_hhUcMBK;=?|oXnL}+DA$T1$t)N%&00qLhZ3ua zWA#s-DP#e^$#dUnAb+-vtX!~D7zqZZ3c)m88{_$sqb*{!fW!FG5t^V{19|6n>89@D-xh zY&=&(-C_-jn7}87F7L&~*zwvPxc3`K9?zhe=O9gf(sa$4{|3YRfTMexN2cJ5tQ((h zVvHC(W#$)C%IU`&(6_t^viGOblQ2G$>!|u4SwxSkY^L5k-mvBdSHr7mR=tBZ9NBPs zK2LY2zYDMGJAVp&`(mk8=9~BD{-+?<8i%B*9!VE(yEo|pg0Y)MgF%+l$VbV?9*!@O2^Hnfc_y6gd9V=TK{Cx;Gh?90Oh=&G4RUS%w|&2v@ON zqWNlz$!CVIeMz9q`3{$z0cyF}r88Yh?8;60$e@0QSXoPWDJh}Gvm**3n2%i+)wHvp z@ngO-qC-t`^)|G!xNvE{RHeJ(&YOX+$f3a!CF{CIdS{nu8Hey>fBwi}Ddj5%lYhDZ z{?VfoDWy;Ek|Qe?Hu{umH)#95e^4*iaku3E-DU?mR_E<%h4AG2>8x63$){A(2^d>< z-d#@%b#ZTW48|*vX?$WuRs~Jvq+7;|`3dqq~r=$JBG&P+{IU|<7 zGLk&)NaC{9g0&F|fCynmfmSP_I-)yA^iw*O&X@x`0Rmi^M_Xql#Te?8o_3Wy5k^T~ z>HQq!VLEu+_?VI*?Di^CqLD)6YiL`5g_50ZIiMg<*yhWw=DrSm=DHZ7U={ zvCk_lTU7UvuJU{3x@R?NY;g(Xx>{q)dGDQiK2#7OhT;tMhM>o8bn22!w4C1bom16h zQ8ohWj|fieusHmRuc>f+BHXxuD4GIPjh;F6NRp_5mN3~t>WE*L;E2g({egYrk0Dsg zDuX89;jO=heo>GiP>-Wl4Y-rQ(UgGwYcV&K_oa4K(>QV}9K>Y<#|EVm*i-hiZF&!< zJ~%d{YJ2VAhzj7u7S1Y|N>}tw<2tu*26a`~RX~roXvUe%syX>ZH4Jn$H1wWll-QP- zzq6*8Hrwb3PwYVHXxY#(S`A9}-98!k&=KK9L`h6JBfsZeEPlUxhwD48Jw);QyY^0R z+Cg**=Kshj+Pi_=hJPkJx!`IQ8R&KLBx=PH9-~n&==&#Lz2B{Q#!_sgFMwB2xOz=NR3D^jWv8_Ct>I|CF#Qb>`dwE)15G#JH z^ecguAStGD<{2x>P!ItbNkkz(PR$NKDfQGvXfY@E+35Xnd4{T6wLBhotTZ!DtW5J) zMfvLlaH+);cZ|7}Xe@|YsyDCxFfKoTIhpumAMRHusi+`->m2y}8NjStGLG}pBvY(? zZNCa9i>8_EuE?#Vm3dAdoZsrtpYspi>EJkOeMG2h*gqH!w}bNa@xqGSzgmu zfo+vIn<`@mmw^e391D^S z#)(EJEs2a$9HX24EuccaYdB(TV349%C{YH}Pc`nsJjwu=fTPv~fYD+T(*MT%m(LcO zJ!fIqU*j1l@J%-(=q_~|fu-L~#&ohAF-GsNsmIY(aRsY^>+&%zY^Rw9x5V6loGhve zC2FF&M;Kz|-z(iTPiCNL5Nxw)*ZkNn5-vR@nu@>XCnWfea5~&y>L}ztZB+UnRcnQb z$SLkh;Wywihf(pUgUEhKw8m{Gq6i}Rj9Bh`1jTOFyJOR%kxpXAMK`T^#y5s;C&=S1 zN$UiZDP&Mhz1aCGB1qd%Fhl9e5&rwmotP+x>rox1B10CWs9qY72X{KV!6}W*u4nda zi4H!Y2S_qOAhsL&l1qr-{EpIWPS-vrKCe#Of(P?a|uV$Fjo5ZAR5oI z62d(qD3F9Ab>CFM#RYWfCa01Z)J_jcCrwvJ3<3GMaU-Xo>E#zgZ`3T+9%!c@VhK6d z0_a36>~bbgCMO9!CdO)-id~PAd!6EB^N+01euBW}RZXSx-Qc88c;r#CR84Tg6`-2v ztZoUq<__p5Y-J2wkFOxW|Hxfd286+l_6zM<_mqtnhco+Qiy@ z^r^9om}AdY*;P`muCBzd8@<=p$+A@|MDVa+DQAG3Ws&*i05;SF;14Bqbxe(945Wg2 zyA+vptE2Lj3=jUEDx}DeG%TwSS&5ZQBk_8ehO5W+ju+0bdiSru_l;LcnjjmI?!^Lz zNQTI~39H zjr>;+{+)vJr0-ezy$+mqOMX~~+*NzsGrs%d$QZ$ADC zpy949b4QhL!T_)7oz zW;U5dC69}Tvz+eRa43^#$Hpvl|K;y{rXK$%r?VJo(;aw7rqqUB%)+>j4LS59v~8pR zZ@RG4pYR|P0`R!1?sVMfd>>+G>wpN1y`@K?HGSj}tB}WTBo}G(et#2f@XDxrrdMmP zv47u=t)jGkil|l}{d?w21`v)Tpw7l_+QNuz_EYZf3Wv#rW09WXMp4Hb(7)zLSCj6^ z!|KcD7|@JHl~7L6Ph}^GVIB=QM5QvM!lVm`ltl@k){bO1RQ|09+?l?ZqLk1A*t5%6 zR;#T&4lgY5PO+De( zKEvjXz~5fAHzyK}cV5^E15eQMP*hx}z>r&6M685muZ;D>o75|(ECF-#^+Jpuvl0K| zWDL&Uqpd1t;t;N0CGIl0H3HgN*B=F7h^X~u0H-90O99=5B%)TH0_6?}d# zjCf*=bEM~IIpUY$fVt%NnHW9O7VySc+rxB&3mzus+q#O=@1qQRHq+Xw>O@k}rQ9jn zC+&1KB$fSJ#hRj8+gjhuyE|8(P{RMP#n1crQK@W(b#0Wd1JmYop4-Q*=Rn46|0C^(p^SF0IpdvMduj{``k%^XxNJI;K<(*c@u=**Jrw!-O|u59#Ueb43XBR zLaUR7KPf3Gvn6VAsy`aue52s#Ujw#4JZzk1*A3HnWd#O9$ zZa3P!e<_xiyFzol-OQ;eQ$maB>FBze)Oj4gP>rFt6<1-Xz$r+Kq?vk^Rad+0kEQqa zmdw{6o4xORl=}j)E62QenQ=*1xTdn18eVO`N<{R8mTs=LH{Uv#oL7){Z4155#%rrg z)I?sOa?uOL!maWOLhCi5jD2Vl8SBUQIo99jEw^rQp7iXxcqL{JXT6ziI4n-&uZuoflr7w~cLRAN9ECmcnd`3xu zGa#>-dsJGoFgxjgPkDF4;mF>yvO-~r+kvS=fp67GCg1nKbo>-v(+NG|1+V7vn96X7 zN9YI&RQ&<@nIB`@dqrdF3z#@xNVQ2HfihfC@7gE~#qt+$sniQ+Ui< zE&?p6UnB1yVFM>7RKt1`hz$^69t^<1n*mwPk;2n>Zv`SdwHy`qhGAElHDaB)lt`{Ke88lnO&b0otdgO8 z^z{i@>_I|DXHQ4Zx$Si)_Y89Mn49}f$_Y6?3hKkhPrtjv$cu)&oT*W~yjA+$X0}@> zA9}bcF?escQ$Yz;n0CeLt)XW~aTMP>{@ktQVDZPli>?oyq1Vt#Zz{XW0#K)VTc1M( z4+!Me>}Fu5BB~g%-F+5Tkf25ZZs^Fs*TMl9HOvG<>?1LF5oFbC`Xb=$6kVeKX_h`K z;1o)Bh7`(&%@z#}%@Z)7U!a0K0!s{Zr@1p^nb^dorkR4e*vC>?jAWsR^*PYqUMd>q zH&i7w4&>#)K#zu5h^0jN-uk-L9o+f64smLFLkb&zD}eY9<~2@V5&>C<&gyeE(`FLMxfeHEm-te`Gy168^tV!L>nsbEC@ zJx|tz@L;mQo(6JuEI+_gTdYR!MJZ-ayrjF? zmE?zV4VwF_Gp75iWKW(k8+wcnLfTtC??|^ayDw?BIvC(+*8rEV5bNn4mx{kZ;NzRs zx#^Q0Ypm;2w>S1rQ|=KxbPi3Hfp7)UPw2vr^?Tqu=uvd{VL6_(9mCSRNE3bX8im5W z+7GHWn<_(nk_EMCB=paP9}_$L6e4M52Q6JRE`fHalgl%xnPbn^(~jolL<3Q4+zH8n z7A_%a{mK1yu7VEJK+;08-8FOefQw*3n8FWH{n8qw#Hd(USP~d8tgv!0?(&I;65s+0 z6z)~HGo4_N9Ru!0y_=pOQuB76u{fP*E+oqA<)0E;d+E?jiRiT&Mum=EH97XmhX|#d z?~JN%i6o-#2idu;ZY~@)>7IxP=WY8Qxh>z`thu7sSIr>&)8H`P&N|Dr>a9B=F+Zh# zk89%aeQ$~9YyYK`zfGqLlk1*miqBKElMWJnVHQX0{@yi+neHswS1X?Sqe=d&zDQ3) z!|80CH?MnRoZWB!-uD!1(kWfAKDEP6Etz#HGc$F+ZU`CiBF$OC`-N=V7$u{E^1}of zG;f7P4%&zZnuTngUV3Lq20O8wVue;Tx)@1a^Xduk@NHovo?1gB5uc($i&d_LmR}~? z9n&btR|y8x?GB#PvsLffY1Y5*`(AIHk9G*eg}>Kb4IbE)9Vvyr2afJ5>3q=R^XJ`F zsyIhQ8m51EM9?+<7ox$zT%f2to|T#nAp(A-{qu$8c_tdou)S;DO@7>syiyHZn>A26 zuV#s-yad5|G@+4r&@R|ql#vt3q7z`?pEJ&9^}XBNeC|2NYI|KU<8$6H)`N=rbQ@gv zM&91u#M$|4OpBKt=z@b(GI<@BYpgdrd|TZif7kB~EVT+2&zM->WI#t(JZi!TNlDL* zjhp4p4!-zc zlxEScLZvtv7Q(4h8XG}`3+g}jW`kJj+*1sDbw;Y7RyM`NA8K=UiOg8g7LD=IRMv0& zp)0GZRitW2IJ~XBJGX*lyJTxp3*7_z`-N5}M)noHLw4*$stwuv{^wcaHuME>-3Mp< zo-=m!`hOOh-L9`)-R$h`jal`Sl(+`nK%dJfe4A4AW_eFwKF=M^VEcI1{dT}7PMcfs z*}smWMh`%hY8lWv7Q#dHoP{(~k6J*qYtdq4v-8!oXE+cmVmOYfe`(p}U?#%)EB6z* zzDn708;TMX80a2dKbokTD!4^w%+ek8d8#vB8Wsnk8H~#j@p%4BE?o2sTIp=N?k-R1 zG`))IXKTOs!i{?sR=~*lMJEXhO@Y+#j}3Pl-G`f##H5e7`mO6ZKTF4z)nYy~xV@VX zu~}II6!5;?n_i&#T~aZP#tTzHDzzgIgl1=Nh-Wo@-pnUGqvnt95b;tVdOD8&kgaZK z(i{%DXV^Y7A8$-PF+g~~TZt_RJnCu0JSxopbQ(G-;p?J!vuOGw7&Eyt`CV}9y1&S_?15Dg=zWfnrJc%q*OZp zR4l0eMMov1bMHzxJg_ED%PVJvOZ00y^c=-08Hf!EvV19E}om<-|9 z!A_MQ=C2q{sFaZKQ0?l2Z06fcaaeGKI%jp zDsUD48U!*1V({vxgf0%|n_`wsl>k79DHbDwo3^j}6~U4EQ`{^Z{qf2<{ca9$QeVQP zVOdlgs8r0_I6rL+sI+p>idNKMbCwV!&DK5urm{sBE0pp$zS{3!QyUvzN^8*g>LrFJj0*ZJCK z>-135vX9K?IWS8?fa&`H0n|S9gxtY9pW5M?=}cWuAP>qKS-5OllAQA)GRrYC#-Wc0 zRG50R>#aZ6KS&0RxA@;)$s8Gm#(Isj%+DjMVzQ}a8eH|bq4yQBL;#m8ou2IuU@sT3 zDZ~{vz>hNPgxEw|NSQ(I$rFBCN6*F2$L@~5f3KNBCOe#OBOS_YxJLwv?9X>6&nj2+ zn|+-L{SPAX`~TtI1%Jm*V`x~e!&}*z0b&*smmCK>9V{_bK7|B)woOgUzj7WwJ>gL* zO1`?A(Q&^P$<@_yS~K-d?R>q&NB4vt);wV)70|AxzKUe5>Iv)oP8<1Leo&?F=ThOA z8VT#CODDs9SP#&9exq)e`tH4$u=45%Z*j(dvcJ3cQ{SzZ{w(!VYtij>3+u|)QD#jC zHxDA-K$>7vh>L)Ms*;8v=D~G~tSL_h@Syqp=G4dTyM*q0Kz18YdVz(mxWvN0qF>Ys z^zLlJ<~Wkhq@$s&PbsI=fPR)saa1&0Vun>)MVV^0R@FxKBCHY#tnzMK$$Fgar`;J+ z?d@34%_cg}iHqg-V8m^2>uZy~K+}*akKm-a>=?0EoPrE$a?61-)nBv-;lr1yTE7=?sbQ|N5s4Lf*3Zi8np< z+CMR%zx}b(|Fz$CfrTk2{iOgYNv~!*2D8^_*rOLC5&-t{P)STYK(Gy)PsvKOQJh65 zFVPli5uY`9K1Hl`6stqk9QLSDl8rr{Jn>K8<~Q^O$}@Ie1@Jj|)c4V(m=-+(?PZs1 z?a|-a$dg-EQ`_4*_&t7~w`s$Hxs)S;c~l~s+8y;}`N!sIz3hKJG7~2*5maE-Y|9V+2L&#aUV_%v_c7@2j?$SL|;~GyN7J>p%*0htT0n#{~ z6(@6z-W80ZM{{e<9N}(nQ{c9wmTwZA%3zg$#edJb3zDp01R` zoRN^fXuHd1CTb)Cw#cgWI%pY_(Aw^O9KdUL*|^HjDt#O~+D5CLA2`w?3Y13XIn2}4 zGRR%!HFkUTn)oSY5TbNIeEWIeMK01tdfbG*uw03X1(PfYw2_Dh%2iK*pE6si`>icZ zcaQDu?za-IA24jmDIHvSltd1eGmcXS1FBDj6{|Xmu#A+!LE0wB9Ix zex}Q`=r(Ci^CC1*8X2Z=bur>KV?=r|NGGlR1iM9_83etV*GT+-TwxE_yZR`1P`=O*;zc(3E)8-4`oQ7+g<&x4)p%%#kDtz7 ztS;LnaVDwZ15R)b76>(3jo5v5Qihd#0UOA fKLk{$&%MLYG<_g(R;uHMfnEwSs?vWY&4d02J3sP5 literal 0 HcmV?d00001 diff --git a/internal/glance/static/main.css b/internal/glance/static/main.css index a4b7591..5312e64 100644 --- a/internal/glance/static/main.css +++ b/internal/glance/static/main.css @@ -936,6 +936,13 @@ details[open] .summary::after { border-radius: var(--border-radius) var(--border-radius) 0 0; } +.video-horizontal-list-thumbnail { + height: 4rem; + aspect-ratio: 16 / 8.9; + object-fit: cover; + border-radius: var(--border-radius); +} + .search-icon { width: 2.3rem; } diff --git a/internal/glance/templates/videos-vertical-list.html b/internal/glance/templates/videos-vertical-list.html new file mode 100644 index 0000000..b7ea6b2 --- /dev/null +++ b/internal/glance/templates/videos-vertical-list.html @@ -0,0 +1,20 @@ +{{ template "widget-base.html" . }} + +{{- define "widget-content" }} + +{{- end }} diff --git a/internal/glance/widget-videos.go b/internal/glance/widget-videos.go index 398989f..bd36bee 100644 --- a/internal/glance/widget-videos.go +++ b/internal/glance/widget-videos.go @@ -15,8 +15,9 @@ import ( const videosWidgetPlaylistPrefix = "playlist:" var ( - videosWidgetTemplate = mustParseTemplate("videos.html", "widget-base.html", "video-card-contents.html") - videosWidgetGridTemplate = mustParseTemplate("videos-grid.html", "widget-base.html", "video-card-contents.html") + videosWidgetTemplate = mustParseTemplate("videos.html", "widget-base.html", "video-card-contents.html") + videosWidgetGridTemplate = mustParseTemplate("videos-grid.html", "widget-base.html", "video-card-contents.html") + videosWidgetVerticalListTemplate = mustParseTemplate("videos-vertical-list.html", "widget-base.html") ) type videosWidget struct { @@ -24,6 +25,7 @@ type videosWidget struct { Videos videoList `yaml:"-"` VideoUrlTemplate string `yaml:"video-url-template"` Style string `yaml:"style"` + CollapseAfter int `yaml:"collapse-after"` CollapseAfterRows int `yaml:"collapse-after-rows"` Channels []string `yaml:"channels"` Limit int `yaml:"limit"` @@ -41,6 +43,10 @@ func (widget *videosWidget) initialize() error { widget.CollapseAfterRows = 4 } + if widget.CollapseAfter == 0 || widget.CollapseAfter < -1 { + widget.CollapseAfter = 7 + } + return nil } @@ -59,11 +65,18 @@ func (widget *videosWidget) update(ctx context.Context) { } func (widget *videosWidget) Render() template.HTML { - if widget.Style == "grid-cards" { - return widget.renderTemplate(widget, videosWidgetGridTemplate) + var template *template.Template + + switch widget.Style { + case "grid-cards": + template = videosWidgetGridTemplate + case "vertical-list": + template = videosWidgetVerticalListTemplate + default: + template = videosWidgetTemplate } - return widget.renderTemplate(widget, videosWidgetTemplate) + return widget.renderTemplate(widget, template) } type youtubeFeedResponseXml struct { From 260bc1557726069b256a5e01770e7a824a822206 Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Sat, 11 Jan 2025 22:31:45 +0000 Subject: [PATCH 012/237] Remove reddit widget title forward slash prefix --- internal/glance/widget-reddit.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/glance/widget-reddit.go b/internal/glance/widget-reddit.go index 5025772..e7109fa 100644 --- a/internal/glance/widget-reddit.go +++ b/internal/glance/widget-reddit.go @@ -63,7 +63,7 @@ func (widget *redditWidget) initialize() error { } widget. - withTitle("/r/" + widget.Subreddit). + withTitle("r/" + widget.Subreddit). withTitleURL("https://www.reddit.com/r/" + widget.Subreddit + "/"). withCacheDuration(30 * time.Minute) From 5723fbdea566e13978920d88cc99842a4a20c608 Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Sun, 12 Jan 2025 04:21:47 +0000 Subject: [PATCH 013/237] Add markets widget link templates & automatic name --- docs/configuration.md | 20 ++++++++++++++++- internal/glance/utils.go | 8 +++++++ internal/glance/widget-markets.go | 37 +++++++++++++++++++++++-------- 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 92c5d8c..44f0b90 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1719,6 +1719,8 @@ Preview: | ---- | ---- | -------- | | markets | array | yes | | sort-by | string | no | +| chart-link-template | string | no | +| symbol-link-template | string | no | ##### `markets` An array of markets for which to display information about. @@ -1726,7 +1728,21 @@ An array of markets for which to display information about. ##### `sort-by` By default the markets are displayed in the order they were defined. You can customize their ordering by setting the `sort-by` property to `change` for descending order based on the stock's percentage change (e.g. 1% would be sorted higher than -1%) or `absolute-change` for descending order based on the stock's absolute price change (e.g. -1% would be sorted higher than +0.5%). -###### Properties for each stock +##### `chart-link-template` +A template for the link to go to when clicking on the chart that will be applied to all markets. The value `{SYMBOL}` will be replaced with the symbol of the market. You can override this on a per-market basis by specifying a `chart-link` property. Example: + +```yaml +chart-link-template: https://www.tradingview.com/chart/?symbol={SYMBOL} +``` + +##### `symbol-link-template` +A template for the link to go to when clicking on the symbol that will be applied to all markets. The value `{SYMBOL}` will be replaced with the symbol of the market. You can override this on a per-market basis by specifying a `symbol-link` property. Example: + +```yaml +symbol-link-template: https://www.google.com/search?tbm=nws&q={SYMBOL} +``` + +###### Properties for each market | Name | Type | Required | | ---- | ---- | -------- | | symbol | string | yes | @@ -1743,9 +1759,11 @@ The symbol, as seen in Yahoo Finance. The name that will be displayed under the symbol. `symbol-link` + The link to go to when clicking on the symbol. `chart-link` + The link to go to when clicking on the chart. ### Twitch Channels diff --git a/internal/glance/utils.go b/internal/glance/utils.go index 105cd0d..8455bfe 100644 --- a/internal/glance/utils.go +++ b/internal/glance/utils.go @@ -178,3 +178,11 @@ func itemAtIndexOrDefault[T any](items []T, index int, def T) T { return items[index] } + +func ternary[T any](condition bool, a, b T) T { + if condition { + return a + } + + return b +} diff --git a/internal/glance/widget-markets.go b/internal/glance/widget-markets.go index 48df6fc..63eda1a 100644 --- a/internal/glance/widget-markets.go +++ b/internal/glance/widget-markets.go @@ -8,17 +8,20 @@ import ( "math" "net/http" "sort" + "strings" "time" ) var marketsWidgetTemplate = mustParseTemplate("markets.html", "widget-base.html") type marketsWidget struct { - widgetBase `yaml:",inline"` - StocksRequests []marketRequest `yaml:"stocks"` - MarketRequests []marketRequest `yaml:"markets"` - Sort string `yaml:"sort-by"` - Markets marketList `yaml:"-"` + widgetBase `yaml:",inline"` + StocksRequests []marketRequest `yaml:"stocks"` + MarketRequests []marketRequest `yaml:"markets"` + ChartLinkTemplate string `yaml:"chart-link-template"` + SymbolLinkTemplate string `yaml:"symbol-link-template"` + Sort string `yaml:"sort-by"` + Markets marketList `yaml:"-"` } func (widget *marketsWidget) initialize() error { @@ -29,6 +32,18 @@ func (widget *marketsWidget) initialize() error { widget.MarketRequests = widget.StocksRequests } + for i := range widget.MarketRequests { + m := &widget.MarketRequests[i] + + if widget.ChartLinkTemplate != "" && m.ChartLink == "" { + m.ChartLink = strings.ReplaceAll(widget.ChartLinkTemplate, "{SYMBOL}", m.Symbol) + } + + if widget.SymbolLinkTemplate != "" && m.SymbolLink == "" { + m.SymbolLink = strings.ReplaceAll(widget.SymbolLinkTemplate, "{SYMBOL}", m.Symbol) + } + } + return nil } @@ -41,9 +56,7 @@ func (widget *marketsWidget) update(ctx context.Context) { if widget.Sort == "absolute-change" { markets.sortByAbsChange() - } - - if widget.Sort == "change" { + } else if widget.Sort == "change" { markets.sortByChange() } @@ -55,7 +68,7 @@ func (widget *marketsWidget) Render() template.HTML { } type marketRequest struct { - Name string `yaml:"name"` + CustomName string `yaml:"name"` Symbol string `yaml:"symbol"` ChartLink string `yaml:"chart-link"` SymbolLink string `yaml:"symbol-link"` @@ -63,6 +76,7 @@ type marketRequest struct { type market struct { marketRequest + Name string Currency string Price float64 PercentChange float64 @@ -91,6 +105,7 @@ type marketResponseJson struct { Symbol string `json:"symbol"` RegularMarketPrice float64 `json:"regularMarketPrice"` ChartPreviousClose float64 `json:"chartPreviousClose"` + ShortName string `json:"shortName"` } `json:"meta"` Indicators struct { Quote []struct { @@ -160,6 +175,10 @@ func fetchMarketsDataFromYahoo(marketRequests []marketRequest) (marketList, erro marketRequest: marketRequests[i], Price: response.Chart.Result[0].Meta.RegularMarketPrice, Currency: currency, + Name: ternary(marketRequests[i].CustomName == "", + response.Chart.Result[0].Meta.ShortName, + marketRequests[i].CustomName, + ), PercentChange: percentChange( response.Chart.Result[0].Meta.RegularMarketPrice, previous, From b4ac96ccaf13529f7dfe5414f5fee70cb33c68b8 Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Mon, 13 Jan 2025 10:47:55 +0000 Subject: [PATCH 014/237] Remove whitespace in template & increase popover max width --- .../glance/templates/docker-containers.html | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/internal/glance/templates/docker-containers.html b/internal/glance/templates/docker-containers.html index d9ff2d8..66c79fd 100644 --- a/internal/glance/templates/docker-containers.html +++ b/internal/glance/templates/docker-containers.html @@ -1,64 +1,64 @@ {{ template "widget-base.html" . }} -{{ define "widget-content" }} +{{- define "widget-content" }}
- {{ range .Containers }} + {{- range .Containers }}
-
+
{{ .Image }}
{{ .StateText }}
- {{ if .Children }} + {{- if .Children }}
    - {{ range .Children }} + {{- range .Children }}
  • {{ template "state-icon" .StateIcon }}
    {{ .Title }} {{ .StateText }}
  • - {{ end }} + {{- end }}
- {{ end }} + {{- end }}
- {{ if .URL }} + {{- if .URL }} {{ .Title }} - {{ else }} + {{- else }}
{{ .Title }}
- {{ end }} - {{ if .Description }} + {{- end }} + {{- if .Description }}
{{ .Description }}
- {{ end }} + {{- end }}
{{ template "state-icon" .StateIcon }}
- {{ else }} + {{- else }}
No containers available to show.
- {{ end }} + {{- end }}
-{{ end }} +{{- end }} -{{ define "state-icon" }} -{{ if eq . "ok" }} +{{- define "state-icon" }} +{{- if eq . "ok" }} -{{ else if eq . "warn" }} +{{- else if eq . "warn" }} -{{ else if eq . "paused" }} +{{- else if eq . "paused" }} -{{ else }} +{{- else }} -{{ end }} -{{ end }} +{{- end }} +{{- end }} From 1c03f0a07ab05faa53429996a061b6ca908d9654 Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Tue, 14 Jan 2025 10:41:46 +0000 Subject: [PATCH 015/237] Update forum post templates * Use approx number for points & comments * Hide comments when limited on horizontal space * Abbreviate "points" to "pts" when limited on horizontal space * Don't let domain wrap --- internal/glance/static/main.css | 22 ++++++++++++++----- internal/glance/templates.go | 13 +++++------ internal/glance/templates/dns-stats.html | 2 +- internal/glance/templates/forum-posts.html | 6 ++--- .../templates/reddit-horizontal-cards.html | 2 +- .../templates/reddit-vertical-cards.html | 2 +- .../glance/templates/twitch-channels.html | 2 +- .../glance/templates/twitch-games-list.html | 2 +- 8 files changed, 30 insertions(+), 21 deletions(-) diff --git a/internal/glance/static/main.css b/internal/glance/static/main.css index 5312e64..2a5db10 100644 --- a/internal/glance/static/main.css +++ b/internal/glance/static/main.css @@ -804,7 +804,7 @@ details[open] .summary::after { .list-horizontal-text > *:not(:last-child)::after { content: '•'; color: var(--color-text-subdue); - margin: 0 0.5rem; + margin: 0 0.4rem; position: relative; top: 0.1rem; } @@ -1023,11 +1023,6 @@ details[open] .summary::after { display: none; } -.forum-post-list-item { - display: flex; - gap: 1.2rem; -} - .forum-post-list-thumbnail { flex-shrink: 0; width: 6rem; @@ -1042,6 +1037,21 @@ details[open] .summary::after { transform: translateY(-0.15rem); } +@container widget (max-width: 550px) { + .forum-post-comment-count { + display: none; + } + + .forum-post-points-word { + font-size: 0; + } + + .forum-post-points-word::after { + content: "pts"; + font-size: var(--font-size-base); + } +} + .bookmarks-group { --bookmarks-group-color: var(--color-primary); } diff --git a/internal/glance/templates.go b/internal/glance/templates.go index d9b1a6c..fb2cb13 100644 --- a/internal/glance/templates.go +++ b/internal/glance/templates.go @@ -1,7 +1,6 @@ package glance import ( - "fmt" "html/template" "math" "strconv" @@ -14,8 +13,8 @@ import ( var intl = message.NewPrinter(language.English) var globalTemplateFunctions = template.FuncMap{ - "formatViewerCount": formatViewerCount, - "formatNumber": intl.Sprint, + "formatApproxNumber": formatApproxNumber, + "formatNumber": intl.Sprint, "safeCSS": func(str string) template.CSS { return template.CSS(str) }, @@ -45,18 +44,18 @@ func mustParseTemplate(primary string, dependencies ...string) *template.Templat return t } -func formatViewerCount(count int) string { +func formatApproxNumber(count int) string { if count < 1_000 { return strconv.Itoa(count) } if count < 10_000 { - return fmt.Sprintf("%.1fk", float64(count)/1_000) + return strconv.FormatFloat(float64(count)/1_000, 'f', 1, 64) + "k" } if count < 1_000_000 { - return fmt.Sprintf("%dk", count/1_000) + return strconv.Itoa(count/1_000) + "k" } - return fmt.Sprintf("%.1fm", float64(count)/1_000_000) + return strconv.FormatFloat(float64(count)/1_000_000, 'f', 1, 64) + "m" } diff --git a/internal/glance/templates/dns-stats.html b/internal/glance/templates/dns-stats.html index 7938038..8128edf 100644 --- a/internal/glance/templates/dns-stats.html +++ b/internal/glance/templates/dns-stats.html @@ -18,7 +18,7 @@
{{ else }}
-
{{ .Stats.DomainsBlocked | formatViewerCount }}
+
{{ .Stats.DomainsBlocked | formatApproxNumber }}
DOMAINS
{{ end }} diff --git a/internal/glance/templates/forum-posts.html b/internal/glance/templates/forum-posts.html index ae1ca44..513c428 100644 --- a/internal/glance/templates/forum-posts.html +++ b/internal/glance/templates/forum-posts.html @@ -33,10 +33,10 @@ {{ end }} -