From b27a062040a1245aea5885c0918e3ec3a422ad43 Mon Sep 17 00:00:00 2001 From: Herwig Birke Date: Thu, 8 Oct 2020 18:36:50 +0200 Subject: [PATCH] initial commit --- package-lock.json | 18 +-- .../data/entity/{Series.java => Episode.java} | 34 +---- .../application/data/entity/Serie.java | 128 ++++++++++++++++++ ...{SerieService.java => EpisodeService.java} | 18 +-- .../application/views/Series/SeriesView.java | 123 +++++++++++++---- .../application/views/main/MainView.java | 11 ++ .../META-INF/resources/images/logo.png | Bin 0 -> 16070 bytes src/main/resources/banner.txt | 12 +- 8 files changed, 265 insertions(+), 79 deletions(-) rename src/main/java/at/windesign/application/data/entity/{Series.java => Episode.java} (62%) create mode 100644 src/main/java/at/windesign/application/data/entity/Serie.java rename src/main/java/at/windesign/application/data/service/{SerieService.java => EpisodeService.java} (67%) create mode 100644 src/main/resources/META-INF/resources/images/logo.png diff --git a/package-lock.json b/package-lock.json index 5d4c8c1..5cfd820 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4150,9 +4150,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001144", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001144.tgz", - "integrity": "sha512-4GQTEWNMnVZVOFG3BK0xvGeaDAtiPAbG2N8yuMXuXzx/c2Vd4XoMPO8+E918zeXn5IF0FRVtGShBfkfQea2wHQ==", + "version": "1.0.30001146", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001146.tgz", + "integrity": "sha512-VAy5RHDfTJhpxnDdp2n40GPPLp3KqNrXz1QqFv4J64HvArKs8nuNMOWkB3ICOaBTU/Aj4rYAo/ytdQDDFF/Pug==", "dev": true }, "chalk": { @@ -4953,9 +4953,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.577", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.577.tgz", - "integrity": "sha512-dSb64JQSFif/pD8mpVAgSFkbVi6YHbK6JeEziwNNmXlr/Ne2rZtseFK5SM7JoWSLf6gP0gVvRGi4/2ZRhSX/rA==", + "version": "1.3.578", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.578.tgz", + "integrity": "sha512-z4gU6dA1CbBJsAErW5swTGAaU2TBzc2mPAonJb00zqW1rOraDo2zfBMDRvaz9cVic+0JEZiYbHWPw/fTaZlG2Q==", "dev": true }, "elliptic": { @@ -8669,9 +8669,9 @@ "optional": true }, "tslib": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", - "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.0.tgz", + "integrity": "sha512-+Zw5lu0D9tvBMjGP8LpvMb0u2WW2QV3y+D8mO6J+cNzCYIN4sVy43Bf9vl92nqFahutN0I8zHa7cc4vihIshnw==", "dev": true }, "tty-browserify": { diff --git a/src/main/java/at/windesign/application/data/entity/Series.java b/src/main/java/at/windesign/application/data/entity/Episode.java similarity index 62% rename from src/main/java/at/windesign/application/data/entity/Series.java rename to src/main/java/at/windesign/application/data/entity/Episode.java index b54acac..fae6512 100644 --- a/src/main/java/at/windesign/application/data/entity/Series.java +++ b/src/main/java/at/windesign/application/data/entity/Episode.java @@ -1,28 +1,6 @@ package at.windesign.application.data.entity; -/* - $sql = " SELECT serie.seriesID seriesID," . - " serie.seriesName seriesName," . - " YEAR(serie.firstAired) seriesFirstAired," . - " serie.resolution seriesResolution," . - " serie.cliffhanger seriesCliffhanger," . - " serie.status seriesStatus," . - " serie.download seriesDownload," . - " season.seasonNumber seasonNumber," . - " episode.episodeNumber episodeNumber," . - " episode.state episodeState" . - " FROM serie" . - " LEFT JOIN season ON serie.seriesID = season.seriesID" . - " LEFT JOIN episode ON serie.seriesID = episode.seriesID AND season.seasonNumber = episode.seasonNumber" . - " WHERE season.seasonNumber != 0 OR" . - " serie.seriesID >= 1000000 " . - " ORDER BY serie.seriesName," . - " serie.firstAired," . - " season.seasonNumber," . - " episode.episodeNumber;"; - - */ -public class Series +public class Episode { private int seriesID; private String seriesName; @@ -33,9 +11,9 @@ public class Series private String seriesDownload; private int seasonNumber; private int episodeNumber; - private String episodeState; + private Integer episodeState; - public Series(int seriesID, String seriesName, int seriesFirstAired, String seriesResolution, boolean seriesCliffhanger, String seriesStatus, String seriesDownload, int seasonNumber, int episodeNumber, String episodeState) + public Episode(int seriesID, String seriesName, int seriesFirstAired, String seriesResolution, boolean seriesCliffhanger, String seriesStatus, String seriesDownload, int seasonNumber, int episodeNumber, Integer episodeState) { super(); this.seriesID = seriesID; @@ -50,7 +28,7 @@ public class Series this.episodeState = episodeState; } - public Series() + public Episode() { } @@ -144,12 +122,12 @@ public class Series this.episodeNumber = episodeNumber; } - public String getEpisodeState() + public Integer getEpisodeState() { return episodeState; } - public void setEpisodeState(String episodeState) + public void setEpisodeState(Integer episodeState) { this.episodeState = episodeState; } diff --git a/src/main/java/at/windesign/application/data/entity/Serie.java b/src/main/java/at/windesign/application/data/entity/Serie.java new file mode 100644 index 0000000..2f16035 --- /dev/null +++ b/src/main/java/at/windesign/application/data/entity/Serie.java @@ -0,0 +1,128 @@ +package at.windesign.application.data.entity; + +import com.vaadin.flow.server.StreamResource; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; +import java.util.SortedMap; + +public class Serie +{ + private int seriesID; + private String seriesName; + private int seriesFirstAired; + private String seriesResolution; + private boolean seriesCliffhanger; + private String seriesStatus; + private String seriesDownload; + SortedMap episodeState; + + public Serie(int seriesID, String seriesName, int seriesFirstAired, String seriesResolution, boolean seriesCliffhanger, String seriesStatus, String seriesDownload, SortedMap episodeState) + { + super(); + this.seriesID = seriesID; + this.seriesName = seriesName; + this.seriesFirstAired = seriesFirstAired; + this.seriesResolution = seriesResolution; + this.seriesCliffhanger = seriesCliffhanger; + this.seriesStatus = seriesStatus; + this.seriesDownload = seriesDownload; + this.episodeState = episodeState; + } + + public Serie() + { + } + + public int getSeriesID() + { + return seriesID; + } + + public void setSeriesID(int seriesID) + { + this.seriesID = seriesID; + } + + public String getSeriesName() + { + return seriesName; + } + + public void setSeriesName(String seriesName) + { + this.seriesName = seriesName; + } + + public int getSeriesFirstAired() + { + return seriesFirstAired; + } + + public void setSeriesFirstAired(int seriesFirstAired) + { + this.seriesFirstAired = seriesFirstAired; + } + + public String getSeriesResolution() + { + return seriesResolution; + } + + public void setSeriesResolution(String seriesResolution) + { + this.seriesResolution = seriesResolution; + } + + public boolean getSeriesCliffhanger() + { + return seriesCliffhanger; + } + + public void setSeriesCliffhanger(boolean seriesCliffhanger) + { + this.seriesCliffhanger = seriesCliffhanger; + } + + public String getSeriesStatus() + { + return seriesStatus; + } + + public void setSeriesStatus(String seriesStatus) + { + this.seriesStatus = seriesStatus; + } + + public String getSeriesDownload() + { + return seriesDownload; + } + + public void setSeriesDownload(String seriesDownload) + { + this.seriesDownload = seriesDownload; + } + + public SortedMap getEpisodeState() + { + return episodeState; + } + + public void setEpisodeState(SortedMap episodeState) + { + this.episodeState = episodeState; + } + + @Override + public String toString() + { + return String.valueOf(seriesID); + } +} diff --git a/src/main/java/at/windesign/application/data/service/SerieService.java b/src/main/java/at/windesign/application/data/service/EpisodeService.java similarity index 67% rename from src/main/java/at/windesign/application/data/service/SerieService.java rename to src/main/java/at/windesign/application/data/service/EpisodeService.java index 9476e86..1fd99a2 100644 --- a/src/main/java/at/windesign/application/data/service/SerieService.java +++ b/src/main/java/at/windesign/application/data/service/EpisodeService.java @@ -1,6 +1,6 @@ package at.windesign.application.data.service; -import at.windesign.application.data.entity.Series; +import at.windesign.application.data.entity.Episode; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; @@ -9,12 +9,12 @@ import java.util.ArrayList; import java.util.List; @Component -public class SerieService +public class EpisodeService { @Autowired private JdbcTemplate jdbcTemplate; - public List findAll() + public List findAll() { try { @@ -37,30 +37,30 @@ public class SerieService " serie.firstAired," + " season.seasonNumber," + " episode.episodeNumber;", - (rs, rowNum) -> new Series(rs.getInt("seriesID"), rs.getString("seriesName"), rs.getInt("seriesFirstAired"), rs.getString("seriesResolution"), rs.getBoolean("seriesCliffhanger"), rs.getString("seriesStatus"), rs.getString("seriesDownload"), rs.getInt("seasonNumber"), rs.getInt("episodeNumber"), rs.getString("episodeState"))); + (rs, rowNum) -> new Episode(rs.getInt("seriesID"), rs.getString("seriesName"), rs.getInt("seriesFirstAired"), rs.getString("seriesResolution"), rs.getBoolean("seriesCliffhanger"), rs.getString("seriesStatus"), rs.getString("seriesDownload"), rs.getInt("seasonNumber"), rs.getInt("episodeNumber"), rs.getInt("episodeState"))); } catch(Exception e) { - return new ArrayList(); + return new ArrayList(); } } - public int saveSerie(Series Series) + public int saveEpisode(Episode Episode) { return 0; } - private int updateSerie(Series Series) + private int updateEpisode(Episode Episode) { return 0; } - private int insertSerie(Series Series) + private int insertEpisode(Episode Episode) { return 0; } - public int deleteSerie(Series Series) + public int deleteEpisode(Episode Episode) { return 0; } diff --git a/src/main/java/at/windesign/application/views/Series/SeriesView.java b/src/main/java/at/windesign/application/views/Series/SeriesView.java index e2629cc..2aa8d95 100644 --- a/src/main/java/at/windesign/application/views/Series/SeriesView.java +++ b/src/main/java/at/windesign/application/views/Series/SeriesView.java @@ -1,21 +1,31 @@ package at.windesign.application.views.Series; -import at.windesign.application.data.entity.Series; -import at.windesign.application.data.service.SerieService; +import at.windesign.application.data.entity.Episode; +import at.windesign.application.data.entity.Serie; +import at.windesign.application.data.service.EpisodeService; import at.windesign.application.views.main.MainView; import com.vaadin.flow.component.dependency.CssImport; import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.grid.GridVariant; import com.vaadin.flow.component.html.Div; +import com.vaadin.flow.component.html.Image; import com.vaadin.flow.component.notification.Notification; import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.router.AfterNavigationEvent; import com.vaadin.flow.router.AfterNavigationObserver; import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; +import com.vaadin.flow.server.StreamResource; import org.springframework.beans.factory.annotation.Autowired; -import java.util.ArrayList; +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.*; import java.util.List; @Route(value = "series", layout = MainView.class) @@ -24,61 +34,120 @@ import java.util.List; public class SeriesView extends Div implements AfterNavigationObserver { @Autowired - private SerieService serieService; + private EpisodeService episodeService; - private Grid series; + private Grid serie; private TextField seriesName = new TextField(); private TextField seriesFirstAired = new TextField(); + ByteArrayOutputStream imagebuffer = null; + StreamResource resource; + public SeriesView() { + resource = new StreamResource("image.png", () -> getImageInputStream()); + setId("series-view"); - series = new Grid<>(); - series.addThemeVariants(GridVariant.LUMO_NO_BORDER); - series.setHeightFull(); - series.addColumn(Series::getSeriesName).setHeader("Series Name"); - series.addColumn(Series::getSeriesFirstAired).setHeader("First Aired"); - series.addColumn(Series::getSeriesResolution).setHeader("Resolution"); - series.addColumn(Series::getSeriesCliffhanger).setHeader("Cliffhanger"); + serie = new Grid<>(); + serie.addThemeVariants(GridVariant.LUMO_NO_BORDER); + serie.setHeightFull(); + serie.addColumn(Serie::getSeriesName).setHeader("Series Name"); + serie.addColumn(Serie::getSeriesFirstAired).setHeader("First Aired"); + serie.addColumn(Serie::getSeriesResolution).setHeader("Resolution"); + serie.addColumn(Serie::getSeriesCliffhanger).setHeader("Cliffhanger"); + serie.addComponentColumn(i -> new Image(resource, "alt text")).setHeader("Preview"); +// serie.addComponentColumn(i -> new Image(new StreamResource("image.png", () -> getImageInputStream(Serie::getEpisodeState)), "alt text")).setHeader("Preview"); + //when a row is selected or deselected, populate form - series.asSingleSelect().addValueChangeListener(event -> populateForm(event.getValue())); + serie.asSingleSelect().addValueChangeListener(event -> populateForm(event.getValue())); - series.addItemDoubleClickListener( + serie.addItemDoubleClickListener( event -> { Notification.show("Clicked Item: " + event.getItem()); }); - add(series); + add(serie); } @Override public void afterNavigation(AfterNavigationEvent event) { - List seriesList = serieService.findAll(); - List seriesList1 = new ArrayList(); + List episodeList = episodeService.findAll(); + List serieList = new ArrayList<>(); + Episode lastEpisode = null; + SortedMap episodeState = new TreeMap<>(); + int oldID = -1; - int oldID = -1; - - for(Series s : seriesList) + for(Episode e : episodeList) { - if(s.getSeriesID() != oldID) + if(e.getSeriesID() != oldID) { - oldID = s.getSeriesID(); - seriesList1.add(s); + if(oldID != -1) + { + serieList.add(new Serie(lastEpisode.getSeriesID(), lastEpisode.getSeriesName(), lastEpisode.getSeriesFirstAired(), lastEpisode.getSeriesResolution(), lastEpisode.getSeriesCliffhanger(), lastEpisode.getSeriesStatus(), lastEpisode.getSeriesDownload(), episodeState)); + episodeState.clear(); + } + + lastEpisode = e; + oldID = e.getSeriesID(); } - }; - series.setItems(seriesList1); + episodeState.put(e.getSeasonNumber() << 8 + e.getEpisodeNumber(), e.getEpisodeState()); + } + if(oldID != -1) + serieList.add(new Serie(lastEpisode.getSeriesID(), lastEpisode.getSeriesName(), lastEpisode.getSeriesFirstAired(), lastEpisode.getSeriesResolution(), lastEpisode.getSeriesCliffhanger(), lastEpisode.getSeriesStatus(), lastEpisode.getSeriesDownload(), episodeState)); + + serie.setItems(serieList); } - private void populateForm(Series value) + private void populateForm(Serie value) { if(value == null) { - value = new Series(); + value = new Serie(); + } + } + +// private InputStream getImageInputStream(SortedMap state) + private InputStream getImageInputStream() + { +// int reloads = state.firstKey(); + int reloads = 1; + BufferedImage image = new BufferedImage(400, 400, BufferedImage.TYPE_INT_RGB); + Graphics2D drawable = image.createGraphics(); + + // Draw something static + drawable.setStroke(new BasicStroke(5)); + drawable.setColor(Color.WHITE); + drawable.fillRect(0, 0, 400, 400); + drawable.setColor(Color.BLACK); + drawable.drawOval(50, 50, 300, 300); + + // Draw something dynamic + drawable.setFont(new Font("Montserrat", + Font.PLAIN, 48)); + drawable.drawString("Reloads=" + reloads, 75, 216); + reloads++; + drawable.setColor(new Color(0, 165, 235)); + int x = (int) (200 - 10 + 150 * Math.sin(reloads * 0.3)); + int y = (int) (200 - 10 + 150 * Math.cos(reloads * 0.3)); + drawable.fillOval(x, y, 20, 20); + + try + { + // Write the image to a buffer + imagebuffer = new ByteArrayOutputStream(); + ImageIO.write(image, "png", imagebuffer); + + // Return a stream from the buffer + return new ByteArrayInputStream( + imagebuffer.toByteArray()); + } catch(IOException e) + { + return null; } } } diff --git a/src/main/java/at/windesign/application/views/main/MainView.java b/src/main/java/at/windesign/application/views/main/MainView.java index 52b6cb3..5213865 100644 --- a/src/main/java/at/windesign/application/views/main/MainView.java +++ b/src/main/java/at/windesign/application/views/main/MainView.java @@ -1,5 +1,11 @@ package at.windesign.application.views.main; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; import java.util.Optional; import at.windesign.application.views.Series.SeriesView; @@ -21,6 +27,9 @@ import com.vaadin.flow.component.tabs.TabsVariant; import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.RouterLink; import com.vaadin.flow.server.PWA; +import com.vaadin.flow.server.StreamResource; + +import javax.imageio.ImageIO; /** * The main view is a top-level placeholder for other views. @@ -68,7 +77,9 @@ public class MainView extends AppLayout HorizontalLayout logoLayout = new HorizontalLayout(); logoLayout.setId("logo"); logoLayout.setAlignItems(FlexComponent.Alignment.CENTER); + logoLayout.add(new Image("images/logo.png", "multimedia logo")); + logoLayout.add(new H1("multimedia")); layout.add(logoLayout, menu); return layout; diff --git a/src/main/resources/META-INF/resources/images/logo.png b/src/main/resources/META-INF/resources/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..d9215808bb18eb91ed3d80d2ae38f84dacf98767 GIT binary patch literal 16070 zcmds;<8vilw8kg4?PP)z+r}iBm=oKW*tVUM2~TWW6Wg|Jo0HtURrk~V6YhuZUES5y z)wO%?wV%D#^NUcFmqdcchyV8N8_P=IP-8Uy#!`TYP3HZCRq-1ORzWwbNn?1D#^RZ^f42y zLG*|TOG0q4B~7Y83i`V69}#enrU^u$HaTybcU@O+3+hMCQ;Wry z7g=ipzu0`rPRq;eJi4yRdEM+99YxD8e-Z0C67Uz2C z%rI(;moL#q)-BjR2`jh#V9mPOO$f>6{#Ucxs%f_AS!(Om(cqbkubXT-<5Tv=R9VMg z)%~b>O+rwq{AnY}p!A2tx25g9SJUdyv)EO>S9AYXtdl=w?{)$Xzc0J_0qZ*K@*&SUui1rvcWp`%0Wf4@fC!?Hy6x^qUoE8QS#cwdyTAY9lI7Y4i6JR};hOZ;+$RH4< zIbW79D_pIDs)KrLBD?J@LZDB$DikvS6fAa{`e&ZjlMjCa$Us4AC&|)16s9H`W7$Gu z)9BU7hn~h zv{(|e6}bvzSvbMTj_#YtlLFUv}jr#GQR=5s%yWOR|Ns@W}zA!A>huzc^%lhS-mmNLc_ z=fwzK?AanFT$#37W`cu#62rMA&1?k0HLMAkWzS#Dv!yFc1W^=f(wF!_i1oHkc1u0SSDb9EXmh{ z#yj;PpBELeWH^iRY!#$1M&!l!^||p@rp$9m32w)RDs=bjr8c)NTb5`Cg>L`Jo?+z%)S{fAJV_y6&oe@47@M$>Cn z^lwYPdJaQ-CmNo&E{a{f*GtB>?W<_}*6S;M$d(Wzhz3vc68p$psyl29(1kFGRhmoWf+mjxxCaLwwJLyGghe_f6HH*#Zn&$RMkG39d+ zxsiF_Tn>LG+rGTP{CgpX;iD`pLiAe^u`vhNl$M8EgxY@ zBJGu5CC#OmbfERUOtP+8t`&+nJ30jg`#k?!IZ((9bzhIAf4?`>pk>D@SuBM*$BE_6 z_eMM7Vr<|00glV`HFMsdOz!8ne&TG**49!meCsl*IM0k}n@o_V3hkBBC~T4Hd5_UD zuIy3(Hu+YMN~Iou=BFeP>;liiysqCWvx$qLvUnR&^LhE*BO6C6Q-toG1Ejv^7boo+ zWBPHDXs2OS>vI`mqxBxxkaXY4(whGBRR zD5?FAWPulK5@%Z+0K>c~FL4Bgd9PZaqSQBKfe!(^3W?hW2aF7jXc%P?slfs^Bz~|; zYdBmCDkU`~=V8}gDGN*FJOq$I37plNyy1p-COG&A7z@prIU92aXZ2GWWmU+oP4JP@E54z{?&I+lgIpCY<*Ml&k`O6vGF(EC1#~V#9?p`{%3kz|9_@fclUe5Ez;3eQy)xzXZx@FKO37*k zjT#dt5Pb#YcT0o(5M`@*cw!yG1J)EGvRDNXy+^{3UD35@smX!_6SL_t^joIpVt1WS z7w%K+i!*dGAhdjqidc4M8e`NCq2NEXEZ`Gx>yH;O6u>6J3^Gop}*sdQe#ZGPc{_OmEosy_p7EhU3J!K6N!B=QtZWIwG zrk9m~?wI5i7b0O!oD`9p0d)ok#5hy&`5I|JS)vf_t|8?Kum3gD*-a(ovH+UEPsfA|~y(&>JK;4#bFc_e60h#NYfs}S6>V$E~xYTeVV zT;=_t?#}H4Ja8qCcZRMhwHQR14UU;`+&Dl@!o(^p7V4fwHF_^>E~xA?TBk4@TD?tD@g^4qEHyT+@DS$np> z=iUe1^i6HXW(U6IZ*9Gh`}hg}RltJz+ddVKTfzuo-1J1o)#3YI8)nx7Bd;KlYCDo@ z*v%|B?Z*>%>=YH({;w@6?yu8Z4{YO_+#tY|8ktPNkZ&l;T~d-l~^)_rwCf3@pP$3wDuiLdDV55XM1bh3bHD~2!e zWgeT|XNFVPJ&?&p*1;)vyp_UxDA(<`UaSj~xMDk1ffy{VQ&Aw4UP#c>*<+UeUlTaN znshDHc~wflW@sDH?jq?uB6GPcggcWY?-j5B>H=-vvbE<~nwt~hP{nTU}=e>cQV)LTywHm-zb{K$3!cqzc} z9uuhs9b7rFJSm?Lb9Ge4h$iY0LW|aw_1i`_Q>qc%F?)*k^50O$lw_Hknrbi3WEw|=orp`%(KZg>wYkOTQ zx626xBj#$Rh6cUY&1ZVj^XT14)zWZ-RW84wHt&~H;sv+LZef-P|4HQtDqbdJko=5M z$$yRA3x42eTmFq>jKIbC>C>A;<9hkmVE_#Ead4ZV@_VR>weq<%z74{?keORk3RrOe zwXkCQ^xBj>p-}EVs|;+`kHudm9vCP-oE?{0pX(e0k;4#VEH}v`fj_>xfWOMlmjcKz z+1E-06+&r8QmK==yPeZm@Kg}{(&tb-A9M{~A4&xASxPCXVVyqai`9K^k~TIU3xN0w z7mi)S*og%~F`~8bvxU*?<_&cZuTvX$DH$sjD_$3OkhqL}Xj@DyVXb`Dua+|A1ftL@BD=JorVSnt=19{vyC_`w_(FX&iS>}hD%ty?b@-ld2ee1;@k3}^F z2&D;2+1Uj$bfb)VZYpn2xPp)bw-NL_sT!yh*^e~erw+AkeIlRmmpT#!h2dV$OcSL2 zGUJ)k6@I9Hh<&D^3AR4ABtLqz?td6Jdv|VlLUrmE*XK}Q@!Fr&`^^BxXc(@@DT@02 zBmg@Q^#m=#Jkkl$(!;Q-&UBwY40U$&s~0kdG$#;%Iq1)d9gvYC(#u5pwL2i{Tk9SSs`)-hDsOJz z=>8r+==*IC6MP=@JiU85#ZIV=ms0FkX7NTesFFVAey5e=jHlREQl0Y;F+{p26hVG)g5CfLo!+sl0(N3LmV&D} zZB+mdcL*Z^ws6951409f6( z6mPp}*-Y$v^S;OcxNJRgl6$GN@{L&Hq;;9;WpMH7%gcVp&bS*l|E<|n5qY#~q5t** zCz!^-xDpsh z9&O}&Z<{hNAb*C2EJC%crQJBv`-^=t0s7y1EOcg1eBN;SmL{8s;12Q?Q+u1K+f53%tsnV zISHw_SsJ`C-Aepoay^U1gffVheC(SKyHM$|*hTpgg^OeA z>hY`Ianv|V|8`&jgyXX`DJy7qZImgc8ta{)eDrYVYfc|?%8=fpmd|2m?of*6Y6hV*1o<`FEH~S1x-Y0wUiRr z4oJm9$L?QIF6rWf=k)?&A5;9ecqF)FA2+YvsIj171nc5e#!^=-Oi|kJ3pFZY^@*j- z6>=3WBhvs-;5twow$G!gD^ukOb0*JYWbRKY=WX|T6d@c^jyjrq=4dghxk}^cltk>8 z+jzdL8dh5Z?@^E)wIk~6xcilw9<346YG8-`F)S@4K5P2~4`kAq6%b(DPS_}*i-!%k z<)BC6u_rAYRWaFvOOa578+ao4X@dMPO(KjkmoN7yRKG!I3gC`p)|KHVIL9{#Sh%a{ z$l8?P-@_R6M+>B%FIqS)(36M&ay68pm}~Wv%MqvA2yE-@OY%pkPd36llm+LJ2#Q%^9J{T-JhODgBCgeM6v; zN^Xi66Oq2d+i+6M6D^yLEF28qZ4hv-7<6$7b{2F?Zo>RZb)fyD`+E3o`k6Nu6gkRC zvJC$hP+Dp2TFBmkmCPhN$~QO%nFflmx#9q_{aJCMhl8X3)}P&)6fjaE8HXnQSqFzc zL>IQo8=sDKt$Itdt?N2KH<~CrJM$B1Ewz1C$5Yy`Lob%gC5aR?Painp*;2|R7*IO7^hjNeY{3#PM?%)W|M;)hmL52S#8mL^xBSe81H zl3NOyM|q8xn=Y}_+=leR&0&|;aWGV8HSLNhN5}Zr?>Ot`TeoqyH}wJGo8s#?x+gRm zjN317cV%1M_#~yy*k;i4?m?ncca#-J8JPgKOYjVgdx*);J}qz%K0LG9vs8CX)1dba zubqjgKj~>n=XO)<_>veos(6Sb(A0+HsnGf@iI=3Tin@fwl(zN>Vc;+w+bWTX&hu4q z5fEfb*h>UV*F_)uL=`3AAx^)uR_v5js%0))jK4(N5u@ZT85j-HxF(?%yh<0p_dp~T zj;I+aZtDyd9l7>!!bd>HuXy79){Y-JUCNbl44kBrxWLxeP|Jocp=!%~1PQhwNEZ3|*#QXZ&_Cs~Ex!9% znDiuDvO@25JXgEhVjr43&%O zy0G!OWD>oYr~Q6&O0TdHCyK=iS&s%Hvil{t6lA0kOcE~uc>L9kLCX`mQw zzkw0IgRC;p6e^Q!EO6dr-c)Nnol&(sJLjbvOK1~(>&20^@o)sSAS9jLZV=k|X->cW zq-YtidmYu4$ zUXdvQdqh?po!Lxc7q zHY55bqYtr$y~BCfe7#cZ#MrjKHukvwFshEIhWD-50!lp~DqUkY4vWdz-jl_A#gi3l zseAqT4VQ=~)rgfkvXXa;lxTjs40b}?EsBVWKJcTnG`!>YA7~{I4ZGzAB$f5~dvzZm z^s>3;M+7dFBCSi0+1iH5@13coVVB0BZBbv2uK4Om{N(*hjy|5r>okZ`a|$>&uLnvy zLXxXZ*bKMQXwExCb?<>6)$3jrxNW9!0#&}Ie@(w3BW@UG86Xo`8^$6ON*bsreIvPb zPRl~QR9}>@*CrajJaTQoW-sarhIui|kb~pK?N3coTpjSPN@PIJsb}fqjua{kim6$n zYn+5t>B2U3;8{tJqy0w*R}}msied7g&TYalO7QxAzHr_=(204{8>7u?ns)SXz-ZpN z+zD5ekK?_F-Y?syY7u+K->M2$S9N6cI-XroV?=K4`%cz!AB`jrR1qgX30NP3_MX>>0Nzou414IL(^uI!cy(S>ZdVc1) zEqEYsms{f+7o(?^!!1qD7T$(w^`LZ!iT4J&m~!FLkAZ3lUdU6~@1Eu;BzU0!Oh3;W zW}K_8kFOHBw!3*QF!aSXA86wEJ8$da5jg@8pA*v`Jf%eh{j*yP)eC|nBe7adjLh)w zT~&25?49|xUA`lQY2jwc3o=kvYe>Nl6T} z;gDR=&zK>>miuEudVi*OwFipc)kuobOT&$Iedb8*nge*56*Yj99)!kzq#^ug(G;-3 zqrxL8-GYAE*ZoUGK0~%`owsuChwppwo&+Y*bLjj#|8UQ>w4!4#AA2$dA92F4!d%X1 zIcyOKxeCm(!KhsYPt9oY2oSX10xkU_z!m7ahBuuNsZF_ek#H%h?Rw`e zAnyB1y%H14Q!taConpXjE8y)u^Xk6A2{?;1~9Y2@bwGb(x>{_Tpz=^1rf0e?W z#~_d{^zmi_;5%JB!3C9;`2((0pfmjU&shwF@dMaFD2GF+bUXj*9uyAjUr1$6CzQyE zEHEn{za1DgorP>fDmR`wEpBGD$2u|?!0}3oi-_&oXgIyLsY*%W&4Ra^HsPwfft5CQ znixMv9Dyrxzho2OF|`^JvZ&13AIsiYo|$)C?^F~Q&hh}Jj=7B-e_jDB?s>+#Cv8mBC8Qcgz(n?`yQYSMjW{82ET^JC zKjzno%g;Ey*31#LI_Be3>xfxUG3nX+z_)@1G9~G`)$bsfRj_w4qIStRNBSssX!R;$ zO5PcTK7=uY$}7{2a&DGqrDzVo~v_udE>{$ePOvh7Y!|P$Wv0 zqw?4a;vE@wJ@eF8xP}DaBK-Bwws1KVx2{;Wzdz(H_28pmyMWKVa+J+Zzk~K~q10y> zp;$V1d9!SXQFZbv!@5OSa3d@yLoX-JVE0T01sA!?eHujU6$`+yH*cL7t_qib37pk? zLv{`Beq*BKnV(m{AObms*%X?C%C<{iqAZFY6yP(QDaiRxclV!LF$|QqF4qCg*UFH= z@0l<`N?I`4%1K7(jVs4&O2t{h(~~zw!l^uiDFMA|x@Mmu#*w2;Cb1It(U5pZ>U359 zPv+t_&q@o+@J;Z>B;R6|CEs9vuOU*9@fUq^ljAb5LqXSSqF_D*&A51Cc)id>&&(`( zks2Lr$;E*qD$W(SdGE>vv)KqbsXVh9{+|V* zE8N<)l9m`d5lyXei1p!=MZXBN*jHmnehOSj{cIG#JD*9z+htFuuHO)(vdAvd^}5NJ zJjJZky?I@kfYhujfGs?^%D8wL$fKKFv((JaizY*ipIj9Y({>zB998?O2RI<0%yEaq zpAwi60(5UE3FUlK=UZk6MX&=(U*i5<9}#lsy{wG%=_&}Tl#L1|;IUDJ7zb(4(w$jD zn{PC9X(%-QgRJNU1}H;Oul;IKt@It&ah)OX4Ss05yt~YB>pR14+sS9m_(MJrG%$Sp zl$_ao-1W9I(U_Tc?s{_xPL;X>-Vr1>lWHODqc`FfbgvXmBVKEI8>5SP1g{zl=>d#A zw*c@zu8h7H+1N_WrH?eGOaJphpIA5@JbL*`aAZX-0@VVo=tKz>@kMlCPUGMi* z=L|+c2TH2y$5Fg6*zwLM9u`hNf9 zw)?vRlJ$z+YdFl{eztkz{NhXfsbW}j9vh*RY{?YnuR_$-t#$QSIu@5*26M<85Mmd3 z!e93y1wWkW?K#GbtcYNngBjT5q7p2paks?v@lQ~w?I41wdGvBj#(M;*ulP8*@@Nd} z0IxaoBScQWePAeV^{`|=`>=?)#v668BN)uQGXTaC-A25Rr7*%)$m}*u6h@D#kIx?L z7Nxb9838^HesQyCW)UMKlZ?r0-0vjQoeEq321lM}em-4&Y4bHFmuwBM@Z!-$s%WRX z6!6EL&A&U^d9e{8JU4@)LW`nv<~y@##AMx!aAU1tb}G+BQT02e?Mii^5);?uU^3^U zrvR=Fao2lpnBVgNpMqCROo49hol70WSkEdvJPS5AkmcCRvTsQNVCMr|z5LYQz4)8n~IuhXFZiXshF!1Neaz`qa@ zvMG_0uv~ZDQtH+j9@>1EhokyuOYn`+`9^>bKa10;oc>Ft?TP>t{mq!^{3a*PLgRDK zOZ(n4!hwf+iaKCxBnGpx-hQ+L^#R3|J4=G=P2749Om60*jh%j}o%XNm#N4dp0k7US ztL5fB+x#{EbUR8YAAA9V(J1W8>*AV-I00k0qB6T?9z$3H9+3Ne8VPMy9591@SB$+c z)bYDt0;29wC~C+6+{QazVc_(RKJ&sGV|#C zP1-C+O%B#I6&ZDu+nHIbUAP4&>{FbJI(tH~{^O{wqleWt6xcq)zSZ_>EKLKiGG>G!xbGcB-^ z1&B_2vt8~daZRg^o0H6EckVWmP?78gfm@;nY-Qx7;?vz0W>#$YO0$<%>c7q^$ZsHT6x7+( zn!JCu-`|DpjZ|!b^@U|hnd-F?Rs*^|w{i5ZAKfsI9v^*)QPBay_ia*@?kq)_ekppN+ZiCzj2c`d~a#+*S`5aF{%9P+(}bAh1ND2x|&b z5wZcn0@@e=K@9lvBokXYn$Dg6=N=siwPtPmjepNFj9qt$O!OV4{EvBFm)2JcHqCk= z<{@jD@<&y2&5WJRb`Fn`CW9(E+z?V0e7Il(#^3qiW@oe0>)@sSKy!Yce6<&Jl~EnyV0>{CaND_QO72 zayr{lk)CFyu7BUMB!!;6dI{g|iI?!A`CJV&(9Ekx^zmxCWYMv=ZlN?cBF$|S+4ToF zC9+ggi;QeRYc4;9!lb173^wjxoD-8;YtHSZSFp{xmkp>mBRMxRn#0cuw1R9K7maUE zFxp0~Onan=4nTFa&7)C-DD#Xav$sK+e{ZQoMlN+D_WBI$anObVJXI%Y47 z;ik z2L146NQG8bWxip^YgeS!BGuf#5TK*$ZysH`tV6muB8M5`H!B4C7(`bcsh^8?bu6Ok zdpu{jp)!A!WiECIGrop3@*gRBkgI$BJ&FfPQG4Why+l$^V$uP-lPli?KqhXpWvP?n6IsLSZ!w_zt^0k?I^<+-@cz{fS zC-Wt3TW#OV%jrL_Fe8PF!0$2CNPRjbU8-GVmy4+!EO90Ad7j!%*H6ediih+qIp+LG z2&_Kxd-9e1Ja!{M(3C_NhewbYs)YXu4ZuPOpwSlNQ_`0)qjxnFWngAA<;HD2E0FFW z`h$BLI2k~Bpj|u6lI=K3%9+;f3Hx72>%s5dw>*Yj0>hralmP>Uj_(H9ZV-3PJAF6R z$Ws9|9%wuoHRPanNNz*#z>>QU! zDaK?6r;p<|YO)>6E~1z6+OD0pD#-CyJLSuIq2rezTSKK2Mpr>af!XDQGSu{_)!QKu ztvN^PU8=PROr(0CnhV#M1P@~~=P0V8e$DDc3}WBh8IhldsEJ?GAf29a2r~o{%0zVQ z73Z^u@9O-9Aj2pcgh+`NHF|@z-6m#B!k?5N$y#t>Feo00g{3m6XW)gc+h*DJ&;oOd zh5e+hNw)~m=kdlfZRtDT&%`B95;Ii0(b~St8yK6$eN`S}N(FmBQokbT$F8a4SfTxL zH5kkG9%=$NULgi zWr!FHD6L%pdJ815Hf3^`z(@Le`%>6gtl43Kpd19>Ses{kF+`?CK9j1h-{Q=5Rk|h> z7RVw-HvAx!;ksk`e3&w+pFT!|;?v>Nu@v@Zy_$}LhHLW}7x+b{b06s9nhkz|DfO;P zUNKY}wpDw5EU!r!=}XIam!L1Vzz`u6vNL`=P1d5a!D^JH#cUs<-r}RT8w5>xmgjw< zV;@Xg*D?_a_-fN}LrSy6YV%Ia+Eb;ctC-a~BLjN~u}F~3V3&Hhw`VX z4%gN;sCE%8Sgltq18vz~uz4tcIvQx{jr|yi8gC>#!w$EEyozE*2g@Vy?7*RwA>UfU ze=i$PKBqWSTYld)Z08Gq|1_Z{s@c!Inp`uuZ?W?=s{gc^Y;6ienSssL{Ql1}Tbfy( zRYdu_G)%0v{aQbjx^GszXl)k%O`MvC5VfLlI181@uGBEQb@O#2)AJDIzQp&p;U)=V z`<4|mzcL?=g(U|S+e~>P*Y)dP=G_iLn2z^kU8@X0r3xTYW(ZV^v!6X$!}={Jd#_63o9N|<176Pz)Um0>ZyO)R~hGHnRR%p&)^`i9BYyRcyGO}Q*j{?T8DEGs(7^)Pict40# zJ1CRp&o#L%r0iFTQ3W^3N)Nn9e#zht!6uLUC0K_t!~0w<^_4rzC-VDTE=|PFlFnzw z<@*Gme(hY_WA9!ldBDZ2Ynu-Sa|f8;(M~zZrqA9)*A2mve%DpU1kaNCk7}sAR%tK- zqG&Q%V9?w3ej?@TyY@4@kBska0rXcMLyR%7*TnEw=jGrT$r?&!LEbk+UN7cIG>baP zKo=#_uu`cyv-c-BIh*7Etp%;_M2sMXvacDu)}qRW7Th<|aW(GrB0L^1H^%ktb_2v4lMp)a{nvlniPP*!%&yG!wB2)|BJ z)jW@Z+FHz`!a3GxLi2w&Qo_;*`b^+Dkm0O^Bq986D{W^r z41Dh&3LfQ#D?Oj(g7F_TmnnszTl1FX`~gkWV85uho?pM{9}&6KCz>l#Z76+>{f_`t z3UA!mC%<3+NZc9iL2w(}oW(+66Gs(B9km-o>>f7BX?@gr8(p`j4aL!%=WlYIuPw!a zXu)dJ*NjK;n}ty%+93f<&52rA%X(TkmO_XRe+k%{AzW)D&4+kKdlOx>qv@MwEH&KS zOj>xiFMKb~QupSTw}!6R?WHP7M@5!K7C%cp8aVU-*DJ*ox%xM8*~_tPonJL}UWw6b z*AipuKbwgi?TELBMxj$#?tfd<4suufL2Qr*r0%B>ucb*4At@t;N;Hkxv}jWD$pYUu z!)I1nE*rZyIsZM~sgy^cFFW&P3}KvtoFN1mNc!7sJ?mi%B+va!ZTi{}hQ9 zhQ{ikY46X(O2?eN$=VhDLpAj8-4hNw?95XGMC`9Pu?>nu{tz^MdsGxY;kofSRT!p* zMkL{W|2hT~YCrzL4q`d@CBPv{*GD*0Y}J><@*LGn_!aH+M{y#v6a~n-&eK5K$<~k zhBD`dS?2&OMrgo599)5|xE2bW2vxu4mrugz*?t`ymK8AI3QzUvta@Wiv6X?$S9}NE ze&rFDr)vwwg0g4({g$MHrrA>bo+YLN82H$hNbGsQhZ_f>>Lf&?Wi(Xloz*L*G$2upV) zK{Hmjrd#d9&=8}2avQVt`n1+qzvOB^!kVpZ?wUGg@q>IZl%e^W(T3I7Rb#f^GC2d z`v<2Luc7m|=6n~AxuwG+I7=jWTAMEu@hg}x(i#+yTi}5*Qq6%W#S0u>do<;9ym%I7 z*^wCG?LcDhNz?98??@Fr`EFI+$_=rnuiG%2X9qdCT$q{G>j1;+^156qF8@Ctgs1;c zwQzJH!d>o@dNc>zg8-6ojy^hwG&%_xemK6$UFp8L8dW}>5A_*KK$X=C7(6zhfWk||vu z>StSt1!Tzz90iL5^w(ua?I*Lu$yhkPb@}Y%4Qb_PLZIOa-B`@%Vt@zV6mW|`0Ji^# zvs^KQ0wK6F&atJXVDOT}L>4yi6;RQYph+ii<*r-?g%n_&ISpn!cOS}qyX?3*nB1t&F$*FTmNw?mw$>)b1*oyU8c z?jbhCW$>Z3o7bzJuC6)BIQ~P9A^t)rr)}0DJwOG2-T8USoq4PR&;9f*FfMMhQ_Su6 z?|R3EyX`NJ>kM1&z*1T32m?jR)+4RrS7+YN%f}Yf^PZp7?^8slKG#;oP*7hD%|U9B zQhlvyluhzF_nkx2URz)G+N|s8Weg^3EGGK%hQkf7_sOBBhuRA1Ui-!`gDvm)&fL43 zho7gFpo2ki-UjDN3a=whGex1Q_+14L91*~V^t78b6}1Akuc2mfpCt$zQ|f;+bw935`>8j)oLLbO?_uMu}TI_SN+{O*Rd=6q7GWq0XehC zI`;D04JGKnk#L9hl^J;q3F;4Md-U%whbeTP*_Q%KUL?Mk&c=d3&3n(v1GiWKkN%~s zkN3k2+lKvdh{(>ZN%4OVXmWVMITm6y@p6A6i&XsloAVhBtCk?vQ;v95%WIkXbBq!t zNh61fw>nu;D|0R}Zp5Y--7W;?+A5c9cFwTJVlu1eskJkly$)#N1YhP+Vl`gxdex2y1y8)qZRON@j;v}mHHqIY zo7}Sk$U4`Ml`8gU4Ri^V3Y!T@TPwQ+DZtQpxC|;w1N$C3vN2xOf|Xx@C5bm8oaA=E zQG1wYb#LQ2eLUWI97dWAih*p?@4Y!|c^uYKeGl7xa46^)_@hseYG2RSNFtTJl_K;9 z2AY!_V~~Cv5H(tjjT9}B%xn)=ip)S|hMI4qc^eXb#x8*Ah5tcEFqMu>jHC<5a(iA+ z*>%I0JAQoxhrte_lW|0+@bc9plbZS5+E73+o2PASCwjh~ z3mVohutzr*j)2vC4`ce=m|Wy&OMagGH=NDi+UlPj8C*~BD*vN-37WN){R?C;ByTAj zF)hD?&7b%_DNpXY{Iq;;Lh%bMhSbI_Qj(TY#csz-PlADl{(58$JwH)urND`Js9-GE z4nF&DyKDKAJxDIAR*dXpC=_cYnz3^QFd}$VFSy79htbh_5!KX%A;f!EF-ZcMEzdjE zsWtpsTHr7S%D@np4t@3q6F;fAI}SsZPKswpuKAV7p1g9oZo~^?Xyo6omJDN?C>LPJ zC+yTf*g+Y6XchS%KlNP^Se)5Wpb_vkih$`$_QEgHuJ&a*Q#DZD-V$S4wWyZ?+*!?{ zxsJSSkf-a3%i{J7trfu0HWu(`y0`y74P_6jrQ#A93OPG~%8veE;o=`@;b`Fu7H zQgIdge?eR{{tbU=5U_3ES$-V+iIh6GiDhpqD!9I0?wElgdg|w-XMC^_x2t%;`N&AXbtCLgY>wjW2sIfe)Wv_fh zK3bRq_yyY|`(U*~3nP)^@*Yry!aYxln?4jti+|0i5Wgo|NXyz+6hNO~pi|0GsQWzn zFa1MeePwV*IrsAl91|`DD;4+9R&w67KiwTTDv;6aQa|LfN9q1d@$qc)ibu2)*habB z!hjj*{25_$^ME(jX8N|6@G@YElihwGECf|G7bmsdl^oS>oZ?|sOgY5Q@`r)6AZ67T+b&%7%ADVir-mZ+@m5>$ouXiWYN7yc(;GOs}54`FeS+7HPJ%u z%1xF*v)Qzu8r+_Et0c0VEHCAnGq|MryPubMNgy4K#goSa?T3j})tNv+3k(2gm(vg_ z*IP{^Ru}=PGk!;}=l`%nZ$ZsU39=6MDlwMH{Sou#`~o(-J4@UiyjKbN-dwjC6Q~P* zlRTOms}&1!5Q!F+AuDj5C7;97=pB_L~`q&lL|F`wqbBor_$H3g7mdGw@NS`1fnn?ELNNXr0gVP6rTvYNR^zpU|`X zNqDrMab%yp=}armKp3MlL;nIS*&PDLcbG!GAYjqk58is;*Fy~VNl!*;CXARW) zq5nN3c9Q((&#FoX4Ym|JgWct2*|aV zGp2b(pLK!Np>qECC8#aK&W-h6ZOV?1oxWDall-7J8~D+2Q(jb9F0Q#A-aA5e@ShF4 z8~P`DV4YDn5b3V3jenmZq4bNo=Zc?=3Az*(PaCvTz6f0^7$mK*al32SeW3kysyu-t z$kx={@QCXMY?tY_iCyqBqB5y;i0F@r_u^H(wu_$gaRW^v9tviFH##!rWSa5g+R>l4 z9T{ < | (_| || | | | | || |_) || || __/ - \__,_| \__,_| \__| \__,_||_.__/ \__,_||___/ \___| |_| |_| |_| \__, ||___/ \__, ||_| \___|/_/\_\ \__,_||_| |_| |_|| .__/ |_| \___| - |___/ |_| |_| + _ _ _ _ _ + _ __ ___ _ _ | || |_ (_) _ __ ___ ___ __| |(_) __ _ +| '_ ` _ \ | | | || || __|| || '_ ` _ \ / _ \ / _` || | / _` | +| | | | | || |_| || || |_ | || | | | | || __/| (_| || || (_| | +|_| |_| |_| \__,_||_| \__||_||_| |_| |_| \___| \__,_||_| \__,_| +