From 1ea2967b359cb40debb9711819aff825bffe66ca Mon Sep 17 00:00:00 2001
From: Stefan Koelle A custom HTML5 dashboard that displays real-time temperature and humidity readings from sensors across the apartment. It consumes data from InfluxDB via the Flux query API and visualizes it with Chart.js, auto-refreshing every 30 seconds. The dashboard sits at the end of a sensor data pipeline that starts at physical devices scattered around the flat: The dashboard monitors 10 rooms across the apartment: server room, balcony, living room (desk and iMac areas), kitchen, bathroom, hallway, study, children's room, and bedroom. Each room shows current temperature and humidity, with optional pressure and light-level readings where sensors support it. The air quality dashboard is a standalone page, separate from the main home dashboard and the Tasmota energy monitoring setup. It shares the same InfluxDB instance and MQTT infrastructure but queries different measurement types (temperature/humidity vs. power/energy). The home dashboard shows a summary of room temperatures alongside energy data, while this dashboard provides the detailed view with historical charts for climate monitoring specifically. The plug collection has grown over time as different brands became available at different price points. Gosund P1 multi-socket strips handle areas with multiple devices, while the SP112 single sockets cover dedicated appliances. Eightree plugs are ESP32-based and flashable to Tasmota, while the Athom and IDS models round out the remaining circuits. A Tasmota RF Bridge extends the ecosystem to RF-only devices like the 3D printer plug in the study. The goal is subtle automation that improves daily life without being intrusive. Lights turn on when someone enters a room, music starts playing in the bathroom when the light switches on, and LED matrix displays show the time, weather, and laundry status. But nothing talks unless spoken to — no voice assistants, no always-on microphones, just simple sensor-driven automation that runs locally without cloud dependencies. Beyond hardware automation, several self-hosted services run on the Synology NAS: TubeArchivist for YouTube archiving, OctoPrint for remote 3D printer control, iCloud Contacts Sync for keeping the address book up to date, and a Google Calendar sync for dashboard widgets. Each service is containerized and backed up as part of the NAS backup strategy. Beyond hardware automation, several self-hosted services run on the Synology NAS: TubeArchivist and TubeSync for YouTube archiving, OctoPrint for remote 3D printer control, iCloud Contacts Sync for keeping the address book up to date, and a Google Calendar sync for dashboard widgets. Each service is containerized and backed up as part of the NAS backup strategy.Application containers
-
diff --git a/smarthome/air-quality/index.njk b/smarthome/air-quality/index.njk
new file mode 100644
index 0000000..3bb2096
--- /dev/null
+++ b/smarthome/air-quality/index.njk
@@ -0,0 +1,38 @@
+---
+title: "Air Quality Dashboard"
+section: "smarthome"
+parent: "/"
+description: "Real-time temperature and humidity monitoring across all rooms, powered by InfluxDB and Chart.js."
+layout: base.njk
+---
+Air Quality Dashboard
+Architecture
+
+
+
+sensoren bucket, organized by org Heimnetzwerk.Rooms covered
+Dashboard features
+
+
+
+Relationship to other dashboards
+Special devices & status
+Special devices & status
Network shortcuts
diff --git a/smarthome/index.njk b/smarthome/index.njk
index 73c9fbf..c39975a 100644
--- a/smarthome/index.njk
+++ b/smarthome/index.njk
@@ -36,6 +36,10 @@ sections:
summary: "ESP32 dashboard showing weather, calendar, and MVG departures."
href: "https://github.com/skoelle/m5stack-dashboard"
emoji: "🖥️"
+ - title: "Air quality dashboard"
+ summary: "Real-time temperature and humidity monitoring across all rooms with historical charts."
+ href: "/air-quality/"
+ emoji: "🌡️"
- heading: "Personal services"
cards:
- title: "iCloud Contacts Sync"
@@ -64,8 +68,8 @@ sections:
summary: "Remote 3D printer control and camera streaming."
href: "/octoprint/"
emoji: "🖨️"
- - title: "TubeArchivist"
- summary: "Self-hosted YouTube archiving running on the Synology."
+ - title: "YouTube archiving"
+ summary: "TubeArchivist and TubeSync for self-hosted YouTube downloading on the Synology."
href: "/tubearchivist/"
emoji: "📺"
---
@@ -82,5 +86,5 @@ sections:
Self-hosted services
-
The same InfluxDB instance also stores temperature and humidity readings from HomematicIP room sensors and ESP32 DHT22 devices. These feed the air quality dashboard, which visualizes 24-hour climate history across 10 rooms. The energy and climate data share the MQTT-to-InfluxDB pipeline but live in separate measurement categories, keeping power monitoring and environmental sensing cleanly separated.
+Tasmota was chosen over alternatives like ESPHome or Tuya firmware for several reasons. The local-only control means no cloud dependency — the diff --git a/smarthome/tubearchivist/index.njk b/smarthome/tubearchivist/index.njk index 5b180c6..8a4f8e7 100644 --- a/smarthome/tubearchivist/index.njk +++ b/smarthome/tubearchivist/index.njk @@ -1,55 +1,43 @@ --- -title: "TubeArchivist" +title: "YouTube Archiving: TubeArchivist & TubeSync" section: "smarthome" parent: "/" -description: "Self-hosted YouTube archiving and media management running on the Synology NAS." +description: "Self-hosted YouTube archiving and media management running on the Synology NAS, comparing TubeArchivist and TubeSync." layout: base.njk --- -
TubeArchivist runs on the Synology NAS via Docker Compose, self-hosting -a searchable archive of downloaded YouTube content (Elasticsearch + -Redis + the TubeArchivist app itself). It's used to archive channels -worth rewatching — tutorials, long-form content, and anything that might -disappear behind copyright strikes or channel deletions.
+Two self-hosted YouTube tools run on the Synology NAS via Docker Compose, each taking a different approach to the same goal: keeping offline copies of channels worth rewatching. TubeArchivist provides a full archive with search and metadata, while TubeSync focuses on automatic synchronization of playlists into a media server library.
-Running Elasticsearch on Synology's DSM kernel isn't fully -straightforward: newer Elasticsearch releases require a Linux kernel -feature (SECCOMP) that Synology's kernel doesn't compile in. The fix is -version-pinning Elasticsearch to the last release that still works -without it, rather than fighting the kernel.
+TubeArchivist self-hosts a searchable archive of downloaded YouTube content (Elasticsearch, Redis, and the TubeArchivist app itself). It's used to archive channels worth rewatching, including tutorials, long-form content, and anything that might disappear behind copyright strikes or channel deletions.
-Running Elasticsearch on Synology's DSM kernel isn't fully straightforward: newer Elasticsearch releases require a Linux kernel feature (SECCOMP) that Synology's kernel doesn't compile in. The fix is version-pinning Elasticsearch to the last release that still works without it, rather than fighting the kernel.
The main frustration with TubeArchivist is automatic playlist detection. New playlists added to subscribed channels are not always recognized by the app, meaning videos in those playlists get skipped during automatic downloads. The workaround is manually submitting individual videos or playlists through the TubeArchivist web interface using the built-in submission tool, which works but defeats the purpose of automated archiving. This issue remains unresolved.
+ +TubeSync takes a simpler approach: it syncs YouTube playlists directly into a media server library (like Jellyfin or Plex) without the full archive UI. Everything is manual: playlists must be added by URL, and there's no automatic discovery of new content from subscribed channels. It's a pure download-and-organize tool rather than a searchable archive.
+ +Both tools run in parallel on docker-host-nas, each with different strengths. TubeArchivist provides the better archive and search experience but has the playlist detection gap. TubeSync is more reliable for syncing specific playlists but requires manual curation. Neither has fully replaced the other yet, and the ideal solution of shutting one down hasn't been found.
+TubeArchivist data is split into two categories with different backup -priorities. The downloaded media files and Elasticsearch metadata are -backed up as part of the NAS backup volumes, since they take significant -time to re-download and re-index. The Redis cache is excluded — it only -holds session data and can be safely rebuilt on restart.
+Downloaded media files and Elasticsearch metadata are backed up as part of the NAS backup volumes, since they take significant time to re-download and re-index. The Redis cache is excluded, as it only holds session data and can be safely rebuilt on restart.
-| Data | Included in NAS backup? |
|---|---|
| Downloaded media files | Yes, via the NAS's own backup volumes |
| Elasticsearch metadata/index | Yes, via the NAS's own backup volumes |
| Redis cache | No — safe to delete/rebuild, only holds session data |
| Redis cache | No, safe to delete/rebuild, only holds session data |
Channels are added via the TubeArchivist web interface, which provides -a YouTube-like browsing experience for the archived content. New videos -from subscribed channels are automatically downloaded on a schedule. The -search function indexes titles, descriptions, and metadata, making it -easy to find specific videos in a large archive. The system runs headless -on the NAS with no dedicated display — all interaction happens through the -web interface or the companion mobile app.
-tOK)o~@X#pE!T4~0ilSK~>=)QyrY- {T zgZlox_rI#Wllm=80Wy Y%5gv?%p=Tqu}S{*tvL1ereJe#XE zn^mu$I=Bp>MPDPde6qBppxE+&$5-&~V>sod&|tA_Q47$whUb-~+PbE+-#c2u^OHa? z8UfyuTQ3|a?-7xWrau@T89kr3=<$C?kC`BHy!N%F2f2TK mMt5+0$9Jb?}Z z*b!bbn(iTTK0NTWaq51wYkoU3iBx?1E2xXQi6nFV_aS>qj$EkasGp8UB4#V9h4WcB zbK%T`QwHY|I6L7?fU_FTV*EAgM1SWHe|jP<>xb-_X>^8_p(ZvIond<5)WCBsYGz+V zXDD}cnJGsymWB32bVfk>LOa`z8d-DxUdj9k-d#h<%mngg*P$Ms_EHqY%knF<2>pYD z*@(2v7SzM6Lpe+b$PkQjs2eB<+6tIb^d$Z>>cwBqTxBfy`Y|Dcx|s^}B-4+wfBA7e zD37`X&rWb3LZ(a^+C_hgoCGvlOaBe6p>HBvxM$6uldVP_|A;3#3zeXskDrg9kDrhK z3l8de)cw!EC&@woE%R0(N2VJE3Eng0oPWk+77P6UaF85rgi|z})^NrAok9IPQgVbE zxjQ2lv>FAVbd(7hycuml$I-N-K(phyDSBpRu7@jf1MEe56wK>^XJ%$T`(eRqtoW_w zx8{Ohe-Hot=f_fGX@T-IdY3O>pl`7`UXJr|Ek2F^N|S*x7y((6nlUMVF}ZKL#x&9N ztm*rv|7IpOi#E$Jd&=zgf`tpx793r0-F%U`%)HRN&HTLiugvueA2XKt@0Hr0%g^Qi zK rjP{I#dbJPVOkq z-b1cMyCJrzX6`e8VP8Xk;n3e#E|>YZh@Axj8*5uzJ1oW?l*~simwMaU+E@z&Le_#J zZ=~MAluSw*_&>3;iwo(7kK74~%1#SNa&=4arY`(Oe=D{jV$-S0ilb@XS%KUq(cz-t zt@&xgTVnskB{9g<%ry3H<(_wI61!>FqiZwc0t@6>GWYz_fawW;>ePmPyVutYrlfbL zDyp*GK9J?Fw^cSM ;&$mNJB=fPdlKa|O zP?U|0wG~JqbaA1muEK$5l#;;BCBeZZn*$}vX9fx>h1nfkfX&WJn%##!=ia(%ah1FM zzfP{xNzP+aTuA7DN`S7ffiAYOrYM0>5=>diWImLOi^SK~*2;?VH4tu61&5b4$_#{) z% BAyQ-OSd@ZdtNpe(4%Bm-g_CmChIEuk(C48WUz{+WNn4d@-R(!M@qjery^ zMSq~5Um!UPJ;TC0JwihX712xwZOM-CRA5 Eo?d0*)2tbOls_4u*E1Lff>yvonD zaDON~s8u-mRGlY$J`2oz#9l#Q!q`%5$;wtyAB}R|lqGv*GMagN=hHVxuUx 44n4&sQ(H&zmjhb*8}4I$E ndzBngrRe-UGMeL}8a8-&!`z)Pw>^6i$%$TV zc&oCpeq=i05%eQk1+SK`q(c@j-ZxPv^++o54K0pZ=@?!V8Q+;MD71*L?Mu=Qsk{Pz zYM-fU7^w>gK8zQ$7YFl(Csgkj98mdqWi`iyZO-$J-K@mA;S$f3UC(Y*zpyi|;He2! z<`L}rbuaLh0NQi`oe iF)sSk*Qt%u_t}xs$t&!V0l=Hp!2Keyi^YH{*CFCu z*0T|i_=>HqaMnzWh9I(j7$N`OduCC8%iA3t?=(lWoKbbXvw2LhB{jVzGNLUbqcvhc z_i9Vq^~$POTiaf(8V# 2~Roh6FkA3oyzrH9sx^dta zC7%=>DV0mJTVukS3;n&)HG!!oo=8mVc`mE;Qg=e}Gw)PIRDbc_(*+1HdMCs(4HE?@ z-Rj>F*t6Blw{$I7xRwhP+-47dp)gbm>;ogfnXgDn3yj>#`LIL_1tcm#*e9y?prGAK zE?-I5w_<0z+8IX&Gq4IID-f{-H<)$#hc!{^u%#x_eNutQRl4Ny+_065aCO1454*Sg z`po7ifzU%e^wzcwF9x|N-p(1A8sGM~P?)~|Uok#(Wb&0(|EX_<7Or7`ZuX(Ua;tE= zn2jYqF_n>znVR~gmNf)xTK&@Pb3=Xe<9+a7vqz8Qcx7)-qSol&kIDA33aQ$cc3|?= zE=7F*oBF*6r(WNsT(h#q-7R(a_t^Q|DeQdz+3d8T&$v%#6qRuj``}_lbV_U5+K{>v zMP(Oz3Z)@yi k*OSkK9~*%62bp6!!K)MG <2NZ5vUA8yA@k8p& zQNOa7q!Q1`Kd~e3d3#kG_hc{ByAFodCnYz89`!RVIhMQgr2??oCh)iq!Db~SUd+V< zgR|L*jpl2xU+|_S*A{L2^8B{94<;uc{&2_X&$ceQW)as@U9hjn+daFtpk;3?zP JyNmgMt#|uX`;yl0yjr)f;^p4tguO;Rya9Sxh8z%bGK$N4ij&OA=o1u) zvy_y3i^3kq-YR>%?r9Bo1xNS6l4U>l7jAfbu;amSR@?O*ilMyc^+TCM`iptIz9IfH z{0s^{ACuU<$dJcGK#`B)a59Q%y=0vB)fZ9U>4k%XgRF>ujMeuJ4pKF+STK^%@SLN; z=gZmAxO|)z>+7hm^p=J>_0>Z|R390KQ8VcC9_Vu|8AJ350ErK<^1rK5UrXTT-eV27 zPj-HCGAsVzohP6E?N+Pth4H<*lKuIfft81I)Z3y(+ 1*uBR1R~J5SZSnzd<;l{6K!fyD3mI<@qM8OR*(u`l?<$K2Ci~x-msl zgE07i2%{p%p>gIuYX&x8!&?DhTZ6*p*?|>3ml|es18bIY!3<>z0*%&F{Cn7*8!f0@(Ipxo^@b}AG*Z*0%) zxVcNA*mV;bxMpAxd3;Sg>yc<<*m6*>axJ)jv$`iNtf!iLW}I4j`m=_Ht`=xr&n zPb8DzQFF7sXF^T%Svh0I3P36vA{gM FNCykGI{dN!c0`TpsBW8!BHa&ZyXt zp4G4Nh18^ttx!1ml@got1}z+#^$Om*NM^czmD)RX)Zj{n_|yY(oP~ZiB;L=tGVy97 zvZlYhw)dMS_kY#>i?l< `7-}@-ik*6rxtraue;&1)8)hwjJI)>7&HYcjRMpMBmx8a*f8*+> z?!qL?IUl&%)4%84&xDI+R^e{KF~o1?WthnXR+qRiiB9)%Gj6%dnT>O15F=Jmcc*pw zPbo*bpP(9uR$np+=rI%kR%-cwa9?3uE|ApDM(pAuvNJ$4gWLuLV+5M?0;wuiQ5HD* zc=d2$!;5N>Xxw74BlS{ZYnq!!PGtJ_csfxStbTGs<>^h4fW=2C_s~3_bqVePH95XX zCpL2?@@BWijujNUeW`b>w=~Twy3{LcjVdQ7W6#FS&MXh&Ph=&W1SDU7EhGLUl3EJI zcy5azGhlS#tS<>|46f8Ow)iZ4z)y3mM18b8#N0fj{D?|5RN*(~5Uxp7sH5E%ERJc} z6k8GDC_t0%yhFLzG~C>uqU^fbnB8=Bhca>Rtvxo$ecF(9$!gzk6zwTN8iLMqKxYp? zXMh4$5oP>CBtQj+>!R6z5w`JKZS#wbfq{)LHgCPEg@&-I_35<{_RAw`pOEJT<)1Fe zICx#VMtl8WhWdgoLK7BI4G>JZTNeS+lO5nU52arP7AVHEu-MMV2q)*#q|C5GrhUiG z>X!sn4;H8nR|K0c2&p)t&Ks-_8go);VzV2gt J{WrU9l6y5l3EN`7@l_|U3(@u&rT+^^57C-^C^bPM5I1FyW^DfBM?&@G z4n;!O*-dq4G(OWGQdNw!GB2b&Zq3@%#<;?rQk_^cXdT~kt!B*=xBJ&8^^Mo09 uYKapx;a)@O-H-^{r_7Zz4;L_ ??CuomK8Ae+R*XIwk3;KD6eexkv~J8h zUlCQE><;z~xqVteSH02`zc%+kg+7paBVFwopy~j+pb}ihXRAd9y7auSI5=a>!dEWy z_m|0if%OT0CIGK+4-R%;8$_04<|-G9H^Nv;KBLU)aZZi%DeWB#Y0Fz0VTVQQtXBKk zi~MAAKR>z552!{J?N*uz4=}7lxG#HWmOM=)W)|`i&mkdGO5$q(Ldr2Zk#pt#w&)d{ z t z@1^t)Rl7>~Lv2TmjV#Z=ewC**aocizM*T|_DV5>&)GMvnUwd4gxg%%Yn7>*XlpE?q z7flZ`0i3yE39|cDdQa*`x{54;y-U`qZLuDC`&D{>>gJ}B)oWsM=hoZE*N<`q3x3}D zhbvBhr%pfjaJuiWcs9gS8Bpd?muUVDo0@0p^LFLgk=rg+*IaIojBJ0grsh(6 z%F?d>=7H4I12^mK>Ti(BjUKz?zRHl0%D!Z~q`s=q(5gN@mUH>c z3SKHcni(MCkH>OL11DH9c9#0WuL5HEP-U2Zxp}zu7{qdo@0hc)GLDbs*3nIyVzo+V zx_t6m_KyBOAIu}SU#ijlAeeJ{MN2I3MPe(LPk%k18(-;9aeevXv(r@px?z>-s5aDm zL8x|6T|8VB2;696vs>0%FYsJnriiOlI&=A~*;|t?^o76Y;-H aoLt1mD zvLW45_0-0=tW~ZGV%erM_o+-a4D@ef+;z=@D#Mo(;DbuhU!E9smanjrF2uG<@5q`6 zCZM+$3#V@R`dOLMhlC5|TQ%fA4Itw^Ccxk&d~Ou^&caH9)r|6p$1W_3cQ1Z_sxGl3 zS32tCuXJhH9W+UYPEFw7P@2nKu^#zHG}M?rGA7U0cGFS9r4yLzOFU&$g5d$E(bx{a z+WXk`6|SZAF7~o%<(i(R_mQYLUHTMsg}x*+z6;ekv 7kf`_qf^Ahe4 zjVB&hws8}T#qX|g6Rq#!#VZ k(ajg88-Z%;CAf6ZZTu7mZqwcT*XcFD*)5oZ z>{&%*w ?wp=Vd0;5H+ z58&nE;haQbM0da+Y*${v?h{ IMYDjn=YhI0X7k_0u~>$sVyMy2Pd}i()%#RaZ#1On?FR-1 z=oQm3JL!vu4->gM@IK}%T1>vDW5Xi4NQ`D`w0}F}x5~@`&&)<;W@myl!&@3HIpLYn zsNAqC#y8c=Cw?t$isN@1ssj~~o<3e1L#TwVV&C;)-d^&2B7F(-4fPe1wna`4rBG&R zl+Wnz =BLn*TP#ZQdpUu=%v9kaq?b97_bJ^e4} z=SG= Qdng9prFM*~N#I9xYXg&mJ qBHUa zWMNtExPO!zG$J*t<%_zkL;%&M(%26tU5U?=|00q-l+=j*T)_T+J$@7c{-`Y9gN9%0 z&w(&`7n@^t$2ht-E9b=f9$p0bekkzFj3Mr@6O;@8TTLM<=YI=A4sn{6d6*sDUo> z2!qryv|lvVDP)1J8tXJ*j$az<3|fvjW1U4Vc$u*-K+AEcp^jG}Gn{R#OOQEM8SAc4 zuQAr$9@59&(7pwKMW8CALz__zDnn{iit4}yywN)31;r7iK}!kTQ=nHNoON(Iq9o{D z1#*?3BEEkZs)u_iwAG+mcy{IK)B)XE*gtwgQ3G|-qaLVuz^E#u &|8BFpuHAo6ag-u&r1r7R0CDgqXtQVHsM@ W4q90_!kACSYNU_+R{(&;8z8fL0-YXbXgb!6QfnibA=FWTX!fMTJx0&_asI-0zeS zazj*Oaa}1f*bQn_m)3!u;Ig^`4cG;tXoZ~lStzijVuP(h-3@~+Q!n$+6g<14xnGC> z2Trw)?X!|d5pRFZxedYq5Jb@#1Lnq<%iN9$pa>#_L=RL#36w!fNLeK0#$TH}t!A{l zlBz1vK>|Yp4J(VR2`xySo+E2JzsJ;pF7%)e0~o>xG8jV+6PUsb=CFXm#aHsF{_D#t y&M#pFYhQnnZD0#K*!%W~qV)S&?|zQb9}S5Rd vPI r4g9gL+Q}8^XrheuGyI}R(2-%-Q$mO%z z>hdawYK0fP`xZ)gEi?@LtGyQJJHzwH+R4qW!&02~z%z`o>8_tzSsow_Z9~Y`h!8)2 za(Qb5NkdEEeFXIPm{LBuI`n@|&Q^q!+Yll)4O5$%&680T%>O2PkC<#6cX?OPo(HA& zQ4i2i8^qGdA02|&{fAQ@Z!mAB5t6HtZ0Oq$5oAd)PFha~z!jS}n{P|5+MuTsiDiA@ znt*te2n9d=8lHLnHS#VJ5E3>CVL)<(<<6Z)6NuQQPvYYGJS1mkCIf%(9$iF&C_)pY zn~0Ss(1A|aD@w+3%bA={5;mb w@q~yF&6Uj#N$V2meej_Rs zXV_@z5BEqY6QMjc4~a*!(Z5JS8Ip?kD3lMfF68G!sX_~dW>hM)p@pOXZQxsxpWp)R zxoDvj!@D=2EQbC*;yr&?@PK!JLrMGt GgP_F@A|xfm4 &mvKVu%JK%NEpWqg@ >)3hn^+33r#5@@ae{|2}_TNDvAjHw$gTsb6Nva7ne~HOWn>LYgLR zlU|VCvyt13w#l{GZu5D+f&KCz&+B)#-~Imb{`&q?`oGlwz5d_)dbY*S^0WLOm;-Fb z{zv5+uusY6+k&s~5wnw65gx8lE4@4=5}C7$iz}AnAfkU!hlhu$TwG+%5{Xo>BkWC> zDu!snScCZS@>D8WH=KvvV*EzO2F8pC$ySj)^oZ$Pa$Qu#{?=)2C91+mdP1SJQx!*L zZ<>|zb3jFwL?$geH-F8grleV%?Vo+e1P5pNCi(@AtBLCFATJiKU7psst90DUC5cVt zzSliR>4$&n#;Q|ZINH!~defsDYh!=h6tW1J32H2svrgj*j74S35#v zGG|ASL#k8~GPh{$?tE?Jl%nwPqA8Ku{M~Ddh|c8#F2urrD_{0odx>5 -^ST#vVWzdt6@Yw_drAKBR8}T_t@5FF-$`{s<|g&LUNf1~0%< z^EM0)@%ZV))XtQQps`a%e-3?{2qJHiPUgX|Os*ksn$D8W&Q5qU&-?(N#ByYdkXFrB z2^N0|7GqvfT3Qh+%i{9$ M_a$#~%UTdo9+O^~OQRd9@fKjFDxW<%)UoWUUGCyU>3ro}J4Ujbw<|qSQNSS}; zK&Rd~jKkPL?!cFI-Lxa6-#?^ZkSf|iJUaJqAJTGaiiFWM8IWG!gVP3aY;F;O!)r z$vMW9JF#kvc+1_1xIffE@GQYiKjd&K(>o)Fx1`qXXo`xO_4d5+dzR%8>@Lw1>a~Ut z*I~LMy|I97)RNA>()S#^N6kCbRK9;_i6LUj*6Ns|5Wn `ibktP1szk zPFirVq4~WRQ)@oJj>54Y66fxneBUr5)7vMtQm?N{^@*(rkH}a$DcbPj{_20aLobfW z+jMbW!(Obo+yXJuY(U}(z8K;pM-u|QI+{&fBw$U7kWd2J;!!^|kReZw!!Y)S!jSw0 zZKfy4@Uu98HhFwXJm~IjGk>@%RoMI3$RB?6*ht)O-v+7kLFz8Rgf~!-GpS%hi(-jz zaFsK`do>Xr&V7dc`>iw|Sbl$HYj)miSC$;=T4qNt3Q;qw(i_GoJd>vx$Ipt#*Vo>d zUw#OaZPnW_cc^0VU)B}Qj*V#iQ*+I swyW2_E~00(umWUh~ub^74HT=-2e(tx2D)Np64mW3&Et<=f^h zNt?~+a3vE_)C-# 4TSrQ#=Bu?gQ<>uYZ_^p)3oN+Eiy&aE9`lJ2fg~UF~6->t%F=6@SZPq zytd*mJBtfm?^yEw&kKL->36m MbbemlLyl>*aQjQyT{ zxB)IFtoDq_dxBoFzQoASe204sH7CnEXRC{ni>@m?oP3V`=YM~ MkwLP4T6lbttm+^!#=Y*ZG7Bju_>rBV!f$(d%X(-LPLR41$ zhSE)V7*^x&0l(XicE5qFNb<8v*}KBLpUJBn;L)?9mN_MJp(X)c3}Sm6!^aDUL3bR+ z#I&Wj1-DSs{dRxTL{kvG#G5EUdvDhTK9G^ i>AZ$ zA`T#FtSfh}J4D#q9n75vK4GT`LEr^sA|^z5{{j_`g2mAEu{=Uh@s8_Dmt1cvDSqSn zlBL(*D52;5vRlTCnV#h*-dl`* lrAI3&j?zbWlAHIoMn|{q zZBB05H!~(?<~}Rm{5QZi^SW%OiD8M-OGJe=6d_0G3fz=muTs_L(+Bh-(e8S%aNz?Y zy%jkjF1{hLOE2u5{nfG+pEZD1b7{8_2vTuqF!OE-EXBW9HtrR?^gTL 7LpM=?=8$+SyoDY2rkX6)u`)?Kf&G(q6cv_hNZ7MxpMl>sdCk=h^kSeCxmzD z$r55(WXJTG1om?W$Pa!GgMi-P*G0Du^T~UhE69KA>dy5#4SA0(ZFP-lD5~7|LWXhG zM=jfbe4c)(nUrOyRV&i!lV|*SR!rLR4_fQL*fjwM`ejUtGgOD-x!$oF^)L_Pq?g8* zte>Q7KC>{cJR&$VR1u{Pav53N@KSN6COza4`fEMBX zw2l4%c?Ui~3x&Ou$K9qNlP8gw9+NBN3#N%tuvP+ZKtquZcyxFY`&bvu!P&)CCRZw* zTt%E(O&Wx|oFxp0Zscvx #d3NPEK=?(eGq3CD|UC8$Q@G&Og3PgU5di z(&n~g)$A;foBQsZpK+%;-A^9vn>431Jon9cG_+`%pF_a&xbwe;1ji^8dbxUx=PcjC zjL@95 bBNZ zuC9o(w~wk=RWa$ciD9(EDJU~WpACN@BNtq5h&Bc~O3>qn4~dU#=9#rw#x*CKgPKpS zF=nkj{gQ0d^dhxSN~L~L=FFs!!Wj(ZpgHaVXbz$T1yhN S1HD>vTGg^ M8~`wS{%ucI}9#YBr@c{_JLgPV2Re*=}SbgD~m?1(ktcrX8C`l!M^hwrcPCU zWvb>k&3>!E*5+%0_eu;cYi|dwCeeJ}6QpngyAZ>CK#vP&M=qvFjl*v%nH!FUMYlF5 zZd?-doNBSrP_Hv3Mo)WvLj9WY8V0)6RaM&?qp`;jZBArnm5L|s;raT=9PKb(*L7>% z=aWW`(fv^uA2~ULbEkjjevkGEng~E(Xy5=1q7`%Uvc}?2w<;emp&kFs#Jc*8V~vYS z)%1#QMnp`3+6|x%UcWnG+OZXez{+inrd+Z+CC4i$tDaGw4D|L1-vecP3uUg)c@J-+ zR~-w}Qj3aG(+Yw6k9i#)5}TbJ3k4DLW}1%w1Y;d6UdF1+UR8hgr8FPQ3)@;0$x7@N z=o%O`!j(~El!5B=t!?=>{l4P`_gIy%zK1-s10Z#Y1ow@TFqV32EpgH++QFTne%%vK z;laW5_$T-y34UajU>a%qi}@VIsa+rApLd(aGxR b$^lEKNYe5L@@JS7e$O#`p7T0JdZkb@1UjpYx z?^KoApdP{%cen96+K(-Sf63} (9(>+@-5R$8RS5E<_O=EQdpZh zw(3^S{xx5CDeb^^ZibkK&1GZe!F*SIG9q+&+F@Ky_n&{*e61&zqz06|+GsM611Uy1 zTX>5%NC4VmJm&OdH(RZ&qWAFEV`fJsE_{FX?Bk0P6Boh#*rG)2;ik!tiON?G9<0fa zj)rqKag@zCy)Gwb-RT*!mecFAv)7+qCQEE7QmKks62Y*RsMRIY*}Bp)K3bGZv~8B~ z@i*-|TX27DOFq!nZJkiLrZQ^KpeQi&HCrcX=~dUz%m{rBs8|RpGejCfWnA6ke+d6$ z`n#;<%=#ST>f=+iEg!8m8rGayB} Fd`~n>o{@W;uI<1O$#35JW$lI zxCpGvzl@8lhiP_(uoxL~WMp|s_KF&ve(Lt>6=x^Y4zE;Q$Y_NuBqMVA+x2m+J8L(d zpM)JqWRW@|%^UlVQ29GLY7LW;5?jY SOuB&Oa%K@+^||#>uH88G%ekNJqD|kL;dZsB41s)VhpcqZ^yRX zI9TN*a2E&I#V&7T)M^1mgLqvZggR+^0zGy hEwfAA8_$b9!4e6_pw=6WVW%*TgMm&x(HPV?4!?2ju>RUBdE4y|(!1Q< zt=N^`J+Px=#HMSJ*p2g~ADJ-Fyh?Av^$zDO&TxZv5{jdkJpr8XJj}w*l}=798smRB z7LXMlcpHb&&u|=V|L{ZF4)@Ps2Oh?$roWpm o+xH}$J&QZu<>fm*FT8)h3wVge zk6+#WBmG>)=QE3z2A5BPy47xq-*$gtFAWa!VzKY1-DfzZ$#8<~IXS_^UAuOT9O$m! z#jWh@WI8YBzu`)Siy#^M# I1hA3SozHQL!Gc)yigHWJOO;xK?Qo=MT zDH?ThGR)4jR1SW75OQX6{?c=cj+-65@K^Nev GXdpKWXXv z74jiB9o)wihqkw~HDJ;~G{DyYRY#ydqz~060YUHA6c7~Dom!#acVu*Haa(#^VIZyr zBpM+!Sn=GRVq1Hg>w_GXso`Bs!cUI}GKeFy* 2R-wwno$h&pslZW}w>yCxu|hH9(#9m=08eVAOw9h#FYyRLC`` z9w<$K+7#&11nrG|W($Pg^{5=$n}9|oL|uJ(83m;tRiQAT%6QfwJxWHIkdvX7{S=*^ zzE8{2)0z)FG>UUDK0KbHXweA!1@_k|7Qm<~Q9gsHgUP^eJ+xN$>NFJ!Yhw~{7BHCW zp8h}DlRv *^6Mm(GKYSFP;=BAY(X1M8H*tqS*Nv)(8Xl 0jQ55Z(ay`Kf7PX?cSYGI*|m``jXJfo^q%^BV}6y$1KE)CILVWK@F4csIB=S8Fz_ zUO#nk8A6M`LTLG9X-Pq`<$+Zm@a$ta<)zSIv20Nb(6@&Bm8IIcrnKKVTEhJmgiOsf zRYe6eiv`^XEht5Z*{LmP(ou NGeP8d?JG;d z1N!{N#KD=X+#10HK?U5Cp)VwV815Nn2kwWbh&{qef#eFqFa0)BQGA!#V;eMv&TCL6 zCMr=Va-5 dSK^h8?L57{%* z=nN}EO>8JS!}P$Zf%{t2%)W@uQ10k5Q;uXT3+;*MjDYlocD5ZgvgZ76CG$skb`2#n z6UdughkAJ0OHmLn%P-L)^e+x(BhoTkP!F>X (W-8E=Oh3wh=EwD*Jn9nMJHhV|GG)rpF8WjCB%sk+`X6WweG}QjZ`S-d z*=p4BuXv)fPzn0!`04oR`04n6;GmvI-TxK%Bsu6mW!@^}$aJG1!Fz_B^I!3p#RC5w z4w9pdaEgZ08m^fCWl%qllpLW(ew~pET8#owI?99$-i)@O<7nDi(b@6b6g@LD*TWUL z0rnz23g-2|Gcz-veZOEeR{Tcu8*{<0zJve%_s3FWX@T-IdY3O>pl`4_UXJr|Ek2F^ zPFYha)DU%nUQB1xrSpoOS;3SuCz HDUCH4~dfn`M|i zWp;bP!UbsyjxM-vzQ|l=UTEHCe%}0-=K6(?8B6?kO6^bOr}BTHbpHpG+y4jUTMJi< z>i-W*8$`-ojEGt(fUOH!0J*}37F)`k_$#(`sKQ4bssv~!cNAyuA=jea5ZhEU_nE)2 zuc3c%= =J5?u0~Trv)Urx+Qp17k;h3726Q8=~QLK(KPR@K<<<1a8dBq{IuaMvH#|h7-VW@ z8hf{L&$~5=-L&h`wV82&1@bJJdwyxa^aOu(YQw(W>uUy6(z{a?RoQMI$nw|QDjSsX zeQ#_o8aWhfy2La&xqPfCyQi7#p1Zg;)Ir$i+aV;9`B+)WeeEnL%Erdp3ZxLaxKLDA z;lMLWN#N#^;NX(YffD621BH~r><%u#X6Gf%?n9q*Z(X&x%H95-C)epD=dmd+By@iz zK-bqm7u#4
zQXq__U!HKQmYnCl;f8^(J$Dbw(8tIOp;e$)LRBWivh36{M>o5V4{W*>8RNF8Kt4ct zaG_RE7Sv^u0kMsfjI!XCP?rY=;7Nb~%wKT>dWWpEuMb%xAO%a&AL!>7NX|mfurN=L z&`?4}G}A#_vLiedSXSCne`1)*XGgw$SKv-EY%N&90 TY#CF;OY4INLZh)P1RJZB*McMR`weiyn<=OHXf!i0jU!rD1>7%Cwq*AYEM5 zB~8xdoxW|FDA%g+%8oGAP^F(-eW)O=CM2+F)24cVvT8EWLo%$Y(BSQ$2`P<<-k9X6 zb5PjSiA)=~WBfR_H6`&ge#PfR9}mrNKPf%W!)>T0-=h@5PkXd==>F(gt4iuZCK z54acLqWv+{AM_X9Tw8yVN{&}Q?qBm<{f5Doc(W1n==y|km131ktVWTON4@Am{pwk+ z&dxPz+Y41?BOTFRC5KcgI)9Ih=D4Va4PM?bcPGqk&t61wqE{Q H>lf2}Vrwg$H4~#D zh^!w*$ba^nS=4{>c1OoM%@HkUR9)|E9#d>dO>c>eXv@fGjTq3q+R}Etvg*~=wpXi0 zgDYcVv_V1S8jN>$j^^i&c4qF;1gc-qCATRQZOLhkAt8;_RQcJ$!n5UDFXrZ6+#aI~ z3)02M>VkuHWZjErIQk#Jy&rfEuW*CLNmw_mfUk5` sh87lD#s5w*BHd5tdpM2!+FN%(C9QawuCq+j}< ?YU%dBp0RoKP39(GWL;*^-`Wpg!wwn2dt_2I% za)E-|>>+;?hDw2bU<5ex6-jA }*#% ZDiFC!mpq;uwvrL9E;#mK_m*Fs*&HPhdZ>rq+P2}v zAQ#2kIRjJU+a4DR)A#=Z<3mR#UupH9`bKEs8s>jy9~vyT3b%{dSmF~?8Tpv0sb6YY zL$IdRFWo*j)Hgrg2md{L^hl0Z_Vy%djsE?ZY%i;js(on(CSUDR#P`3c-+OTC^ =XRw5F{MsXI|rcCn{W8nU)%`8q${ zX|jJmvWKMa0M^SOQ?$?!<)s))q?jgI<2BCVb!zQayoa-=w^Ht(O#hPgoP3)dfq3BA zKAA*4HZ%m !NEGaXr-q`-;5XvwI6#_QvAdyYFnxzwqthJ%_)&nBRYT zw_mj{Y5mTtb^9t_?oCeEYt+LVpoeA10U;-&xV)!0$()QnL6JC1Nx8Qu>~ZX^vd8P5 z)^JyFbRR5P_H%#XhQ|jx9t>x-UEiS?%6ncvlsTlon8)iI;xEI`py2Z{iQS6~c}xTp z`6v!2qnOr9#%W)D5%sNJI5;@SipYOheed8PRRfC!BMA-9IU0PvoE?qJ$7!*?j{1|{ z(lDpKdT5C1BjYe?27TTGeXb>Ah&}-z@c~x;Pc`am3EbR!tl{>_&QDHe#UH%$ | zYBjzvzE@YWKi@O3@^FrNTeOHfPyI^&2iKyQoaZq Uo&9oOc7tD7yHTGk%hNY_ z5a9?s2xAfU#h_7Uo&F?u&Jlkj{Dp`9_q9~7QMFmz@GtQ)$`RaX;_&ndqx~#5$~U*N z%yPY}%lO<%8fO%w@EKwJy2nUoO$WM4T1xlto--LB3wq#9T)r-f+sZU8arf6yq1|NT6R0KIR&fI6s zzy@r1D*$Y3P}n>>u%hQu!)$I~%~Fnh(AoaMU`G0}5869FIGXx1nQC9o#yx63zp_0W zbN80`(1Pq!-1MdV{7aZQm3<1+m-F*4bNU&SyZy#ag<|K8?YSK{cPSLRZXyHM3@jp# zuZd?p5^W4y4(e5|1$Tc|_k@M@RCCXaQ%g^O*3j@76*w5ZEhYAeWD-1TZnpPKsEIx+ zXUtduNJT>g101^w3-OPYjoy!IwsZUO7mtYe;SnO@-rTG`r6A(oEF$95+}$SZMBV+- zf*S1MO^|a5iPEB3(S*WBBdimcnavse+f%=5Og>a5=K?95QM!Ly5&mQq_sKY&$_?Gb zYIdafdT;UR+T}KbF|Dy_TcRfaNbSe^Msv_+GWc~ZNDt5ugLo3a@5U$zh; ^RePW`^=nxa>$?h2Enwr^~Gq252b>!sR~>%)210!rEy zB|R}%Cru0uaBzQ2R6UWN-e2)}+s&Gktuevnksh(3@}=U8iXG`${VHEbP1@KBg_B zu{m$h!l7BO;Ju4vrt4R!y;DaGu4IT$Js`(f=x0OX{hTWkuQnoU`pav3zkYK6pSpjR zcBr`IP#XAx aEtm}EKU16O v+)X%!_|3cwGnv5Z5*H@X={|18Eq6Jyan1~4#476Uv`+si 7D NWC zoBLCgT~`~ko38FqChonp$0oT?8?r80?fbQ&Jtas((0LB%>;dQuP{1mpjDLv)sNis2 zG&_I7HeRc3ez7qyu<^y_tyi_s5LUH5y*9#rc|`3K^1Pt@( OPR9&X17gp zuO=vATkO}q>g07H+CHQ7e*x(sTC)$OCP)P0rtHy-&A EAy1-GVDA0D3(t3Y^yRsCt9p%IXOx^2yvrL?-s7whBZ_lNJxz~S$ z>OuY|f%Q)Xg#TrRxFwq1okHEmu#dos(I?|^Xx)jzq-~qljd|xQqN t<{qff2U2gOt33l$9Y7aUg3I`9wa7r1p7$09XN+0+%4PokGPy6XKEZzk;1%w{ z!R~8=$a2hF WYIR|&tb?WnPl z YkE=6x S1W^ZL!IcN=|LudGdC _SktMKq$vU+y)+2AfO7BnI+*Go9O-%0GdK>xrL9SrI&pUsA#p!?4>E|9!_uUoG zhIlFi$~@{4&EH{D^Gto-t~@((+okH7%k7bo?Jw5UTxyRTb&0QwkE@N7NaAbZH{OM^ zw5z{)AT{;C&3e1~8>Dih$1b_AG9;w3FWD}suPQXOs*jK5Tt2gcmx_;O28j5>vE0(Y z3091qrM~d1fLK0M8D@WO9 _j zmi5*PJlB^g;wqKSTs~{|)}#x4;h(uUXeX%yT)Z^ZE3~TLu;PEz0MCuBQ8TNI?+1iJ zLwbSbegS7 ^qgnd4=kCnHD< zqT3H5G2;s^vQsevF M`a~3@p)@)AbU+SS2R;%w=V)|{zqNcU7dwJ|Phm8*hS zw&~1$Dw7QZ{o5FKU9+Id@a6>gpi=agCq|v+E9|5Tv8~cOvL=EF= ! zrl;wBBq~mqJ_TK&FUgGWLUj)9!AK!Ndv->}kp@VQkyHg!_Hti3gT#+yrCs+bi5e z>$`aIiUxn~-jZu{^M&a~pxSx~E**3mKgEIDbT|KYdJS-P3+5nuRuS2)iDA7k#%2$` z`iL9C+V>|XKfoGp7$QIe-mU*q|1mzul~XGzTOyY&7fX-8Xc6oKc)55uCy^M@9q ~^AFqueR6 drcy0Pq@{%7=aqs&0d*$v`l$E=(x zG`YRK#4-s@fCKcGK+_6h*Rpvu9|AP;LIfK?TIT5nx6VV+8F>S;uq=1nKgtank($-= zMO{`RfNE1|?1z)C#OKL>5y>7(YQ%mnVE=y}KZpQ-P?qmN!>{z`K$yIX%`v-U9Nn9h zbK-pmFM@pE7kFmI5O>%K%7y<{Q;5p>Z$Zdmjt-J9L>Pz~=pv6WNF77_MPr>p7U-(6 zP6Ounxv|cm<%l!ZS>%G38S4VH9ETd}coj0k*~YpAnPZi)?h5r9W8Li`ee4bGTTp)l zszN%n8P%XNq(-Hv4s5_1twUZ=98nsyl)!Ha^eTk24o*ju1ih<3t`bzl_YXt$@LLLP zHK-QuU3ofnK(`k5kDgG}K%Mlc2Pz&gstRfO)+#7!qyb7Qs8vFrT4=ACH=8^3)}R7t zuLT-KfXnCek^&>uK$Y~UK~kViIG2B+K%_*8P?S(hd4$@dBOaCO(PtTOSHsUrICFf2 zx UdMdv5_+h5Vr{5DEs5AQ31E Y8f6U7X z!T=CO(f6Xpe`5T_ziSaJ!j%a2U?G-Z8SY(LmS6)hm)RVKJIqL`sze6~3<)%>JX#Z4 zkUBj_YrD9|)PXMapbrBWLIydEpnx$`IOaMUh#ebOIZ2(i?)UhY+>iy kBNltVpY`qMDE$EpHxO|OWo~41lO(ts2r&vJB}Gq03JJg@wg3PC