From e5821c03f41383684f91382b9a99d8f8c56fa743 Mon Sep 17 00:00:00 2001 From: Darya Plotnytska Date: Thu, 16 Jan 2025 12:33:29 +0100 Subject: [PATCH 01/21] console: Toggle console theme --- pkg/webui/console/views/app/index.js | 16 +++++++++++++++- pkg/webui/styles/variables/css-variables.styl | 14 +++++++++++--- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/pkg/webui/console/views/app/index.js b/pkg/webui/console/views/app/index.js index 6a9f1c0f42..d22e8849fb 100644 --- a/pkg/webui/console/views/app/index.js +++ b/pkg/webui/console/views/app/index.js @@ -82,6 +82,7 @@ const Layout = () => { const { search } = useLocation() const page = new URLSearchParams(search).get('page') const user = useSelector(selectUser) + const darkTheme = user?.console_preferences?.console_theme === 'CONSOLE_THEME_DARK' const fetching = useSelector(selectUserFetching) const error = useSelector(selectUserError) const rights = useSelector(selectUserRights) @@ -92,11 +93,24 @@ const Layout = () => { const { height: splitFrameHeight } = useContext(EventSplitFrameContext) + const toggleTheme = theme => { + const htmlElement = document.documentElement // Get the root element + + if (theme === 'dark') { + htmlElement.classList.add('dark') + htmlElement.classList.remove('light') + } else { + htmlElement.classList.add('light') + htmlElement.classList.remove('dark') + } + } + useEffect(() => { + toggleTheme(darkTheme ? 'dark' : 'light') if (main.current) { main.current.scrollTop = 0 } - }, [page]) + }, [page, darkTheme]) return ( diff --git a/pkg/webui/styles/variables/css-variables.styl b/pkg/webui/styles/variables/css-variables.styl index ea2b82226f..994e65a5a8 100644 --- a/pkg/webui/styles/variables/css-variables.styl +++ b/pkg/webui/styles/variables/css-variables.styl @@ -19,11 +19,19 @@ make-variables($name, $theme) for $key, $value in $dict[$theme][shadow] {'--shadow-'}{$key}: $value -// Generate CSS variables based on token definitions. - :root, :before, :after - make-variables('tokens', 'theme-light') + color-scheme: light dark --grid-column-gap: $ls.s --grid-row-gap: $ls.s --container-vertical-padding: $ls.s + +// Define color theme and generate variables accordingly. +:global + .dark + color-scheme: dark + make-variables('tokens', 'theme-dark') + + .light + color-scheme: light + make-variables('tokens', 'theme-light') From 02b8605bbd425066f629ecd25de06fc99da6ecbb Mon Sep 17 00:00:00 2001 From: Darya Plotnytska Date: Thu, 16 Jan 2025 12:34:28 +0100 Subject: [PATCH 02/21] console: Switch logos on theme change --- .../static/logo-tts-horizontal-white.svg | 5 ++++ .../assets/static/tts-logo-icon-white.svg | 4 +++ pkg/webui/components/header/index.js | 9 ++++-- .../components/sidebar/side-header/index.js | 7 ++++- pkg/webui/console/containers/logo/index.js | 28 ++++++++++++++++++- 5 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 pkg/webui/assets/static/logo-tts-horizontal-white.svg create mode 100644 pkg/webui/assets/static/tts-logo-icon-white.svg diff --git a/pkg/webui/assets/static/logo-tts-horizontal-white.svg b/pkg/webui/assets/static/logo-tts-horizontal-white.svg new file mode 100644 index 0000000000..39b48f6853 --- /dev/null +++ b/pkg/webui/assets/static/logo-tts-horizontal-white.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/pkg/webui/assets/static/tts-logo-icon-white.svg b/pkg/webui/assets/static/tts-logo-icon-white.svg new file mode 100644 index 0000000000..7216bd60cb --- /dev/null +++ b/pkg/webui/assets/static/tts-logo-icon-white.svg @@ -0,0 +1,4 @@ + + + + diff --git a/pkg/webui/components/header/index.js b/pkg/webui/components/header/index.js index f07e1c2d1b..3b21bc4a96 100644 --- a/pkg/webui/components/header/index.js +++ b/pkg/webui/components/header/index.js @@ -14,6 +14,7 @@ import React from 'react' import classnames from 'classnames' +import { useSelector } from 'react-redux' import { IconStar, IconPlus, IconInbox, IconLayoutSidebarLeftExpand } from '@ttn-lw/components/icon' import Button from '@ttn-lw/components/button' @@ -24,6 +25,8 @@ import AppStatusBadge from '@console/containers/app-status-badge' import PropTypes from '@ttn-lw/lib/prop-types' import sharedMessages from '@ttn-lw/lib/shared-messages' +import { selectConsolePreferences } from '@console/store/selectors/user-preferences' + import Link from '../link' import style from './header.styl' @@ -48,6 +51,8 @@ const Header = ({ ...rest }) => { const LinkComponent = safe ? 'a' : Link + const consolePreferences = useSelector(selectConsolePreferences) + const darkTheme = consolePreferences.console_theme === 'CONSOLE_THEME_DARK' return (
- + ) : ( @@ -85,7 +90,7 @@ const Header = ({
diff --git a/pkg/webui/components/sidebar/side-header/index.js b/pkg/webui/components/sidebar/side-header/index.js index 858ac8a866..80534a61a0 100644 --- a/pkg/webui/components/sidebar/side-header/index.js +++ b/pkg/webui/components/sidebar/side-header/index.js @@ -15,6 +15,7 @@ import React, { useContext } from 'react' import classnames from 'classnames' import { Link } from 'react-router-dom' +import { useSelector } from 'react-redux' import { IconLayoutSidebarLeftCollapse, IconX } from '@ttn-lw/components/icon' import Button from '@ttn-lw/components/button' @@ -24,15 +25,19 @@ import SidebarContext from '@console/containers/sidebar/context' import PropTypes from '@ttn-lw/lib/prop-types' import sharedMessages from '@ttn-lw/lib/shared-messages' +import { selectConsolePreferences } from '@console/store/selectors/user-preferences' + import style from './side-header.styl' const SideHeader = ({ Logo }) => { const { onMinimizeToggle, isMinimized, closeDrawer } = useContext(SidebarContext) + const consolePreferences = useSelector(selectConsolePreferences) + const darkTheme = consolePreferences.console_theme === 'CONSOLE_THEME_DARK' return (
- + {!isMinimized && (
diff --git a/pkg/webui/console/containers/device-importer/processor.js b/pkg/webui/console/containers/device-importer/processor.js index 643a7145f9..73058d9357 100644 --- a/pkg/webui/console/containers/device-importer/processor.js +++ b/pkg/webui/console/containers/device-importer/processor.js @@ -32,6 +32,7 @@ import { isFrontend } from '@ttn-lw/lib/errors/utils' import PropTypes from '@ttn-lw/lib/prop-types' import { selectSelectedApplicationId } from '@console/store/selectors/applications' +import { selectConsolePreferences } from '@console/store/selectors/user-preferences' import m from './messages' @@ -60,6 +61,8 @@ const Processor = ({ handleReset, editorRef, }) => { + const consolePreferences = useSelector(selectConsolePreferences) + const darkTheme = consolePreferences.console_theme === 'CONSOLE_THEME_DARK' const appId = useSelector(selectSelectedApplicationId) const hasErrored = status === 'error' const operationMessage = step === 'conversion' ? m.converting : m.creating @@ -181,6 +184,7 @@ const Processor = ({ showGutter={false} scrollToBottom editorRef={editorRef} + darkTheme={darkTheme} /> diff --git a/pkg/webui/console/containers/latest-decoded-payload-panel/index.js b/pkg/webui/console/containers/latest-decoded-payload-panel/index.js index 2c4cbb0a6a..b1be694593 100644 --- a/pkg/webui/console/containers/latest-decoded-payload-panel/index.js +++ b/pkg/webui/console/containers/latest-decoded-payload-panel/index.js @@ -53,6 +53,7 @@ import { selectDeviceModelFetching, } from '@console/store/selectors/device-repository' import { selectDeviceByIds, selectDeviceFetching } from '@console/store/selectors/devices' +import { selectConsolePreferences } from '@console/store/selectors/user-preferences' import style from './latest-decoded-payload-panel.styl' @@ -95,6 +96,8 @@ const LatestDecodedPayloadPanel = ({ appId, events, shortCutLinkPath, className, const [copied, setCopied] = useState(false) const [isHovered, setIsHovered] = useState(false) const [latestEvent, setLatestEvent] = useState(null) + const consolePreferences = useSelector(selectConsolePreferences) + const darkTheme = consolePreferences.console_theme === 'CONSOLE_THEME_DARK' const dispatch = useDispatch() const _timer = useRef(null) @@ -301,6 +304,7 @@ const LatestDecodedPayloadPanel = ({ appId, events, shortCutLinkPath, className, name="latest_decoded_payload" maxLines={Infinity} minLines={minLines} + darkTheme={darkTheme} readOnly /> From f450e09b98be4f6c0e3a5fd5c886b4944df1a2d8 Mon Sep 17 00:00:00 2001 From: Darya Plotnytska Date: Thu, 16 Jan 2025 13:39:32 +0100 Subject: [PATCH 07/21] console: Fix LoRA cloud logo --- .../assets/misc/logo-LoRa-cloud-default.svg | 9 +++++++++ pkg/webui/assets/misc/logo-LoRa-cloud-white.svg | 9 +++++++++ pkg/webui/assets/misc/lora-cloud.png | Bin 21353 -> 0 bytes .../index.js | 12 ++++++++++-- 4 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 pkg/webui/assets/misc/logo-LoRa-cloud-default.svg create mode 100644 pkg/webui/assets/misc/logo-LoRa-cloud-white.svg delete mode 100644 pkg/webui/assets/misc/lora-cloud.png diff --git a/pkg/webui/assets/misc/logo-LoRa-cloud-default.svg b/pkg/webui/assets/misc/logo-LoRa-cloud-default.svg new file mode 100644 index 0000000000..f1f6ad7041 --- /dev/null +++ b/pkg/webui/assets/misc/logo-LoRa-cloud-default.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/pkg/webui/assets/misc/logo-LoRa-cloud-white.svg b/pkg/webui/assets/misc/logo-LoRa-cloud-white.svg new file mode 100644 index 0000000000..8b6f3b1ca9 --- /dev/null +++ b/pkg/webui/assets/misc/logo-LoRa-cloud-white.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/pkg/webui/assets/misc/lora-cloud.png b/pkg/webui/assets/misc/lora-cloud.png deleted file mode 100644 index 3bfd08dc91fc8fe00fa4771795017d974c48d734..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21353 zcmZ^~1wdTOvMxLjJUGE^a1HM665QQAxVyWP-~CZ%!u&!3clQT?a;t356Ovjw#^6&|g{?0APd|DKA7HQl<^D0)`?AW#(_uveGNrhom(k z9FX?e6S0E}6kI-D(E{qUa?({OhXP#c2nAgd;m8yLPVhizm_9F}9f%>4tE++%Hv(hm zBKp8KG$!tCnr|AuwONeDSrZdDhR)jWg7JtIh8!N5Ungdt&%Y*@;-&W@s-~$EpcFIU&q|=r09~b+bB&anL!M=cmG|)h3Dl}$q$RfsO8x=wuc1@obb_DbB!&v&dh?p6 z6mZ}wGdIN06Q-!;ua}HT?wFsf ze~5Goywk%BNBc^o1lCm){58*fXekci1Lx(J&-h~{5@XQ>vtMYom0yN#K-Uo#gmY{khuL$R&!8aEpK>cY&p2BmzZIv0O}G-Ohgai;xv!4eBeN$^S9h!)8^0Ez&-%86(9@%k_N>vARG08SBs{jum?p$0COZhpoZoF4<#^& zMH7Z-jlmRS$^_<#wBm4fD0Yw?@HivuNE+jwBrvZ~AN>p|5m*I&$a6b=7!l(%Cr$H{ z6{?-|s)P9`n4Fzx&f0=oE*|@Rf6CGv`WO6ZKcFC(kx^<4(#S}g7D}q0iII~Hnx>b! z>T?;QWx(4FdfB_B580g4pV zbl46E0t0ZONQP+nPenj03Ov&Epw{B}ix3G?rtmuv+a_G4u*JUAzWzRhzV<#-L+(qW z>SPgO?D%xa*E}rLEM);|vU0Lha(ogUa_6sWU+RZ2jM*KqI1_2fFym>4T8G4klZWMo zyg%qfeC$s~6-H4sl}}P^P)MW1q{>L(DucaO+hm&1%X&l0)m#u=nJ%%kK3+d2N6w>W>sGHmS-ziPkgX#1~I z76L3)>>Jp|xCyu?jONS-jI-=F4AM;LHtHsBeN}i(!e)j0DTNqoRU6D3zm_G^9XylyX8RA*?N_KEK+nAp!4$*&$li%65KGW^-(Ry|EqOr82;qk4nJoyMXTnI^i{X?=^OOuea=nPz2; zP4!uIbrrT5^Ju~R9=le=$7NNk)`7daQ!Q@KR^!(5Q=F5`CEUg9lgJax({qkVd~p0L z{1W^ME>!%*7|s}6JbKO?*-Tl(Lh8cE@uJ$~+CKL{$0wK`m@JfOlsOWcrb%rMx?s9` zx_faZaj|Gxf<=a_N6K#s#ov=+xpz;cDT6e{m(3@sm z5sop6mJ0`EdHQK4->M6O!Q6T8|0)()f0~VZ6lvR0TY`_WWW5 zMg@HIoi_r3$3TP0yKD+PaalGq_I>v%%PO7+{R^!MdRMkaPKfugNL24F-p?V)!0TXo z(2r5m(v-24QLHd~nYuYb5D_yOy7wVuV#{@vZr(=S5^#H3S(1Ka;&ag138XBfbXT6? za9a6kPcyh0-VmK6#@^?Lr8_o~(pr62{aD=@MG+H=ugCgozjDx|VPCk7eW|qN+TSS& zBdeZf$2~=)koxm$UVK85a{LV&C#k!r!(fmCnyDN|mf=@oNegMReDZu7xzh|RF8kZQ zah8d?>AK_i6AGCuCzqPxot0tnf&=MIInFp)2|3yI#Mdu`y_I|SrWZ`}W;ZZR0jvRL zJ-|(BgXAH-I-wiV8Gc96y&2lKvP2D?Edl%BCas>tviP>4n4z_V7d8rVGjUm88;7$s z9tT~IHKO7U7V#ynIj^Ie;!`Fwjp8zrb#`B8pI9En4jq3=aw?qn@Ee;i0n>ty8CO0A z0tPCZtrn6qh|&w+=rVi^LS~{wnKM5GqrY&VWl^OpGL1USKWp5ZIhxw0296D<%rGr@ z*bJ|XyKi2*j2Dhiq`p~JTV6(NExiAV$oI7Z|Cp!48bpTCrUHI2Le9-Mf@1L}bUXD@^Nxwd~9z~S*l?Q7P+Da|C{1U&5WnGqONVa{e z6K?r#WVSLsk8_@urc=`yEvo1uh?ip?`ZqTS0&ec9-B4o+tR`B z;5!O-=iicL?W^k>XJ1uDP@JW(J_EElFqgKl;%B*&mx|Y$>DCi_t=X>H-7Fyq5l zC-}&@s!ordN$pw=Gj@kf|rBcuF=8DAZcbwl6N-@CXu<24gHy!8Y= zKsOS?5%78Dx!qLP?l8XC_oGEpu*$7w5}d&ux7-Z&@pEMjXWlv|zZT!`|Jp~K@O`B@ zsC>_h=E0>mq<7P){XFt87qdW6spVnhdEP$kIdk7|l5yFZalUvi=PU7gk!QOkK0P=h z7n7C7C+^cRleMr;zdic+P8J(DU~v4s?U4|32S+4FN!d{-J{IpltAea)SqEzxyW)=m4bw1eJs(B|%Rm zBL@=`8%J|nr#%{mYfuENorH!X0DwXE`v#L#B)tIHO^z1I>Q3r1(p*Ni)^rBOwuUBj zZq|0c%K`AXae;!?CQb%GH)|^!M=m#B;{W8}0)>A^(-Q;#lf}uBmsnj!9w=<N zW1(Xp=7R$Qfjkbzrd*05Vt>g&|9FYbot*5r=;>WuUFlqz>1-X$=ovXVIq4ag=$V*4 zf^vLxbhmLbaQkTENb;wUf65UtaWrzUuyeAowE_Mv*TB%$*@>5!_;*GBe*U!6#LeQr zHQ6}+?G~tm^uJT+8R;14|6gQI7N-9{WWQ7Xko~7$f2!m8T^N^&qltsCt+lm@jT7I0 zN1W$BHT|!||F-iFp}d8giIuvD1&GoS)F(bRc8)umH8w;P)8vG4jy=f8ze{{E8-ywpPx+v#Z!xIPo$4CHcRi|5EYL|DKlrF-?DX z;6Je-Cg6kPq5qem_~6#!voiqz0f3~4pt2j-X$Ex42bK8{q<6hLL?rN%A_3rEA-))^ zN@o)@S-R+`sp|B$7%u7c!$(l2EcB&Ks(jHwGqp#D4+9cQphASChe(pXJ)wWNW6@F3 zS#4}-ZRxn?5p`B;az5AUpIx|LbCiu(iwfiHe$OZz7Rl+pzhU>t(> z|8ESqw4WhE7kicr1sE#u?-e1)_l{Hm{O^UV5B?z#tmDy&3pNh$_nIXRcz{hfe~|H6 zZ4p*YI#nJ;q@r4ZUH*V2owEQ3hK z!Sa)WZaJ^zEoWoWFWs4+n7+{(;QuZBgj_x_$7F>U4%yq0%_^R7-j;p-p-nTqLqsF+ z1pZLHv!U9FX+CwjfI*4rGieD_8{$8-0$eEBSar?c5=+F-zp<)Z-5yatekwPsTqe(7 zcD+AZOi#Md(I{a@0l!Q!U39RD#PgTP`|?kp;sjVAD4~QYRj4lSha*0vcC;vVsBGC5 zp!)jM?LF4-xRJp@m*m^dSn;#@JCpx2S`x@$5rUAvBENoe_qI=czE5`Oe(rRt2^fRt z%*jU$`OMj(5tEJiMGTxYZV7^1HeJ0upufL=uH*Xs??xYxBCA7x)%)Z+MDxCZ8b#fP z!}B00?URXt`cu8A$pAP-;`am~j{z_XQNdl1#?R0i!-F;qF-Cy_1VQ-&V zi3*QAMk>(*@}&Zou99Vg9TZEoHz^%T);`Wh{$-OkqPTg(i+!18lV>EY9RyawI8zz@ z`Cryd&$Z5C(!HDb?{`;R9>rFKkC~f7|6whl4oqG?mUe+5*c!iMt+b{hdF%8jVc*O? zqF{~flj(OJ7SCGksb+b)6M21zzPp=T+Vp=(iy@{z!B-Ujq(T~BqD7mHv#Tk$Q4L`k zt0+!_A1+TcxT)KvhDJ0}h`}9V0iW27z;C@PyL@D)Qd(Clk|rNb%$7;AE?XjV^=g$Q z$fy;4ozIUUf{Rzd)J^`UiY_g13nHk|gs=dZAUDapZrn!8-lgg9_DN1k$Ha+36$Y|0 z7G)UtAyyQv$r%A_vhbc0%S|#Ewvtiu+Ir1WHm{$*Z)sAi5!84-sEfC%L;cHvN5~iL zSV67~A#4jJx`LGm#Tzl!nIxgqmkZw&lIkkI9UhWt6>UtZ6Jt+r{8(<%@ligWP)YC0 znl-D0cTcL!Y7oqPDONr^R?=%JZJ7CYF;52y80T*WHhf%a(-EWeXIkw=X2hC4E$^v- zm)GF=g=r!M9owIUdm_OZx;w_^K45{h6ioT-m9IGqLO@!qGmld7ZpJ@zR(f}=tbDK7 zVV2FY>7$MPI~u66UCD+Q71*u&weEtYRW2c4Myw}an;oK#Aa5e)lpH@On9)`dCWJE7 zlt`=c7N$rQk8Z?X)3Z`sx0|3lcvgBi9AzFKQfKY{D<4Rc{OJ3E>C8@={-}P1R0@u{ z5w)&CM_|&>$7P1lhRx+>yd>*PJ;!b3;IbrdHHd*-A{=Rp$M2(ch44*k;Qx_C{(Wc{ z`B-hzkP>1Ov#yrgqr?H6zP>y~0wEwk-?XzD+x_hKRx?~&L^@tw>jrlxANWpD>VA#KtqT8gKngh z%JsftKcY*c1oJqOIbtXEJFX=E?gv!mzz0!*!$aYSog5#8JQe>Z#I4te_5KpIM36}M zBV#vg!Ov6#;Og(A-d#nlwAj8V+Gx=1BGVR@Zokgg$JEuq%ow`Ygy2g_xek3wTr?VO z&{1sgcJ;GxL{La71U2hjSi9J;w!!ml^kXkxdk7>I|7pcr} zpqKCVR}_)+Y_ z2I8urhSB@j@_m`LGlI>3rvTm`r;|!*EWfRF1e3aAP2;?B(G$#VYHhi-;|sp=xmYwI z^72LRE;^I7N*J8OV$FV&9mE?7CucDVZs0=4O;`kd556dV)2P4BGy z(>w1)8m#f)bx8pV|8O)4Rho*XrluuVAEMu4Is;-_2p)V$A~D#w28XVr*i#2P*Q05} zICnIT8OuMN5f1^SNdw`r;49Gsiy<+hRjSbq@TdgWgT31sBpAiM9DI2`sUs%otf{c9 z!b1i6d&A1ZpN$4-ffi>QNgSIY^5wNlG2b{|l>6r@MY0EAz?zOKT~=`!0dkN}Rl`W@ zJv>>+gz`1O8G+(E#f=LY+_^l#(7~7AJCB=`pW&od2WIXhm%g$wkCzD}hGPntg&e1+iGYS^Xt>?fkE?qt4s*6O(HmckzP=DB;10iQs^JHL#Fo^h!k`i<10@m z-4JY5;FQTL?Itn?iTJ494~Z`4=hS0}A@LUfLlKZ*49o1=-%A`J`2-ZCgdE<0xULvc z&|YEFt2kFx!!dqhJ9CS(!Cn6Jw~9;@m~<>JK}a=%>lafErD|JkA^ZdsmR}nlsUz;+ zlOmARXRwm`_o1lqr1=6qnawjy9}so1c#t=GQZ{Whiy3hT#Jx-%W~lCNfE#5}lb5wO-?CER&@ zYjTD73I zXNVG-fX}Vd*Q2NHN3b5<6+C&9>V;-Br&_^HVS1Sg#yhlPX-?~<}w!A~5TTaTqMDr#!toNiLt zYiDpd=jpV%OgC6-8D*d*8j}5GIiM)ai3%8UAc=U)tY-P%k8g$PShGt4kv$lcp$Nu2 z{@Vj$=y*8q1N3a+G)N%vJt(6^`{Bz<`A9@{bZ(n7HGz{YY-Oj9$PLSY8RS4W)n_Yw zE~mIaL@o&~mlMjDr+fCK^mIIa_HgIFLfStC_5?kUF&X&+jp(97Ly2s?^u}(zvQ=K9c7EHx%OnZu8iIVY6o(Bl8d%GQi!C3c6vGe} z>SpD5XL@M(c37ANmsDEWp&5dJOWqrbl)TpNc}$)8kES6of|`xxWN*nwU!0(Zk%Ub= z*>9nVBwD%sO==_>Qg}>QS-UF|i8}73w=J+SjhxDw$3P zT*Oa?>_5{EgX1p{oD{yhN8G;Lw5XN0U`dnz@WLvI9e($RR8a$HebadDiQcO`p0Zbda?wi`$*{lv!Tx^lLxoN&n?mxA z^FO>`0Kp-R2X;&1*f8{t+FNT^mbb@@Kk>M+;|kd(MQ7&XgH87Q1>Tx+y<=tLB~t%U`{UIpeZI+PQq15r z;IB}*cn=oQ9mgGP$Kd;Dl|j3VqeZXp@&jjDG&t~ZohuJ$wd;E%|XMAkE zNe9Dvk%*s?e)m2pQA+Yrc66KMQ~-A}$(MfY%ar$#loFYQvpTXTl#C6HYFV8BJLr*{ z!zix*1zljAq~*4KXfXLw6^rgHTO8%BQ?bAeCme-M3%F4`fz8$r~{_q?KV2PLtkFv)i{;RjzHpf4&C>kC$fi63$uK_<_L$5Bv2`h z$!Px-aDJ7rcH_TmIbX!5*2##^X*@robKbe0iQMTGl-a$K4PFY$o~xf4b&JQjd-*K! zMVhld++M~FP25OFC0z(#2zdd{0aW_0m;3cXrEu6l%ReKwjus{>^U#qx#lC@LeZ32V zzQOr5<0q5a8eenxmxcS53g;cao*kz$my%8`tnn9NNB1JVcNTgJEraxO`Rl!mEwl%` zf#l*GiC%9n_j_s;l79^Ou11hmO0v>Y?TriLfb}h8WBef6^Qb6ffJea5le%m|*&d1? zXGMA7-d3L@I%wf=KJ&Kj2d2p43HEaa1Gw@(CPdfye~J+t!^bNQiHubxMs_?U$D0|t z#_L8YLAfO#nrBuP`)ctS=FvsPc84tlL7q2#ziyPB@0#!hV#DD1to8heK85VBB`E+7 z(t$L)__Po(`71^AF?Z2VD1_O*T9|zp)|=%SVD!F0Kza%nBtGV{S!oi{jaeZ6YcHRI zT2W6TrxabUg;qz3a}7PJF_6$gN@)>5>|QvoKo z3webiwh?7ru*o}MmI&577S2& zR>WiPRv1Z)#DZy!4j)inSC_6-wft)$jT+AA)$VA%YPn{O#SHoI#02|m=7udC6H>kP zvg+q~`0=pO2J2PK^>jrVVLNH*N1 zSYjaj1snst-9E-mP8 z%hrv!&-H1D9` z;{*etBrA2>bNMECkQcl_J^WEQH&2n_^flde&3&$cY7al3fb~A5!FGMkZNk|2fN(Y+E6Rzz z>Bm=rl6!bfRqfL*-vKhIq@ff>qZ7nPi}eLPUl~SoVZ?UYgW?QM#{wYfL@=f<<Na5uztuWK3i!~A4gy&ISO@0geE_iM~afk=Gn zAxMOD-oI|Dx$~F!q7>D`CkTC?tCy<7UlmnV$!*(jlcZA^x(^Vdc7Ij2T}9~o>(kNE zC1vt@em?#vVw;EFs($p@711NK^Vbp0s4(zs1;jKJGWlCwdVrwqfU!5!%D=2x^yoaO|PR#1jDrk^Mc#jg+}A%V(4Tq zz1A%AGfolGo{kXd?;UqwmkP#t9WsgCVw$x1xT3YrKZV=1Lfd^eaiBIDc(XZC-|(I+ z8z}AUe$fpLX{Z(|lfk7@<#aG9C>Bd#4NrAUnQU@G4#~g;st|eP4|6$ zJd>;AG`c%kWb@o!M?b$dnFkocM_S}e;52ML_8=kiINF^}UAE;c*lrI*4@{y}gl2}y z_trCrL>+Iv0bZLnm)!O&NRjEmZnk*tej07fA;H5JZ-u^PxUON(Oxm}dM(%q>-T3`r zp5Q@~V@%o~|HeLXa7xJU)5h3m;SO}|lLp|Us51m_wj5W)gVAk(v zlqe?l{aWNcO@lF>~}agE(>kGQX8P-x7pi3}mkD$|u17JgZrjgW^q z1Q{T7hw&S7V1$_A3Vm4EV}X4K`xfrsHD9i^yJT6Jh|O#&;_UMB>lV@%^KRLezuPP< z|MqwRSN6k!yFC+pXwUmaq>x8{_7%H8>2GWwOODtq=cN&OZ{!0JUf+yf*IJy9jr$|e z1Ei&=utH{u#x}i#uVVn2Djb(9K2N9Mg?Z*b2<2?*$|bw(4_KS`(kxNwzt?HeXAj2U1#<&Gk|t|(zcw}MKxjGIuAa=Sa~qlRraLm>vrX|tFPG?b#5q*Ih75Rl zFbF0Pnih3-h{WZ8jp{Aye((MGH2spios)GjH5O8}a4VDYzXH{LNo>#*Z zyMFHwe=gfdTT_1gh~B1FrJsht(|YMTGt%pRKJ3XS;AUoKCjO$W2p@u0_Yjjzj2~X{e#_{P4WdmfR<$g|3|09+yjXW|@)!A&V{ZsTy&9PCr|L99ki7;%a$tNXGvITPbSHA4 zDh;J=yW*JPV~9;{fgOR6w2HC0)q!tueh6S=Xd*}n8GmBereW;Sr$&#A!^$J&Ic3Ed4+LQ7dHTee_2dylDV*7l!deV}{-BY9hDNOtGzDA5 zh{ck=CFqtY1HzPhypC-XT}}34df+t}3}LtXBL{Eprtr5=LdisEw-Q}c`o4^^>2c_0 zAAAhow-o@5W7IyT@KkDQs!d7qtPv5A7{T#dqEID&&v_s7J&JHwEZ?sp4dXu6HH8#M ziO39q2+_?jXumpDmta9u{t(E9b@{bti@jIGxAG{14v{n^FlTuMikP($$>0NZ(%7kw z`Zub#vZII`V~)5kLDH`|rw3FlS!&PO-PQ2lKZIj6a-#T6x<6kIS|bUUDXdOGSkb2t zbAS1SxHUJzu#RoTFhQ%^n{GAsy^hJPBLr>IEr`}KpK{E{(s<$c)e`~w)Sbkg~KeRlBet)fNYdze>|l#oxVI9|T^ zcLg?bFGXy$ZN4=!R3ZzZJSkv=#8gL%f!n}Jr!w_lec*_C-bC`PTFE-&=6l$9H%cDx z1KTX!pqW1j|G+>5PM-T4pLffu%~|AE03LBh&zM2x-cr5gN2xNCW{Pa?$v^|vyj^ip zw@bqzgkI;mb=c=~-?yii$O1W=exOI!*rR<~iT-m@Q@2Y@OCeJ7jL3wDrR4aX$n@a7}EF z%dJ!ja}~O_%JZge#L`tU)!gk^{xt`FR}nb?!Kz(UKwwPb=J{*&AOWtut5{z-*lJj^ zBG+BsVN_%aA|mO9ji?)B#(b{mdqFn;^j*e-@}N*=86^L$EyLx2lf8n48eV37ZX$>mK4Z+oq#T))145Y( zFB1EqHosR>#_*90+k?v9e0qr5YC@>z@xT)XF^c02u)}G#_fXWT0n%B7o+ui^2~FUc zpC%BR(WeS>?qYjlWFzs24EMRb8aHmUm#!*M_TI6#o9t^ zPNhQG`qhbyDKr6qT@Z8)lQd?P!%_~G^6aEzNRIL4xPEX#_~CJD zL_Obd*|ve)B{e=Sq~yJbpB(davKN=rerYTd5rWARamu6P3)0oiBQ_ZoPzBTpxobTL zD520Zgw6*;_auKKy4;Q~@4%vE1hfTO{|qaotA?q_-O8 zoodvXPx0|MSyjESDEaQy%0#(ya$u(?55r;dCK}8lDj^{OCM5b~Z}^~zV8oBcH!sJx@XC1%vrn5p$SmiJz$EO?a6xzlLpl}tAK@}Q z7LU0m5gZ{dAyK3*!ox264tmbuvVwC|P^H&PPaoGZYuX`;kpiKSVk}=(%{6keh*p3E zPIKtHebi9SNN7e6^Aq;?gdi<@QVado?B<~V=*B=dNNAF@+Zj|50@^~U8vUf(NuPf1 zPYzgKCq)i?w1aO4xtFqt{;G(i{%6>Iq(1n(EKPDvU~E97G~DBO@ac-`>@Jpu+BIk5?r5OpV z^zA*zWQ4PRKTy}t4g07{Wc;nC-YHD54j+DH9QQ`a92@_htu0DT&s*i!%^_L`=WfUL zT3RkrR&@$E!!GqG+!uj#2pl#ma}m@qU)-Vu_8<`j=qoJW8#K8f3CE{E_ znpZ8^F$6M_tu6KElnB%ri$?7sX3?;ZKPEAdtI9!n1h2qptgiK`I!o1`!bD#T;M#^M zIo%u2;tCb=$LkHC)l0`(%P3CD-inz0WTaenX zpW!u`(Equ*KnB$=fs3g+=iNbI--j|V>YIg6$1Wf;nGWm69t51G&JRf4Ldr$D)^)zM zD->E*hXyH$ei<9p-z`d@1ECOTOVf*Vl_>mkE$P}!gx}TmO1de*hw#F;=w{o5 zYV?+%%&7Gh&M>ZjF`Oje_bFckslpB*%lT7H=%9V&Z(A=2bNW_zpyPH$3jCEw|6UkD z2!dXsG&$Q>6I)B>v=0~(+i1H^2U32j(Ft}nWU2Ny62xbOyT(27)T%yZj2LWjJPzV= za3qZ$w~+Vi8~;M~+0XLrh{9$TJ9&*0#;&&lr({Ha(A)Tr7e&4Pd&l!txK&F3%RQdCzFyQGlo+h z(xTQRFeSV^4~RnXh(T@^4j^kvg80f=(_g5PRRnmYrBtP*u;qgKkl{D8ZV>hb5ufYX zN63$F@iq%<10*&LREK_HKMsf0s>j{4GwQ94{xz=dINsMpTvO4Wf<7(5s zBD9Or)3=x_AX}7*ech|pXNXR!53kFzqB(?kl8l{zzzV!vv%UsWe}UP=(-7yxY2>8Z zc=&4yGnHr{bnlJo+89Tt%r~~F58H0=ZRVEqWruFsEYKXmJ>dmW#`w%;<9N$bTD#$h zR#0EngW^6K5S~SuoN2Upppod+&XAhX+cJ8*qi;DN=6t!Cp@L|K_)#;CH-wMd~+tIx!%m&SSojEyE%QWjpO5iFQE47=a z@9+v+erBF*j#DWW{7mvWsUFlkLn_0{qiNk`M)`^VT|5?}kRQBdGew9Ym0$KN3V|fM zc#=3c$O5emz5tnPi)V8C86YgH%6e_KSjqZ+u*GqqLgxwuO=@PwcxXThBJvkkRWW!e z)t_^{xg;kfDARD?ybsY(a&DRJe0w>cEIGSgq?5JR@6XQK|8?pZ>fHub{LFB3V%qJ6 zNKekArlK+&hC+fWh9=y5fHI4|Hzd>F?G3W!10IEjKjhjRjTuRH#RxRotXc*4A6ItL z$)+-#jND&$fWWxfhF@=w6TViUMqPuTueuDMz)s((w0NvKG`lI?ULKprtKGdp?|E5A zhI>vTL0pCvTXuE~VvHH8GFlJ=!%4(7h;yrv%%$l6d}pB7R`nZ%GaXMq6rFlXNR=Q8 zgS}JJaZZ#@V;M$Xvr}&VbyUiWGWW!ifGYt6gFvR4sMvpZ-F5NC9TxK32Qu60OlB_G z2(5`Vt%bRpj3~WIEv?1H-9#{nBqc03|ScAm(Ai$tDGr}Np z!WL7ystmXh8qefiK5|g79YiwWKHpdVrW&ZgN-AFE=+Q0D(^Igh0h%l&ZE9}w;Wcr_ zrYFQGLjJXQEk^HOPVTpJYP?jq!CSA8Gz3-Ir@##2a^hXbD*@GwlZYIBgN3R2KmBoPMY8VEVqu$0ahA)yvP7mK6 zz=bd_{~J&x0$i5f^}MJ5!2kAhYBMcrUu%<$SC2Vylfbr;vvgm-|uIcfG2_eeFFG=o%O~7G;%w8dj)wOJMJj1GPt@uTx>SXd2I$`?j&j1 zgoAWw(53)i;Ub)ravw@7SFNtAn|aATakc`Qi*YP`do&Il-u{DOuf0^WlZcp4%8MA; z1{6Kno2x;belCoV_Eg4M-50(r_9&JXMc?QnC+BEFlDS*@+AnPC!6T0k8Fb*CX36H6 zHt>V>#AEqi-O5DOGeh06e4n=o^A)~}B@H&M`e$B;PAn9r{6h{p7nMnFd)B z3(UNA40w5?POJRz?~joK%rX13D_Tb#6oUa`?`=9?T!c>+!=Yv|iOi~iHv=Hphb|hI zoy|iT2p~dc_yjP6q3Dfl1er(`JjTMKBCom`j^RW*#IQLalN#45J;b3K;kG-#-2rCx zT`1B`6VU@ovSHUXXw|ZXBof_x@%}Cvi4oxL zg4~mGemGleste$?!txF;2>rn`_yb1?x2C41B%{XpSXHYq?lW|#cQ-Tqz94&sGH9Xc zLstUvg)7j=r5VVNLRXRGI`}|`L7F4|c7iSNG+W(+gnZ9tbJkdJLJ}BxPSXbQ6ml`G zSS#EdAqPx4j`GfPp}TQ@h~OzSx6@Me!@J3PbapXzOnBEI9F!B^wAB{`hc`T-HP>3q z6eJ}Fn)eU&=)L_~D1sOqB=n_K-(tL(M!;dA%p|_c^aMdMqaY5$QYiw4Y2K8G9!;%k zW%ojJ%)32yMD0B~6>Y7pV)2EiEzY$7}x@hn+pqM z?&fA@M^wcVWba}O>G3at#U@7WR21NAm&8+Jn9&d`Ar-It97|R5|c-Kqi zT2x_KjfW}$1@>&$gU8g`R(3i2zBkscg<~(pXp2hhsd)-Qe89^b-gdeFJhIRbOSk_6 z0eg4;_jZB;aDk#6*O~Xd-u-w(XtEsLkz4hN;fDxVOyas*Zm5zFy6{IM3Q^7ax_4C@ z`Q?s$k}cta&lA69vR*&f$3(@vIb$WQHanVWi*6DWq-{3K^n2vvP|OdmLx2vIzd!@M zR`LXDEm?yQJq&bx9!(@g&eL>sdhT+O^~y(i5ox%HA^G28pvnZnMNz@LGOf6L(5)Ng>Dp0zYJ}TaNEhE3bjxaJR&qL*xAS?3 z0(_C}^>h;)JYM}U0=|X%NvF`j?IAakZd#QT!m=#0&rWF}6&bHbIXSc(w#at9BS0Rh zrChh&V_;=c{Y}2BTQu|`K={4lXuoC4k90FRibx zG*sI=8P#ON$v&RUR=%bj>t`0dN_;MsI#`FVi!BKC!|{0j=rpB7E%n>A(0>R5oY!pf z89kd>8hS)Tj=%$VJ5@MLkKq7ec9A5k#T~^5a<|~C0TztEaXZ6Kxrm$)6G9B-D6#{If)Cxyik!!z=6EOf>-3nTyB=>?aM{>EaDWB9~Bu2=y7c0^LaLH|sQ3`c00 zOk^i@AOw($u^Kb$2UaMuulj|ZTVk zgEdE;TmSFynN(v$b>H4a5Rw22P%@7 zf-v@_o)wx{H3_c~DT*LOyO6?JyVa%KNdEfby>J4FA>Th9`kdPtZ$jRqzZ3rUpLZY34pe&I%MM0P z?=fk*3c}=$e+ZbXM#N!}0AU|W-roys={p{BzuXPU*xMc0J$kvp6>)?jaKEWZ*JG8suhCX(LTI z6anC0P6`lm2Ddc+zVPu73FyxreF{!y51C5>VdFtClB#k3k;Bu@rN}a+jz_>28DJxR+FiWUvTdJ}AZxT- zpgUavX_xedbZCa~?apo$8~Wh(#l1iVloOoxK^K0!3+YYl$bC*RMB_j1l75{qvkx+< zoh9il^{l}}9^wqz7!y+H<$Y3k;9$M3ZmG-dLrTeTmKZc(JmL>I{`Jdd!yo+Id{S;n z=egtBu7AIba=P`uUPcjMEQ&V`s<|KzO||q2k%#}W9f8?kf$VdT!?>{LQV}Qvn0TN0 zO=1GYhct!%!v$@y4-y;eTSKPdWaoVhD+L%oXnJn8b&N7Vi*EY2FPG-JE?W$QVvK;; z$XpouKTbfuMV^m{2>_1v4zpIzV^Y4AV=AOCde7?)M_wzoaD6+Ly3$_a} zpe>wHu#NxEHCrIXoR7|AIr(k)5U-M`i}x*($CyCmtd$U8i#OwFeShLpo(ns&-hK1> zKD4_H7~5BOI&}iS#|ZtSi6fDcx3jm?`$xJJm(vQJ&YE96b{fILQ;!nFylLD|j}*a) zgW!bm;Gu5`=hJ)c&w8fqVt&3hRV!8jzH)m`0x)+y*Ut^+?Hn88QnjblD`#7b-zWkey92h)szWAmn(~4elF0l4!QLsD5ESvm)Ww>F$SsV9_btG7Zpd3 z-yc4-%z+O(D3G7pDCrdXe9UxeGdy?MA?2TRsx%KeRL}E~Kp!1E@(K~Z>YF+83qNeI z=`g$>6EsHkv0~UjI{LA&Y^~ClU2|5lnKlUeoRzjN5o#7laC>;S@=yjnE!8S!ME6dG z6Q<@_bo-d6GM)yf}3fbLzm&4|9J>WzTNq`@=NZL9y9qK~c!qi^oQ^2jCEm z2cKb!(QE0J#xn}IN7tpCA5Y2J8+UOnCl-n{T4s;tdKCJ)8CXs*IqAdz-aVPS71ec> z1ZH{1@XVU;JB4c+{j*gF#H+igyV&>fXgBJI*WNyVCf{OzJOYdrSZv;@ z4xtW%Z*^-li?42;9TbtTM6(Hb`G}KeGxo@8S}V$G*96cjs!S@-Ha2?gfG*rx4|89$ApMdDUg-pwiB2foVqp>qB^%{UQuV%df`JhQR=DA!NFs5 zBXvGECqq^zB_=0nDt*cSwh9nAYr7C<@pW`1tZQeHe<}L%fe!*_;`Vfz#oh0mdltXy zttdD%g^TJxPflCRR2@a`f4 zScKOAk9veU-@Bfk4uq7-?s&j1oHS1lt0ffwGodIv;A#4&TLb~YNIIW zS^6X4i~y#~41>-fb2CsqP&i|xaq72?9-4cUPoj6;>3@{&@;(%La?2#P1~$$k>8s#N zyigbNSD@(nrY>_zlJ*;VPC*ftZE@z$Bm^@Dd;6z>MY&Kj+_ZeIW4W)pnY`H{ z&6vfpY9Jzi=$hp{-o_s9!z+(uVZI5mTmC^Puzw%shJGkLdrE2V2Wv>nZ5B-TXVyUy zch>u%kC}yTJ7&U+5bz&z2IcJS?M>J?_=AbaQ5D?pzXL#*vW|zyK>bJgW-nCYOWqV@ z-Fzw0U3MkX#5@usqlcS$O(0S^ByZDVt7`R}DiZq{zpMZXj%2FWsBW z74N3&kC7|4n(nQwI6ZHX7ag?hIdM%9e-;&>Sb?8n^BUTL zbQye4fw~nDzT?9OShxXwk(#2rE)+$p*c=4<_bQ_s*8T7i7DffpY2S=>0V}sgVIl}) z%&Oq!rE{h01vd)O^(^_-bRK;h{k)BV;{Sg0xBZlSpT^!Ws$XKep;q;56c%nGpd|W~ z=pW<98~#7uq&+kR@3a`?^+3#MI{w_1R7z)e(JY~R0ZFkAuB+#GFL@Wp@daB}bej9v zC)P(uo`g#+7<7f={p7S@McUM8(VK%N6lb7^b;%R#xeV>W@t>vGmS$f;36g9fT7F!L zoL5#LU<=yJe?{Vgn=Zhc3UxV^-^>(+!7;L~saPSr6J2YTl1wzrmzF%v1F#;*m7hYo zM33F?wcV{!Bg;nu;Ec`)s1Rg$yWS#+*q1m`8R{;Jh-#CqunI*Y5613|oWK}zAlFYy ze`@81%?oK#t5tzm%!-7=c7Xa>pWiNlxVzKXiME&DLe0et92sOQ9TVoO@={dmV(Xsb zvus?*ak{Ds6Y79n_oUQ=KN(a|S%Wc?mVV!$s|xPoDcTstUtPM7nOQqSILPBrOLm9Y ze!T6d0i@I(GZwg~{`w7*e5e*=vO2Q%Nr5paZTK6{x zs)4;DkL_0ia#U2MVC%E~D7-^?>@R85v=m`Rpv!ClGi<1`kwihjJtlHash0(pSSx{> z_lQa3izA*=L?xkvZW_+0(O+TQ7x9@zjJhbZ<*B6$gZdA-El` z-6&RiHJqhXK?h>scKl%JdJT$r>i;im#F!~A!e){Uq}V=?Plz=RP_h+r#RnaJI5TDx z)uElLpcsaqDg*g?QtgzNS3KM;Dq^M@JQyJN5C^wfM(v>EG8AtJI@OvCyim{=3uYCH zrl@Z0UiAD|0&_#09uEOAQFEO+M6M!@TBB@a<(F=naz0PYj_Paa$xh7r^WmlP*S< zP|GYh2rVdIn zPM`PKG0wOteA*_q)fJCl?EPkn%1xO6q{xYcv0OI%H>6crq}NsL&KiJzyk&+Lz4oyS z{IV#ZeeoWBn}R+2aaYlD74(KF5(2&tz+e^%{^%jKwiL@HBAeTHR`kN)`?;lqfokP zF=%rdx3pbt0c9Vc*?;{R(L``o5RP@qAWN4DHfJfCLNEtT&^Qx%bQXZit3X{xuDVq` z9TpeYo>dzPFGlASj*BS?Z51?#fBCv}fomiO4;uiwvZPxG5>v%j5#~>u>odE!Na{e< z|IW+oW98?Q{~?L94zL(mBtC5^TTkTQZ#8Q zuwFLo30^7)SUy0A|-S0#Fr6R5!0nz%bTJ+L7XLU5N3u+fYYWXp=3ooO#jXZMO zMkV_3t|21`dYSuol+(_Gt2O9hfS2QipOvC+ApN1?+4bL+>2kfdUeLgM{!o{|+Yu&M zlBwN?MXFp0H7cz<;`V`qkNo~aF0n> zx{Ljxx^a$KLU_^cunsuyb`rVbCs~6Bjc7A#T#n##i(RH5S^vI9Q@L`=nm!DB{iwdn zg+|}SE~&r07yP^yO4KDn^VYmQJVw;0Y#@sY*4Q@;&k>JqKA{Cy^#LmWLt_*kA(MH@ zWQ4K6T6K?ZVgn4lxg3JAUPnsuO^G~fZ*5MQzjPc2TAqIjLzy5#W%I`m%XnH28foBb z9;Ht_RCKvUIO*e1k_cJ+02Bt~X;sgiDZ0tUBjU+bJLCDX2xJ7v+tj7mSKB8@J->-N z|7mNGpm3JR+#0UdOwkJH>Vy=2ENazZ6L~`$Hz}|Cmhvlpfp3r;=US(Lo>>SRIZizP zLmbm;Uuy9Nxnw0k|F{P=K7~_uZx!*nh*5TYK&*)~3;+9S2a1}j zmfyt>=M&kh*+Jf0X=_G#)$TeEwA418A&LcUU#4KjNjw!eYLAm}hMhhFTBaEvF9a;o zTr*@-GlhFY!fSJVitd{5Fwl^AqC+*kSB6!c82`7(#-=k=ujG!(Yinv5&o8lHDe-$k zbN~&+*q>AezUPs^PX1i1AQ@~1HYz%>_M%-U0(s{GOqT@odl*micdu;Tagn2=U$oV4 Ks+FtUiTFPg$|0@* diff --git a/pkg/webui/console/views/application-integrations-lora-cloud/index.js b/pkg/webui/console/views/application-integrations-lora-cloud/index.js index c21ef0e25e..5cc91ef7e1 100644 --- a/pkg/webui/console/views/application-integrations-lora-cloud/index.js +++ b/pkg/webui/console/views/application-integrations-lora-cloud/index.js @@ -18,7 +18,8 @@ import { useSelector } from 'react-redux' import LORA_CLOUD_MS from '@console/constants/lora-cloud-ms' import LORA_CLOUD_GLS from '@console/constants/lora-cloud-gls' -import LoRaCloudImage from '@assets/misc/lora-cloud.png' +import LoRaCloudImage from '@assets/misc/logo-LoRa-cloud-default.svg' +import LoRaCloudWhiteImage from '@assets/misc/logo-LoRa-cloud-white.svg' import PageTitle from '@ttn-lw/components/page-title' import Breadcrumb from '@ttn-lw/components/breadcrumbs/breadcrumb' @@ -46,6 +47,7 @@ import { getAppPkgDefaultAssoc } from '@console/store/actions/application-packag import { selectSelectedApplicationId } from '@console/store/selectors/applications' import style from './application-integrations-lora-cloud.styl' +import { selectConsolePreferences } from '@console/store/selectors/user-preferences' const m = defineMessages({ loraCloudInfoText: @@ -59,6 +61,8 @@ const m = defineMessages({ const LoRaCloud = () => { const appId = useSelector(selectSelectedApplicationId) + const consolePreferences = useSelector(selectConsolePreferences) + const darkTheme = consolePreferences.console_theme === 'CONSOLE_THEME_DARK' const selector = ['data'] useBreadcrumbs( @@ -84,7 +88,11 @@ const LoRaCloud = () => {
- LoRa Cloud + LoRa Cloud
Date: Wed, 15 Jan 2025 17:25:29 +0100 Subject: [PATCH 08/21] console: Make progress with last dark mode tokens --- pkg/webui/styles/variables/css-variables.styl | 2 +- pkg/webui/styles/variables/tokens.styl | 25 +++++++++++++------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/pkg/webui/styles/variables/css-variables.styl b/pkg/webui/styles/variables/css-variables.styl index ea2b82226f..f8faa498d0 100644 --- a/pkg/webui/styles/variables/css-variables.styl +++ b/pkg/webui/styles/variables/css-variables.styl @@ -22,7 +22,7 @@ make-variables($name, $theme) // Generate CSS variables based on token definitions. :root, :before, :after - make-variables('tokens', 'theme-light') + make-variables('tokens', 'theme-dark') --grid-column-gap: $ls.s --grid-row-gap: $ls.s diff --git a/pkg/webui/styles/variables/tokens.styl b/pkg/webui/styles/variables/tokens.styl index f3c08ebf8f..a3a52f627c 100644 --- a/pkg/webui/styles/variables/tokens.styl +++ b/pkg/webui/styles/variables/tokens.styl @@ -199,7 +199,7 @@ $tokens = { 'bg-neutral-min': $c.neutral-black, // Background color for panels, dropdowns, inputs, tab, table, ... 'bg-neutral-extralight': $c.neutral-1025, // Background for navigation element items. - 'bg-neutral-extralight-hover': $c.neutral-900, // Background color for panels, dropdowns, inputs, tab, table, ... on hover. + 'bg-neutral-extralight-hover': $c.neutral-1000, // Background color for panels, dropdowns, inputs, tab, table, ... on hover. 'bg-neutral-light': $c.neutral-900, // Background for navigation element items on hover. 'bg-neutral-semilight': $c.neutral-900, // Background for the console dashboard. 'bg-neutral-normal': $c.neutral-700, // Background for the console dashboard on hover. @@ -211,8 +211,11 @@ $tokens = { 'bg-brand-extralight': $c.neutral-1000, // Background for navigation elements background. 'bg-brand-light': $c.neutral-800, // ? - 'bg-brand-normal': $c.tts-400, // Background for highlight elements. - 'bg-brand-normal-hover': $c.tts-500, // Background for highlight elements on hover. + 'bg-brand-normal': $c.tts-500, // Background for highlight elements. + 'bg-brand-normal-hover': $c.tts-600, // Background for highlight elements on hover. + 'bg-brand-semibold': $c.tts-400, // ? + 'bg-brand-bold': $c.tts-200, // Background for tertiary. + 'bg-brand-heavy': $c.tts-100, // Background for tertiary button on hover. // Semantic @@ -236,6 +239,10 @@ $tokens = { 'bg-error-normal-hover': $c.error-500, // Background for error highlight elements on hover. 'bg-info-normal-hover': $c.info-500, // Background for info highlight elements on hover. + 'bg-error-bold': $c.error-1000, // Background for error secondary button. + + 'bg-error-heavy': $c.error-1025, // Background for error secondary button on hover. + 'bg-success-normal-disabled': $c.success-100, // Background for success highlight elements on disabled. 'bg-warning-normal-disabled': $c.warning-100, // Background for warning highlight elements on disabled. 'bg-error-normal-disabled': $c.error-100, // Background for error highlight elements on disabled. @@ -254,6 +261,8 @@ $tokens = { // Brand + 'text-brand-extralight': $c.tts-800, // Text color for tertiary button label. + 'text-brand-light': $c.tts-600, // ? 'text-brand-normal': $c.tts-400, // Text color for highlight information. 'text-brand-normal-hover': $c.tts-500, // Text color for highlight information on hover. 'text-brand-normal-active': $c.tts-300, // Text color for highlight information on active. @@ -317,16 +326,18 @@ $tokens = { // Semantic - 'border-success-normal': $c.success-400, // Border for success element borders. - 'border-warning-normal': $c.warning-400, // Border for warning element borders. - 'border-error-normal': $c.error-400, // Border for error element borders. - 'border-info-normal': $c.information-400, // Border for info element borders. + 'border-error-extralight': $c.error-900, // Border for info element borders on regular elements like tags or banners. 'border-success-light': $c.success-800, // Border for success element borders on regular elements like tags or banners. 'border-warning-light': $c.warning-800, // Border for warning element borders on regular elements like tags or banners. 'border-error-light': $c.error-800, // Border for error element borders on regular elements like tags or banners. 'border-info-light': $c.information-800, // Border for info element borders on regular elements like tags or banners. + 'border-success-normal': $c.success-400, // Border for success element borders. + 'border-warning-normal': $c.warning-400, // Border for warning element borders. + 'border-error-normal': $c.error-400, // Border for error element borders. + 'border-info-normal': $c.information-400, // Border for info element borders. + // Gradients 'gradient-neutral-light-01': $c.neutral-300, // First part of gradient for default input borders. From 916a5df738e1e4ebb51a5ab62ebaa4af56c01ed4 Mon Sep 17 00:00:00 2001 From: pierrephz Date: Thu, 16 Jan 2025 11:03:39 +0100 Subject: [PATCH 09/21] console: Add button changes --- pkg/webui/components/button/button.styl | 35 ++++++++++++++++--------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/pkg/webui/components/button/button.styl b/pkg/webui/components/button/button.styl index fade683c19..b4650a1916 100644 --- a/pkg/webui/components/button/button.styl +++ b/pkg/webui/components/button/button.styl @@ -72,15 +72,15 @@ height: 2.5rem &.primary:not(.naked) - color: var(--c-text-neutral-min) - background-color: var(--c-text-brand-normal) + color: light-dark(var(--c-text-neutral-min), var(--c-text-neutral-heavy)) + background-color: var(--c-bg-brand-normal) &:disabled background-color: var(--c-border-neutral-light) &:not(:disabled) &:hover - background-color: var(--c-text-brand-normal-hover) + background-color: var(--c-bg-brand-normal-hover) +focus-visible() background-color: var(--c-text-brand-normal-hover) @@ -125,12 +125,12 @@ &.secondary color: var(--c-text-neutral-heavy) - background-color: var(--c-bg-neutral-min) - border: solid 1px var(--c-border-neutral-light) + background-color: light-dark(var(--c-text-neutral-min), var(--c-bg-neutral-light)) + border: solid 1px light-dark(var(--c-border-neutral-light), var(--c-border-neutral-normal)) &:not(:disabled) &:hover - background-color: var(--c-bg-neutral-light) + background-color: light-dark(var(--c-bg-neutral-light), var(--c-bg-neutral-extralight-hover)) +focus-visible() gradient-border(var(--c-bg-neutral-light), var(--c-gradient-neutral-light-01), var(--c-gradient-neutral-light-02)) @@ -156,11 +156,19 @@ &.danger color: var(--c-text-error-normal) - border-color: var(--c-border-error-normal) + border-color: var(--c-border-error-extralight) + background-color: var(--c-bg-error-bold) + + //Backup (light) + // color: var(--c-text-error-normal) + // border-color: var(--c-border-error-normal) &:not(:disabled) &:hover - gradient-border(var(--c-bg-error-extralight), var(--c-gradient-neutral-light-01), var(--c-gradient-neutral-light-02)) + background-color: var(--c-bg-error-heavy) + + //Backup (light) + //gradient-border(var(--c-bg-error-extralight), var(--c-gradient-neutral-light-01), var(--c-gradient-neutral-light-02)) +focus-visible() gradient-border(var(--c-bg-error-extralight), var(--c-gradient-neutral-light-01), var(--c-gradient-neutral-light-02)) @@ -184,8 +192,8 @@ height: 1.2rem &.tertiary - color: var(--c-text-brand-normal) - background-color: var(--c-bg-brand-light) + color: light-dark(var(--c-text-brand-normal), var(--c-text-brand-extralight)) + background-color: light-dark(var(--c-bg-brand-light), var(--c-bg-brand-bold)) &:disabled color: var(--c-text-neutral-light) @@ -193,7 +201,7 @@ &:not(:disabled) &:hover - background-color: var(--c-bg-brand-semilight) + background-color: light-dark(var(--c-bg-brand-semilight), var(--c-bg-brand-heavy)) +focus-visible() background-color: var(--c-bg-brand-light) @@ -220,11 +228,12 @@ &.danger color: var(--c-text-danger-normal) - background-color: var(--c-bg-error-light) + border-color: light-dark(var(--c-border-error-normal)var(--c-border-error-extralight)) + background-color: light-dark(var(--c-bg-error-light), var(--c-bg-error-bold)) &:not(:disabled) &:hover - background-color: var(--c-bg-error-semilight) + background-color: light-dark(var(--c-bg-error-semilight), var(--c-bg-error-heavy)) +focus-visible() background-color: var(--c-bg-error-semilight) From 899ecac1b97f31d693012f80e948831efad67006 Mon Sep 17 00:00:00 2001 From: pierrephz Date: Wed, 22 Jan 2025 11:36:39 +0100 Subject: [PATCH 10/21] console: Edit modal and dropdown menu colors for dark theme --- pkg/webui/components/dropdown/dropdown.styl | 4 ++-- pkg/webui/components/modal/modal.styl | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/pkg/webui/components/dropdown/dropdown.styl b/pkg/webui/components/dropdown/dropdown.styl index 33e568e2c6..64d3f7527a 100644 --- a/pkg/webui/components/dropdown/dropdown.styl +++ b/pkg/webui/components/dropdown/dropdown.styl @@ -19,7 +19,7 @@ ul.dropdown border-radius: $br.l border: 1px solid var(--c-border-neutral-light) list-style-type: none - background: var(--c-bg-neutral-extralight) + background: light-dark(var(--c-bg-neutral-extralight), var(--c-bg-neutral-light)) box-shadow: 0px 3px 16px 0px rgba(0, 0, 0, .06) position: absolute padding: $cs.xs @@ -149,7 +149,7 @@ ul.dropdown color: var(--c-text-neutral-extralight) &:hover:not(.button-active) - background: var(--c-bg-neutral-light) + background: light-dark(var(--c-bg-neutral-light), var(--c-bg-neutral-normal)) .icon margin-right: $cs.xs diff --git a/pkg/webui/components/modal/modal.styl b/pkg/webui/components/modal/modal.styl index 272cdc7ec8..90f64ebf11 100644 --- a/pkg/webui/components/modal/modal.styl +++ b/pkg/webui/components/modal/modal.styl @@ -13,10 +13,12 @@ // limitations under the License. .modal - background: var(--c-bg-neutral-min) - border-radius: $br.m + background: light-dark(var(--c-bg-neutral-min), var(--c-bg-neutral-extralight)) + border-radius: $br.xxl + border: 1px solid var(--c-border-neutral-light) display: flex flex-direction: column + box-shadow: var(--shadow-box-modal-normal) &-absolute top: 50% @@ -153,5 +155,5 @@ bottom: 0 left: 0 right:0 - background: rgba(0, 0, 0, .5) + background: rgba(0, 0, 0, .85) z-index: $zi.modal From 0f060de1f1510ed9ba6ed14a77f3ac42109d3427 Mon Sep 17 00:00:00 2001 From: pierrephz Date: Fri, 21 Feb 2025 16:33:22 +0100 Subject: [PATCH 11/21] console: Fix dark mode buttons and notification banner --- pkg/webui/components/button/button.styl | 22 ++++----- .../components/notification/notification.styl | 46 ++++++++++++++----- pkg/webui/components/panel/toggle/toggle.styl | 2 +- .../components/search-panel/search-panel.styl | 4 +- pkg/webui/components/tooltip/tooltip.styl | 4 +- .../network-information.styl | 3 +- .../console/containers/users-table/index.js | 1 + .../identity-server-form/index.js | 1 - .../basic-settings-form/index.js | 1 + .../index.js | 1 + .../containers/collaborator-form/index.js | 1 + pkg/webui/styles/variables/css-variables.styl | 2 +- pkg/webui/styles/variables/tokens.styl | 39 ++++++++++++---- 13 files changed, 85 insertions(+), 42 deletions(-) diff --git a/pkg/webui/components/button/button.styl b/pkg/webui/components/button/button.styl index b4650a1916..ef48a84dcb 100644 --- a/pkg/webui/components/button/button.styl +++ b/pkg/webui/components/button/button.styl @@ -105,6 +105,7 @@ background-color: var(--c-bg-warning-normal-disabled) &.danger + color: var(--c-text-error-min) background-color: var(--c-bg-error-normal) &:not(:disabled) @@ -156,30 +157,22 @@ &.danger color: var(--c-text-error-normal) - border-color: var(--c-border-error-extralight) - background-color: var(--c-bg-error-bold) - - //Backup (light) - // color: var(--c-text-error-normal) - // border-color: var(--c-border-error-normal) + border-color: var(--c-border-error-normal) &:not(:disabled) &:hover - background-color: var(--c-bg-error-heavy) - - //Backup (light) - //gradient-border(var(--c-bg-error-extralight), var(--c-gradient-neutral-light-01), var(--c-gradient-neutral-light-02)) + background-color: var(--c-bg-error-bold) +focus-visible() - gradient-border(var(--c-bg-error-extralight), var(--c-gradient-neutral-light-01), var(--c-gradient-neutral-light-02)) + background-color: var(--c-bg-error-heavy) &:active - gradient-border(var(--c-bg-error-extralight), var(--c-gradient-neutral-light-01), var(--c-gradient-neutral-light-02)) + background-color: var(--c-bg-error-heavy) box-shadow: none &:disabled color: var(--c-text-neutral-extralight) - background-color: var(--c-bg-neutral-semilight) + background-color: light-dark(var(--c-bg-neutral-semilight), var(--c-bg-neutral-semilight)) border-color: var(--c-border-neutral-light) &.small @@ -294,7 +287,8 @@ color: var(--c-text-error-normal) &:hover - color: var(--c-text-error-normal-hover) + background-color: light-dark(var(--c-bg-error-heavy), var(--c-bg-error-bold)) + color: var(--c-text-error-normal) &.with-dropdown&.only-icon:not(&.no-dropdown-icon) width: fit-content diff --git a/pkg/webui/components/notification/notification.styl b/pkg/webui/components/notification/notification.styl index 7fa4b01780..e03d2788c9 100644 --- a/pkg/webui/components/notification/notification.styl +++ b/pkg/webui/components/notification/notification.styl @@ -14,13 +14,13 @@ $border-width = $cs.xxs -left-border($color) - background: linear-gradient(to right, $color, $color 5px, var(--c-bg-neutral-min) 0px) +left-border($color, $bg) + background: linear-gradient(to right, $color, $color 5px, $bg 0px) .notification - left-border(var(--c-border-neutral-normal)) - border-top: 1px solid var(--c-border-neutral-light) - border-right: 1px solid var(--c-border-neutral-light) + left-border(var(--c-border-neutral-normal), transparent) + border-top: 1px solid var(--c-border-neutral-extralight) + border-right: 1px solid var(--c-border-neutral-extralight) border-color: var(--c-border-neutral-extralight) border-radius: $br.m margin-bottom: $ls.xxs @@ -44,20 +44,42 @@ left-border($color) margin-right: 8rem &.error - left-border(var(--c-bg-error-normal)) - color: var(--c-bg-error-normal) + //dark + left-border(var(--c-border-error-light), var(--c-bg-error-heavy)) + // light + //left-border(var(--c-border-error-normal), var(--c-bg-error-bold)) + border-top: 1px solid light-dark(var(--c-border-error-light), var(--c-border-error-extralight)) + border-right: 1px solid light-dark(var(--c-border-error-light), var(--c-border-error-extralight)) + border-bottom: 1px solid light-dark(var(--c-border-error-light), var(--c-border-error-extralight)) + border-color: light-dark(var(--c-border-error-light), var(--c-border-error-extralight)) + color: var(--c-text-error-normal-hover) &.warning - left-border(var(--c-bg-warning-normal)) - color: var(--c-text-warning-normal) + left-border(var(--c-border-warning-light), var(--c-bg-warning-heavy)) + border-top: 1px solid var(--c-border-warning-extralight) + border-right: 1px solid var(--c-border-warning-extralight) + border-bottom: 1px solid var(--c-border-warning-extralight) + border-color: var(--c-border-warning-extralight) + color: var(--c-text-warning-normal-hover) &.info - left-border(var(--c-text-brand-normal)) + left-border(var(--c-text-brand-normal), var(--c-bg-info-heavy)) + border-top: 1px solid var(--c-border-info-extralight) + border-right: 1px solid var(--c-border-info-extralight) + border-bottom: 1px solid var(--c-border-info-extralight) + border-color: var(--c-border-info-extralight) color: var(--c-text-brand-normal) &.success - left-border(var(--c-bg-success-normal)) - color: var(--c-bg-success-normal) + //light + left-border(var(--c-border-success-normal), var(--c-bg-success-heavy)) + //dark + //left-border(var(--c-border-success-light), var(--c-bg-success-heavy)) + border-top: 1px solid var(--c-border-success-extralight) + border-right: 1px solid var(--c-border-success-extralight) + border-bottom: 1px solid var(--c-border-success-extralight) + border-color: var(--c-border-success-extralight) + color: var(--c-text-success-normal-hover) .message display: flex diff --git a/pkg/webui/components/panel/toggle/toggle.styl b/pkg/webui/components/panel/toggle/toggle.styl index 88d237d00a..9c23218c9f 100644 --- a/pkg/webui/components/panel/toggle/toggle.styl +++ b/pkg/webui/components/panel/toggle/toggle.styl @@ -49,7 +49,7 @@ color: var(--c-text-neutral-heavy) &:hover:not(.toggle-button-active) - background: var(--c-bg-neutral-semilight) + background: light-dark(var(--c-bg-neutral-semilight), var(--c-bg-neutral-extralight-hover)) @container panel (max-width: 560px) .toggle diff --git a/pkg/webui/components/search-panel/search-panel.styl b/pkg/webui/components/search-panel/search-panel.styl index 509ae5d47b..795de9c92a 100644 --- a/pkg/webui/components/search-panel/search-panel.styl +++ b/pkg/webui/components/search-panel/search-panel.styl @@ -21,7 +21,7 @@ overflow: hidden position: absolute z-index: $zi.modal - background-color: var(--c-bg-neutral-extralight) + background-color: light-dark(var(--c-bg-neutral-extralight), var(--c-bg-neutral-light)) left: 50% top: 10rem transform: translateX(-50%) @@ -48,7 +48,7 @@ outline: none width: 100% height: 3rem - background-color: var(--c-bg-neutral-extralight) + background-color: light-dark(var(--c-bg-neutral-extralight), var(--c-bg-neutral-extralight)) &:focus::placeholder visibility: hidden diff --git a/pkg/webui/components/tooltip/tooltip.styl b/pkg/webui/components/tooltip/tooltip.styl index 18df47b6d0..49acd73504 100644 --- a/pkg/webui/components/tooltip/tooltip.styl +++ b/pkg/webui/components/tooltip/tooltip.styl @@ -18,8 +18,8 @@ .tippy-box { z-index: $zi.tooltip border-radius: $br.l - background: var(--c-bg-neutral-heavy) - color: var(--c-text-neutral-min) + background: light-dark(var(--c-bg-neutral-heavy), var(--c-bg-neutral-normal)) + color: light-dark(var(--c-text-neutral-min), var(--c-text-neutral-heavy)) padding: $cs.m max-width: $bp.xs3 transition: opacity, visibility diff --git a/pkg/webui/console/containers/network-information-container/network-information.styl b/pkg/webui/console/containers/network-information-container/network-information.styl index d4014aacb2..98ef6040cc 100644 --- a/pkg/webui/console/containers/network-information-container/network-information.styl +++ b/pkg/webui/console/containers/network-information-container/network-information.styl @@ -14,6 +14,7 @@ .registry-totals-container display: flex + justify-content: space-between gap: $cs.m .registry-total-box @@ -23,4 +24,4 @@ flex-direction: column padding: $cs.l margin-bottom: $cs.s - width: 12rem + width: 100% diff --git a/pkg/webui/console/containers/users-table/index.js b/pkg/webui/console/containers/users-table/index.js index 4a812db040..9e1b06bcc7 100644 --- a/pkg/webui/console/containers/users-table/index.js +++ b/pkg/webui/console/containers/users-table/index.js @@ -218,6 +218,7 @@ const UsersTable = props => { onClick={details.delete} message={m.revokeInvitation} icon={IconTrash} + primary danger naked /> diff --git a/pkg/webui/console/views/device-general-settings/identity-server-form/index.js b/pkg/webui/console/views/device-general-settings/identity-server-form/index.js index ed23ecf825..336b3a391c 100644 --- a/pkg/webui/console/views/device-general-settings/identity-server-form/index.js +++ b/pkg/webui/console/views/device-general-settings/identity-server-form/index.js @@ -297,7 +297,6 @@ const IdentityServerForm = React.memo(props => { }, }} onApprove={onDeviceDelete} - naked danger /> diff --git a/pkg/webui/console/views/gateway-general-settings/basic-settings-form/index.js b/pkg/webui/console/views/gateway-general-settings/basic-settings-form/index.js index cf96f83fe0..2fec48320c 100644 --- a/pkg/webui/console/views/gateway-general-settings/basic-settings-form/index.js +++ b/pkg/webui/console/views/gateway-general-settings/basic-settings-form/index.js @@ -261,6 +261,7 @@ const BasicSettingsForm = React.memo(props => { } type="button" icon={IconTrash} + primary naked danger /> diff --git a/pkg/webui/console/views/user-settings-oauth-auth-settings/index.js b/pkg/webui/console/views/user-settings-oauth-auth-settings/index.js index 3683583955..8866e4f5b6 100644 --- a/pkg/webui/console/views/user-settings-oauth-auth-settings/index.js +++ b/pkg/webui/console/views/user-settings-oauth-auth-settings/index.js @@ -110,6 +110,7 @@ const AuthorizationSettings = () => { message={m.deleteButton} type="button" icon={IconTrash} + primary danger /> ), diff --git a/pkg/webui/containers/collaborator-form/index.js b/pkg/webui/containers/collaborator-form/index.js index 4c649f5e45..ac6185b352 100644 --- a/pkg/webui/containers/collaborator-form/index.js +++ b/pkg/webui/containers/collaborator-form/index.js @@ -232,6 +232,7 @@ const CollaboratorForm = props => { type="button" icon={IconTrash} disabled={deleteDisabled} + primary danger naked message={ diff --git a/pkg/webui/styles/variables/css-variables.styl b/pkg/webui/styles/variables/css-variables.styl index f8faa498d0..ea2b82226f 100644 --- a/pkg/webui/styles/variables/css-variables.styl +++ b/pkg/webui/styles/variables/css-variables.styl @@ -22,7 +22,7 @@ make-variables($name, $theme) // Generate CSS variables based on token definitions. :root, :before, :after - make-variables('tokens', 'theme-dark') + make-variables('tokens', 'theme-light') --grid-column-gap: $ls.s --grid-row-gap: $ls.s diff --git a/pkg/webui/styles/variables/tokens.styl b/pkg/webui/styles/variables/tokens.styl index a3a52f627c..87fe521443 100644 --- a/pkg/webui/styles/variables/tokens.styl +++ b/pkg/webui/styles/variables/tokens.styl @@ -69,12 +69,22 @@ $tokens = { 'bg-success-normal': $c.success-600, // Background for success highlight elements. 'bg-warning-normal': $c.warning-600, // Background for warning highlight elements. - 'bg-error-normal': $c.error-600, // Background for error highlight elements. + 'bg-error-normal': $c.error-500, // Background for error highlight elements. 'bg-info-normal': $c.information-600, // Background for info highlight elements. + 'bg-error-bold': $c.error-075, // Background for error secondary button. + 'bg-info-bold': $c.information-075, + 'bg-warning-bold': $c.warning-075, + 'bg-success-bold': $c.success-075, + + 'bg-error-heavy': $c.error-100, // Background for error secondary button on hover. + 'bg-info-heavy': $c.information-050, + 'bg-warning-heavy': $c.warning-050, + 'bg-success-heavy': $c.success-025, + 'bg-success-normal-hover': $c.success-700, // Background for success highlight elements on hover. 'bg-warning-normal-hover': $c.warning-700, // Background for warning highlight elements on hover. - 'bg-error-normal-hover': $c.error-700, // Background for error highlight elements on hover. + 'bg-error-normal-hover': $c.error-600, // Background for error highlight elements on hover. 'bg-info-normal-hover': $c.information-700, // Background for info highlight elements on hover. 'bg-success-normal-disabled': $c.success-200, // Background for success highlight elements on disabled. @@ -154,7 +164,6 @@ $tokens = { 'border-neutral-bold': $c.neutral-700, // Border for divider lines and default element borders on dark surface. // Brand - 'border-brand-normal': $c.tts-600, // Border for input element borders on focus. 'border-brand-semilight': $c.tts-100, // Border for element borders on active. @@ -170,6 +179,11 @@ $tokens = { 'border-error-light': $c.error-200, // Border for error element borders on regular elements like tags or banners. 'border-info-light': $c.information-200, // Border for info element borders on regular elements like tags or banners. + 'border-info-extralight': $c.information-100, + 'border-error-extralight': $c.error-100, + 'border-warning-extralight': $c.warning-200, + 'border-success-extralight': $c.success-100, + // Gradients 'gradient-neutral-light-01': $c.neutral-100, // First part of gradient for default input borders. @@ -231,22 +245,28 @@ $tokens = { 'bg-success-normal': $c.success-400, // Background for success highlight elements. 'bg-warning-normal': $c.warning-400, // Background for warning highlight elements. - 'bg-error-normal': $c.error-400, // Background for error highlight elements. - 'bg-info-normal': $c.info-400, // Background for info highlight elements. + 'bg-error-normal': $c.error-500, // Background for error highlight elements. + 'bg-info-normal': $c.information-400, // Background for info highlight elements. 'bg-success-normal-hover': $c.success-500, // Background for success highlight elements on hover. 'bg-warning-normal-hover': $c.warning-500, // Background for warning highlight elements on hover. - 'bg-error-normal-hover': $c.error-500, // Background for error highlight elements on hover. - 'bg-info-normal-hover': $c.info-500, // Background for info highlight elements on hover. + 'bg-error-normal-hover': $c.error-600, // Background for error highlight elements on hover. + 'bg-info-normal-hover': $c.information-500, // Background for info highlight elements on hover. 'bg-error-bold': $c.error-1000, // Background for error secondary button. + 'bg-info-bold': $c.information-1025, + 'bg-warning-bold': $c.warning-1025, + 'bg-success-bold': $c.success-1025, 'bg-error-heavy': $c.error-1025, // Background for error secondary button on hover. + 'bg-info-heavy': $c.information-1050, + 'bg-warning-heavy': $c.warning-1050, + 'bg-success-heavy': $c.success-1050, 'bg-success-normal-disabled': $c.success-100, // Background for success highlight elements on disabled. 'bg-warning-normal-disabled': $c.warning-100, // Background for warning highlight elements on disabled. 'bg-error-normal-disabled': $c.error-100, // Background for error highlight elements on disabled. - 'bg-info-normal-disabled': $c.info-100, // Background for info highlight elements on disabled. + 'bg-info-normal-disabled': $c.information-100, // Background for info highlight elements on disabled. // TEXT COLORS // =========== @@ -327,6 +347,9 @@ $tokens = { // Semantic 'border-error-extralight': $c.error-900, // Border for info element borders on regular elements like tags or banners. + 'border-info-extralight': $c.information-800, + 'border-warning-extralight': $c.warning-800, + 'border-success-extralight': $c.success-900, 'border-success-light': $c.success-800, // Border for success element borders on regular elements like tags or banners. 'border-warning-light': $c.warning-800, // Border for warning element borders on regular elements like tags or banners. From a8e03060d3fe874628a98eac6ab58a7490071ea7 Mon Sep 17 00:00:00 2001 From: Darya Plotnytska Date: Tue, 25 Feb 2025 16:48:16 +0100 Subject: [PATCH 12/21] console: Fix disabled button --- pkg/webui/components/button/button.styl | 8 ++++---- pkg/webui/console/views/app/index.js | 2 +- .../views/application-integrations-lora-cloud/index.js | 2 +- pkg/webui/styles/utilities/tokens.styl | 9 ++++++++- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/pkg/webui/components/button/button.styl b/pkg/webui/components/button/button.styl index 8c49e4e510..2d43f24d84 100644 --- a/pkg/webui/components/button/button.styl +++ b/pkg/webui/components/button/button.styl @@ -171,8 +171,8 @@ box-shadow: none &:disabled - color: var(--c-text-neutral-extralight) - background-color: light-dark(var(--c-bg-neutral-semilight), var(--c-bg-neutral-semilight)) + color: light-dark(var(--c-text-neutral-extralight), var(--c-text-neutral-light)) + background-color: var(--c-bg-neutral-semilight) border-color: var(--c-border-neutral-light) &.small @@ -245,7 +245,7 @@ &:not(:disabled) &:hover - background-color: var(--c-bg-neutral-light) + background-color: light-dark(var(--c-bg-neutral-light), var(--c-bg-neutral-semilight)) color: var(--c-text-neutral-heavy) +focus-visible() @@ -259,7 +259,7 @@ color: var(--c-bg-brand-normal) &:disabled - color: var(--c-text-neutral-extralight) + color: light-dark(var(--c-text-neutral-extralight), var(--c-text-neutral-light)) &:not(:disabled) &:hover diff --git a/pkg/webui/console/views/app/index.js b/pkg/webui/console/views/app/index.js index d22e8849fb..d355ec1019 100644 --- a/pkg/webui/console/views/app/index.js +++ b/pkg/webui/console/views/app/index.js @@ -94,7 +94,7 @@ const Layout = () => { const { height: splitFrameHeight } = useContext(EventSplitFrameContext) const toggleTheme = theme => { - const htmlElement = document.documentElement // Get the root element + const htmlElement = document.documentElement if (theme === 'dark') { htmlElement.classList.add('dark') diff --git a/pkg/webui/console/views/application-integrations-lora-cloud/index.js b/pkg/webui/console/views/application-integrations-lora-cloud/index.js index 5cc91ef7e1..7f9c6673da 100644 --- a/pkg/webui/console/views/application-integrations-lora-cloud/index.js +++ b/pkg/webui/console/views/application-integrations-lora-cloud/index.js @@ -45,9 +45,9 @@ import { mayViewOrEditApplicationPackages } from '@console/lib/feature-checks' import { getAppPkgDefaultAssoc } from '@console/store/actions/application-packages' import { selectSelectedApplicationId } from '@console/store/selectors/applications' +import { selectConsolePreferences } from '@console/store/selectors/user-preferences' import style from './application-integrations-lora-cloud.styl' -import { selectConsolePreferences } from '@console/store/selectors/user-preferences' const m = defineMessages({ loraCloudInfoText: diff --git a/pkg/webui/styles/utilities/tokens.styl b/pkg/webui/styles/utilities/tokens.styl index fd63d80cd8..842305e93c 100644 --- a/pkg/webui/styles/utilities/tokens.styl +++ b/pkg/webui/styles/utilities/tokens.styl @@ -46,5 +46,12 @@ make-utilities($name, $theme) .focus\\:c-{$key}:focus border-color: $value !important +// Define color theme and generate variables accordingly. :global - make-utilities('tokens', 'theme-light') + .dark + color-scheme: dark + make-utilities('tokens', 'theme-dark') + + .light + color-scheme: light + make-utilities('tokens', 'theme-light') From 5dfb0e403d5fe8a945c4eed5998c1652207e741d Mon Sep 17 00:00:00 2001 From: Darya Plotnytska Date: Tue, 25 Feb 2025 16:48:46 +0100 Subject: [PATCH 13/21] console: Fix code editor theme --- pkg/webui/components/code-editor/code-editor.styl | 2 +- pkg/webui/components/code-editor/ttn-theme.js | 9 --------- .../payload-formatters-form/test-form/index.js | 1 + .../containers/application-payload-formatters/uplink.js | 4 ++++ .../containers/device-payload-formatters/downlink.js | 4 ++++ .../containers/device-payload-formatters/uplink.js | 4 ++++ 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/pkg/webui/components/code-editor/code-editor.styl b/pkg/webui/components/code-editor/code-editor.styl index 82bec8fa7f..6b1b142323 100644 --- a/pkg/webui/components/code-editor/code-editor.styl +++ b/pkg/webui/components/code-editor/code-editor.styl @@ -13,7 +13,7 @@ // limitations under the License. .wrapper - border: 1px solid var(--c-border-neutral-light) + border: 1px solid light-dark(var(--c-border-neutral-light), var(--c-border-neutral-normal)) border-radius: $br.l transition: border-color .2s position: relative diff --git a/pkg/webui/components/code-editor/ttn-theme.js b/pkg/webui/components/code-editor/ttn-theme.js index 9b90fed27f..5a2851a052 100644 --- a/pkg/webui/components/code-editor/ttn-theme.js +++ b/pkg/webui/components/code-editor/ttn-theme.js @@ -152,13 +152,8 @@ ace.define( exports.cssClass = 'ace-ttn-dark' exports.cssText = ` .ace-ttn-dark .ace_gutter { - background: var(--c-bg-neutral-bold); color: var(--c-text-neutral-light); } -.ace-ttn-dark { - background: var(--c-bg-neutral-heavy); - color: var(--c-text-neutral-min); -} // begin language .ace-ttn-dark .ace_string { color: var(--c-text-info-normal); @@ -217,10 +212,6 @@ ace.define( .ace-ttn-dark .ace_cursor { color: var(--c-text-neutral-min); } -.ace-ttn-dark.ace_focus .ace_marker-layer .ace_active-line { - background: var(--c-bg-brand-extralight); - opacity: 0.2; -} .ace-ttn-dark .ace_marker-layer .ace_active-line { background: var(--c-bg-neutral-bold); } diff --git a/pkg/webui/console/components/payload-formatters-form/test-form/index.js b/pkg/webui/console/components/payload-formatters-form/test-form/index.js index af9efff7f0..22ee2d8156 100644 --- a/pkg/webui/console/components/payload-formatters-form/test-form/index.js +++ b/pkg/webui/console/components/payload-formatters-form/test-form/index.js @@ -176,6 +176,7 @@ const TestForm = props => { component={CodeEditor} minLines={15} maxLines={15} + darkTheme={darkTheme} /> )} { const formatters = useSelector(selectApplicationLinkFormatters) || {} const linkError = useSelector(selectApplicationLinkError) const mayViewLink = useSelector(state => checkFromState(mayViewApplicationLink, state)) + const consolePreferences = useSelector(selectConsolePreferences) + const darkTheme = consolePreferences.console_theme === 'CONSOLE_THEME_DARK' const [type, setType] = useState(formatters.down_formatter || PAYLOAD_FORMATTER_TYPES.NONE) const dispatch = useDispatch() @@ -115,6 +118,7 @@ const ApplicationPayloadFormatters = () => { initialType={formatters.up_formatter || PAYLOAD_FORMATTER_TYPES.NONE} initialParameter={formatters.up_formatter_parameter || ''} onTypeChange={onTypeChange} + darkTheme={darkTheme} />
diff --git a/pkg/webui/console/containers/device-payload-formatters/downlink.js b/pkg/webui/console/containers/device-payload-formatters/downlink.js index 5f6a26e8e1..1430d0c6b7 100644 --- a/pkg/webui/console/containers/device-payload-formatters/downlink.js +++ b/pkg/webui/console/containers/device-payload-formatters/downlink.js @@ -44,6 +44,7 @@ import { selectSelectedDevice, } from '@console/store/selectors/devices' import { selectDeviceRepoPayloadFromatters } from '@console/store/selectors/device-repository' +import { selectConsolePreferences } from '@console/store/selectors/user-preferences' import m from './messages' @@ -55,6 +56,8 @@ const DevicePayloadFormatters = () => { const formatters = useSelector(selectSelectedDeviceFormatters) const encodeDownlink = tts.As.encodeDownlink const repositoryPayloadFormatters = useSelector(selectDeviceRepoPayloadFromatters) + const consolePreferences = useSelector(selectConsolePreferences) + const darkTheme = consolePreferences.console_theme === 'CONSOLE_THEME_DARK' const [type, setType] = useState( Boolean(formatters) ? formatters.down_formatter || PAYLOAD_FORMATTER_TYPES.NONE @@ -169,6 +172,7 @@ const DevicePayloadFormatters = () => { onTypeChange={onTypeChange} isDefaultType={isDefaultType} repoFormatters={repositoryPayloadFormatters} + darkTheme={darkTheme} /> ) diff --git a/pkg/webui/console/containers/device-payload-formatters/uplink.js b/pkg/webui/console/containers/device-payload-formatters/uplink.js index 9f612142e4..e5763f567f 100644 --- a/pkg/webui/console/containers/device-payload-formatters/uplink.js +++ b/pkg/webui/console/containers/device-payload-formatters/uplink.js @@ -45,6 +45,7 @@ import { selectSelectedDevice, } from '@console/store/selectors/devices' import { selectDeviceRepoPayloadFromatters } from '@console/store/selectors/device-repository' +import { selectConsolePreferences } from '@console/store/selectors/user-preferences' import m from './messages' @@ -56,6 +57,8 @@ const DevicePayloadFormatters = () => { const formatters = useSelector(selectSelectedDeviceFormatters) const decodeUplink = tts.As.decodeUplink const repositoryPayloadFormatters = useSelector(selectDeviceRepoPayloadFromatters) + const consolePreferences = useSelector(selectConsolePreferences) + const darkTheme = consolePreferences.console_theme === 'CONSOLE_THEME_DARK' const [type, setType] = useState( Boolean(formatters) ? formatters.down_formatter || PAYLOAD_FORMATTER_TYPES.NONE @@ -179,6 +182,7 @@ const DevicePayloadFormatters = () => { onTypeChange={onTypeChange} isDefaultType={isDefaultType} repoFormatters={repositoryPayloadFormatters} + darkTheme={darkTheme} /> ) From c030e0daeca0e3b5deb34bdfa4fa4662c4e0b0a7 Mon Sep 17 00:00:00 2001 From: Darya Plotnytska Date: Tue, 25 Feb 2025 16:49:09 +0100 Subject: [PATCH 14/21] console: Fix notifications dark theme style --- pkg/webui/components/dropdown/dropdown.styl | 2 +- pkg/webui/components/notification/index.js | 4 ++ .../components/notification/notification.styl | 16 +++--- .../components/search-panel/search-panel.styl | 2 +- pkg/webui/components/select/select.styl | 6 ++- .../network-information-container/index.js | 49 +++++++++++-------- 6 files changed, 47 insertions(+), 32 deletions(-) diff --git a/pkg/webui/components/dropdown/dropdown.styl b/pkg/webui/components/dropdown/dropdown.styl index 64d3f7527a..abb8443355 100644 --- a/pkg/webui/components/dropdown/dropdown.styl +++ b/pkg/webui/components/dropdown/dropdown.styl @@ -146,7 +146,7 @@ ul.dropdown border-radius: $br.m &-active - color: var(--c-text-neutral-extralight) + color: light-dark(var(--c-text-neutral-extralight), var(--c-text-neutral-light)) &:hover:not(.button-active) background: light-dark(var(--c-bg-neutral-light), var(--c-bg-neutral-normal)) diff --git a/pkg/webui/components/notification/index.js b/pkg/webui/components/notification/index.js index 1f6cbe15fc..88ebb5dcec 100644 --- a/pkg/webui/components/notification/index.js +++ b/pkg/webui/components/notification/index.js @@ -41,6 +41,7 @@ const Notification = ({ success, messageValues = {}, children, + dark, 'data-test-id': dataTestId, }) => { const classname = classnames(style.notification, className, { @@ -49,6 +50,7 @@ const Notification = ({ [style.info]: info, [style.small]: small, [style.success]: success, + [style.dark]: dark, [style.withDetails]: Boolean(details), }) @@ -80,6 +82,7 @@ Notification.propTypes = { children: PropTypes.node, className: PropTypes.string, content: PropTypes.oneOfType([PropTypes.message, PropTypes.error, PropTypes.string]), + dark: PropTypes.bool, 'data-test-id': PropTypes.string, details: PropTypes.error, error: PropTypes.bool, @@ -104,6 +107,7 @@ Notification.defaultProps = { success: false, messageValues: undefined, details: undefined, + dark: false, } export default Notification diff --git a/pkg/webui/components/notification/notification.styl b/pkg/webui/components/notification/notification.styl index e03d2788c9..984b910c52 100644 --- a/pkg/webui/components/notification/notification.styl +++ b/pkg/webui/components/notification/notification.styl @@ -44,16 +44,16 @@ left-border($color, $bg) margin-right: 8rem &.error - //dark - left-border(var(--c-border-error-light), var(--c-bg-error-heavy)) - // light - //left-border(var(--c-border-error-normal), var(--c-bg-error-bold)) + background: linear-gradient(to right, var(--c-border-error-normal), var(--c-border-error-normal) 5px, var(--c-bg-error-bold) 0px) border-top: 1px solid light-dark(var(--c-border-error-light), var(--c-border-error-extralight)) border-right: 1px solid light-dark(var(--c-border-error-light), var(--c-border-error-extralight)) border-bottom: 1px solid light-dark(var(--c-border-error-light), var(--c-border-error-extralight)) border-color: light-dark(var(--c-border-error-light), var(--c-border-error-extralight)) color: var(--c-text-error-normal-hover) + &.dark + background: linear-gradient(to right, var(--c-border-error-light), var(--c-border-error-light) 5px, var(--c-bg-error-heavy) 0px) + &.warning left-border(var(--c-border-warning-light), var(--c-bg-warning-heavy)) border-top: 1px solid var(--c-border-warning-extralight) @@ -71,16 +71,16 @@ left-border($color, $bg) color: var(--c-text-brand-normal) &.success - //light - left-border(var(--c-border-success-normal), var(--c-bg-success-heavy)) - //dark - //left-border(var(--c-border-success-light), var(--c-bg-success-heavy)) + background: linear-gradient(to right, var(--c-border-success-normal), var(--c-border-success-normal) 5px, var(--c-bg-success-heavy) 0px) border-top: 1px solid var(--c-border-success-extralight) border-right: 1px solid var(--c-border-success-extralight) border-bottom: 1px solid var(--c-border-success-extralight) border-color: var(--c-border-success-extralight) color: var(--c-text-success-normal-hover) + &.dark + background: linear-gradient(to right, var(--c-border-success-light), var(--c-border-success-light) 5px, var(--c-bg-success-heavy) 0px) + .message display: flex align-items: flex-start diff --git a/pkg/webui/components/search-panel/search-panel.styl b/pkg/webui/components/search-panel/search-panel.styl index 795de9c92a..6d208bad37 100644 --- a/pkg/webui/components/search-panel/search-panel.styl +++ b/pkg/webui/components/search-panel/search-panel.styl @@ -48,7 +48,7 @@ outline: none width: 100% height: 3rem - background-color: light-dark(var(--c-bg-neutral-extralight), var(--c-bg-neutral-extralight)) + background-color: light-dark(var(--c-bg-neutral-extralight), var(--c-bg-neutral-light)) &:focus::placeholder visibility: hidden diff --git a/pkg/webui/components/select/select.styl b/pkg/webui/components/select/select.styl index 63241972b8..1fd0199a3c 100644 --- a/pkg/webui/components/select/select.styl +++ b/pkg/webui/components/select/select.styl @@ -18,7 +18,7 @@ // stylelint-disable :global(.select__single-value) - color: var(--c-text-neutral-heavy) + color: light-dark(inherit, var(--c-text-neutral-heavy)) :global(.select__option) padding: $cs.xs $cs.s :global(.select__option--is-selected) @@ -34,8 +34,10 @@ width: 100% min-height: $default-input-height border-radius: $br.xs + border: 1px solid var(--c-border-neutral-normal) + background: var(--c-bg-neutral-min) :global(.select__menu) - background: var(--c-bg-neutral-extralight) + background: light-dark(var(--c-bg-neutral-min), var(--c-bg-neutral-light)) z-index: $zi.dropdown :global(.select__dropdown-indicator) padding: 4px diff --git a/pkg/webui/console/containers/network-information-container/index.js b/pkg/webui/console/containers/network-information-container/index.js index e9f0fdcf9e..e762aa0c30 100644 --- a/pkg/webui/console/containers/network-information-container/index.js +++ b/pkg/webui/console/containers/network-information-container/index.js @@ -14,10 +14,13 @@ import React from 'react' import { defineMessages } from 'react-intl' +import { useSelector } from 'react-redux' import Notification from '@ttn-lw/components/notification' import Button from '@ttn-lw/components/button' +import { selectConsolePreferences } from '@console/store/selectors/user-preferences' + import RegistryTotals from './registry-totals' const m = defineMessages({ @@ -26,25 +29,31 @@ const m = defineMessages({ plansButton: 'Get started with The Things Stack Cloud', }) -const NetworkInformationContainer = () => ( - <> - - } - className="mt-cs-l" - /> - - -) +const NetworkInformationContainer = () => { + const consolePreferences = useSelector(selectConsolePreferences) + const darkTheme = consolePreferences.console_theme === 'CONSOLE_THEME_DARK' + + return ( + <> + + } + className="mt-cs-l" + /> + + + ) +} export default NetworkInformationContainer From 3d283253c4ea016d6d067f3b1c52dd4e6cf5ed31 Mon Sep 17 00:00:00 2001 From: Darya Plotnytska Date: Wed, 26 Feb 2025 15:49:25 +0100 Subject: [PATCH 15/21] console: Add theme switcher --- pkg/webui/assets/misc/console-theme-dark.png | Bin 0 -> 25055 bytes pkg/webui/assets/misc/console-theme-light.png | Bin 0 -> 23597 bytes .../assets/misc/console-theme-system.png | Bin 0 -> 37749 bytes .../components/radio-button/group/group.styl | 3 + .../components/radio-button/group/index.js | 5 +- pkg/webui/components/radio-button/radio.js | 38 +++-- .../components/sidebar/side-header/index.js | 5 +- .../components/submit-bar/submit-bar.styl | 1 + .../downlink.js | 5 +- .../application-payload-formatters/uplink.js | 5 +- .../containers/device-importer/processor.js | 5 +- .../device-payload-formatters/downlink.js | 5 +- .../device-payload-formatters/uplink.js | 5 +- .../email-notifications-form/index.js | 8 +- .../latest-decoded-payload-panel/index.js | 5 +- .../network-information-container/index.js | 5 +- .../navigation/general-side-navigation.js | 10 +- .../containers/user-settings-theme/index.js | 159 ++++++++++++++++++ .../store/reducers/user-preferences.js | 1 + pkg/webui/console/views/app/index.js | 7 +- .../index.js | 5 +- .../index.js | 10 +- .../views/user-settings-theme/index.js | 65 +++++++ .../console/views/user-settings/index.js | 2 + pkg/webui/lib/shared-messages.js | 3 + pkg/webui/locales/en.json | 11 +- pkg/webui/locales/ja.json | 11 +- 27 files changed, 341 insertions(+), 38 deletions(-) create mode 100644 pkg/webui/assets/misc/console-theme-dark.png create mode 100644 pkg/webui/assets/misc/console-theme-light.png create mode 100644 pkg/webui/assets/misc/console-theme-system.png create mode 100644 pkg/webui/console/containers/user-settings-theme/index.js create mode 100644 pkg/webui/console/views/user-settings-theme/index.js diff --git a/pkg/webui/assets/misc/console-theme-dark.png b/pkg/webui/assets/misc/console-theme-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..ec17b96f9a6ff0c19875dc5efeffdbce7dd6b074 GIT binary patch literal 25055 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

NQsN0_wf(tcfLVbr-%N-bGqC$ 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 awF=9|FIZhpc^k5P+>cmFRqJPn8d literal 0 HcmV?d00001 diff --git a/pkg/webui/assets/misc/console-theme-light.png b/pkg/webui/assets/misc/console-theme-light.png new file mode 100644 index 0000000000000000000000000000000000000000..e00d87c2df16efa55e707494e32001a6d515cddc GIT binary patch literal 23597 zcmeHv2UL^Gx9%Di^UF-haeeca$E|*Yf4{va56nyq zgjY(g1ONyd9y@Xp0HJyS1gkh#B?Z`ir;mK{|Fcal|(%=xt ztdpk0KLqR#8Xp88Cvw&NrDXt|FE>1L@U#zVxMS7ht=0a`-*i_lBQ!)lr+4%@@7_l3 z6}ykQGb8xQg&_41bLWse!DUm2-o%Q}QpXGk>mEDYC>)M|9?)&Bu;F>F+RUEZeH}pt zSHH0jnW-4w)#wP{aivdX-_12b9-estIU(w{nQc=wo~svc?6xYC{>Zw@qI})svk~}3 z&t2XadNpcsuE$Xlju0m6-S=m&$uQcE+0uf#oHZGX5jz7;k>_-6ZA6F<_&0u({^OlD5N{>!~>*D%LkW=>Dea7)1BHD zMy_kHYWw;o3v&3+iw>3_(DVLTpey+yQ8r_7K|V$zQ0jbs6K-KF(1$~_u;A2cepTVe z1&P(8kfv}%Z1baqIeW?iCjZJV6z9i}(W|-63(m|)TR{-NnZUo)pFuZz=pd)7z%AqU zIy8MKeaJTRYpw2GAMPXpX@Qg2qB`Vp8S9rUFElxs!GtrMFS5>B47QKwwg6o9R0Ny4 z$A~Nzi^f=+;PD5W^JpYJ@V?ceHW*Yic+cx-5RY_}a4VUed`%O$V8Tg2Y{x+{*lxplcFMnJqLJMDLzI=76~}z1YQ}lSn| z*eTI}D`fbl_^kS(tEcBwkN;x9nDC&jb?Mwx|6(8IXVaf1nXhCxwd{q+09C>w8*Q^V zB}ZP|$?Ju1C1@&ZVT_g)@Gelaa|+$AJ5w^3>iO|D{3P|p%*ws%YvdN0l`X2=@)7Oo zQ-lRdOboS)IHKz}AToKaWB#1B5ce&?z{c_1Y**=!uHQ{Pia~+FJaT}LM6e~!pAuWV zQy@6``gJFJ+=H796wGh*SXx@@YCPfyp*Tb7>VdftQ#HJoI9VfOzlN`6tc9}0cwB&| z=gh5A*?CXiTfIn&pxM3|@0Wq{1Qp8~l@SbY6y3{9W*3wv#{@hmzp|{7tp~g2Xrhbb z!MY_2cRL1njYvO|Ko)G`o9(=>5R1UdTG~|bCHV?xzxwA;r|_xG_c*)pGX zs&KkF<#y5ahO+6hsxcN~QkgJ8aox=*+6fh60nf&gn5t za5pDa*pw2dW0nuTduLQ=b;7txp)n^YOuTffmAoL5mw?y!`zo zfb|SHowl?{{ugbCWnOzC>6}K}P8IE=wwl%0(txv0MB;ss;+%9b1=2`|HZod*=;xXl znsWc1Qd?FH`!0F#xctVCn}jA~8ZJ4t3F^@b&mis9OY|49Zc3D$hjW@h<}_J6GB5IT z=QZbfwxhrC1OPC|5&;U$mvh46+RlECsj(^;0vk>TZD{g5VJf$0W8`Ix;l3gI z<74=vwkgYwI5;ZA@^{5#t`c1(oaN%&ORX6&$VpocaH;#w2@o`PBn0|T8EFf3?y^?N zB>G16nxj*!wk7bRdsr+r+kLD-FEt7c%aHcL2j4c7p9Wyu4jGPJIloT^&BYn(-QnZz z-qv;(MRHEQc~rBf#I!Mw)07^dyc&4*epB5CfR6-92AA0GEEiDe-ksCv?#5O%k0qjE zlOgZKO08$?6`!mZLur4l=na6AbwXO-dtQ;Rdq?b5YTR|zI3-0nzJzT`BtzOmO!l+o zvm5-i9`OU*$l7|8LWngV=~PO6qZ;RaoiSB_bZUR?PSz%+Fg~B1Gfx313B`%%nSUM8 z1PM19qQ={c*7KoXs?Z)@Yl^%JNSBf;pTPO3@o6GE0;WHBDhq(;zn*@|f1oGF(*!_| zr(pnixPq&U09f;@kt@HR{)^4s-FP|(_`JqygkjPythy6fA9M4s>#8epsjmgAPQkgw zBXg^=6H6gco00+qCW}VNGbrh*w9F*YdljF0jJm7a&+~zCWjG%F1Na2EIB+ML3$ymj z>$Lc(B(5D7ulTlGPM&lBsKd;4+x7f_?Y(y+6o4h+NW+cFD6M6<)b|>?;lyJNgFP9# zU832#sXFIQM3?w@IUig*e%)bDgNNn{_<^P12kuFJ(0Iu-!EW_1nd6ycd$=o?DkfG& zN=o(#2*8A63~AE?1NNx#myM<0Q)4K60Cei>2@y0L5><_T?hlgK$<_~IRFtt&vD9*0 zXl_8|?u+V;iE#rIN>XIwevI`{xbU4B!_?;;UB_d8TL!v2G#9h8C$)30QU&y4jJ36# z#v1=158zAh7Z>|}?hk#Y5|iUhLp@CNl{{>6)boXN&n?Z-5=tG#RGl%nt@A?HQEEn5 z{GCOW@R-JZ0o3%dNRnZfUD344`kMFgwamQw<~7HbPGR5OBeFt*fD}CFr>CnE|1q5= zhq~je_5A$`-RO6{f32+|UKr%hqerMAt{D1l)R#w->D6Pj8*9G{wLrh2k{y_0BCa;{wIA z9Z*WfAW|~5%V}+wA?r@re2ZysR81%t3^7&4S5g)xR-tE+I+LHCQ`g@f^3Z(X#0;RT zj7iAaNsPrD{xfM4K5*Lb0w!>MmW?fWq(c!*D^*TJMY;J+^gMS(1el(RwT;ckxVSb# zpmLq5U0VrPDmGWL`^-XC4pv`3O}57qmm{5ki)@ord0+W&P?8Qtez8o@)rv&AlSjI< zgx%%%|F%?aHUb~OI2-n(XS$mqvcs7(tU|nR%?O}NAO&f#;2NI&HTKuR?kyAgWJWC3RwFb%s zPEsDW78VB_{cp`FqMw(VcB=F-pu85D3uuAThd_ox1xYy3f#u#yPXH|E*_#0D{q=N6 zk7oejPW*b}jS_%OJbMv7@tOnRuU}99U7CBV2{cwhql~)>KI$l$?qiBijk$l0J4d+w zT!CzUneOZJ!T124^-2VS&vh%;*T$6cP-`fWkZAXiJ8D16^l|H8jvVy;4 z(&D|HeL4VhEJRXwX8hbrpVW?51yt=AdnB9r7`h!^`{gUdz<2Bd)2eLZpJyD_8HN-^fZi>!4mqI;WOF7vS*iT4B9y0(4wp z)}OP}>rzu@B~!^rx5j$e=-k@}c>|3u`kmEf4+do|xU*Oif0kKUBidbW(`9rH2N10U z+VVoJ2OVgWx9DSE)bau~1JK;&->zF*-$Hb;ahe&3f4wJ8hg#;O2j#&HYmD z>`nh*oz5M?f4t45JOOF#`8+38W2tlt?3>G_5zX_I{vl035D)sW>GcN=?OS$8k!+PK z)8+J&{nW@N=PF>F`^hdS-+CacN)SZ%v+aVkG0i1m!m=visHZS%QtwHXP!p$lQ}~J> z*nLNLtNHALDm#hl=MjR8#z{-<2>45Irhm&?7O$zU#N?_8tre;R}D{Wz3F_-D}kT1 zKDluAswtX(Mh`CSb-J9-HP}PGoPU02dtK6Lhs*5(2Y{m~dVO=sg8&K~;)r2t(K{zy zlkD4w#h6&QLJ&7{^NiDHiL04%>T1xWuL-5C(wS3=KSztP8$=OyHI^5(73)vJQ?HlP zF2GM3O*Wip^omWX=A5k11s>L{Fr^U%@6@j-_@;8kU+0sxUT}oeYC%*Re|zzeo{W3j)r zMfbdnZ)~%43V2na6x?F2vpS!$iNs*B!hy3)) z{1}SOnGI3Q*E7Z!JYcJA;g;fQUxSFy9KIg{ZdK5Tl9;XHEy3>&OaFZX(eA}u7} zp7_lqE$6)mn6|U1U$Gzknr-mjZsF?u0sBCP{&2Yuv-tIJc}MI!wx4C>ZjFtR z@f))Bp-xyNHlx))fNWid-%Ezn%WFS1jDT#@(5p1E;QCH}5@u@T(G7ja!^Xw+x`idn zF(#VVIH|UNu@c*d53PJljj9$&Xz}+u85VCMpR>#1WyQw``kM{3DHD^G-Q+2!{ZjCg z&|Lmd%H+p!&Uwv$mw-F5IV)2o^LEDN*OURg|JxM-y|WdxEVU?gLA^-Nq6azn#qUv2 zJ=(>boYiSNGC6m-rMO9sJ+bDBcj;kmnL=IZgpZE-_bu84BclRzqs&Wlm+dHN`?T{G zXf9UG#~)SilbP7ndlodOS`^peKUnL0tG^%thAkx}k_*{H?L+U=CYbXrz5&)?X2EM>Dn&*;#3+sa%}N!hIH!e!Fv^#zQnDn!MJEQ{vQ19{T7{ldu497 z6czepO|t(~FH3(H+O=mk_!8XU(^(_q+k9h5LSTC6(&LiM;D-I8fokAlnIwvnT}Lrt zhB_a2%WqwsXdokfjA^|?FmjjHpF4u?$^zF7#?-3oUrKXISKI;`Vejt03C%TJPeYL| zP0|-i(2%s!kd&)Nb?+`>EngQ3kNWN+Y@l-|03u1Ik!DMH_W)8c^WKf9@31u)>+>;@ z&|sU+GR1#DV4edFslMj3K0oNnA06cQ4ncEQ<36TVY6-H6*U(jAHEaKpRq#KrU%HR- z3()=@VC;WR<%wS}wK2%O!QZ_G?)=vuHgRhW#w7A#+cNF)tv*7ELPSx2GOF6@7}r7_ zd;|@nM2E{5TR}aE=L{Z!W|~koETLg8@BxrS-M_l1&hqA*l}@ zI~Ur}GnGnrLUDiGePZW@bnY94^8@^>*Jmq>*1f`w8ZrEG-mT(N(gY7EELIt81wpJ zhW=k@8u{i|v{&LXB_oHV8@M|`;rv>Ak;osHP8{8$S+67C+t4q06$(@&>7m6>`8SGC zu&QA#j%(BNg>i=^&sbn&>;_u~mI{DU^Dp_;9!DnV9>0xXWkz0ydqU}=nWm%9yt9?Z z%VJaiat}UrEbGT5ZWTbv*SNib_x%3=qWpgfKK}zIn-RgMw7%w6Qu+F zB7;S7=U4f2+c$zmI~C)=U{QQ#dgbxnAyE364-3I9R5}$LqzU-2Adc zfg*1{o%zULWvi_f`3;d)QJKbcNiO#XRnhXnic9P8HkeTQ1DOOp@8tLadTVs1Ik&;+ ztcXL&dQ&}fzAsGV-EON#zB;Q<&Abdh??tp=6GVKQf|=B)2jt`2;*%%#pg4Ez6L~N` zdsUqb@5AE$FXO8ICWoy#EopawH}id5tzC;MLJDWQ^fDA)$wz6#oA5sJf`S|&>x|O{ ze3A?(3rN;UC3tY-O;rm4On zjhv`eys@Xi1<=)st0G7W=vl(^(*kYMrG%JY*!>$mR<<|*k0$6ZzE@FaYrf$qLte3X6ENrt9s4-m@K(7=@vlxWRYyjT^;%^ZmS%#6MCj6 z(^&Jl5;=}%8Wdw1GFl;Az*_0+NLHrF@=gxt$A?S&0(a!F zb?m0GA8SXKFpbC5f_C`Xos>X+T0kUA8F9egRM4dxRek12UP!|Im zcTQxE?af7yaQcv45O$wS_oOCh#v_PR5uq`XrM@Ynx32>JC(FzCli%}`7QzfXPcLha zGR3Mr5(U;4<>hSh-U^`iNKOpSKU*~A1O|TsB8Xv|9a^6oH&iKmfaX$6XC&Ob;ybc@ zytl3fS{9!~a<|2s*-60po{^M_p74$9DYPDhjDW+8uOxahyk!{(*{_pBg&xrD9Rhf9 zub!Gocm_zL(Q0bh5K?%hXQh6CoSS0lePi=36> zc2E<$9?b3*T{XnQy2P9OSsj_NwgJ^0B-2)M8$y=LIZ)6Q#~r9DJ>DqfTh!vcZ#B?$ zwi52?aeN%9I+9!MBTlJ9raLZc(KL3~Q?#*pV1D>xGjx1zRm#vBVw4wo)8~&}Uox5+ zd*ue7dgR)Q2JeYevCDDf1GAY)=XDZ(CtXWyN2)mQ&15!rTScgw+6CE5P_@;Lseta{ zAD2AK%-{T&Nn{t$XHFgh5$B3FnxMx$tt%b#Ka)rJNjX~mQr*Eh2UiNH7q~+*<~}>; zLv^)Apw3Z;2EB8CxIB^p?Z;>8sI>#VX#?_&^Bdry={&ApPJiP3$6XH)(UfBv5qMrR zfB%Taal4?(#0OOlhk*2EyCB`$R###YA`_|v4`~9jf=<8FMC#qEx>D=|Qjfi;5-Oh)?aQI!6PU5G zO0oSSXWrcP0+W`pyEa7L^DQXM`GAKObLez-11Q@hoU*;3zkUvhlt70)~jMVWz;@S1ye=wLu9RlS7CRI>|$ z*4p=+gBHTfo+F@Jqd8QRt6;!C091>wsTXS61d1{x-!H|b01%xC4ery3eE^M_f772V zB+RO4^vYhYegvPsB38X;Ys(6c7FUfhh+?^Am&|%!#;~@~PF$uT?Uktto~QZxc5NYu z23v@nhG2O+-6M>B^VHfH7}bcR&ZH$nbYI=B75~ zv*f%6xP%>Y1l?nljnf%FQE`54VFkCDzelhHx8=Wy8Ix@;1lB;XpKc*FR7D z9Got}v@zK#R$40jN7|5)*`gkOVN;j9qfNTkhz$zhIt^!5PGz^Y?^?~IeJU+SA{V8f z^j-VS5o6nLxCh1nxzP@uYC?A}Lz zl6?CQ#`_4yF-?O-y(*U5vKL(jSrxK^jBdc~g19)$R3wSgMZam64yy`* zZmYgi&(vmC=FaU^DbksKs7&Cmzex{T9Cc2Jw1L*@=wWQ^hU1|pB7JWu>N6+Z*VLgv zcV|Uno2m&$H(q+=_w$IfD2h{>NQP|3_+il~J7cQzA*{b@l-*3%OuJn?Ks+PQ=BB0; zRo)wC*=>a#XwfSme7#14{EHtBhX0&>)8nZ5;9GXrTK~KU{ZL9pdhtOw{kZF`rks(Z zx}!qYsCum(3ASDLAt5uq!9kjHZC`{*l%4+*V!@GQAf3(U{R+zwZTgq5N zF}{z25zGU;d@yQa8s*X_&0mtHz`$m(Om(SsmEls_ELGNR35RvJ3Q}8`R zaSH<=d!NHe$J3%ooh3$>Un&7;iJZ&Ulohtyz2QigxVisH?M2p)ClGsls>rK$*br=I z0MF%c=SW6L??$C}%K)y!DAK5Ci2lC#K2F&TWj*DpDaelT!nc`2NKp4e#PABJqiJs}D)eSrzGd5nE(Kj?yQJ4j8^?G*P1bEYsV4+*rRS%iUPai3 z*?iR%Myg^Q*M)aigWaf_vyfA?FvFWK9q?Utm z2;6HQk_RNc7%lg#5#yVbW0eQFb<#nE_jR?3J1t|~i-A*WUXKi**#fR`a8qT{#*Xc9 z1usoGn5X~pNB@mgiMgI0T4a9!fqm4IOJoBm_dT)Ly(@5;=|eohyoAxHbi>uJ4+4*t z$~gzFC^gI965(2=A%;-lG=<1GZmxpu+RB09$tz-MuTb^-cO>BP#mLlPnmj0TS3}oS zOFNj+->>`=i0Kq-ghy3ta4Qc6U*^N^jW?ONnPXM;_N;zeJ}TQ3hE}A>R{3aiF)m=G zq~R7e-QC6D{f%?l3CSvMeUN<-3!&a$WBQwDpZ}}}M#@wCdfpAY9IGR_b1Sn= zlgwq3iXy(%v$ig+4?Idc2{4!q#%9Kp@kuwrB@VS8Fpmtm5X|KvNaw|K?@rX#I{Eoe z!QgAnOD!2a>AJ*Ep;+$v4hC=GV?kGTW|lsT+s({!VeaRCktIJz>Og!d6adywwqT2$ zx$MXiQ`XhqSy^N)q-U8ocL>bIV|{LxwWaTw_{2h1J}>cwb(WO{`2YWP*Y z2v6W^;zc^P*Y)REDMF_iq3O?Q&sAaWVTD9<4k%b-*YmU$lEsyhfVBCSH~2p*>Hh)W z=k%KTVv}B>PwGF|+^G_rD{1sxsJM-2GuGTJvw|LeR^^;3F!J{FmF4Drc@wg$JxlqB z2jPOH#DJ_i*A&(($9jVV9#J{2p$Zj&Y`!&w^^FU~G2C|UWG=JvR#kETVCe@!_ zS1(axQQ`w{eH20cY0?|92#?QKZPHNMlyfd> zZtlI}+|!{q0$&sqc%#gU<}Pzb2EM$3typF95j<*sMk=SBXTU&iLAoR_e*4G2;zu?= zsOQou2M>)}C(n;_14J&h8_e3x(+>e$TYtz z-Dek9G03Ct;#{r-?6J=0%K@aa(9^1KDOz!1NGBODJ0y2O ziU0-^>U2Rrj7X|ef!+8@K5SXM{5!Qa2M{Y%Zon-egm$iVmONck?kJsV!28*fU6m4{7R zuWNmz4m^MuH1DJ~`iGDzB>pzVEBwjmPn}eptZqiSnBMO6PNs*>JOUj(H=-B{N82j* zz}0qZ3P{|hGFX@cRhq2z8!0EW5iEeEV~?(~gVcskqmyaOK-6o~=;XzFp(BAoWQgNP zy&ET*MzkQHX{rgmEn&X}j#m3Iy=8Z%-EfiGt96(P2qTT6dwfS=bI@MAxMo7A;6B_8 zXr+#E)#RZKGalR~)OB{8EPdwjPL_;+hKFvhBzRO_^d;Hr22Io4XT>1l!l#)DqQ zxYaEMH+gr?iAK3EHFU#D=0`^q?t>9ZM=7kd=y@eJ7qT7QF0rqw?fTy-co{X`YxA)1 z?<&|6r}P;b%{K=)MJxJVMoj7;yN#Ex{!HBt%DD^ zK5jH*R(oC0{!t7=W4k{NA7Wukt5;nKt=vhT4A z>uE7~$sus+hqANt7+<&5nRL%i5@dZsA;)Z*S(oJW2mIVHK?@At7VueUvZUDMTv(>J zV{~-X{lp^O9*^t{B=MW+Gkh5nN414QqD_)@0|Ugk`G_h>F!6qMDgmU#LSyVU7fS)e zn(C_i=uYq}P(w~LOsBI##Gqb@Qz@~8n-8WhnXqnx%4##sF^i=PF!g_h4TfCTS$n}c zf%najrHCXaEg4!Tt*u|&Zs(zUaN682;ez!?$UNd2q2=5&aZ8fB4qvh&jr>^O_p+?O4YQG1sayjP$6!|M~hvULn&t4cOI>mBZ zf~MNaK|^evYf+uQWTppiNZpLn|ITv`$IC4Y63cf%=kA_2Ux%!eX*uUovMe0c*0wD= zmAUYN8x5+)?`ns}=sA}DUHS!_yZL$cEdMtJcDTMeaBzHBwY&s+zes=jx;s9+%xbxE#Sy^)@|)t-%Hot>DDZbD z*Ggo`e{|U5_an7VF@m3@uAbdqYv)yVKa{@Bb^!bOr1tyLVz?aL$)yY0emZIzQwVdv z+e(fE#{G*QCdgILhoX~*tf+@bqan9J_f-2_U+wS}^_G;JgDgH^({^{V@0R~tDdc8@ z;Es6YW`j0zvtf%8aH`XxVGEsjevAM+3mxvJk94h2SfNFw>|%t6zFDq z*#(`_4j=vI4OW}19FF7SCRpPT>YTil7VVL;? z9&ntuFZ0~YDMY#}WZLlKW^zLZckC54my~F4wGskjea>p_cW+6-$Y)M`YfAoK*n36`L=*BU z=hUf?i|??&9juEQ#>8U~A0ro9;ePID!U%0v*UqGKMJU;}Z)$g%< z5wm7{Dg||M@rLGIjJKy2kUpYBIV3@WA?WvJ6=2v4?nkoBmgMQ)fZzgUpGVqC-TWZfVq(i&{rYhfVg2EA#fTmEsTFA{ zr0?x#%EeVMQeHa6`EqWd2#BaatjFI%m$ER2Dv?=4oE#YV3a`Rw+?!m!4$k!SFWpR~s+R1kE&+u;#F^tubzt@7blVOE-1 zk)~_uh04o?t8s@NTGd)#JqY+RFb16r_%;}9qhYiZcrSfe^Nx*$o~b3Xw4^Y+g`=(J z^&6joDh%ZK(W6~dr_aOIhatsL7T-Y*jZrT@VD<+jHxM(vx=BBR&K0R&vO?>G_7_etGWk*nmFV2MP{RS@l5IBvs*6=ubd2DnxV)k@0EcCNBrf@a)CfXG3; z|J9!O=Ukk9+ry8gszF$p&-nLaPaESWcyRvWSrbd>(>}@#M32rp^2k#JePZHGeu6Qh zpC$y7pOCQ2k3)ZA|B@eJjOaQ%Qk;drH1n=Xdm3Kjfr$9_O6Fu|bY~KGQPOPDPkdw= z@E>a|3-;J5+U1>FM%t6?8gM`-lo{$k+|K1RaF^2L2=dmns#N@ie!OLR-hC123q>oo zmP&9}dABy?Jk(Qg+b?tf2IE%Z*Lkb{-{tc0-z1>(Kb~wx+(yt zwp@8pR#YduZE2}+oBxy}q*^WfXzEZ)=z^c2b|BP;F(Id1N9ln_i@Th=S6c{7ic`v1 zKYSIRrUM22BH^u-llb}XhVR0uJfk%)J#jWUDxv3qSt9(>&SY*)LO`X^q(>2RbQA-O z^0Xds87V!4`Y71PkXGn=6OQ4QY=V}XibM@i=p;=U+Vd|GyRWkJ@+0=KlX* zmM6jgzCYfBEHwcCB$vQfgR3wg*l%j8<{9KoC@)?y>Dw^Aw>Bm4J}f z6pYtF5@Oqyd3&mfdffI#N7fES2Dg%bwYn2SxIL{ZnrEfhn*)b$#`fV&*43)=*Nr3% z0WL9tn`u-vhD6&V2x2Tw)T40fdDrrQtN676Kr%af0}ytG@6ZI&`fX3=Hnxi+%ymQs z@iqb)Xu=q%CG;#LkT0J&iucHQ|u%Tyry4dIACZ5iaO4;L*vdKZqM z6ov;0#jOA9cxidZPr%~vxe>b{1*F>_ejN?p2GWeGSIvUmr?=}K+8(~jF`FNvs-JQ7 zhi|l1K^^CMqW95IGl1dsy%-}k$tN5(Kkns@0LS|C>JVE=wr)L*u+Vl}R)gRuuSYQf zpFSgfWi*lnIbI#45s26{Qd}}`+d^5@WGMFSan|Ey(3rZ^8w*iDw`)}rrgdfi_ozEc z-}&|aywU8lNX*y`%u=d99@zjyUOufH$gNfYI8J)sA7>>iH13K3w))4p_izE9OhkB# zT>{PN=S-e$r{9xItw&ufYiuSwrL>7t;tvTy6q`z+&R)Epp$yF4(4R+L1KBDLzxkbM z30I-!x&gpG)z(acTzYfX%T7Uf>DKIxxxQ8xilFB3+l3lBGu~NC*|l*sym4OzIgEik z{XmeWujz|Hc=aDZuc?agK4-rwL}zw&ME2b z!K{pR&=l$5^MzGBp0K~bU~bvU$&7_%x1@$)P-1f4>`R*tB8-gOy_|md{1G8sq&o(; zY$Be~4BMWyI(%-EsnoFYt6l&w?SE!ezzD|G_aNhrmW!{_>{3>U6wD7o0>m-xYjh3R z#875#PShY6N0~T8=nONbz>60hLbJmGYXPZvB-6<>_3b@{aN$PDxsK1sK(@f=yphAD zvHLqtMpfyk7tG{z!q{`4f>UjTQD~J0MPdG;?kM^iaSP0vTep2|s&wt0tGl8dA|G=K zp)`W?{Y!J42PylF?eI0B`kSr=wtjd5~z99M^r}SJ931XRvz7!|W+8A|ib|y|&(+z+&S=pZS?; z$|Uq$#fA@u{?B@cIzN{l6PNZEQzEOUFTD-YrIAxunHLH9PVVpLtEZy;Dp{L-Ic}e6 zUBT}my-l?0$1i@9_!$82VhMjJru!R|hDgE%r}wPnxtu|BLH>hU>QX*@L!JH%*(7ed z9-BHM7n{mM<{;HkjM7?rjfwu5A+M;jP~w!xfu5hG)cuE(8UyW=dsY_)lP)C)iwXAu|QmJ*2pPe*TYH70aM9yAs+jeF($wZE)Yb&*FD0oM>UhCXZBSg-46 zd>wQ^wfYTe3r)Ht1T84?dg%V>(IF*YPj#3QmCFy7kMe{H54507>qQ8m^cVfULBmpPYBd8?beWu@?EL01m? z7tbF?B>Yk$ky5AwNtx`PT3hxRy)rnRexBbSfWrl6vli{Cs-|7@dDF#RMZg98|2nfQ4(_DJZ@fgf~OP#tCK zF4T89bWLX|#`U@6cO`I{E2!oxa)~zsX7bDCzTy@_hlWx!Z}BE}Q9&(d&KeoY^h_I? z9TVuqsYb^d`~6&Ev)o!1v%tE8$V@`%&|CY)3c84^d3~mtQ~eG|h6k`S1Bc^L9Qf^LX)UPDLQhbL`v~%M-@){249b?Da5L{1qvU2=;6lzoLK*!a zN(b?cE~T_eb`|schkuu&&=LHR`Ms16`!;m24PEwg3<`!+zq!o}ZQn6mLh}8ET>J&j z+m??5KeylZ<_z7jw*H_V--&}L|AADzHOGtU7?8_hAnrgUk=(S~GAzra!jG19R53+I zY3OzJQDwye6XdJ8^H)_FsoY`!7j%O-SUerm%a|2qJi=%a{0s+;=`Wf_zm35q%$H@AEu<?DGS96f}QgqB3qV{ zrCbb!?7JEJHjH)r&pQj_@AJ8f*O~L4^PK1TKHq0K^GHuebLX~w+W-JN&z(JE004>r zz{VR}Hp3^~O{NFnf3`ZDz3dFY?t{obZ08LAoPZD6oDDSp0_ipUgYcJ)R;MnU0w6PV z`_ey~00`f9?#wA8ceauCcKd#c_wV^y1+M|+D^D9Lv(pa6nCAXIbTw)F9p0c^-c7DS zk}ZX;*FEc&x7VBft_Ry)Ji8~4Ttx3HO?-6j+xPb`wswX6-15|FTNZX#@c(XVv+Go* zefacOfaTXGVz(>1cf@-L&U%HOx$^WRXJ2eU=eV0$#z2I{<+C>*#GX*2b`*~j4Fe@j z%roNC%9o{@Y-WhVb(E@PgXMXHU-7ytS5>rXQ9#$yenohe^Ki9LyrT3Ua69nlvR+{B zmC#EM$(d#*)-F9|Vim*7j#Ij|aT4vplH%&9WtrzuzG+5pmkpor;|n*s&^{z=ucdGD z5c65EzeU2^acD+o^GwJ_a>LA`x!uwR-@-}Xk*b-8AKB2FTS&C==#I#t+B?PGmU0iqdoPg3 zHG;DK#AjrTE1SPD_DPv6l|q3R`|<3wQ7T=Wi`vU8Z+BU=S54jD2t?dk|C}5ox1u&1|AH$CqDfdBELk1?4=bM!n@*NG?9Ix-iX#ezlb$wiYx(wjz05FMKxqb(G`Ep@6wpOX33DYo z_@r@FXHdULR15h=_nskFa3BMy%mH;?s zU{>eSm16HvhuV1yC9N~Q@32MrpXU7^E@W&3c?TF0^Ke^?qx2-(KR&68Q}a_B?Ywn{ ze7|X2b;NuqRPz!d9ev(f+Li$z#a1*s`)n*WP|;s(3JzTv`e&v7v@X7wLM`;wKOE&F z3MvnZ64>ivqp z?xK|1%*On>QBc;kQIR$*?8dD#i#bK!N7H?Xk)$LI&XvxUq2kZf0=4N{wNY~)U)yOZ zntD~9WWGOvr{*VaI@NbVtBMk<7NQ|$PHGijZody@;X{sJ`ELtFX_&HdH%$^p*EB%D zbb9vcB9f~Zb-S2wWr(ZRSfkfm)@RNae!zERp#m3^mIpc) zMs4DLJ5zJVX2&C_jhebIk>RIix~h_$2Im}CD{@H=)GM7u&-xvxhTh4( z6HP1Q!xm6^;n%2fCR6*U(%d#Zv% zedoSxaqDemyw&}@cx;La(RigR(rZM)_nyYl6{jT`yxhuZ$vfjC6z>ZCY|@sV z!*uI^`b4>Ychv6A=tx<6aPVAV=i+j%r<+J%f^UjTy6GdT`J>0$z7L;KF=avrgbky| zFH}iXha!v8`*W;{S5tJ%VgV!0VJ@Y7R`Feqi|5JR`^<&JaiUhWv5$PIwJVonRXh&` z9vD3(rFnF*xAmt`f`1@-lVxqUq0{Ol+6CjtB)iR}yo|Ch1~n-0Nf(pt+B#e2U#zIA zlUL@2RuaVmO}NL;6i`@*G)rgdWWN~leRv`#*@e(mMGo?}W;v9v3JP z9ThU_X>XVr`0gxN({KRfh4;+I&Fq}ycTXbwWcpBiP6+PO4^;0_n2?v1%ZVA^tDaR@ z(BzfDTkEH(uw+*MO%ULtl2nMPZnD>X2Cq&oNh|nqpvQ8%+4vg@7q3WPdha+!$@#Q> z@fsiq4yuTx<;qJd@~b~d-zp~?IFCFG`1v1B(G9|D;8@MVvb(*l$nBGqpP^s3x&Wse z1&+PO%BYaTqh&|yzgLlmxoZ7-&x+RB%=DOQCkH$NAwv%BoB*w#tU?_8HeWEF5k#y& zusZKUL9r01&{udZlc=8;v0`=B&5fdRej~p&28b30JPzqw;mHqpgcZ%qE^Lj}+Xzid z$#XIDL%!gZB4f;f4RD5@2;g8Up7rZ+Fjh5e1#9-kXhT=-;mF%Or!dF1b>({5Zv{Nx zyK&P>ZsRCj9W+YVcqkhKkIhF!nZnt(@<;AK;s4w>sC#g}F$$U#1_Xh@ZY_ZQtljNp zyX^D1a|=-;J0}Fo;09qLlpNQdxP}?|V{xhd3=RXZ{7}7u8nO#!V{@LY4*h2l73uDF zx6orMcJ>cC9|GWbC2qO~DkY-q@V5aSk=Wv#Py1utp09q6>sBoyp^C8%AA$$mA?*hp zH7fJ({Es0FM59gZA`IURT+X#P7h$YK#-Ne7#51QL{39Nlk=7YX;p=Y0O^-0h7yybS zYNO8QkNJWqRHX2g)zx#XuHI^O6$Fj7)!$iNZ%YYodWnmWPn6UwvS0^Fh4&(AfN8^eTD~mQl;Q)MaZEld7kotT&eFz zR~LF@6my$X9!K@NzL89&USCqgj_n~ym8W5giarEL_*rOoUfBS$wAKXB2L*smkLBOH zo8V`$cduZe(;I&EV{LQUZLMv)gRvsR!^1%@yRV-~biv4|?08@7`#+$0QdwpX0J?|o zPiN08PWp(%wmO^fm*x6zLD!y5*%-?MLVACFuM-R83D$`dtI0r-V(T`joR5fA@&4ek zO`uDxzVwWU$Z0k(@#mQR=(nZ%g2|4S2kvIake!FyMa=H943#GA75Z$?Gh9#kMtaXz zT=FEz-Dj%rEYCTNy_)mX8K9g_F6=WT>YzZ0qpj_D*;n(7Z}p=M^75}YmRa0WqRsP) zPY^=4dbY_3tbzZ&dCiDtrsfthWzKPnUYY&=bE!|8ilKBK7slGEZGExQ=ZbX3p z_of{($q%2V?+@6#U_t(N*165&Nu07m%R|jlM_*^9!;x=othz+&XACe{vBJQj4Wi5Y zI4Ljf$Hz`~ZokU6;at8f|Gques%I?)_5cU|*;oqhKNPvH?&a@X;vwNM+tSlTTgRWd z^i*!Kz&9nIb)Eh1J0RT{EF@&_2Y{gEwy(P_WV$1K9_uqe{;q-U+=e}(J^nY{2B;7| z#*2zOVtus6zf-r8pLBDIEZhW^buWI3Ml%Qbuoz0A#59|V$LtH|%%-`2XChExCvP?N ze6004gv^H*`_ccwv20VMYR>3f=iqSibIjoI!BGYC!jD{TV;!6!R&F`+oB~-?iQ=90 zLa&I$6V8(_oKrRkOQ<@Jxp;NktF}H1qETJaGwxSMcQ=wM^|GQfqI!nzXGE1cP!o$k zAH}J?EGtVE3p9;ItC5>i)VPT?v34QOogK|Pu{zqBUheM4RGnwD91wUx?~hY*J3MA@ ziz;&->a(Uzb$FqvYB?>=-RiCi2gl(r;fr;l9U%#of1`CbZ(isfOsS!fAZS2|BBj;g zDXp%6S8GVZN+= zPUO~K>P;>-d*mNDS?=*nXHnL_AMNR%oDp?htfxsEn&>AVwT@y>wcEi$KNW9{&!=W| zSZk0EKq%RE9*u&V?>cAO*7|rcrnUM>Rga-+L{EFJI7a_uLiP*GT7|en ztG|VRowxU1jCRn`WWIc-rhUIXDwij>_ZAsjatr)_mt%{Vk6k(p-QkgMtZvT+QXih{?2DLR8GP<#Ny@$x>2 z6=}Pr6ghTG95T7;inA_EF~J}HmfQla&d**7W<@RvV|I5o3Ny3;UF$KEJzl;2jUz2BAc?9!Cg7j-?`9o3U6g|o*gqXg-e1Ou6WKM?stG?*XW zkWZfK&vocdaNy8feUl&Lf>NIyRBsXoHpuT|igMdEJ6Fk~sh;`VhApI$Nk;ex!YrUu zZ;~{7tQ{qZny_RZDH7oqd(1n1ZrehfjXiC%I{ZXN(QNwwZW`Hyi6(O$vF^Q%F^=8C zyrT*MvdkR__ph+knGS z+WI>2$7mWgcQ3CwZ|+ABvG*dRhVv1rSlsn_7&l)k@YI!8`?ve$7kRf?qgVy+tI zyR_uhe13FM{~`SN*l5MnXv0lXuXX)+yOM<4_1=z)OKl%@%SzCmYNMXP4n@V|(=JAX zr~EmuyJmCUT(q#hCfp*v+}V1|%XSMyzylU1j^=(#}#>buv$Fjw>a>E{n>2 zZojvuo0^6?EuV?SO%K_0+Kwrho0@FH%RA|N)qi)M{Cu*$bW5sR%k)O0Y%Ytk>Be)# zQKO0iMQ(b~!zFnDYI zF>Z3Qy(fq|nyE=x>nPXZXKN;#1b^`}y;DXLM%R`Rg@BHy^DQ3> znijZov#43_)$$Xc&V4B;E|xM$Ho0q%FR-+iHdG9!EoC0EomX-jk#PFB5Mflc7PT1P zS}|^`I;Tuq507SxGxh6sqJ^uSB(~#v2VG@=%zxE2WyWU8_7w``V+`}b;-1aM`i}OL z<+=8S59@R})`t_~*xPNre#U7C$$*JK))-q|R#B7R;;Q=S^X3MOXji9ypv zAh9_w56Ew0uJo_xF>yf|pWRjMPHs>vaby~Lp9$P-b`WoGeR37s#GlNSI*H$(wuf^| z$$iaJA)+N#hqLa$gz3YCEvsWcjwqlM z&!JKHl)r7VUmM-lPkUv2a%kpZ`HGBcBRiN%fG3)K~qxrR9+nHO_aB z`Hn96S;{91UpEQYPh;g@#$4~%y(_O7Xz#Luk|xJ$^~SXO`)iE|8F`m(NAFK6u6ObXv)RC=iSIW4r~AvZPx+dg@8Fy% zkad4ZUW`glsh|0x>AQlhiS{0ry6$!T@Br^Kc6TTL(}~qh-%r#o^~I0+?x}C;yz;QR zAoU9h${SPeBN9D6`ge3n4I7@<$Y$nub9-o9c_<3Cz$aZ;?6L5eGl{RKAh=UVuAGgu zYjER?Pg?yFRsJe>l8wJha0v?TTlPOG$%?tiH#gC!78?h58PyX@Wpn?1G`~|$j!e$E zZhK=tCN5P3Y?F$U?QB+YNZ5hJee#|7Qa$Ao{<%pvE>D322OQ zBemXtQ>&6^`c8aR{li(Aw<^JRP>NDza|X2mE^GqWuTwjZfu(n)VXDe9 z1h1K=G9f3`|1IUBfD%-vQfFt&Xmh|wefB8~TYLCdkHCS!NS_@pP5+!#a~yba^Q^At zPftiL(EF1OiLC`F*I4!v_9VVC@uYZufuToy{SCK|!kpsyBsMJSY}2O5+u2s>JL~<~ zue26aN6Mio=WG8f|NU*|(&ek$g|F0KqJ#@+kj<2WCGqTf@;E^hwj$h)-(EJssjlMF zm~U=Png3ld;V{_J)iGfAcn4=W;hLkpfaiOTe5p~nVp)$;oO5Mv=}!`SaHvF(y*ff( z#CRt8LCCe12T}@_@gUx+$gSiy|rArQYk#^~0~M1~ycN7Ej)n zI;l3Rb%qyyc86RgTbFzN&c4yOWw9u&y3S5s_3jn`LdGY?2?x~41Nk}SCpifo&^JIPyS7{mv-?I3xaGedinRey4Py_crP8np;kO z5>PxcDkl{GJaGPgKL`|2C%0D@WI7UEc_NX7K(hV6ZtcP-?6Y&eId(9<{;qMRHqphR zZKo5kjys@yElMyyBTp6^^1|FSWKzPg8q2}+lju7*URJ|NH5?hYQ|E$~)fa95FB^X5 zaD&OnsPT2{W4@io^Wjz+ZB##Z%qh8Ax*wZ5bRkV!3ctLnU4dyCzId)W-;)DYD`J6X zVdg2vi+cwc4YzyB$wBTPO1hk%7ynfa25*Dozq7Wh=q9#ZNb|2b+pVlVO@{mjQvnU^ z+lv&OM4y-&o4|3&+5*v+?er7Ybx`ZOqQU@|%spy$H^H zGz@cOyV2twV?a;xrloJEXU)rsogAU% zRyc3f#*4cX&O+a#3lsC%1r-0reFC!fU%8yTpw=xF z&L=LopF}|L@ld>9WbdK`T+S#qcppc>>Q%t(S<&i>L$9u5Zc2iuDQXn+t)w{Dv5{MB zg=H}0wQxzANqlDT{O&(3CjS0uDTjCdmn0+@ZuD(6+D+{r4v z*6aNDn~O1W8SYMlWRFzMQK5Z;{EtW5Rk+zrEUmBM=jRigkzlXkVV6l+N~l{{JWeec8e!sV{-J7y_4Hw*x$ab_nEP#hBOWos|J z3ka8C^6os!rD-!^AB=nEz8U=|bp%yX8oM|$ovFNHrO%W1MipjsP6P*i_~O1&^I*BU z;#kYW%y{pC6Vfo*H5&1C{E^0)&Q>++4$EE=hyR^|ifhSF7QMYoGYblY8loM?G$U2j zPO~rDdJ5l1rD6j4fuiKq*3dJuCv_{Y=xzi8f2TE^P$_ROlypBn9aJUlbK~t^0-KIQ(ii(Oz;}ULUzEE<>X-w{c;P#bkOGWmQf(N~Q7Wm>*T>{mH3yK1NKyxL1HhEzG z)c8X225g9S)26{9^WCDq_^EB!L~W6lpRZ?SJ_vNZt`~G+D-6=X?XfMY{KR8b6&ytJ z+YyTCV;A4d`7AE!kdQKo4YcdO`E~u8uxHb(T^KvsEh*sl2Y0#erFR`%V1#XrGlQ(8 z;-pj09iIEwH>1;Y&vAhECk?v}3#PMU$0~;?#4)~-Iu^Lbib{J;o#(laz)h|uZLr?x zA*hC$8u4j1Ar2_PqfAW3-&k1KoG1nzrBm`nw{U)t|E16xbR`b$U8a7%c~42%Nb#1c ztn{v*C!E;`THed-`aHB~CGUpfPB`DirUDROgLB5WGpWsSDfQ{paJl==*a~KB#B;vI zUR70k*Yx%(wvt|ET)pkOkE23)#`%-%ia=A85vTN-?yJLTWT!kC1^mqXahTz%5R?@d zd`mdsmDNp)J3W|p@6tDcG$v!~JKJLKV>|Ugg$Qh!v1K26Z3k#iCezw`vsM93T>Xt{ zBItnCN8z(Ep}ObGmcBYcvt>kRXpJ={fS+b;87sMZ+}JT@G?oA7{b`=+pU}dwV^ufM z8BN3bZyGn?`H=dKWF#%D?>fhFWZ=VoW46MJsTE^XAEPp7e3ii&A;En-v`Q$bj8^{zZ zdKk*1x-uCWitdJaxn6kG#qasS+Q4H2yipcQKa5V`*-P{p(GGeHR=sZ-dG2fG02R!X zKwcz`G2WOQwZoP=9H2wibmjIEIRBK zTr@$P`P*ftoC#daM+$3B0=U2|7wvc~%a?kb9-F_oz1anjWSDZ!mq}0wzO5_L%7$ka zhwwHA^15}(g;06%txVBKutI^QA7f4zqg5!dWY)`|Uta|?a2bZsW``pa%rfXY5~d5+ z9>%M%g~YX>5O%lUiPkfKjb}mw$P1gtA{MfktpzME`!e83C~^%a&}PsAAepK-m3;fL zQrP8w1M$t9kFU7WG+scuIG4ZI_*FFA-_#*qB|^Yv)O9y|HSodO;eGMmIwUy8N39){ zM`VylIQz1mW0OVRt-Fb%ss{PYoMsE92ZJPO#V)X&3V;_nO1TH!=0vnQ30=3`PbVAFyg( z=nRJcz-wMui%$TWZs=GXL~Zk!&;LNB_WGBh2`UHTWQ1a#2M)f-1HgxwlHFtl$0#$6 zdK-*AXu4~XI32s`U^wdCZ4mPFW#N;cK40YVc_MMWB$hkGBhV+(Orft=!>>zJ{4I* zUr@-%$zbQM)q2n!1}J2BBz(%MMz7|z@K&rE%{Wn3jh>KZ9FvL&i$>4=Nk4n+*N;Sg z;Lgt&bN?BG^@EAC%tsMxPz97Z7$5tKML8Vkxs1S3mEGlDx_Ruy(MT*$KOI7O%AGXEdKyI&~5`}8!;wEi7jjsOsdF^*~*Ik!z@Pf*Ro_KLHlZD(htAIS!>djx1M zP_UCPr{nQ<^I~g=N@3zJI7x#MDefGW%}6thvdnM(VPsfI=}{JOg`Gr(krmL5u)Ona z&`=cF4OSPywJ;R?Q=~uiQ|)6NMKm0o0ISJNHtc^@UTC$~M(o1F_4!+oEvZV5D)@Ha zpO#jVgPm3$(9_YDg)U-bWrcE(qKvRE!#qq5j4G_Olm$5s*7w816=A57=+m$BaxncH zg*19N1L0c6@Q~4lrlQt1=c3#!9ymLL>^oQ@X>CcbN-}gx*!60WdG2nv7k2=>H0#1 zjKRWMl>0R+|J$&E?=a_0>Y_GR0Qt#V1EMDj|zJYII&0g`1z5NKK9+Y#p(*t zSJ!?1fvm(m3l0evDb380z_T~Y(ppAfr!@<|z*a=fV{tlnUo}ywkU8jMLig?6i?9%^ z-D<1?u!&F$bZc;`dzrl)M+S$7ZHhFJ#kv@-dIC@p6+~NcN=;k{EQx1+EZ_x~!*p;d z?zoObI2PpJV4;oBJe;@);XJQva0+`9MNVfHe&mhRI(ayo7D15i8RYTw8@$Xjj~e?}n~|&o_-f`O zEf#56tI@SnnDy+L5gl41X_XnHi40J=`fQaMqbUsSyDFn{g3p4x$>PS{qp|Q_dus|?DMepN*H+d5bJaP@KUk$3VA~n`+vWddRoLqc*DdIe zC~O(SUX}j}955EO-v%FTVm@LC{{VWDA;0)zYfKm0!C17HSg^HjV#`nHPXLCoX!2*C z8bcXfDMU1wDEdaoS*&pr+MX^5EDriE2C)Nbj44$PvbaHPD4i@~an~RKf>1_D=YAB^ z4Fb-{0&EdfMx_EzN4+;^3NLbEb)bDceA4}Lj{wa&gj-pd2yl;R+en61I_x%n@~g*5 zkblc}1wY@?))E2@;SsE#Ajj5xd~L5l&{%Ql7mr_rrS_#>-utmWuBRvEh%A_HdR7q)kerlC{lT7hm_V?5{_x>cc# z*D)T_A^Myoo#O(?8q~vT64ub#3P)jsd@>*^H=(*%Q zSMa*-B0rRE(nfKS2$LRU6G}lsL$L(b)01%em__OPUbhDtMFHhgf=SwDv|KVJ(Pc{6 z8)lcV2hOeOG3El~JWu~>u!>jZLq*;;;^0UyNZW)KouNb~`d$;>ys(I{k-*g~7&Q97 z(>E-< zZ41pf0XE4rlHEsZ;cMt$A^{0t9{ym}xSS(^nIQ1pQH%DG>oK0Bw!-7LQQVZ`3jOl|> zruSZfZd^k=Z%Hq7(6oeRY+G~le*+h$s)HLKz}0SX1Ei;Y}g_c!j|^Sr2A z&aSMrmbdYUXwbWw#{Z4l;ktt(7}kUo)G-gCwF?__*mpGz&%kL!()7N+b-5ZQ_&)X0 z#9+L*kCDxjXgBL1!#2?TE%R+t0pN&?qd&kA>2^nlOtNro_GsW$vPtXZmAlTO`?` zy~Yk$UR=u>sE5sPr416JH1a4joEu?%$wp$k{-4M({p{RAx)pIJ`=*fu$hv}YI6C~; z5yk|ozMiLS;m38P*4J3*yEy7TyWM;nz!%of%^nz4LpZq8E$i26pWGhb-h_4K`!P2+ zdm0wsGV=-%UdBW*o(pC=&(kD}+xdIPcoaca(~tTq`bfqiPez^~R8WA@Pio?5|8dV`bQ} zvS&r=rkxg+^vuok6r6lA9KE3jVVb|8J1i6TU#HA#CL59liOX$LOVHt_MIQReGfDP% zT7@lw4bu>Le%=0eE8+6sp((Vl`3??@lY)eX=7VU_>LHChc63!z-RNMXrudQ&zfqb8 zTZ`l>VZbJ6_gLxs+eI7-!?)-WAA~2LGTx<8^X`{c}$QQPT?W9MG8t^WSp{T~cV_J!A0kA`%U1&nX7g3^;cHe__^a&}&xK>vVvN;kfsKDY7A85Fix+wkg?U@hlPj#;^i+yYr( zvVYZ0V$BSa`1+Ktz^hYrhLFC5h+gI6@o-su30aBD4?~2NsFR;O`J!=Fs=RtYnY#|D z!hfHBqMFdM{h5#V^he)c{6tAOyMHoj z7;fSOQphJig~IUHIte~Vro{+f*^F99EY8UA_``bz{|6|kNJiCgh~|+0g^2K-yEGm4 z$g^al2tgg@J_Q~hjrG zMGbA79YOV{*=@#;%AQ`xvnt*L2*dSfqFdFdKXFQTsrnEM?nmh)rWh;Q9!g>-q#DQz z2@2lv8M%9_b8*m6q}s-Rd0EToJomr2h}EnwT54#F* zjK9s}?-BXHHUW zn>Hg+Ho-Ys`X9^p^S!rwA9zgP^hj%LyAf}PFL2~QcO=QwVu|$iwD+c(tsqN$r2^r$r&j7nb74*!ebcdEoAsn#T6up9@-+ zDr;dNLb~NGetgHm@c+OZI&jb*HZu8n_UMTr2@f;(Zm<7p_BL_wUkDr=Y^d_Q#)fYa zqczU+)VGb8di9r0JEqbiFhP373jOjS+6cr5I>G?RZdut7^u$d1MuCCW~^5Hbj zns8y(e8R4atSsWvecqai zkv3Dv=(56ToEd$nn%>AqPZ|ZkqqHPOGwc+DgB-kAx_M#b^bF1ev9kx(cr4o{2-lDyF6;Jr2+opX7&q9@ zqZszLx3{Nh|z=MA?AZ0kX)wXm0!+4c;t1XRJ|E@!ezsq0Q8D75TcuMJbeuk&Pe#*+_G54PIn(l*BqxI=3qAZJ0ZR`Ph_~d?sRT;k0!*2K2>y&|qo-->+iDqew zgcC~9HFxeg9BsoZRi3OJ1-FWiqQ6IGU0)|WTy^@YCfC|$;r7kw6-@H`wZ2aHls+-0 zew{LV(er+!{WN7(re7x`h)5QCDM*^;iXj@VOfT5#Ik2>KLPPojwbmM`kEJyxbj2j_iAC)VST zj;xu8XpIJJWr4DLl7ubF%WRo5>vo;)rH);kFidX9UJPVIpBfz%k~!d*Jl|Wp(q?$- z+bNOfWLsRW~ z%9de?pv+Gn{s&Lu{vrH|(SrByb`|T8+bDSMYwl~7;45{XoK4vsEmw(ANfLT6ZG~G@ z7p-OkB#!{j_F2qX*qaCM(1Z@0n~sYseBHQo7X{GL)kQPBj^kAtr;S`9KamAt8?C8k*qkt_KnlSnt3)KXJ%;|Z>- zXcYc`-{6S{S~Dp=CWYr{LJ&lii9U>Y0$f5L&Yc4$yP4_8j-9p3OHviEleTUAj1a#n zSG>)V2~=}Yw>@>fWdD^t4L?rtL<%5Fmrx?)xXt=b4Q~WkWjcGm-GrO2h@9mgm@mH+ z2ycqH`5fIGpaIuz9T%*WW6_w-WYeI__mAdF25q>NkClm5#S;f%4<~5p`p>Yo>_q%x*`=#K zN`Yc>P?}Q(6xkRy0sIwszjb76RL-1nfw->8m?K{#*simEh5}vI{4-i&udYso7&`od z=p#K==&K|vcTq%F6*7z9CSGLKuor8n<;P$9HS>rE;5S+LSb3K|auzn^=!`i-9&2t_ zdQX9AlQyl@>f?uz>0&aar`F2u3@#~r8XC_cd4}_wv)YQpq_JA`qlEA3Xm}O*onmYV zywm*ilvVOiqDBro2-Ca_>q+wUVicDIr8vp&{$%Hq`4Dqkq%L@yT*gSuy5-P13!%Kf zISc=+zx{~34`%2UMdMVVoqRrrWTLB0?@fm)^4C5`!FCsbCPD=dbls)`GeT~@u-I>B z<7tc@7e>-Al`*R+Uy;yyadNm7?)#D?8CoR~_6!0Sz5LC^?P_|juab~LkC7<4(IaE% zomTcf=wwi3tXK{71n6E3IlHFZPSbvajP7ODkn6d+8UUdi@ob*74m z>!m!zHAs)$`lbvAdkmT=S8=uq(i&U$bV3EbxRxLZN>H38J2&qnS#5&XAV|+#REj34 zqhcFiTeIn#i@{YW0NaXbjRxB?iA(wqbYp|x{g|rV3C%<@?k|WV`0Z~`BHzkT`Cv7b zl3@JUQr^I7o(TDpx}3brfxy3z(Es*Hq|Qi6KQOM~8_~5g&WVU0})6Y z9O7VH3~34MSyTCy*G1GX|7{{4h;xNmuzYy42VTRz3%x7029~uMg%(VE7r`0{!k>|M z%6mhsX_t{#-iM@3AaW>|u%wYdAU&@?cWth5@42v zF(zxJBtUbCX!|v#hHn+7F)w(V2APX_Z9zq3HH!pP;Yq;1@R+S-A&`MjSxQc_gmI5Q zp)X@i{ecOw7gDMsrKdA*z1tV&2$?z*i>2mTnE^H!!Njnp<^u~GD>>xCx@E(g@I*Ms z#eA(!1o;1!)X0V3{j(2#t-vPq?qteqvKgctE={Z*1h8aWSytb{omdJvQBRR*h2P_I zlS_TypTLFYi>{V}0Ki>>*>tBVOW4}d^q7QDvV8GEp*Yo(`$|vyBd^w6%L>8IriH~| zagQJGIB5<`y)ePAk#=!AR_Ab3l{BG~*WaHV`9uK1<3N@+OD2+}vYI#qgx#=E3&5CSoIUkE4_47f)6TNbni`=E#d1r(f>Er!s>! z6r@4JwD;g8SQEvd5*iGk`p%9~bJ7=eCKdy9|9FF{3hAAE=l`u-CtT=w>v_MMC=$;o zxSF+c+HaXVU+vH*Ut2y+c5AH3!y`ewyYWE>xBve9_3gPouc7YCx&99mAntnldSUiS za+ucH7YXW*p3N;~EtzUQ68iHB=jSM5>>`HEs&c94$xc6I%I8|jG#kLDA=LqZr^gp~ z+vCxk!KQyeUkSwM?FZI*ZT4oVa@U=1AA)jVj=OOv#VWxyy^bbTJr^3Adrx#a;~8?h z7Pfdo7r&eS%<6col}s({mW0oK(A!C7zma~s?`W*8Xj}RVK1J`P@zxTN@5=+FBJk24 zvK%r^U|lc!&P{*8h-g$Cf(`||rIS9vhqS{sqFY2;&f|g8B2o8{7aXQHVH6pR$z?R~ zNh_S>h7a}rrme(5H~i-beWfOA*op?gYegF4p8J=-4wu;C3|nQO64Be7=KOaM_f}6M zrAUC)p{Iv0BwF-JUs4ltp56{61L9zlJ^Uj_)M9mjreupV)DUz9jYH#4_p`2;#$EBf zu)hv|%8gcAL!-W1tI9Z?lSgJKpbud0^O-g&b^QDFM%buhjs!Rva7>TybsL>%VF#q%n1(Ynu?kxzhuu ziV}PKn8ePGay^}22yJa7w9Q^s*$Ljwf}`Be+~*`|S4m`kEaV32*@YjuwY6;=$q)6% zpwSxRWQ5+yU3a;20FK0J8qdKmUMS)M>N%f2!7C|%AWP%;Xd50?y!{=!P3SsX+xg3| zf56jHMrdCiLN)<-}u)_`xErT7>m}Dq4*i4&EaWvjq;kwn9^F!cF=Pr0KtD?5z&aklc!hSr1Lq&8$18(sV90-17Ot2NE7QjniZX58G`33nKpzB1s?f@_{ z>}JQ9+uOg(u-}M&GBdju_O}zn*8l_m?>2KUju{~yg5TGw_`l%?uB_YE$z3q$-@*Sl zxxeA}@3tM-14Dy@x2W%6!$&kLnxL~IuMbRchYAG`%c+K>rKJI}r;mxcs*{(Xyi`~e z8h;`JhV5h*Irhkh96aCS+;M7&(6U2Vq@k!Sz5(+CJtJ!Ft9Fn4=rxOc%@3Io9j+{TU!)bNx_x_=v~O`^m6Y*I$9t->ek{V zs9mUp`qibs4x;eCXxb)-G^)ciKs!zBE)i=G)wP{=j*5S=iUzpRU`Fp2>xpBf=nv1a zY#F;qBPn{~duvWa6Oj&IXo14C84p{y+)>^!4MO(VUHZ(u%TN@F7^F6@l@iG}i@?D^Kv< zX=|E@{Ys-#)|?I-J^9qVHI*R zZN>@0Iw9-1(mv1mA6>|SG&u>L)tG+yL>tL10X_On1j<25Ow&;C^Vn#ldkcG*mV=oy zSf>|K?J!a8;5>k)?!1vfXBmi+VCyZy&X0#@4Ld8q0I1CiwmkGer z^P|gn?f`PY_|i4V1zxn~Yr=k~Vvn?rhu`14fG-1GLCDUqfibbTM=g08uvZ;Ebg)NO zf>!T;ILqIFgKgjN*&MAU5M9RNa{z^gtFOb>qiq+xp>r2hKc=$<6I*Dn`J*a)z<);L zamWQkB|#`{YhwFp@CIga$OiO|uc0mQq=B^9qjhTW+mp7sFBf!b&y1QT!Yf8_DtcKL zk7r>tAd5cXF&4EzFVYNr(|WW8S+tfHJ-{Mlut?L=-t_L?uvB`lWE)B@W>Q`?p! zYqp2KM%$jc;HO5RFpRZ?>79XQ&}|J(RVK~wp_#dq)Cm6eoyk;lyGk;yLbdxBDK ztWg5cuOEml%FY&OvOgkQyn#nugY5N&_+2#Q5ebwCt;bN%ZxD#3PNu;ef>_d0v&(dE zYXR4CCM@AXmmnmVhcrV%jd%n-LPmO;oD??Uhat(M`4I<*6JKZP5m&m|7vPQnPka5; zTX>)X<#bUEiF=`I4dWn7$jsXdL*vR-QUzW=|B52Vjm817{I>fXz{q?Z)Een_Bh0D9 zXPt`b(Y~soM5T{KMPI8TI^X5Y!eFsAH2n4Yv5vvQ*qU}qS6Rx~MFqHQFS)u>8N(_Uk+-l&vmtXS+I-Kc)sKq9B2(w+(R0H`-M4SW9ytW(z98<;if z4$@uu!k(G+c^@3m+R6>k!w??V=q>O}n_yd>c*({lAoe*?lVcMgD6--ku#Pl%?4X8m z7q;75y@lsjU1>nHS}MR6MzN4J>_rI}YKmxbl+D(Jgp<(S{Hni-7f;+4hT|exJPkoI zc?)SUGch1BBPR#e@oa1)z^tLMo3XQ^Mmj{S*~axJiB^g{girDF^RKqKYpWtFD{Eon zsRUZy6r@Tla0))`DC!u1SF}4=LKSeWGvYA5^U364DF~2D>rfvozKK9|NKB0`Ju#%$ z7FZXs$ZH#oueBUvg?+#nm&eNV0dmP0vgPw3*0uVh3LoG^FrPwekeW4pF#UMI1Kv?W zjOsF?10}e90(_xg7UrMFm?KOSh;bvY{>{y*q7gI}to&5@mg*&Y7?hns2BKdekW_Ly zljeW1ZxKksqMp@xS@%7qe|;2`C>-Ej#R^H_Ee(5%>RIUkcuTu}G{#B?z~8he$UKbo zki-%5={liNQEu_xM|EI;7a{IIk#@IAhSj$cGLexahjk!|)j>QiI)E0j!H#F->s+uL z5o;?3@ksOz1Fv-}o}+!2i(<*T73V4;Vmf?;g}?wW+TFy%Vx=A$)1T>sB;47+vU#Kv|I#Nvq#ThCKVGGD_^ z-g3o6MmKJ5lX=G|FKi-EW~ef zGuM{QVns8-@G35Bc%HCkiB7<^__cV??#^bQ{BE6^g2j{xn1kNo^jHZfi_y&se+ki! z-zXN3uP2NEZkGN!7l6)0G?=h?9qQnpBOkVY$-=6D9u2Ou&@AQ!`jP9WC4zkG%?qzg zd$kCwdFdG-?^aG&zwUmd$W?Nhp{#Ea^T!5+u_)^)nW6j+L%c*4MPQ z%Azx@i13>BP2Se3Pgwq)Y}Q&xfkJgkEJ0;qAKAn+YTI3QNcs<|XRi1prug_*Qy zys^~^k3zp#m)-y*)B94YFp}B=5m*2+4G=*qs6u#1ff^&E`b$W=Di!*QT|oWU&!61v z>>Cu(%`EN?`053|DAiT=kxB2ol(k(zEH-^C-F@m&#RlxudI5C(gb9g7jAzfA43#3j zIyKin1jHUId*GzzXiTL{PCnxw_vQO7wP$6x}~F8x?aG#fWKKXnmyt)>+!dR8f+r# z+H8I&$h95+)5Yy>#cYi$@Or`OUS}H{8#Q>U7lvS86Iise`RE?cEqL)3LOZ<7R{2jB zVPVLCr@CR;spK;_Hj9D|a+QRCXa_(s<@Re)Wf8gji%p$JnJ4aa_M6 znaXBs)E96)6;aX=ds?F8Rj~}_wcUPI{`<3147u4&j zFBJ1>7EzjzMd>~z6UNHHEZCreRCVtl# zr1xm?yKZh}ennkq$ED|WL($u(!oHI)NbTcxXx}D>%(K#%WAnBbu3WQ!_s(vko+=a3^sad% zB%M#G9k0Af5~?;0$?&Cpx%Eh)SKX(;lv>!Rfqo;POyG@y-){(6kpfFzk;k}MH=-|o zIWxnzRLl*+q{R*Ix>@8)P$N2C`ms9>&)&Yn*UxcZcFm9iZEc)I4vG5c4{;xyA3rt| z@6*8F-$7HplEl<0(yS69H7U(JA%!-foTxJ{VhOA0smJkA=>N*P@<6E8H+&>%*P>Lm zmRqDnrLvo;n{-=H*&r8c9DAX;~wN2!zl;t9Xp#?<@KiSusn8BFA*vHKL z-ZLol{pUDymiK($_rCA*Jm33`|GR>=#x%@nzrd0*8pVc@*=xTiI-IB5h{70#3!0lZ zYDk{=F}m9O8i$FN&t2}~`Id*EClClxD}=9Pdz)b>GaV~ULHQY0bz0%cey-zRN)cEi~Xrn4E8zV?mbM8ggd0FqkY&xE&*|57$%cD%W z>68?rblK5wQ;q8Wh*lyeMr&=txM8Lbjrq{HiSIQG~y0hn=#X!Y3)Q zq+HDEOes38(=NXobYFseDLU& z_g>MzfyZsdzmVySmYADAq(CiNNgRv32Mk?tX|=waX^UgaHvAsgJV5DXm0nis3I4E| zb?e=-S3QWF{!cH6^?JFp`EFszB~6{k))T=V7+2<21*l2DIFeoSr+6KDGXl(=N3fVrKFT3cG2iagpvR!d3IaDwER zLo~r?rU)Ww5q!3(0T!pm7j`7!VJg_}V6pZGSH~Ze+TGxu7uP_TU0q#) zEzwE0qgjYfD#2~Hzw4NLu4|WjQ&SN5`6zqa&JKlEwYN|#TozqN*tW=jEG?#(L(N}P zWtt>J4zLL*ell`BvxRS)J3yoL4Y5q2qX7PY`i&5cPITxlOK#Nk{4%Gf8XOtSF)kw& z1+3x2exlVbwqr-fdv8dg<+{)xX&8eeDe7;`G`;Yr*Jfm>6tH}bSTuxVYu2c(36a&7 zY_>e8VK|9}A>$_jqb%awxKRkG=t5Gg*_ksAMFYtguj7Zrk9L09mOzUS4~C_YXv;VK znO1Avr(|VGqP`O;*$6uc2*&U1*4Zt@$KaX()kd>EpN+j z@wOXMw4P=(nE*d61%6sNIgpO++mZZo0Rwx!J(?pgi;+vv7Yd{x=6EFu6l|cA-+QVO znXo5P@O_|@V5^GO&O`{6o2f8_Cvi`Yz>NxcKHWXm zMaM8YPQt_=;vdxBN^K_$f3dy1<&;=1Lt6 z36>8zouDra50F=A_%3O5lM@rEBb&^;2}K!&pUxabpcKh5d?vk2n?BV$kRCKymi%ae z6YQ}X>vNerc?hjYV2GIhoBTn-nvm+%FMMhe4?UT=Y4W5%lvSuxNU&0uRnBuii?TkD zjG@&j$Ythp>Tr?&U_F&SU$TIvHr zLo)!g|D7ieqUDIpBLklJ;(n+w?&v56j8zvaFz%N4x84nXG8*;I zP4$b9Da%Std=919y&~GO>aL1tMJ7MLP5bw&MkM@Cq@m{=09#DV8Z?S?|F_AFKh9Au z8u=j1UlBvu_=SwE!;4X>;i?)G-R{}@i$%5LL70Q|g!z;c-Ny-$8XhpGKzoL+{%e!_ zrIQ=_S#lO-ZeJn(>{-TOkXdWp6@Nh)vHxPPu0>;GDyXn6EW8{G%UQU>@xrV$TCGjO zwDf=!+t|>=i^_lfW&F*5?keC$Y}$t|yiDFHCeeWvd{uL0K4)NDw=b2^k`dLD3yF@V zFgkk{A&PgXt(mFK+;ayae6?eOhg07=)o zxdYS^!D&G%TMeRj5L#4(H3!E-XC;4i*r6dz*BF4a}O@A5>D zsO>i1l#BEhpmLw>72&P)YVfu7*z`JTKYeFdn8~-+vt#(OZTaHQ-Yo8n^6&cm-US(n z^EJ~Mj3HK6ZaV9Bqf|AY<2O7HS$5DHf?Du#qGLlt`rDIV?$dkyzIiIOknMcmEb-p0 zihWq&lgmp347Zuk^%y6P^qz?t``fZbdb~4}B8?Q-dGs$DK@I2O3Sc6=G*Q|!(#HR?~St~a2gt_DwBwe487Y~vV2427!vPV2n}Fu1K9hpxAN82{Y< zOi8&$q~LmI`c~ix;BhX1h$%bbM=)ibo{?SYYiL!dS`uU{M!I#nTD;xrr6}oE)gR0A zR1xyV4{kcjQyE`YrY~t6;?;chq`{$YzD74dekQ>#XICg`D`JMetMt8U_K^b}q;X$M zn-$ErN(Z#)oN3StiOXri3zW7L6Hf-Xu)N+J*Age`J;*<%Y7)L}cl;K7G?Akz(1N73 zcB@eTHsE?Zk5DfABleQmU=V9}h$z5}Te`jUInyrMFH^P<(RyR&NlZv;qMYfHV)nPR zQ6Y3MdM#QY_whF6jSnt`;J5$93r&Rl;dLhdf`_q|0<829gyg>}TqNNB(I?ZkT!w-9 za+hHnDp91pUYwNYMi~&>eZXA4HK0h4FCv}4&e3ydPy^?4fsa% z`HH)M^2-EwG%qsnqcxs{wL49su1KB5=rv1z@Q%1-ZC(>=@Ct(XC|JMbcHk-U#esEA1giJN)XW6ZW% zws{BITpF)-!~c7qL5r_A zVyThUl*I5SY^Nk>3J%p!z5IBzM&>YoMsh5>jZy90)Gy=&U^hYT6$tcQJ0zK(<1 zq~}4Lxm($>lkJzKpn?tAFW8T_7R@}XIyy`YE!AWFfMJEo5MrkWB;FaI(k#cpx(8HA z4YEbg9Hb{S-^XqXaiuYuJSbTdWty7&Opg`AiYY@u@BEih+z!ei_AxTm=HGX-MD>CJ zUe@ul-sSwg&n(+d1(lGHja&ul)u6P(_Q^6ZMs>HokHRz9CwKhb-+bHZ!-9Qy{uNLc zw3qgP-(_C!aTLirI>jv>U5^jg3F)vdO++0e4!!}eZi_URdLSv77Xzbb(QChs#3ujs zlVDQ3B`PkVx4gZR01Mj#$L=)=PafNreh`o!vXKl{IrAsV+kWbcVKaLJT=|YnsMR4| zo|_1^dT>DI_6rD?6hnJt#q#d{NSq&@4%L}2ii9LRdoqS4?oQ}Hu+_$$n_r)rH_#Im zRoBuKh+-c0;YlnOg9QOHK-Z>ii9gcl^lP`i!()#veA6O^)XC2o)A^K_nHd&l1GqOz z{-4WV3=TBzmV~Z>0Up7t&SVi0!+Ag;l_om$0m<`KM)5E3`DPZDA;rORPDSo*A=8mO zL@^4`7%dk{7C{phj@JIsG(O_#?t#}89MC+l;b-oQdSJuDfH|qZ)`oyk(wNfb*7m$O zE~iutukir#WwaUTLO{|mb{IyYq;d2iYjg8EaeDLSXq@;-r6NeEA!taTE+w!-l+;u% zQOsRK?`Q6VUdC`0+($YhLd4KLLfYS?a_tOM6fxWf|JH2Ognz3S$-bBY2P4MDXiUqD znZ~t(_XO^Qlrsx-M;LRV3-zx3F*l;Oc9%hWTgeRO5^+cQRgK8WmqfiRqG2}umHvWT z%5MD$&7fCmTM1WpzxT8Mpa**)yF%PaKYRyz%oz{IjLd#y+UPNBpbkiZvmdxE5fV_t z-7_Azmjqto+3lGyCL)3U{_n|99T`H4|8Jhg62Lr4o~!mQB}?RL{+rEF&(!<&0?M`dCUjJ8G+a=42sB%JS4tw6U~c% zr6lHLO8AU!O)djSvPuDX%`6WebwCepfVAYI8fH(0{H>)DdlN1eSbduLl`H&V&^(8j zT@K^A_^Bbte?(eAd=`Zo*fUT@h%896~1=G#_7-sdLv1+0-DeEX)+81 zISTv^NqdI63C!;cJ%ey)GFQOvgZ!m;{?t^7UWq&hJz@UOhzdQ3R0AGeAo^&!L;wy# zURU7vaT-Sr#{e`d2>&>ZVL-?YaK)@!vp?GlNZd%&>9ibBK#=4WuxA3+2m?)~WT`?D z8DzKc{_g41=s2|A7+GZ|nS$JdTWXZdv~XJ$dhpDG6r-~wQ$P&C1) zzoY~hf0*8>Q4CbP;6r*k3^LMh#I)V#qVWm>$vJXFCK9#&ihPonKM`yEmJQQQ5g-eClQM8PKY z!IDlwXFN?PD}wpK8=gvH^DKY}F@`bNi``PB@J(DfcMXm$RK)_kq68f?OBrmXR~%CO z{Isx$30NByEKz>NOGu~|DJx+%UV^QLapn7V7G6RMh9TZ7J_|2F$W^Ep7;rBJm<+st zH7>hVZ;~BD$a6*Vrh^v&|7py8yNW(QDYcykK0Z;5n1ur%hSx~`fO>&4Ksi?QMkprE zwfWGQUl1Y`e+wIu1CRkCR~s8Q=r6xn_j>`9p?Dpxh<5ug&#NZ7eSuWyMlv4nQCJ(J zwK@~0T>L6N6sf~mHe0$}B^a^e7|oq@=7@EyqzEr~v9V~*+sgoA znAFzT0N0B&Y}LyE=f~o2*QoQ&PGInP0@dZoODu1XhB)1x2zC(bCq^RLwz(zFp;8Eb zxLdGmxt*1C@UYH^rHmI-sMmxjAQ6N=qRzN9)8xW{2iN;LEZBPm!<9DQP>BspH9Ry= zZmW3}zs8?;aB-f?lTmHqKZG7!F?%sRIa+r01m1$kp*tL%g0KIfG=sqIhw2l;OT@uf zKDy<)*G-O4?+wS8Q1*iSo9iL&dy-Wig4o?xH0#);fNSQ_G-2zfBnQA&@-_Sw!5g#(cll!M*0Skbi;3Y z=`re>GQTHJXd^&J0UN^Dr!J<$788u1MU(yvk%VQ16$f#YLH$UzGk59}-6qT-^qM_&(c*}y%qE$UluZ}vxU!r2t}}=z{pLrH8KqHPbJ$~wnpS2L^irMHR!Ye z2T;tLVQT`+&xYo+ZHt+h3`PrChz%DL{0bH6-xls@*>(uZ%g-g`~@N@4!x zeov;-zk}(#IB!CB4O0x133wt3`G+?BcidSh?LA>1)&cCTKp)O4{I?IE%s*R2!IC_* zwYAK3fA*{i=iiZWerhbV=`3Iv?w*{_(QRymt$??(;>pITenNs`M!$<)R3i>DQ-rcC zI41;)y|n^lSqfH3g+Ae!`4hiutDMg;Jh=9=N~9fjVss0$watIe9+)YabKMoM&h97J zJMeSoU;9Zq$bZE`XZDkHP;7~*_zapys;SqZg+GNY9g4z<{g_OcFqbb}|9&*l?$!jO z1LTd~91Uh1*x*~cc`knR`ozzWA)wj0>!|PM%n}k^H;# zF9u(D6nks+uLdV)&2_iGKhxl3*uSUFX12kxUh^3#dOr*fOZd-A%ryAsE#&u`K&LX( z;N+&c?u7X>4E_Q>zWBY_1~=R>N2BT1F9z3L!027o;@cgi=JMa_G*dw7gbgJpSQ}s# z@N%r1^sESD*&Geua%Q!I%eU|6ge&{eQ!CWxx{qj2^(J!K0!GTV83t#Zo1-BMI**wX z3aNYxx$6F&M|Nsd$p3^5G9Qhj!S)z8Pqmv?!j&ZG;TSk?`JPC6H0O!x&WW{6aI`6u zq~D%5TBGUm?c$D0$>n0gD0kc?J zig`m>vq%-QG|qD42L*`w+kZ@6t{ERcp08^j%=vV~qkmRa}On26kQ#uBYfTk(VrBn^{^0 znS3Phl?CmBb;PlOn7O{@nm?XKr}^X@H;(ED&b1thba|_wxIXK3O5IT9*xJ{EaDf+2 z?*q}CpH}F`im(20+ZfP;w})1n0qkga{8*{OZm;(DBfW9b+&2&SKCRqji~UMEg8E)t z^TA=z2tXqZDS3r+-_3nbgVg8u{-pC?l^NF{5X!R9O zPF~w=r3em|KX&14zSp+E4hyQk%1}eq;Y_y}^S_m~PS9*_9+1dUy_h`mEj>CctoDNc*Gt=9y%Y|!0$?DwfT9Ti z6OLH7bVT3R@gNviq}cj~rrSaZ#*yyCV=irNPhj<$gU>KW9l@?zz!*P(4!0|g5N)Q& z*VKl^-hQo>D~{;cI#hikfLyLSvGgRk<`cE}_oEp%bOGnh?GQho@EIZZ1g?9L3H}03 z+6I!d+b;%s<&ct#ab)Ed%v}~a4#?_H+vJOG$u}>fUOi=IX}%cXZxbge&IYfOg0qOB zhwhTCN) zBv2FgZh%d75VWWJlqc`l4hubv-T@H``yf%@H5p0P7uVWBp|uzgtSSCi7}6w-U^Q3q z+TVz8CY#p%uiyMQ&uM4U=knsBqDzR;4T*QaM2xQXsx%--Y4?g^t0j3Y>jl35){0=c zMm=uXB&!46IjLH4qhCIsMZYVy`n&jfu0BvRI#!DO`9?NPK$tjvK2eOy2AlQL!r|6= zdvXZ^^4x)i*=cmG;tYD7CrOEG-yx3@JEMP(mq&r>2vlp^N*AO7XQcl`6f6DN@_7s0 zMI>)yQft;Kwt)5$wy7)rD8cM@D24aZKcoLB-nX$CEdlo`S5>i;-FTOd{?4JjlcSVm zyt3lhP9TK>I1-pQ8zMzz?L7N2P^xd;=!TK^f9L7yXpTkzhMI6?c%JY_#!%61Ma8kp zwvO8W!l;Kr(QmlgSOxQ3o$jZ=Bpvaezq7QHqiGW6RHUb(|BncE+xIsQ|7(`MsFm3v zhL~?ss4|+k!j|Dkq8f3NPFDYUp=}blJ>2}E{lJu@?jg=Ef8bJ+3$lDA+Qok~L1pDL zDu)c2J!UUq-6C17SX)j{R)#V;)-W)UkwX+7zj3&D4pJv=D_9n(Tyuh#VD0sGDKd0~ zuOAgTqWiG^OHO|OHCcrDWRLzUpJj8r7r?67KUwPeuTx;%3M5d9_)YalTV=Bs)@n%N zt$K;ykSMo8 zXdV^g52Up&0jywO@#_#ltd~+^U_bOe*_hF^{P}RWon0o=XjNVLa+I9`assVkI&qcw zQn`ijFOO4N26Ma*oNZk~_ly)}294`dD6gCDGISP;7UcQuDREEVW7EjC^&fKGzVmZY zj2}C>8L0JeGiytyVD;p#J0AG&`PLLHqXj`IO$sZ!i?GHPiQM=MJi#eOG`Wmv}mn>G?<5J?IrvEJf?ieHB6?WuZ-Rg<- z>K@CX)+Xl)x=ZriiK;+iovB~a0seuhCT{;^ywJa$mwM?4ew{3$Q~61r#BP%Q%$_&L z#zLfRr5CRE>p)H!wLD7EdYxI;{+`X6$Vgt~5f$!RA~WkW9fF+9GXTuxQ`XetS{5P= zn+)RUgBb}iEB`0LFpJ_lk5{=~afntc^|_whqoauNWj+VF7_Fr(gq3>{Pp`iUs(c0W zX5LFJ3`e4@^%kTLxCe{ri&UKo^>WZE>Li|v!c+Nrza!D|w#_0>A#7uz2@^L6q3obS&EfMBljtxOX1(nJvB zQ0hXbvk`%y>1&qu4J5V9gL&&)*LYA}UEN}2s5L=eaxv3?nat#y6pORX`ZscB z1x$yZm78EuC%K@1-rEy%5NAD|UDhA7c7c+)%;$QphL^;4#C@Geo){1*wD+UZKk^>r z;dK(_)>Ie{YD)0tEEen32S#_!*YSpTvCfnb6VqXTBYs1Jxr`QJS6gEGH@5tQv+Svs z6~hzAm_X=k23DiHbjBGs2^8wT3CSO<911ZHF8AXn;#BfD;K?zBZ}yUvB@N!_%>D1B zjtd^cK0~cswsmmc5L>{n6~yP|bOv>4h^p};AAdFeH zZf@ntR{4LHkCL|Lyg!!9v~8nE9np2~=q{eRnc(TC?q-?pk7dd@-Qk*^EI+${>AQWp zhK?V%ViSzGq{q>Z0}K+K&vZN(=Js`A_>~g0P*aM$GG*YxmF7Kaabk>^j9ft&ty8uP z#5x^KWAC`^$q0Xu1zsdizDOadsP{>nO9wL>F`L?ffK+JF`1YIVzl~9Wm8Wf7`UmQo z)=hkRQc&FejhSvwpVYM-Rm1rD8cm{CNZlh1X@BvtR-KVuH}!%G3x$=+(BF`Plrp5V zy`P)>p8EFTIjeVG5Eo6fD_6F8O)xP}W$06w+4m97m`YWE4EWWL#-nu}A4%0N<#)O8bci7PAIww*Gs70LUH^S)SbD(^aaayV|`}v86zHfYdAkY|1;)3Qjq;%DhT;f-98D41AJqHu+A_t_fK2`Iy>dsbe@V zY;$429zpJQ>0w#9=lpp(r2}Ebs6+{~7b3z@Q~vRaY)hM`bGQBUwd6`04mL2*zmw zsfyB_1Bt2>t!3&wjj?Al4eEWF&*b>5lh7QA>QGVGl8hfVDQ&K_`NgbQ<@nq9goHN= za-K=472%hvm=QruBV=>dT{*?Kxqop0FrRn}vV_Lg+E#PM_iG}&8<*0wy=Wa*KW11L zDk+87V_bdr>PN4e1d7#zDwk*tD8;hRTsb5k zleO;st>E&WNthWSW$cooy7^HD2Hv?**_qEsR@=A4M*O(Udb7(~%By87?&#?btSFa| zmtQsY_-3a|1L%c+&+&Fqj#YJ~NmLh`mij`W0~?n+Hc$1HpvA8ZmgLADDxQ$yUiAzFARfbZ6BVlU5Tj)||dg*IRY+0mvbz z4kd<8ByQK0_hpOcSSPnwQSXC;_Tvl$U(y;p?&jq8m4}}Im(E3XK3q%R zO26OPY4M7YN|`(0bMvMrd)(WCnG|MhNKJ0(^b literal 0 HcmV?d00001 diff --git a/pkg/webui/components/radio-button/group/group.styl b/pkg/webui/components/radio-button/group/group.styl index 4051fbf98b..ff53fb61b2 100644 --- a/pkg/webui/components/radio-button/group/group.styl +++ b/pkg/webui/components/radio-button/group/group.styl @@ -28,3 +28,6 @@ .group-radio:not(:last-child) margin-right: $cs.m + + &.space-between + justify-content: space-between diff --git a/pkg/webui/components/radio-button/group/index.js b/pkg/webui/components/radio-button/group/index.js index 7d8aec33b0..2c05ac21dd 100644 --- a/pkg/webui/components/radio-button/group/index.js +++ b/pkg/webui/components/radio-button/group/index.js @@ -36,7 +36,7 @@ const findCheckedRadio = children => { } const RadioGroup = props => { - const { className, name, disabled, horizontal, onChange, children } = props + const { className, name, disabled, horizontal, spaceBetween, onChange, children } = props const [value, setValue] = useState(() => { if ('value' in props) { return props.value @@ -84,6 +84,7 @@ const RadioGroup = props => { const cls = classnames(className, style.group, { [style.horizontal]: horizontal, + [style.spaceBetween]: spaceBetween, }) return ( @@ -101,6 +102,7 @@ RadioGroup.propTypes = { initialValue: PropTypes.string, name: PropTypes.string.isRequired, onChange: PropTypes.func, + spaceBetween: PropTypes.bool, value: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), } @@ -111,6 +113,7 @@ RadioGroup.defaultProps = { value: undefined, horizontal: false, onChange: () => null, + spaceBetween: false, } export default RadioGroup diff --git a/pkg/webui/components/radio-button/radio.js b/pkg/webui/components/radio-button/radio.js index 4e3fe8261f..ba3bea4a6a 100644 --- a/pkg/webui/components/radio-button/radio.js +++ b/pkg/webui/components/radio-button/radio.js @@ -36,6 +36,7 @@ const RadioButton = ({ checked, id, onChange, + children, }) => { const input = useRef() const context = useContext(RadioGroupContext) @@ -94,22 +95,25 @@ const RadioButton = ({ return (

+ + + + + {label && } +
) } @@ -117,6 +121,7 @@ const RadioButton = ({ RadioButton.propTypes = { autoFocus: PropTypes.bool, checked: PropTypes.bool, + children: PropTypes.node, className: PropTypes.string, disabled: PropTypes.bool, id: PropTypes.string, @@ -142,6 +147,7 @@ RadioButton.defaultProps = { onChange: () => null, onBlur: () => null, onFocus: () => null, + children: null, } export default RadioButton diff --git a/pkg/webui/components/sidebar/side-header/index.js b/pkg/webui/components/sidebar/side-header/index.js index 80534a61a0..e6e318e1fd 100644 --- a/pkg/webui/components/sidebar/side-header/index.js +++ b/pkg/webui/components/sidebar/side-header/index.js @@ -32,7 +32,10 @@ import style from './side-header.styl' const SideHeader = ({ Logo }) => { const { onMinimizeToggle, isMinimized, closeDrawer } = useContext(SidebarContext) const consolePreferences = useSelector(selectConsolePreferences) - const darkTheme = consolePreferences.console_theme === 'CONSOLE_THEME_DARK' + const darkTheme = + consolePreferences.console_theme === 'CONSOLE_THEME_DARK' || + (consolePreferences.console_theme === 'CONSOLE_THEME_SYSTEM' && + window.matchMedia('(prefers-color-scheme: dark)').matches) return (
diff --git a/pkg/webui/components/submit-bar/submit-bar.styl b/pkg/webui/components/submit-bar/submit-bar.styl index 8e7eadb792..0c35a799da 100644 --- a/pkg/webui/components/submit-bar/submit-bar.styl +++ b/pkg/webui/components/submit-bar/submit-bar.styl @@ -19,6 +19,7 @@ background-color: var(--c-bg-neutral-extralight) padding: $cs.m margin-top: $ls.xs + gap: $cs.s &-start justify-content: flex-start diff --git a/pkg/webui/console/containers/application-payload-formatters/downlink.js b/pkg/webui/console/containers/application-payload-formatters/downlink.js index 8c156b71cb..4724b08096 100644 --- a/pkg/webui/console/containers/application-payload-formatters/downlink.js +++ b/pkg/webui/console/containers/application-payload-formatters/downlink.js @@ -52,7 +52,10 @@ const m = defineMessages({ const ApplicationPayloadFormatters = () => { const consolePreferences = useSelector(selectConsolePreferences) - const darkTheme = consolePreferences.console_theme === 'CONSOLE_THEME_DARK' + const darkTheme = + consolePreferences.console_theme === 'CONSOLE_THEME_DARK' || + (consolePreferences.console_theme === 'CONSOLE_THEME_SYSTEM' && + window.matchMedia('(prefers-color-scheme: dark)').matches) const { appId } = useParams() const formatters = useSelector(selectApplicationLinkFormatters) || {} const linkError = useSelector(selectApplicationLinkError) diff --git a/pkg/webui/console/containers/application-payload-formatters/uplink.js b/pkg/webui/console/containers/application-payload-formatters/uplink.js index 6b044a0dba..e99a3c3219 100644 --- a/pkg/webui/console/containers/application-payload-formatters/uplink.js +++ b/pkg/webui/console/containers/application-payload-formatters/uplink.js @@ -56,7 +56,10 @@ const ApplicationPayloadFormatters = () => { const linkError = useSelector(selectApplicationLinkError) const mayViewLink = useSelector(state => checkFromState(mayViewApplicationLink, state)) const consolePreferences = useSelector(selectConsolePreferences) - const darkTheme = consolePreferences.console_theme === 'CONSOLE_THEME_DARK' + const darkTheme = + consolePreferences.console_theme === 'CONSOLE_THEME_DARK' || + (consolePreferences.console_theme === 'CONSOLE_THEME_SYSTEM' && + window.matchMedia('(prefers-color-scheme: dark)').matches) const [type, setType] = useState(formatters.down_formatter || PAYLOAD_FORMATTER_TYPES.NONE) const dispatch = useDispatch() diff --git a/pkg/webui/console/containers/device-importer/processor.js b/pkg/webui/console/containers/device-importer/processor.js index 73058d9357..fc53b31aca 100644 --- a/pkg/webui/console/containers/device-importer/processor.js +++ b/pkg/webui/console/containers/device-importer/processor.js @@ -62,7 +62,10 @@ const Processor = ({ editorRef, }) => { const consolePreferences = useSelector(selectConsolePreferences) - const darkTheme = consolePreferences.console_theme === 'CONSOLE_THEME_DARK' + const darkTheme = + consolePreferences.console_theme === 'CONSOLE_THEME_DARK' || + (consolePreferences.console_theme === 'CONSOLE_THEME_SYSTEM' && + window.matchMedia('(prefers-color-scheme: dark)').matches) const appId = useSelector(selectSelectedApplicationId) const hasErrored = status === 'error' const operationMessage = step === 'conversion' ? m.converting : m.creating diff --git a/pkg/webui/console/containers/device-payload-formatters/downlink.js b/pkg/webui/console/containers/device-payload-formatters/downlink.js index 1430d0c6b7..96744abdca 100644 --- a/pkg/webui/console/containers/device-payload-formatters/downlink.js +++ b/pkg/webui/console/containers/device-payload-formatters/downlink.js @@ -57,7 +57,10 @@ const DevicePayloadFormatters = () => { const encodeDownlink = tts.As.encodeDownlink const repositoryPayloadFormatters = useSelector(selectDeviceRepoPayloadFromatters) const consolePreferences = useSelector(selectConsolePreferences) - const darkTheme = consolePreferences.console_theme === 'CONSOLE_THEME_DARK' + const darkTheme = + consolePreferences.console_theme === 'CONSOLE_THEME_DARK' || + (consolePreferences.console_theme === 'CONSOLE_THEME_SYSTEM' && + window.matchMedia('(prefers-color-scheme: dark)').matches) const [type, setType] = useState( Boolean(formatters) ? formatters.down_formatter || PAYLOAD_FORMATTER_TYPES.NONE diff --git a/pkg/webui/console/containers/device-payload-formatters/uplink.js b/pkg/webui/console/containers/device-payload-formatters/uplink.js index e5763f567f..6847b8e6b7 100644 --- a/pkg/webui/console/containers/device-payload-formatters/uplink.js +++ b/pkg/webui/console/containers/device-payload-formatters/uplink.js @@ -58,7 +58,10 @@ const DevicePayloadFormatters = () => { const decodeUplink = tts.As.decodeUplink const repositoryPayloadFormatters = useSelector(selectDeviceRepoPayloadFromatters) const consolePreferences = useSelector(selectConsolePreferences) - const darkTheme = consolePreferences.console_theme === 'CONSOLE_THEME_DARK' + const darkTheme = + consolePreferences.console_theme === 'CONSOLE_THEME_DARK' || + (consolePreferences.console_theme === 'CONSOLE_THEME_SYSTEM' && + window.matchMedia('(prefers-color-scheme: dark)').matches) const [type, setType] = useState( Boolean(formatters) ? formatters.down_formatter || PAYLOAD_FORMATTER_TYPES.NONE diff --git a/pkg/webui/console/containers/email-notifications-form/index.js b/pkg/webui/console/containers/email-notifications-form/index.js index 5fb0666211..33b7fa56de 100644 --- a/pkg/webui/console/containers/email-notifications-form/index.js +++ b/pkg/webui/console/containers/email-notifications-form/index.js @@ -83,7 +83,6 @@ const m = defineMessages({ requiresAdminAction: "Requires admin action, can't be unselected", unsubscribeFromEverything: 'Turn off all email notifications', unsubscribeDescription: 'You will continue to receive notifications in the console.', - discardChanges: 'Discard changes', updateEmailPreferences: 'Updated email preferences', }) @@ -174,7 +173,12 @@ const InnerForm = initialValues => {
-