From a88917459a28088500da56a3c8e3f9483995f353 Mon Sep 17 00:00:00 2001 From: nwickel Date: Tue, 9 Apr 2024 16:55:05 +0200 Subject: [PATCH] Updated README with all infos on decisions as RMD and MD --- .Rbuildignore | 1 + README.Rmd | 541 ++++++++++++++++++++++++++++ README.md | 600 ++++++++++++++++++++++++++++++- man/figures/README-timems-1.png | Bin 0 -> 6367 bytes man/figures/README-xycoord-1.png | Bin 0 -> 12056 bytes man/figures/logo.png | Bin 0 -> 20677 bytes 6 files changed, 1135 insertions(+), 7 deletions(-) create mode 100644 .Rbuildignore create mode 100644 README.Rmd create mode 100644 man/figures/README-timems-1.png create mode 100644 man/figures/README-xycoord-1.png create mode 100644 man/figures/logo.png diff --git a/.Rbuildignore b/.Rbuildignore new file mode 100644 index 0000000..6e6b0d3 --- /dev/null +++ b/.Rbuildignore @@ -0,0 +1 @@ +^README\.Rmd$ diff --git a/README.Rmd b/README.Rmd new file mode 100644 index 0000000..2cfef99 --- /dev/null +++ b/README.Rmd @@ -0,0 +1,541 @@ +--- +output: github_document +--- + + + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>", + fig.path = "man/figures/README-", + out.width = "100%" +) +``` + +# R package mtt + +![mtt package](man/figures/logo.png) + +This package was created to process log files obtained from multi-touch +tables at the Leibniz-Institut für Wissensmedien (IWM). + +## Installation + +It can be installed via + +`devtools::install_git("https://gitea.iwm-tuebingen.de/R/mtt.git")` + +If you get an error message, you probably need to install `git2r`first with + +`install.packages("git2r")`. + +The package depends on the following R packages + +* `dplyr` +* `pbapply` +* `XML` +* `lubridate` + +so make sure they are installed as well. + +# Multi-Touch Table + +The multi-touch table at the Herzog-Anton-Ulrich-Museum (HAUM) in +Braunschweig gives visitors of the Museum the opportunity to interact with +about 70 artworks and 3 virtual cards containing information about the +museum and its layout. The table was installed at the museum in October +2016 and since November 2016 log files from interactions of visitors of the +museum have been collected. These log files are in an unstructured format +and cannot be easily analyzed. The purpose of the following document is to +describe how the data haven been transformed and which decisions have been +made along the way. + + + +# Data structure + +The log files contain lines that indicate the beginning and end of possible +activities that can be performed when interacting with the artworks on the +table. The layout of the table looks like pictures have been tossed on a +large table. Every artwork is visible at the start configuration. People +can move the pictures on the table, they can be scaled and rotated. +Additionally, the virtual picture cards can be flipped in order to find +more information of the artwork on the "back" of the card. One has to press +a little `i` for more information in one of the bottom corners of the card. +On the back of the card two to six information cards can be found with a +teaser text about a certain topic. These topic cards can be opened and a +hypertext with detailed information opens. Within these hypertexts certain +technical terms can be clicked for lay people to get more information. This +also opens up a pop-up. The events encoded in the raw log files therefore +have the following structure. + +``` +"Start Application" --> Start Application +"Show Application" +"Transform start" --> Move +"Transform stop" +"Show Info" --> Flip Card +"Show Front" +"Artwork/OpenCard" --> Open Topic +"Artwork/CloseCard" +"ShowPopup" --> Open Popup +"HidePopup" +``` + +The right side shows what events can be extracted from these raw lines. The +"Start Application" is not an event in the original sense since it only +indicates if the table was started or maybe reset itself. This is not an +interaction with the table and therefore not interesting in itself. All +"Start Application" and "Show Application" are therefore excluded from the +data when further processed and are only in the raw log files. + +# Parsing the raw log files + +The first step is to parse the raw log files that are stored by the +application as text files in a rather unstructured format to a format that +can be read by common statistics software packages. The data are therefore +transferred to a spread sheet format. The following section describes what +problems were encountered while doing this. + +## Corrupt lines + +When reading the files containing the raw logs into R, a warning appears +that says + +``` +Warning messages: + incomplete final line found on '2016/2016_11_18-11_31_0.log' + incomplete final line found on '2016/2016_11_18-11_38_30.log' + incomplete final line found on '2016/2016_11_18-11_40_36.log' + ... +``` + +When you open these files, it looks like the last line contains some binary +content. It is unclear why and how this happens. So when reading the data, +these lines were removed. A warning will be given that indicates how many +files have been affected. + +## Extracted variables from raw log files + +The following variables (columns in the data frame) are extracted from the +raw log file: + +* `fileId`: Containing the zero-left-padded file name of the raw log file + the data line has been extracted from + +* `folder`: The folder names in which the raw log files haven been + organized in. For the HAUM data set, the data are sorted by year (folders + 2016, 2017, 2018, 2019, 2020, 2021, 2022, and 2023). + +* `date`: Extracted timestamp from the raw log file in the format + `yyyy-mm-dd hh:mm:ss`. + +* `timeMs`: Containing a timestamp in Milliseconds that restarts with + every new raw log files. + +* `event`: Start and stop event tags. See above for possible values. + +* `item`: Identifier of the different items. This is a three-digit + (left-padded) number. The numbers of the items correspond to the + folder names in `/ContentEyevisit/eyevisit_cards_light/` and were + orginally taken from the museums catalogue. + +* `popup`: Name of the pop-up opened. This is only interesting for + "openPopup" events. + +* `topic`: The number of the topic card that has been opened at the back of + the item card. See below for a more detailed description what these + numbers mean. + +* `x`: Value of x-coordinate in pixel on the 4K-Display ($3840 \times 2160$). + +* `y`: Value of y-coordinate in pixel. + +* `scale`: Number in 128 bit that indicates how much the card has been + scaled. + +* `rotation`: Degree of rotation from start configuration. + + + +## Variables after "closing of events" + +The raw log data consist of start and stop events for each event type. +After preprocessing four event types are extracted: `move`, `flipCard`, +`openTopic`, and `openPopup`. Except for the `move` events, which can occur +at any time when interacting with an item card on the table, the events +have a hierarchical order: An item card first needs to be flipped +(`flipCard`), then the topic cards on the back of the card can be opened +(`openTopic`), and finally pop-ups on these topic cards can be opened +(`openPopup`). This implies that the event `openPopup` can only be present +for a certain item, if the card has already been flipped (i.e., an event +`flipCard` for the same item has already occured). + +After preprocessing, the data frame is now in a wide format with columns +for the start and the stop of each event and contains the following +variables: + +* `fileId.start` / `fileId.stop`: See above. + +* `date.start` / `date.stop`: See above. + +* `folder`: Containing the folder name (see above). + +* `case`: A numerical variable indicating cases in the data. A "case" + indicates an interaction interval and could be defined in different ways. + Right now a new case begins, when no event occurred when no new path + started for 20 seconds or longer. + +* `path`: A path is defined as one interaction with one item. A path + can either start with a `flipCard` event or when an item has been + touched for the first time within this case. A path ends with the + item card being flipped close again or with the last movement of the + card within this case. One case can contain several paths with the same + item when the item is flipped open and flipped close again several + times within a short time. + +* `glossar`: An indicator variable with values 0/1 that tracks if a pop-up + has been opened from the glossar folder. These pop-ups can be assigned to + the wrong item since it is not possible to do this algorithmically. + It is possible that two items are flipped open that could both link to + the same pop-up from a glossar. The indicator variable is left as a + variable, so that these pop-ups can be easily deleted from the data. + Right now, glossar entries can be ignored completely by setting an + argument and this is done by default. Using the pop-ups from the glossar + will need a lot more love, before it behaves satisfactorily. + +* `event`: Indicating the event. Can take tha values `move`, `flipCard`, + `openTopic`, and `openPopup`. + +* `item`: Identifier of the different artworks and information cards. This + is a three-digit (left-padded) number. See above. + +* `timeMs.start` / `timeMs.stop`: See above. + +* `duration`: Calculated by $timeMs.stop - timeMs.start$ in Milliseconds. + Needs to be adjusted for events spanning more than one log file by a + factor of $60,000 \times \text{number of logfiles}$. See below for details. + +* `topic`: See above. + +* `popup`: See above. + +* `x.start` / `x.stop`: See above. + +* `y.start` / `y.stop`: See above. + +* `distance`: Euclidean distande calculated from $(x.start, y.start)$ and + $(x.stop, y.stop)$. + +* `scale.start` / `scale.stop`: See above. + +* `scaleSize`: Relative scaling of item card, calculated by + $\frac{scale.stop}{scale.start}$. + +* `rotation.start` / `rotation.stop`: See above. + +* `rotationDegree`: Difference of rotation from $rotation.stop$ to + $rotation.start$. + +## How unclosed events are handled + +Events do not necessarily need to be completed. A person can, e.g., leave +the table and not flip the item card close again. For `flipCard`, +`openTopic`, and `openPopup` the data frame contains `NA` when the event +does not complete. For `move` events it happens quite often that a start +event follows a start event and a stop event follows a stop event. +Technically a move event cannot *not* be finished and the number of events +without a start or stop indicate that the time resolution was not +sufficient to catch all these events accurately. Double start and stop +`move` events have therefore been deleted from the data set. + +## Additional meta data + +For the HAUM data, I added meta data on state holidays and school +vacations. + +This led to the following additional variables: + +* `holiday` + +* `vacations` + +# Problems and how I handled them + +This lists some problems with the log data that required decisions. These +decisions influence the outcome and maybe even the data quality. Hence, I +tried to document how I handled these problems and explain the decisions I +made. + +## Weird behavior of `timeMs` and neg. `duration` values + +`timeMs` resets itself every time a new log file starts. This means that +the durations of events spanning more than one log file must be adjusted. +Instead of just calculating $timeMs.stop - timeMs.start$, `timeMs.start` +must be subtracted from the maximum duration of the log file where the +event started ($600,000 ms$) and the `timeMs.stop` must be added. If the +event spans more than two log files, a multiple of $600,000$ must be taken, +e.g. for three log files it must be: $2 \times 600,000 - timeMs.start + +timeMs.stop$ and so on. + +```{r timems, echo = FALSE, results = FALSE, fig.show = TRUE} +# Read data +datraw <- read.table("../../MDS/2023ss/60100_master_thesis/analysis/code/results/raw_logfiles_2024-02-21_16-07-33.csv", sep = ";", + header = TRUE) + +plot(timeMs ~ as.factor(fileId), datraw[1:5000,], xlab = "fileId") +``` + +The boxplot shows that we have a continuous range of values within one log +file but that `timeMs` does not increase over log files. I kept +`timeMs.start` and `timeMs.stop` and also `fileId.start` and `fileId.stop` +in the data frame, so it is clear when events span more than one log file. + + + +## Left padding of file IDs + +The file names of the raw log files are automatically generated and contain +a timestamp. This timestamp is not well formed. First, it contains an +incorrect month. The months go from 0 to 11 which means, that the file name +`2016_11_15-12_12_57.log` was collected on December 15, 2016 at 12:12 pm. +Another problem is that the file names are not zero left padded, e.g., +`2016_11_15-12_2_57.log`. This file was collected on December 15, 2016 at +12:02 pm and therefore before the file above. But most sorting algorithms, +will sort these files in the order shown below. In order to preprocess the +data and close events that belong together, the data need to be sorted by +events and artworks repeatedly. In order to get them back in the correct +time order, it is necessary to order them based on three variables: +`fileId.start`, `date.start` and `timeMs.start`. The file IDs therefore +need to sort in the correct order (again see below for example). I zero +left padded the log file names within the data frame using it as an +identifier. These "file names" do not correspond exactly to the original +raw log file names. This needs to be kept in mind when doing any kind of +matching etc. + +``` +## what it looked like before left padding +# 1422 ../data/haum_logs_2016-2023/_2016b/2016_11_15-12_2_57.log 2016-12-15 12:12:56 599671 Transform start 076 076.xml NA 2092.25 2008.00 0.3000000 13.26874254 +# 1423 ../data/haum_logs_2016-2023/_2016b/2016_11_15-12_12_57.log 2016-12-15 12:12:57 621 Transform start 076 076.xml NA 2092.25 2008.00 0.3000000 13.26523465 +# 1424 ../data/haum_logs_2016-2023/_2016b/2016_11_15-12_12_57.log 2016-12-15 12:12:57 677 Transform stop 076 076.xml NA 2092.25 2008.00 0.2997736 13.26239605 +# 1425 ../data/haum_logs_2016-2023/_2016b/2016_11_15-12_12_57.log 2016-12-15 12:12:57 774 Transform start 076 076.xml NA 2092.25 2008.00 0.2999345 13.26239605 +# 1426 ../data/haum_logs_2016-2023/_2016b/2016_11_15-12_12_57.log 2016-12-15 12:12:57 850 Transform stop 076 076.xml NA 2092.25 2008.00 0.2997107 13.26223362 +# 1427 ../data/haum_logs_2016-2023/_2016b/2016_11_15-12_2_57.log 2016-12-15 12:12:57 599916 Transform stop 076 076.xml NA 2092.25 2008.00 0.2997771 13.26523465 + +## what it looks like now +# 1422 2016_11_15-12_02_57.log 2016-12-15 12:12:56 599671 Transform start 076 076.xml NA 2092.25 2008.00 0.3000000 13.26874254 +# 1423 2016_11_15-12_02_57.log 2016-12-15 12:12:57 599916 Transform stop 076 076.xml NA 2092.25 2008.00 0.2997771 13.26523465 +# 1424 2016_11_15-12_12_57.log 2016-12-15 12:12:57 621 Transform start 076 076.xml NA 2092.25 2008.00 0.3000000 13.26523465 +# 1425 2016_11_15-12_12_57.log 2016-12-15 12:12:57 677 Transform stop 076 076.xml NA 2092.25 2008.00 0.2997736 13.26239605 +# 1426 2016_11_15-12_12_57.log 2016-12-15 12:12:57 774 Transform start 076 076.xml NA 2092.25 2008.00 0.2999345 13.26239605 +# 1427 2016_11_15-12_12_57.log 2016-12-15 12:12:57 850 Transform stop 076 076.xml NA 2092.25 2008.00 0.2997107 13.26223362 +``` + +## Timestamps repeat + +The timestamps in the `date` variable record year, month, day, hour, +minute and seconds. Since one second is not a very short time interval for +a move on a touch display, this is not fine grained enough to bring events +into the correct order, meaning there are events from the same log file +having the same timestamp and even events from different log files having +the same timestamp. The log files get written about every 10 minutes +(which can easily be seen when looking at the file names of the raw log +files). So in order to get events in the correct order, it is necessary to +first order by file ID, within file ID then sort by timestamp `date` and +then within these more coarse grained timestamps sort be `timeMs`. But as +explained above, `timeMs` can only be sorted within one file ID, since they +do not increase consistently over log files, but have a new setoff for each +raw log file. + +## x,y-coordinates outside of display range + +The display of the Multi-Touch-Table is a 4K-display with 3840 x 2160 +pixels. When you plot the start and stop coordinates, the display is +clearly distinguishable. However, a lot of points are outside of the +display range. This can happen, when the art objects are scaled and then +moved to the very edge of the table. Then it will record pixels outside of +the table. These are actually valid data points and I will leave them as +is. + +```{r xycoord} +datlogs <- read.table("../../MDS/2023ss/60100_master_thesis/analysis/code/results/event_logfiles_2024-02-21_16-07-33.csv", sep = ";", + header = TRUE) + +par(mfrow = c(1, 2)) +plot(y.start ~ x.start, datlogs) +abline(v = c(0, 3840), h = c(0, 2160), col = "blue", lwd = 2) +plot(y.stop ~ x.stop, datlogs) +abline(v = c(0, 3840), h = c(0, 2160), col = "blue", lwd = 2) + +aggregate(cbind(x.start, x.stop, y.start, y.stop) ~ 1, datlogs, mean) +``` + +## Pop-ups from glossar cannot be assigned to a specific item + +All the information, pictures and texts for the topics and pop-ups are +stored in `/data/haum/ContentEyevisit/eyevisit_cards_light/`. +Among other things, each folder contains XML-files with the information +about any technical terms that can be opened from the hypertexts on the +topic cards. Often these information are item dependent and then the +corresponding XML-file is in the folder for this item. Sometimes, however, +more general terms can be opened. In order to avoid multiple files +containing the same information, these were stored in a folder called +`glossar` and get accessed from there. The raw log files only contain the +path to this glossar entry and did not record from which item it was +accessed. I tried to assign these glossar entries to the correct items. The +(very heuristic) approach was this: + +1. Create a lookup table with all XML-file names (possible pop-ups) from + the glossar folder and what items possibly call them. This was stored + as an `RData` object for easier handling but should maybe be stored in a + more interoperable format. + +2. I went through all possible pop-ups in this lookup table and stored the + items that are associated with it. + +3. I created a sub data frame without move events (since they can never be + associated with a pop-up) and went through every line and looked up if + an item and a topic card had been opened. If this was the case and a + glossar entry came up before the item was closed again, I assigned + this item to the glossar entry. + +This is heuristic since it is possible that several topic cards from +different items are opened simultaneously and the glossar pop-up could +be opened from either one (it could even be more than two, of course). In +these cases the item that was opened closest to the glossar pop-up has +been assigned, but this can never be completely error free. + +And this heuristic only assigns a little more than half of the glossar +entries. Since my heuristic only looks for the last item that has been +opened and if this item is a possible candidate it misses all glossar +pop-ups where another item has been opened in between. This is still an +open TODO to write a more elaborate algorithm. + +All glossar pop-ups that do not get matched with an item are removed +from the data set with a warning if the argument `glossar = TRUE` is set. +Otherwise the glossar entries will be ignored completely. + +## Assign a `case` variable based on "time heuristic" + +One thing needed in order to work with the data set and use it for machine +learning algorithms like process mining, is a variable that tries to +identify a case. A case variable will structure the data frame in a way +that navigation behavior can actually be investigated. However, we do not +know if several people are standing around the table interacting with it or +just one very active person. The simplest way to define a case variable is +to just use a time limit between events. This means that when the table has +not been interacted with for, e.g., 20 seconds than it is assumed that a +person moved on and a new person started interacting with the table. This +is the easiest heuristic and implemented at the moment. Process mining +shows that this simple approach works in a way that the correct process +gets extracted by the algorithm. + +In order to investigate user behavior on a more fine grained level, it will +be necessary to come up with a more elaborate approach. A better, still +simple approach, could be to use this kind of time limit and additionally +look at the distance between items interacted with within one time window. +When items are far apart it seems plausible that more than one person +interacted with them. Very short time lapses between events on different +items could also be an indicator that more than one person is interacting +with the table. + +## Assign a `path` variable + +The `path` variable is supposed to show one interaction trace with one +artwork. Meaning it starts when an artwork is touched or flipped and stops +when it is closed again. It is easy to assign a path from flipping a card +over opening (maybe several) topics and pop-ups for this artwork card until +closing this card again. But one would like to assign the same path to +move events surrounding this interaction. Again, this is not possible in an +algorithmic way but only heuristically. + +Again, I used a time cutoff for this. First, if a `move` event occurs, it +is checked, if the same item has been flipped less than 20 seconds +beforehand. If yes, the same path indicator is assigned to this `move`. If +not, temporarily a new "move indicator" is assigned. Then, a "backward +pass" is applied, where it is checked if the same item is opened less than +20 seconds _after_ the event occurs. If yes, that path indicator is +assigned. For all the remaining moves, a new path number is assigned. This +corresponds to items being moved without being flipped. + +## A `move` event does not record any change + +Most of the events in the log files are move events. Additionally, many of +these move events are recorded but they do not indicate any change, meaning +the only difference is the timestamp. All other variables indicating moves +like `x.start` and `x.stop`, `rotation.start` and `rotation.stop` etc. do +not show _any_ change. They represent about 2/3 of all move events. These +events are probably short touches of the table without an actual +interaction. They were therefore removed from the data set. + +## Card indices go from 0 to 7 (instead of 0 to 5 as expected) + +In the beginning I thought that the number for topics was the index of +where the card was presented on the back of the item. But this is not +correct. It is the number of the topic. There are eight topics in total: + +``` +Indices for topics: +0 artist +1 thema +2 komposition +3 leben des kunstwerks +4 details +5 licht und farbe +6 extra info +7 technik +``` +On the back of items, there can be between 2 to 6 topic cards. Several of +these topic cards can be about the same topic, e.g., there can be two topic +cards assigned to the topic `thema`. It is impossible to find out if the +same topic card was opened several times or if different topic cards with +the same topic were opened from the same item. See example below for item +"001". + +```{r topics, echo = FALSE} +devtools::load_all() +items <- sprintf("%03d", unique(datlogs$item)) +topics <- extract_topics(items, xmlfiles = paste0(items, ".xml"), + xmlpath = "../../MDS/2023ss/60100_master_thesis/analysis/data/haum/ContentEyevisit/eyevisit_cards_light/") +head(topics) +``` + +## New artworks "504" and "505" starting October 2022 + +When I read in the complete data frame for the first time, all of the +sudden there were 72 instead of 70 items. It seems like these two +artworks appear on October 21, 2022. + +```{r newitems} +summary(as.Date(datraw[datraw$item %in% c("504", "505"), "date"])) +``` + +The artworks seem to be have updated in general after October 21, 2022. The +following table shows which items were presented in which years. + +```{r years} +xtabs(~ item + lubridate::year(date.start), datlogs) +``` + +It shows that the artworks haven been updated after the Corona pandemic. I +think, the table was also moved to a different location at that point. + diff --git a/README.md b/README.md index efc1976..5aab782 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,12 @@ + + + # R package mtt -This package was created to process log files obtained from -Multi-Touch-Tables at the IWM. +![mtt package](man/figures/logo.png) + +This package was created to process log files obtained from multi-touch +tables at the Leibniz-Institut für Wissensmedien (IWM). ## Installation @@ -9,16 +14,597 @@ It can be installed via `devtools::install_git("https://gitea.iwm-tuebingen.de/R/mtt.git")` -If you get an error message, you probably need to install `git2r`first with +If you get an error message, you probably need to install `git2r`first +with `install.packages("git2r")`. The package depends on the following R packages -* `dplyr` -* `pbapply` -* `XML` -* `lubridate` +- `dplyr` +- `pbapply` +- `XML` +- `lubridate` so make sure they are installed as well. +# Multi-Touch Table + +The multi-touch table at the Herzog-Anton-Ulrich-Museum (HAUM) in +Braunschweig gives visitors of the Museum the opportunity to interact +with about 70 artworks and 3 virtual cards containing information about +the museum and its layout. The table was installed at the museum in +October 2016 and since November 2016 log files from interactions of +visitors of the museum have been collected. These log files are in an +unstructured format and cannot be easily analyzed. The purpose of the +following document is to describe how the data haven been transformed +and which decisions have been made along the way. + + + +# Data structure + +The log files contain lines that indicate the beginning and end of +possible activities that can be performed when interacting with the +artworks on the table. The layout of the table looks like pictures have +been tossed on a large table. Every artwork is visible at the start +configuration. People can move the pictures on the table, they can be +scaled and rotated. Additionally, the virtual picture cards can be +flipped in order to find more information of the artwork on the “back” +of the card. One has to press a little `i` for more information in one +of the bottom corners of the card. On the back of the card two to six +information cards can be found with a teaser text about a certain topic. +These topic cards can be opened and a hypertext with detailed +information opens. Within these hypertexts certain technical terms can +be clicked for lay people to get more information. This also opens up a +pop-up. The events encoded in the raw log files therefore have the +following structure. + + "Start Application" --> Start Application + "Show Application" + "Transform start" --> Move + "Transform stop" + "Show Info" --> Flip Card + "Show Front" + "Artwork/OpenCard" --> Open Topic + "Artwork/CloseCard" + "ShowPopup" --> Open Popup + "HidePopup" + +The right side shows what events can be extracted from these raw lines. +The “Start Application” is not an event in the original sense since it +only indicates if the table was started or maybe reset itself. This is +not an interaction with the table and therefore not interesting in +itself. All “Start Application” and “Show Application” are therefore +excluded from the data when further processed and are only in the raw +log files. + +# Parsing the raw log files + +The first step is to parse the raw log files that are stored by the +application as text files in a rather unstructured format to a format +that can be read by common statistics software packages. The data are +therefore transferred to a spread sheet format. The following section +describes what problems were encountered while doing this. + +## Corrupt lines + +When reading the files containing the raw logs into R, a warning appears +that says + + Warning messages: + incomplete final line found on '2016/2016_11_18-11_31_0.log' + incomplete final line found on '2016/2016_11_18-11_38_30.log' + incomplete final line found on '2016/2016_11_18-11_40_36.log' + ... + +When you open these files, it looks like the last line contains some +binary content. It is unclear why and how this happens. So when reading +the data, these lines were removed. A warning will be given that +indicates how many files have been affected. + +## Extracted variables from raw log files + +The following variables (columns in the data frame) are extracted from +the raw log file: + +- `fileId`: Containing the zero-left-padded file name of the raw log + file the data line has been extracted from + +- `folder`: The folder names in which the raw log files haven been + organized in. For the HAUM data set, the data are sorted by year + (folders 2016, 2017, 2018, 2019, 2020, 2021, 2022, and 2023). + +- `date`: Extracted timestamp from the raw log file in the format + `yyyy-mm-dd hh:mm:ss`. + +- `timeMs`: Containing a timestamp in Milliseconds that restarts with + every new raw log files. + +- `event`: Start and stop event tags. See above for possible values. + +- `item`: Identifier of the different items. This is a three-digit + (left-padded) number. The numbers of the items correspond to the + folder names in `/ContentEyevisit/eyevisit_cards_light/` and were + orginally taken from the museums catalogue. + +- `popup`: Name of the pop-up opened. This is only interesting for + “openPopup” events. + +- `topic`: The number of the topic card that has been opened at the back + of the item card. See below for a more detailed description what these + numbers mean. + +- `x`: Value of x-coordinate in pixel on the 4K-Display + ($3840 \times 2160$). + +- `y`: Value of y-coordinate in pixel. + +- `scale`: Number in 128 bit that indicates how much the card has been + scaled. + +- `rotation`: Degree of rotation from start configuration. + + + +## Variables after “closing of events” + +The raw log data consist of start and stop events for each event type. +After preprocessing four event types are extracted: `move`, `flipCard`, +`openTopic`, and `openPopup`. Except for the `move` events, which can +occur at any time when interacting with an item card on the table, the +events have a hierarchical order: An item card first needs to be flipped +(`flipCard`), then the topic cards on the back of the card can be opened +(`openTopic`), and finally pop-ups on these topic cards can be opened +(`openPopup`). This implies that the event `openPopup` can only be +present for a certain item, if the card has already been flipped (i.e., +an event `flipCard` for the same item has already occured). + +After preprocessing, the data frame is now in a wide format with columns +for the start and the stop of each event and contains the following +variables: + +- `fileId.start` / `fileId.stop`: See above. + +- `date.start` / `date.stop`: See above. + +- `folder`: Containing the folder name (see above). + +- `case`: A numerical variable indicating cases in the data. A “case” + indicates an interaction interval and could be defined in different + ways. Right now a new case begins, when no event occurred when no new + path started for 20 seconds or longer. + +- `path`: A path is defined as one interaction with one item. A path can + either start with a `flipCard` event or when an item has been touched + for the first time within this case. A path ends with the item card + being flipped close again or with the last movement of the card within + this case. One case can contain several paths with the same item when + the item is flipped open and flipped close again several times within + a short time. + +- `glossar`: An indicator variable with values 0/1 that tracks if a + pop-up has been opened from the glossar folder. These pop-ups can be + assigned to the wrong item since it is not possible to do this + algorithmically. It is possible that two items are flipped open that + could both link to the same pop-up from a glossar. The indicator + variable is left as a variable, so that these pop-ups can be easily + deleted from the data. Right now, glossar entries can be ignored + completely by setting an argument and this is done by default. Using + the pop-ups from the glossar will need a lot more love, before it + behaves satisfactorily. + +- `event`: Indicating the event. Can take tha values `move`, `flipCard`, + `openTopic`, and `openPopup`. + +- `item`: Identifier of the different artworks and information cards. + This is a three-digit (left-padded) number. See above. + +- `timeMs.start` / `timeMs.stop`: See above. + +- `duration`: Calculated by $timeMs.stop - timeMs.start$ in + Milliseconds. Needs to be adjusted for events spanning more than one + log file by a factor of $60,000 \times \text{number of logfiles}$. See + below for details. + +- `topic`: See above. + +- `popup`: See above. + +- `x.start` / `x.stop`: See above. + +- `y.start` / `y.stop`: See above. + +- `distance`: Euclidean distande calculated from $(x.start, y.start)$ + and $(x.stop, y.stop)$. + +- `scale.start` / `scale.stop`: See above. + +- `scaleSize`: Relative scaling of item card, calculated by + $\frac{scale.stop}{scale.start}$. + +- `rotation.start` / `rotation.stop`: See above. + +- `rotationDegree`: Difference of rotation from $rotation.stop$ to + $rotation.start$. + +## How unclosed events are handled + +Events do not necessarily need to be completed. A person can, e.g., +leave the table and not flip the item card close again. For `flipCard`, +`openTopic`, and `openPopup` the data frame contains `NA` when the event +does not complete. For `move` events it happens quite often that a start +event follows a start event and a stop event follows a stop event. +Technically a move event cannot *not* be finished and the number of +events without a start or stop indicate that the time resolution was not +sufficient to catch all these events accurately. Double start and stop +`move` events have therefore been deleted from the data set. + +## Additional meta data + +For the HAUM data, I added meta data on state holidays and school +vacations. + +This led to the following additional variables: + +- `holiday` + +- `vacations` + +# Problems and how I handled them + +This lists some problems with the log data that required decisions. +These decisions influence the outcome and maybe even the data quality. +Hence, I tried to document how I handled these problems and explain the +decisions I made. + +## Weird behavior of `timeMs` and neg. `duration` values + +`timeMs` resets itself every time a new log file starts. This means that +the durations of events spanning more than one log file must be +adjusted. Instead of just calculating $timeMs.stop - timeMs.start$, +`timeMs.start` must be subtracted from the maximum duration of the log +file where the event started ($600,000 ms$) and the `timeMs.stop` must +be added. If the event spans more than two log files, a multiple of +$600,000$ must be taken, e.g. for three log files it must be: +$2 \times 600,000 - timeMs.start + timeMs.stop$ and so on. + + + +The boxplot shows that we have a continuous range of values within one +log file but that `timeMs` does not increase over log files. I kept +`timeMs.start` and `timeMs.stop` and also `fileId.start` and +`fileId.stop` in the data frame, so it is clear when events span more +than one log file. + + + +## Left padding of file IDs + +The file names of the raw log files are automatically generated and +contain a timestamp. This timestamp is not well formed. First, it +contains an incorrect month. The months go from 0 to 11 which means, +that the file name `2016_11_15-12_12_57.log` was collected on December +15, 2016 at 12:12 pm. Another problem is that the file names are not +zero left padded, e.g., `2016_11_15-12_2_57.log`. This file was +collected on December 15, 2016 at 12:02 pm and therefore before the file +above. But most sorting algorithms, will sort these files in the order +shown below. In order to preprocess the data and close events that +belong together, the data need to be sorted by events and artworks +repeatedly. In order to get them back in the correct time order, it is +necessary to order them based on three variables: `fileId.start`, +`date.start` and `timeMs.start`. The file IDs therefore need to sort in +the correct order (again see below for example). I zero left padded the +log file names within the data frame using it as an identifier. These +“file names” do not correspond exactly to the original raw log file +names. This needs to be kept in mind when doing any kind of matching +etc. + + ## what it looked like before left padding + # 1422 ../data/haum_logs_2016-2023/_2016b/2016_11_15-12_2_57.log 2016-12-15 12:12:56 599671 Transform start 076 076.xml NA 2092.25 2008.00 0.3000000 13.26874254 + # 1423 ../data/haum_logs_2016-2023/_2016b/2016_11_15-12_12_57.log 2016-12-15 12:12:57 621 Transform start 076 076.xml NA 2092.25 2008.00 0.3000000 13.26523465 + # 1424 ../data/haum_logs_2016-2023/_2016b/2016_11_15-12_12_57.log 2016-12-15 12:12:57 677 Transform stop 076 076.xml NA 2092.25 2008.00 0.2997736 13.26239605 + # 1425 ../data/haum_logs_2016-2023/_2016b/2016_11_15-12_12_57.log 2016-12-15 12:12:57 774 Transform start 076 076.xml NA 2092.25 2008.00 0.2999345 13.26239605 + # 1426 ../data/haum_logs_2016-2023/_2016b/2016_11_15-12_12_57.log 2016-12-15 12:12:57 850 Transform stop 076 076.xml NA 2092.25 2008.00 0.2997107 13.26223362 + # 1427 ../data/haum_logs_2016-2023/_2016b/2016_11_15-12_2_57.log 2016-12-15 12:12:57 599916 Transform stop 076 076.xml NA 2092.25 2008.00 0.2997771 13.26523465 + + ## what it looks like now + # 1422 2016_11_15-12_02_57.log 2016-12-15 12:12:56 599671 Transform start 076 076.xml NA 2092.25 2008.00 0.3000000 13.26874254 + # 1423 2016_11_15-12_02_57.log 2016-12-15 12:12:57 599916 Transform stop 076 076.xml NA 2092.25 2008.00 0.2997771 13.26523465 + # 1424 2016_11_15-12_12_57.log 2016-12-15 12:12:57 621 Transform start 076 076.xml NA 2092.25 2008.00 0.3000000 13.26523465 + # 1425 2016_11_15-12_12_57.log 2016-12-15 12:12:57 677 Transform stop 076 076.xml NA 2092.25 2008.00 0.2997736 13.26239605 + # 1426 2016_11_15-12_12_57.log 2016-12-15 12:12:57 774 Transform start 076 076.xml NA 2092.25 2008.00 0.2999345 13.26239605 + # 1427 2016_11_15-12_12_57.log 2016-12-15 12:12:57 850 Transform stop 076 076.xml NA 2092.25 2008.00 0.2997107 13.26223362 + +## Timestamps repeat + +The timestamps in the `date` variable record year, month, day, hour, +minute and seconds. Since one second is not a very short time interval +for a move on a touch display, this is not fine grained enough to bring +events into the correct order, meaning there are events from the same +log file having the same timestamp and even events from different log +files having the same timestamp. The log files get written about every +10 minutes (which can easily be seen when looking at the file names of +the raw log files). So in order to get events in the correct order, it +is necessary to first order by file ID, within file ID then sort by +timestamp `date` and then within these more coarse grained timestamps +sort be `timeMs`. But as explained above, `timeMs` can only be sorted +within one file ID, since they do not increase consistently over log +files, but have a new setoff for each raw log file. + +## x,y-coordinates outside of display range + +The display of the Multi-Touch-Table is a 4K-display with 3840 x 2160 +pixels. When you plot the start and stop coordinates, the display is +clearly distinguishable. However, a lot of points are outside of the +display range. This can happen, when the art objects are scaled and then +moved to the very edge of the table. Then it will record pixels outside +of the table. These are actually valid data points and I will leave them +as is. + +``` r +datlogs <- read.table("../../MDS/2023ss/60100_master_thesis/analysis/code/results/event_logfiles_2024-02-21_16-07-33.csv", sep = ";", + header = TRUE) + +par(mfrow = c(1, 2)) +plot(y.start ~ x.start, datlogs) +abline(v = c(0, 3840), h = c(0, 2160), col = "blue", lwd = 2) +plot(y.stop ~ x.stop, datlogs) +abline(v = c(0, 3840), h = c(0, 2160), col = "blue", lwd = 2) +``` + + + +``` r + +aggregate(cbind(x.start, x.stop, y.start, y.stop) ~ 1, datlogs, mean) +#> x.start x.stop y.start y.stop +#> 1 1978.202 1975.876 1137.481 1133.494 +``` + +## Pop-ups from glossar cannot be assigned to a specific item + +All the information, pictures and texts for the topics and pop-ups are +stored in +`/data/haum/ContentEyevisit/eyevisit_cards_light/`. Among +other things, each folder contains XML-files with the information about +any technical terms that can be opened from the hypertexts on the topic +cards. Often these information are item dependent and then the +corresponding XML-file is in the folder for this item. Sometimes, +however, more general terms can be opened. In order to avoid multiple +files containing the same information, these were stored in a folder +called `glossar` and get accessed from there. The raw log files only +contain the path to this glossar entry and did not record from which +item it was accessed. I tried to assign these glossar entries to the +correct items. The (very heuristic) approach was this: + +1. Create a lookup table with all XML-file names (possible pop-ups) + from the glossar folder and what items possibly call them. This was + stored as an `RData` object for easier handling but should maybe be + stored in a more interoperable format. + +2. I went through all possible pop-ups in this lookup table and stored + the items that are associated with it. + +3. I created a sub data frame without move events (since they can never + be associated with a pop-up) and went through every line and looked + up if an item and a topic card had been opened. If this was the case + and a glossar entry came up before the item was closed again, I + assigned this item to the glossar entry. + +This is heuristic since it is possible that several topic cards from +different items are opened simultaneously and the glossar pop-up could +be opened from either one (it could even be more than two, of course). +In these cases the item that was opened closest to the glossar pop-up +has been assigned, but this can never be completely error free. + +And this heuristic only assigns a little more than half of the glossar +entries. Since my heuristic only looks for the last item that has been +opened and if this item is a possible candidate it misses all glossar +pop-ups where another item has been opened in between. This is still an +open TODO to write a more elaborate algorithm. + +All glossar pop-ups that do not get matched with an item are removed +from the data set with a warning if the argument `glossar = TRUE` is +set. Otherwise the glossar entries will be ignored completely. + +## Assign a `case` variable based on “time heuristic” + +One thing needed in order to work with the data set and use it for +machine learning algorithms like process mining, is a variable that +tries to identify a case. A case variable will structure the data frame +in a way that navigation behavior can actually be investigated. However, +we do not know if several people are standing around the table +interacting with it or just one very active person. The simplest way to +define a case variable is to just use a time limit between events. This +means that when the table has not been interacted with for, e.g., 20 +seconds than it is assumed that a person moved on and a new person +started interacting with the table. This is the easiest heuristic and +implemented at the moment. Process mining shows that this simple +approach works in a way that the correct process gets extracted by the +algorithm. + +In order to investigate user behavior on a more fine grained level, it +will be necessary to come up with a more elaborate approach. A better, +still simple approach, could be to use this kind of time limit and +additionally look at the distance between items interacted with within +one time window. When items are far apart it seems plausible that more +than one person interacted with them. Very short time lapses between +events on different items could also be an indicator that more than one +person is interacting with the table. + +## Assign a `path` variable + +The `path` variable is supposed to show one interaction trace with one +artwork. Meaning it starts when an artwork is touched or flipped and +stops when it is closed again. It is easy to assign a path from flipping +a card over opening (maybe several) topics and pop-ups for this artwork +card until closing this card again. But one would like to assign the +same path to move events surrounding this interaction. Again, this is +not possible in an algorithmic way but only heuristically. + +Again, I used a time cutoff for this. First, if a `move` event occurs, +it is checked, if the same item has been flipped less than 20 seconds +beforehand. If yes, the same path indicator is assigned to this `move`. +If not, temporarily a new “move indicator” is assigned. Then, a +“backward pass” is applied, where it is checked if the same item is +opened less than 20 seconds *after* the event occurs. If yes, that path +indicator is assigned. For all the remaining moves, a new path number is +assigned. This corresponds to items being moved without being flipped. + +## A `move` event does not record any change + +Most of the events in the log files are move events. Additionally, many +of these move events are recorded but they do not indicate any change, +meaning the only difference is the timestamp. All other variables +indicating moves like `x.start` and `x.stop`, `rotation.start` and +`rotation.stop` etc. do not show *any* change. They represent about 2/3 +of all move events. These events are probably short touches of the table +without an actual interaction. They were therefore removed from the data +set. + +## Card indices go from 0 to 7 (instead of 0 to 5 as expected) + +In the beginning I thought that the number for topics was the index of +where the card was presented on the back of the item. But this is not +correct. It is the number of the topic. There are eight topics in total: + + Indices for topics: + 0 artist + 1 thema + 2 komposition + 3 leben des kunstwerks + 4 details + 5 licht und farbe + 6 extra info + 7 technik + +On the back of items, there can be between 2 to 6 topic cards. Several +of these topic cards can be about the same topic, e.g., there can be two +topic cards assigned to the topic `thema`. It is impossible to find out +if the same topic card was opened several times or if different topic +cards with the same topic were opened from the same item. See example +below for item “001”. + + #> ℹ Loading mtt + #> item file_name topic + #> 1 001 001_dargestellte.xml thema + #> 2 001 001_thema1.xml thema + #> 3 001 001_leben.xml leben des kunstwerks + #> 4 001 001_leben3.xml leben des kunstwerks + #> 5 001 001_thema2.xml thema + #> 6 001 001_thema.xml thema + +## New artworks “504” and “505” starting October 2022 + +When I read in the complete data frame for the first time, all of the +sudden there were 72 instead of 70 items. It seems like these two +artworks appear on October 21, 2022. + +``` r +summary(as.Date(datraw[datraw$item %in% c("504", "505"), "date"])) +#> Min. 1st Qu. Median Mean 3rd Qu. Max. +#> "2022-10-21" "2023-01-11" "2023-03-08" "2023-03-09" "2023-05-21" "2023-07-05" +``` + +The artworks seem to be have updated in general after October 21, 2022. +The following table shows which items were presented in which years. + +``` r +xtabs(~ item + lubridate::year(date.start), datlogs) +#> lubridate::year(date.start) +#> item 2016 2017 2018 2019 2020 2022 2023 +#> 1 277 4082 1912 1434 424 394 1315 +#> 3 485 6730 3126 2356 528 457 1124 +#> 19 714 8656 4028 2743 660 698 1595 +#> 20 595 8461 3996 2983 938 657 1355 +#> 24 497 6638 2912 2251 649 439 1028 +#> 27 567 5959 3112 2318 651 711 1324 +#> 28 601 9329 4394 3056 778 762 1570 +#> 29 425 6865 3830 2365 516 615 1174 +#> 31 289 4118 2051 1218 291 296 675 +#> 32 562 7016 3477 2253 726 766 1647 +#> 33 509 4936 2242 1449 555 358 666 +#> 36 434 4505 2276 1668 373 387 976 +#> 37 242 4478 2182 1554 339 423 1168 +#> 38 480 4617 2144 1397 371 381 784 +#> 39 395 3227 1313 1003 237 161 622 +#> 41 282 3329 1303 1022 225 209 701 +#> 42 203 3113 1307 903 242 191 421 +#> 43 115 2420 1089 806 176 219 486 +#> 45 1491 13561 5924 4474 966 585 1828 +#> 46 903 9181 5340 3812 961 944 1648 +#> 47 306 4949 2395 1510 750 297 675 +#> 48 723 10455 5384 4162 1328 948 2031 +#> 49 433 4326 2124 1414 434 431 809 +#> 51 564 7837 4577 2991 884 659 1370 +#> 52 447 5021 2104 1729 471 349 840 +#> 54 424 5068 2816 2008 529 370 918 +#> 55 358 4859 2069 1428 341 403 1303 +#> 57 860 14264 6625 5092 1410 1221 2714 +#> 60 555 6865 3539 2336 639 586 1415 +#> 62 547 6736 3803 2210 795 633 1322 +#> 63 251 3677 1827 1241 300 282 527 +#> 66 552 6004 2774 1977 505 373 932 +#> 69 394 3730 1827 1438 272 206 680 +#> 70 226 3766 1843 973 293 268 703 +#> 71 557 6160 2490 1846 570 323 839 +#> 72 426 6194 2857 2129 508 635 1553 +#> 73 432 6125 2880 1821 583 395 939 +#> 75 258 5885 2418 1562 369 257 645 +#> 76 861 12435 6253 4214 1753 1153 2268 +#> 77 816 8595 4197 2897 699 674 1452 +#> 78 410 5632 2498 1924 394 408 850 +#> 80 1650 25687 12429 7782 1975 1712 4433 +#> 83 644 8618 4720 3026 987 1027 2294 +#> 84 184 2121 1231 759 231 254 465 +#> 87 149 1618 722 632 99 0 0 +#> 88 513 6996 3493 2272 539 533 1420 +#> 89 214 2204 950 723 156 0 0 +#> 90 281 3756 1372 1143 403 320 932 +#> 93 613 8528 4224 3015 696 1174 2058 +#> 98 462 6662 3265 2565 704 670 1453 +#> 99 180 4162 1653 1454 363 411 868 +#> 101 414 4209 1859 1282 392 411 981 +#> 103 677 8758 4366 3165 1045 909 1871 +#> 104 423 5256 2381 1865 463 467 933 +#> 107 181 2101 1106 788 205 146 339 +#> 109 321 4001 1619 1106 292 188 453 +#> 110 489 5846 2785 2008 494 387 923 +#> 125 640 8435 4519 3334 926 0 0 +#> 129 598 11322 5046 3369 910 1131 1682 +#> 145 419 7821 3945 2694 706 740 1396 +#> 176 507 8465 3968 2787 687 552 1544 +#> 180 516 7563 3720 2765 585 550 1272 +#> 183 377 4014 1819 1741 346 251 675 +#> 187 340 4222 2165 1753 319 312 734 +#> 197 426 7710 3603 2510 671 602 1217 +#> 229 303 4872 2360 1891 482 389 1005 +#> 231 271 3606 1851 1239 318 236 467 +#> 501 1915 15968 7849 5060 1157 890 2989 +#> 502 1212 14550 7111 4749 1105 883 2752 +#> 503 1308 15218 8632 6399 1626 870 2558 +#> 504 0 0 0 0 0 363 662 +#> 505 0 0 0 0 0 426 1533 +``` + +It shows that the artworks haven been updated after the Corona pandemic. +I think, the table was also moved to a different location at that point. diff --git a/man/figures/README-timems-1.png b/man/figures/README-timems-1.png new file mode 100644 index 0000000000000000000000000000000000000000..f08b70a63d0c950cd4623691eaf8d27af425ac64 GIT binary patch literal 6367 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 W-PG|DT#ZM6RG1iA7(6?79sCc^BlETZ literal 0 HcmV?d00001 diff --git a/man/figures/README-xycoord-1.png b/man/figures/README-xycoord-1.png new file mode 100644 index 0000000000000000000000000000000000000000..d72a279bfabf216cb56408c781fe85f7408d10de GIT binary patch literal 12056 zcmd_Q_g558&^Nk4SjmE91Pn+PLgslJg=U zIV(8|OAhaTpYyzbz&+=l`^%j{~mC+Q=vHsbRQ)DQcBY+Z6`hA{cK%ShJYZ0j|f9%WHXcJ zvvj4I)r(d$eJb#K>b-}unnKsE`9^dK)LE+cK}N)%6dvnVprM+@Y1F6$Yc7C$L>;M> zorfuYsR-5zON10tJt5G1tWR91Q2qZ)g0iu4r;4qURvo7>T`qtGM;yS+KffQ$9S>FlQEDyN;=Aw8@5o}bDY0|RXFOvS}t~zo;9$_6!jSWT@xNg?Di22cOT`@fx5?p(?TWETTrd{?3=9uran-yC7R+?1<^n`9RVy-4? zgIsLlHJEv}n-s~@r$k%`(Jx@YXj5;}pa`l}Hl?~1{;SKSuhuNoLDFF1gT2cU`0h2q zrK8#CO2~N|MwoiE;leo`$3H!4;9ifq11MjtKtaTVbG^`N!$SU2DRRK!V&x1Re0<#j zK357p@4CvuM6Iuk&FLbvlI6jX$46L2baqg z?g9FRtdq|FHYM1BiAF6X2aZVrytAbZP9JkBj3!zqX)9>fy%8Egg8kT#so%1rB;x!` zHbt|Zcm@Qj8t|Uql2`wnL5ccm=H|*xhHV}=I-c=7q_)TxMmzv?i5$xVexImq`h7i? zzEaB$xRmzGVY!F>^0^x0ktP*>GQy4n%y5&KXB-Z-`6CqXhH2H1Et~ z4K?fhNs40ps?`dj`Rz22jH8^7yfC^Lmo+!n13g0560hg_%Z!7mr^3*YbWJ z2RrY{0l`BCD*^fV_L)n>oZUhW{Y=M#&fRuMI>fC{lOe^JnsV}}o7g4$*9@oKy8KOd zXzV=BmCW!{@OJkKZh~>v{ZuDM^|+?N@QlerTO&7a>bgMUAh~xTEBAoG0%aO(CE5^4 zv8_8xq-z6zt9(L%U1pasD=@=$oi*3vo^k;tU_>WC-Z>iX$@t?Z1BkITk}I~e*79{} zWVbxnh^>nBn4SX ze5=fZK3~ozNr9{jB24SmC2}q@X5Eef$Kbur%1cq_GSYZS$P{Anob9^Y5PXvUienJKQ8n2BM~QBg+4Y+)$GZN=##+4`6k-0_|Yt=Q0*toujh zvpBC~c&lhVTT%Q(35>Y}2Br3(2!HV_{He{FH6aH5^8`1Jq#V?U;;i3}3`vvU5@H_)qo1;r2EnxBB}}~y+mlP67%1w~v*_oy z&#Jj%mmJ4FT>qx@YjXV>H-tee@`I{52{dm3U662%23){y8dc^xm(PjseU4A`WdAY_ zsaaifWMCdz#MY@x<#dS}5mQ_l7pSA8f`HxEAc@xuE*+vvYvPio152FfllH^)tXUHSkNO@K z4ZZ*ov|D-7xv-Svdum#rn5mX~(ptQg@wrp|VyGY5Z)1^MMDM2hn;I!cov1NQf_v^K z#=3F(@?^u(cMYK@Hcdqbdx31e4cNq`R`Tf3Ze~(p%O17FK@4C76hi*ecjtIq)>||I`IQ$0+U#;!+`d|N0)xSS`%r6`(5Ge=D3{NsPy1GV*1U@FuUy8vc9F*L#IpsVgQ?p|){!Wr*yTL(Ys;M_oP6)%hG%EiQ1Lg`a0 zlQQ11+FLJHgov=K#p&!n?^DP#l+TAgXjyESpWpVY^JQJT=zC(A9fm0zH-p%I za`nF_Biw%|Dv@?jM2@+s%AlZ7ki%r{HESr?6u9sMmv{OV!MHJFT?u92UCzq5lJRo; z;v=v2JMm$$M6=8*_R&d4BXk3uRC!!J17OYaLe>dq4OLT7&@*!0L&vPt4{UK|aerDZ ziX?DEa#{1>%{zHd`p_5h@^Qv$l3%kJ)M-VfFd8SuFGW5ov1zHs+5QyqcMI#jbsQ)c zC~{#Yw&rF4`~9ey#m!tsFt_3!M8SWc6X1Iw`MJmTi~Oq}!y9t~Z`yC$-w8_!G@W}< z!LmVvd&HCy%QAN8C?04^zT3gLa0;Tx;mx4K_#=vX%l@#IDOycf@_4&J-~e5qZlyqdH94cimP|85EyKa$~#R6bazY2RoH*E6=0 z)`=A0m_PZT{J!*|WAmTBnbny*Oq75)wBr_t{leUz*aJCrD_|&Qzr)mRa%WeD9sV9iA2vxTEpHgOc| znCXf{4C{$x>g*2;b$%ObvAiILZcVHrOz`5csoPL66&2lKJvBGOJ_{qv>EG8F5^en3 zzK@oP%mT(4*RtU+hRleA1Trz@p_riRS#HtdC|z{i=8VCE8eObh4|w-RtUs-+v{%_H6Eg{djY z)00Z3N#ElS+B|dL(UW>lxRbL|k zqs$YMN1r03Xs|RXnuT($-hjSw`k~qggd#Q7fRDERcHyJvpQIirm*5BSIWBkNkzYX2 z%c%HUV+FsO#eWEDc-P@3v`M%5 zxPZ?jxT2}Knw9y;*yr>E8mu1AU>@7_1V`HP;4!f+vU#gEm9<%+&PK(3=P(R zjSzK0_6W@H9^qB%P27IFo!>4ya)SPdB@7xrycH5I<_YOLe;P9M##@E@c|@z?FHq#~ z#6+;|)=_u=XhOd-G?ka&hz}X~0?=3rStxnO0hFOZ)OSwE?W?G)|dbu+Jg$Kl^wyDysRLo;0?rgdR~YLYX|u z$hQ;|ZyyJn6t((0%IAmK=?Q5r`F3$hS}6ZRkQvo}eOOlCpSGO_E|h@y znz!$cgSD8NH(Vb8KZMvEjawN|IN%YJu>td&QkDgo7Nx0iXdFN}&r>i&Ak#^^A+}SUNjXb7>@=(z-io7M5)fVERR;#6C zz?Bt8H-}KjVzG}E{ayiKyrF*@5WTiv!e1M-Y|-yRf|C>Ta1Shn^8mOK89Tj0d2Yd2 z;;uXTuW~1l1Y0_4t-$bzfpgBQE&gXK{}WA_U|1)tOVhu98UPo_4odC~|m!H%Kf zdc93+>L>+pq~B|nG1NVM=&-fLIcH`SgI$3UT|m9lP5)a|Lv&XR4`P^v*!oDOt#K6_ z{$!t2V;7C3!5H(5xgw2lcW)~+V8;zY2^uyb$;ng%oGHDH?+eK@viflEzNLE@@s53? zk2h(xCN)l85f8dcLX@aL3%tOw4LwX)WXPMPb|Q9^eVcVn|CvN8at|4%X5VzRGBj8I zSd$i@?l^R7Wy~;DP(Bcb4(Xc>?KWu_E(l+p1{#V`>5$>Tog-X8FNMa46>UbA!m%mm zZRHfRk=+561DLaB>mii${3EmX8*uQYJIwR-9RPEeb2wHdjT;!8qXNoa?U@*YS`N)I zjA^Gy^5lTy{6>%!@JmBH^RZLq=K|JD4apRB0?u?v7n>0QYIJYfDhrjl96GuK6h1Gg z6eIm6i9>$TaEQ!fI+$`jKVwU3=gaBku5q2rP@~DgsjMUp_yGe=QAeH$t3K>+N=9Dp=?uTJEG9$Q!La zn($xl1Qdx9pq%}WA5d{yEHadJICOis8m4&!rKcG$m3tt;R=7f#MNSU?$m2;~2}z^b z`%;)+Is?}3`=7KQ66RfzCI4G&@;h5O46q|O`jXJL_(kC{)iELflLG0J=)UXNb&IzD zr=YeC(xx#^=1U!afS=;EaQVcOQv-|Kw0w+y+{`mWdF?HFKgb&y))Wcu~1OW6OUd0D2S z{ldI)!K=IxG}oWj`)%8OnQ76td8Wm(aq74!vGrvsrlsxyTUkl{ukvq&Ji^I^OZnVB z{V>#~^YrRbn+y8FL2TJ1;9|b%Pp?Zi&(ll#s^4F$nV5sO*Y1Pg2kooie6S2x|I+73 zhhNZugkF?D+uV@>eqxaRBt?nmcuWec zX;n?!CkKa@9nRi@vzRUN?LyJnCXVWj-3Chx1=~+p-7JIGdNu+Ra5Z$%#-opO89Nn; zk4sn@(^;17?v;BMcLzQ$y{>f;yD&(E^bNLMIN$+CJLF`l+t?yrD_{Tpk( zoR2l0O#Ec_hV2>S-WMq@YN9Kv&$G=QUjarE$cCym&U^JTiR@w-KxAlzf zp_q=x+61*@yZPS_Mq*%Z?jHyLb<|sKim%e$<2^xf zxlgTTB)2M=%7fr9SRW8xo&DuMJYJKWs(O9#?E^-PJ%*SQOUoWPp=JqJdR{otAsp@J z#uXv5t;E5`9%Zu$J}Nmoz`H;;Dz~7vT-cX>Y!zCKMB@1VSDg-t^O4as%F~06& zs2&b_Ut*<8y}8Ixe!4<8r3Bk}zqm~QT-*=qPzyrU`PfR5ea%|xFL?5Kc<{B+FjY1@ zN>J&scuqpY8wTrg#ldB=zXH_ZZqrXbN|EupWFauxg=>1!P1A&25;~dk&)g&=Ok+eF zEAzM^yb-Qeoc!sV9|#I!hM*<(FZROG;cI%H;)mNu<~B++ z!s|@aw{cMTQaHNDLM}aISM6US#iy6=_9n=A3y6I@I*tnNT<3uFy=DFOWNwo6BEPcP z(2+=*k^)-C+lAp{(M3aqJCB%h{V7s3Ze(tlv%=J`{*@%3CZB}_KGrfFW}!fT_rJ&W z{mDo?+eY7`5-7R;5<~VtkqU6;XGm+JZKu`YVCk)tApAw(E2BH8A$`kta6V+xps5DmVx7f;zqVbnY!hpRCG@G$mhI`L>(;ahQW`)QFk@OS&xWIiGiz+E73PA`9=6#8bvUB#~l+;sYtC~mDc zdS32alsg&uR#9fQW~0RA3h60`<9Un@0h(j`sEy%Nc=o{2eF5tPI5EyVw9v1SY%Zr* zV)lXCNKm4d2F=-uo|auMd;1CX=G@=SKT;Ntn27GJmhv|9B0HAj0i z!qfg#@8zS~fm{C6Xo zIF=>eX>C+_If~*h@n{~NDoB&jv59!t(uKp~Ge-xbrUjlI z9~-w@9r5yh18r4CupH6wNf?XH@iS%*I_GG8l!|=EZwpJ*n93;CiUnt>9cgm7MeVdR2#cDyUocrgF6 zPzf0uWZNF8RZY<%5Ym|`pde>=k>0TqccG8uNZah7Y#)eSg$d^_{T=W8xGv%r?ZQGm z%d#AG>-^hkRn)Uli^e&CPRm+AjfCERAC{LSkb=mYz%pj-666SjkZq4qBc zovfdI|B=4FZ9V#h+hOtj9@ArTlt(zbzJtCYEH7z&kz=Mv`vR!{y{$`7Jj@xF!6DH?jkL4caHoYDbtVc?&!dAoI% zJQAGn$(zH*mq@Gh2onKeJ&Zc@3qJ|}9qQrcwSxn5v2pJ88e64OVHC0wxh(K*1dC8$ zm+z`a1tm<^dlZi&FkOVcdu@czn=0VNfsou&Lnx=1`P2PBR?8gI|BX;GZ{U{WWC@{g z_EPZph#s5eB9@8Q&l&0vZI3jAofJmM?y_rA1B6y;c4X(SKd^{ClZtJX`yE{mAlMKA zq3OjSsDcpIjgfyDT+_||YWS}i-yk=YzS5lHSfC$_$runJ#U}hGw_lrH z4wW<+@3;}HV-Cx1V&j|n^wbh?fco!9e@X4|F{cmT{2z6;2bkZ{MRSBa|EWaqIOVP1 za-F-ohTbOPJ`PU{GV$lVIocpT=E<0ltCF0<*I#(LZyO;xNBQ2L_HN)X$DfKCuKEJW zY$u!Hw{J2YU6JEA>43`H7`o7b?;53;R@-|Tjbw?W_L~14<#>4CU%28K*Jp8XVIrBD zX;YvN4j2*67iM~CXXi<3uiHL9?rl}aoUem7gFlsBFS|rzFCb2 zQl}&oV3zzN`(5=Y_hJU!9;x}q1Ln+O^{M1HA$jYR%E}+BgVpoEbe~&)v+X{S#}w>=LS)goGbGgm8-(@%n< z59=j7`WMLT<3&G9^FEwl%<^H+=7Fde<<0b#)R}+yg`X(KSdlNu@<1I-b{!2UfaA^E z#6DQ!b$5;4O(A(>XzBJRDTegAk>4@W|NPrSQ!SZ-j_%p8v?<{$0X+1vLaD1|@#WM5?x zbV9S35Eiee1hi%r!&Ka(c9Zn1aR~W5vdl^tZnJ{86cmps46^!S$QsDQ?KQj^D5OwM zUV?=ngVqHFv_++6h@7 zlsL21C1b}Idbf=>LZPNAIQ;yebgip_)UV3rYKTa+&#Up8U2Htu)6O(Jsz^W9pgf7f zUa6g@#I+!D+h+k8x+LB4@E!8A!aF|YUA~AUvh`~T$^5Dz5%RKFUZl}wm=h7D(#8Ur z75#IertuzwEFQtLCl3vD#VV%Y?o5uY5O}`H0u}OGqtwZFCO(!-W3?>HkE85p>=F50 zh&Ae^Ha>i}^)*N>!84J=VvgKj`JGkO&QP5i1Ll0n2(4tp1-K8kCHQ=SH5XE~CR0W5 z@c;R_ej&t+dH`j@IXa+zQ2VrtQeb)qWKFrl2EedO~RBMk+cxK}RU8?u>?M zlDZ4324z!J7)ex6lF5}1H3*vt%|$viTa5mA=C6mHGo_fqG4lMFqmuQt{ly zS-!3@K~y}zlam{&Ir%g$*mi;masn>)`)VbBC&xek!fu{mT{^ zEyZ~E9%j{rH2ia4aUhx93rF|Yd7giMQSVilIx!@Lc#r0O>i2q|z7m}A<)MIN0%QAI zWb9-3uCrSbG49lMsjW-sUQNRbC@m`Lfonju>OJ?^KN-FyaK9~l}W3{`X2jY7@uW|E&#E1YQzP6*pd}%~C)$9Xx zk&4t{Il5J+E~Z(3EKN4^0yzuTF2v1R0Ekf%?rAH-UDIU-OPgG9hJf=-Ntv=I1`q77 zUBo`5M^Mz}dc5)MKl6Ur$7)#RpLXXEuzO|xoffN9-=)&_Tsip;7RyQ%lfnOSn|hUJ z?p_bA+h|s(&1jn=9ZNU8z^)UQih#~r?Dvm+1kZK$g~b6lR3V=tMqK%9iZo2rXdwu~ z{xZCjdn#=Uc5x2m41)9fkux{(6~?jH3Vi zF33R@%M$Pe7%R5)t-lB^vGif$tbNyBY@NSxNxxq+F^YmObjvH-2!t=-r$@FHQNZzP@_i+X=AW z4g5ps(MUW;Tb^SHZut|!Lnu32dWvHUu!z{6#mU51{k2VZ?MVfqd zVw`+4j>wVVdYvAjTCZ85*UBXp+pAA%t))TnmOr9fXJGL(ITT2uz@N3Lg~jqk<}Ih& zHnq+^q4%IQOMfU;<;o7`T@9#!qUtSndBW$mw+T5hIZ=yMb|?FSA%z|MHhUGI1n1n1 zQZviO+J7~W-<8QkX*K+`Ab21y+wJiY$wvY z6<2dCLFeS&+ilb1yHY{h%DTbW{5_`S60R{{4cD!tre-TUKepr_Yuf#6+ z{qXrdpCj@sg*r%BJZHXcG1jlmw$X|~d<;R6vLz25gxIDDE{00l?X|qy>lt4TA1OkY zbsdlNuH_;o_CKAkFf-A3zmz8_JNmv2FLBaY1g= z_qH{EhUadBQf(VMp|gPXYfc^ydVeKWd94Qi!DWY3bJ{&om1*XJ<2D@^$QXUv^^VE8 zN(Rhf=a@RmYKTn@A1^JuAtxI$V01hP@IvF~2_(3uJZ^wM_z=3_JSbF&$8bl@G6>nJk?th+_%6u*3eFd8xEwmv*) zgd6=^u~KRw`TN9hz~WSln4k?Ez57lXf(M@*pU6E)HJ0v8bcYo~QZ6gVQ95_BxT$zD z>+E|f>BH)=sdXvie@_+pfZaFwh8yBo_iY#aJn*LOOB>X-9$oB)}Fo-9KBx?%{^RH*o|$(lNybI7?; znTmM*K7~HzZLb|!YbszO2;ItM0j$>j>baRFd4hN4MG6{at1#28zd+0yg-%=l>cP#< zIOXie^*`^R6kMH+J;$3tDB(T1hBaBKcbF)iF`caEJ>4J9ij4lKEut`d~*0bbmV9nrRfG!S??LI)Yd)O1Hc2 zgjxD3URG$|1L#LvFVCVO==!BUJXUc27py=kx9 zE5AwITk@Y2&)}tsU_Uf+t#s&0Mctg{LT=mRykwhS+a{^aK= z$%>VL=jmPQDnr~nvLx!sJ({2SVJGD9(ap++dc1BXj=!S;bq@2t%f?8E0*C!d-h}-7 z!{_UxW}x#QW>_X-oDRd+jT}V^$a?qCvJ>AJ#e^Kl&Fw-DT_$~Xp9>f!U%!;T(&PeE zDb}0Dxd6X8Zs7AdSsv!ty##}9@K3c@AhtHCCFY#K%$RGaBQF}XkjbxR*;C^n(-WnT zK26tD`|{&VjpVP2e$OXufRJcB5KpIQ8bbEFxK6potn@14qwy-A(M(N(qUw5%Z>s&U zej^=a^MH{$vOc`F*Q4~iC*?^0>|=tX{O<}O%HZ_MqiPA4TF#?#t!MVc>!0!pa9J3I zI0!lp!Yxm{E>B#@#szS20dcvQVoj3&=RnLL&|D^2i^-oO!u^?((}-&B6vOpD76HHY z+MnUk5Wbr%1Ch3KDJx4(nM%Vw{+AaE2gj}sf`nL;h56cTcc!zMi-?`pp8x&MA%Nbb z{h8C=&Izp0jcoOmkkepvzy%Ah9-=DKN_I#g=xG+==9C@acnblYg(+HbDYDgE?_T|LdwlQ*0?OYH(15^ z=5p8*$&~m&WK`&X$jdX|Kem%QCJfkdwxUflPmRU2G&%ikab0-J|Epi?`NrO#tCA;# z4!Wy5CpU){(e90et~t}StAAT%PI}0Zqa-R-gGglU+Iv=ko{NRUh=KQi+2_*j?+z1M zw?8YNF+bj#DQNjITew$nHNW^Cs*MczR<^hS z`W}Ic+#UfV{B=zKQ7_E)Udygf2YgW5doX^ee9-;Y?~%_K*EQ~=?RGSFP&sZ|%={Rfa!{-kEBVQ8}DzCs&19IS&h!sgyaS>ZyO##=4dHDpP$c0f1uWS=2_|oj#dQc zxg{%63v<1SW?9!Xf&O^ZQ`E5H!hf|WC#zo$TgC^z6KAp>Xa9N{#6(rxg?SG{3N-(l zcuMUm!M@JZ6gkVB{(<)z_BnJBh5uh7cuQe~M>}?BceR?$_4nR^5gBn`ZeD8fXZ_Yd zYK4B#-;)B(vCLi^_8<6ScRUws=%~n@`5}mej)amqn4&2G)a_yLz>(h{=Ff=|YN_!g$2O&0K)_9`i)`Me1Ml9b_#l z|M`UH#ikeWxg|Dp#ws<~(+R-*=5ZWe5tzSl%G+tJ;dmpBrbaHTxm+B%UgX4nSYg_h zyV4=3mRIv(p{QK&C;a1;(u@g}mm~!oTc!ezCZC-V?_bz1^@s6kTum!00001b5ch_0Itp) z=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGmbN~PnbOGLGA9w%&00v@9M??Ss00000 z`9r&Z002-(Nkl=_zdTVB?|DN9U4N3g?A9k1`pbr2JaN~|U#@%ix=c%!%~7f{RHkBWv*T_$`~6## zl9d)q^~;1`G;tp}{CZ7z?KNd8S9Pj&Pee%;lVC(H(vY)H)6w^y?-Tz5Au;y;MZuWA zKcn*!cGnlLy>D|h+lX4DL6;w|3s*g%0jC{ozbY*}NAC}RP8TNZtIr;JH-;l-zWceN&`&&%93yCrwt0?6>7; z->RF28mn%%ZP!?7KY#c|5Vv$yk%sSmndZ!xWGpzx=4F}Mb=g`&9z93-+jLaL>Jru0 zH8wLLDN$*yv$f>C>3aM0;VLd&Wz0Ior14tqa=;LsIqGjpNJxmK{`tbsp19APe7nXx z@r+}$u-_D$vHRWqJM}((ca^U!R$X;%EakT$l9H^{{0x2Z@3%DWh9_MZoxzMh;_`EJ z$jzs_u%9dZY>7MZuGjU{1;b1=O0-!QQI*Zt-Ov4vcKz#7swuBhO<7ee<;Ed7D^;?Y zJ@%3(HTlK2jHPE3|VuDw>_9%EB@~{aOeKi3v)vSzNSWrQSYmxR%bD>Ev;#Y1Q4jY@>5Nyj3}!TgOuW zJm6G#ZqrNBqm3c+A32EUYle} z*9eu@6&qhjc1qe_M<1z^U%V=oa?6LG1#w@!@IH_>OOJ`A+;U-yChp{?KhVP` zUTd9NXLBcNa;P)iMwjf5;JWs*V5&4P3mQva#O0V{rl^{hlVP%W4u`b8L`w`4s3D6efZF8HF4w{Zf4ZjT+NK; z8d1+y*Mqk=)22xEHQ!&ZZYm^3layxic;;i{H2O~u8I!KE$sKV@*O1?zqGLw zfGvi&?_BqUUcCOl&a;F}tv6P@=M^Vvr;87DGqtv&I+pUMhop=YC8b9-;fiPV=|iuY z$VhRrxZeJqJmO02^815hDSuk{$%#Art-Lvl3{7*l(foZ=D|F(Hu9jk7?UH4exp9X$1;+Cu^)V+IMs(EuJ zJJSZ2Vf$`9HRO?Vl-IYzw_Ju>DkMY_mDVOpOFo#XQKt`AQSl1XtW%A|Yqitf2k5LZ zH<`@-Y1U_c65>An+gtVCQ_tEsXDQCR3=g>PEcHBQ7nQI2ZkOSf3Xv2eX?~`r-1Ck; z`0HaXjE=?0a`>fZ>sQ0haA7|t{HVnJ@V~F>=|9|RDv1AAZ3@Zm=N+S6u5P)@&;zIk z2Y>jEZ;p>kv@p~#=1+*lS_b0d8sG8dgz}pQ&Xs9d$6fM-Ccp5uY1J9d;S#mkeER>c z*S1IP5li{Q!;eDTuRofl;rm>!g31*QF2mk?;WGTak}^|O)k2qHk|kzt*VLP?n&30? zonqe=_D;5URb7IjiS>?H-&7~6byA&H)+8#^!YVCGev&6IaXI$AsyadKlI>lSpbp7c z)(NV!u1U5;5IqcrW&x&CUWSSntv1u?UM-nDqrsKgwR2ycGj5o2yS0ra{^8&U6$VwM z6}oHJKk263PgP}Qshh2tty}5D*Kg9HFI?nI)vAJ)5jJ9pCzd8@ZEb=+D#bBqv&H&- zY)M3gM$oY(Nm^}0oL1rYT+qM;Rf$H>1V=dDWtI+7@s!wiwNY<%ZK4ejBetbUvWUf& zXL?1FW>-d3WO3;4%?8sI&>2#4(skVUYjxBke^E3k)d-xbRg0JC^6rP}v7`SMOZ>yZ z4>ogOx!_)nyz3zwuUXbDb=Jud?K|vr_50mEuHki6o9;4X<}#Zi_Eg7a6tflLK$u#4 zL)4mBT$t&Eg~oc;>jz6Hi!{8+2fGgGTRd}{KqM_$(X2FmcFSw}@Q!D!j$|tnZKF!Z z-h83#Axs`rHRKW7Jq@ zI#rnQ#8#lQ-n~g%?>``xc=Nz!Bksysi``P(vXu+mY{g~RZNPRq@PVPq=#U$88O9QC z5WK9!T`|kp>b9x1npPgst{F8h>s0&ho>J%D+ojcNUS*3-4y-!RnFe&6(Zam6@qkQx}`*bgxz}S=ivp?9+ds&c>CQpA}2} z{a~{Y_kkf->yuG$JA2i+3{&!S(8K4b%R&8HWbbOPaG^KTk%Cib|Gi(Z0S#UY-tK?;2|DhfKgCjRI(#qUj=JV?{qIIxh8eC|Fu1+0{;hVr=#Wiz8A4zXqVwoV z|Ms2MG|tz#Zk!KmdEB?_Yn+FT@r`)`G>vO1B&DY)IU}kGS3j>$?tjTdS*j7b+RCfb z$-}SIu0s!rrEEED5^-mZ{7erVdbKlY&;Vh<{SV(?d;jYcB}NieRa_BExqb*Ti|(L9 zVR6;Q+JGPfBldG$#i-uNy>G_>-u#JIsL0V&9(y8$dVL(YP^J$HY1Wmw#KYbxpOhgk zW>1FiUY|YTv!54u0%B<@9W)$~7Bz8PYMxtW;~zN@I0fn+*NPOq&C;tDR}| zxyjCs#^Sy-xr&VY*y0Y(@f_fNlb!udE{->IXRpi}mu9fN*{C=sCRe{GPtta&CNrxe z_S<(WW%RQ+Ornm)o=c1($X;NHvD7?ct;kPgD>!vA_Dk9lW7XKrT`ld$W_E!G=G9Cy zj~Fm3Eblf}F6AEr{uYM}Z*6rfv$(BI2bg8Ddgt`ohJp575L}td#?R4Pr{1liqTtFb z(2jfUtFy-3ti&XSOY@-F#C__-VS4ZB=S)?~HAHJ1E8c&^@743@fh}?w!qSkZ%rH8S zjwrHzrh`GG(&Smx;*fW#CJUJn!BJ5c`>wTjlD(^9Z@R72%F47ditUYzEVC>)EQmun zf^gqdCn(F(peP0Txxfh3+P>%88-;9^DQP4Us$9yCrNpxH6~S`>sB?`Z3E3t_f~Y;_!=y>d@QH^a(ct8zt_zf4!_{ z|8%>tmpGT<1;5d*S0CkeLf|%RDFm4nSXW?$z=ma@pY?<>cAMr4aUma}fw9KNQ8uCR z`3MVT1~v*FKE=232>APQ)*nY$D6cuQc74D$AGB+?EAzQGO{-3K{m&BPY0q7w?T+0m zmU8{DLE?V(;dG7I?@AR`t+H8~Zt}H6efAlo{fD3F)-zk`G7Pea&R`bMsWci{i7CMw zsIXbUj796sH|=+&jr^c3qY>xDG}<>xg{v^rgFBSAd3<~ugKTa##9Wyri`TeanTuz9>Ev;# zY1Lgi_Hyz#f2;Pf#OneBY#pd9F4uo{zEJac;yS>!^2%l3X|)JIB}}M4W4H%n?{BNb0@FWbX>gPubKt*w@?b|ZNItamxV*SFYAIUKaX`$K8O=)7 zu^(KmqaV9c(P)|xI7O?MF4L7;AFfA^xFME!U07%4{_mW-G-~*xW>Po04EMY33~h7z z-rv(@=&P_c+85TG{~a_?8jt)0!VISq|{6w`FzQKwuc!_C|m~!IDVJ5->6Ajxc#QhjSRo#5L}s`-~PJB4}03` z3$Dyc9ev{;wExv7#8SqH`}w2q>e16~bOAQbtnn4v>C|6q&wm`R8nabvHtI6`F7O@E z2)?25;6r?agUk)7))z;o2KL&Vd`)F8u<NLw` zxPG7mg3TF#&(JI$WE!(}9c|OTnO#LTC30=Lzyg^`fcH>&bES=G+0LsJi(6}P$Unkz zEMJ)gqZtFm#&)w}vJr2Tvynl-Aogk?Ja1+rY2g5H24?wM>NMF;`mm}*Jeqm2)dgPU zM-J0&;*q_C@c@(!ggSx1c{T-tD|5}XB_@yW)r!RnVy?^r4LbTrMf$JEyN;a@Y1x_j z^<#h5uGbu`+Ugpctu5Dr8^II_Yvg;y$<~?De3Ms;OvWaf%wipNN?F7aafZpKd^1rd znBCet)e~tB^3d8lry|LjD9A_bOu7JHG6b7rW((y|Cguj6HpS8rhMkE5gq_>o;wWpp z$-UNA5A~83d5?L*H+84j$9t9rAM*$HyRYGbyhRoxhf$2?TAkS6uxE4!+V{1+Sqq+I zw)s|OuTviQg6tDkt8qf{e+Td)Q^(_P&HEeL;Sn7^{ zK2)u`b=KE!eW_@Ds+P{2r-aLOSbe!^UdNBTQLXxQ+DseLJh~`9Y1T22Cdf-3ItU0d z*UKzId^$cM3UQ?Umdv%E!9x{Be(*w})bJ*Bee$@`d*y-j@nr_PnzDWFMw|m4Etk12 z$|-8#0iaC-iB?x*P2Ufg#dDtjSfl=Uk7Lsf#69}yE7f+#ZmQixr70;nS;_XqpKIkS z)|USV%>Z=U>Z&T$)NCRR(xaOF^hCXP)kB+)xVd?Gn*7;k`eecc)f!^o=iqV}$1Js_ z*az|rc}#eieId<{0imu?H^5BflNrry(HQ{q`y>D2T;0A2vI2 zv$C^w(^Xe#=Co-_N;2kHM^pbFYznXiwz|4nJMXre{(SY-Ehg}0C2mG$rtbgGfArC~ zaW?YmG;sGl)UHDZ)&7hK%nS^(GyeT!LnIQ>*9#YF%IBZES^TS`j?ytFo~ZJ&vRI0Z z!)7BctT$pK?d+3IQnJn1p?~_b2JgGKD$2_nlor@nJegTAqT^s;?oGUX1my|fI~e;x zA&HM8eaHv*=M50n;3SB}ksrX^3T1(hy+D^nH&&VcTV1IlOTXIiTxxODIn(l0 zS$bEOg^_lag%w&l$^$>*sCSj+n`<~$8a_*7I1)d_+C=(KEj{i0GS=>jiV8iwv_|t+ ztXAr72P(1F$}`<%<%$(b{2r$jHa({eNk$h#Fe4*P1Ji1>tvx-{>Qz)ys;ZJAZCz8K zy0RjrlozS6xLCzS#VWJ+g0&@DxVBWw3eDUuDp8SzmBgM3dq`8x+sY`iJRxp{r7tQj z(cCqqT4niW**m12Zr^JyY`(pV?e{86TWW89Z<|lxa_%;ZsmlqzYrbN9ETj-|VejqGitHLjJ-9zmIad$!ruq2UeEaks z5AX>#aKJm%0iZzj8!$ju-f)9TN=u!HJNM+1UHrAfhN*4)_NuK7E%|QPY-~9mXat^| zuv;+G6s_!>9HpkEIomfWIY|+Fcqhlc-IIiEY+=?Q-e}uVd-J43eHh<_^SHG3kk99D zjBALuxKNJ^vxhQ5-i9ZZKEyRmLmBHl)De4!G!1#dHC9(h501POLmT75c<7h3^fYBz zKV_t+J2xu?WhLo*OxAT^v&`J=Htlroog-9PRG@Zw*}CtFKWouf3w7Y>XKV0&`#CuS z;c*AzlABv$a@uTHmeJTwI;J>TN9D39O!}-8Hy`f4M7M2*B|x^R&~TOt*&f603AV7X zMTTuU^u?6&h|C5(5z#iO zwVG-5?Pm3HIsqG-Ig=l$cdk#$gF~?72v1sUb>OP}up~*pifsk@yey)&*2aaFhOM=1 zmEAqV_bI0#b}-R}`?PCjR3qPbQxl(hP}}XivvxZFYW1ow)Z)4n4L|Ed$C0*(nai1+ z?W{w3S?6@Lj-}h`OfAIk3qgBCYqf1^jq(!fRBho~84-wMe{j07sv~o%RB7Qg_VlxK zZ6ZE>T0))LM(WJ8G8ShKuFOP}^NCi2m-qGV&6%D|OPgSC>d3OELsG5FN4bYv`B@fE zC$sPmKGYTJBW{=UYF8h+LzRV7Zi1P2)Q6cznS@a$-{9TP+Do3nnWi*ZIBna}@^?(G z)m|CZ4yWC$T*7$XjLB^%5Q*2M(kMPu{tfzmpNEid{a2{5SsGqj6H~FJ8xMtNVoqx(H8b4-?nRr!7G(|K3LdS1pXgPsfNL=3; zD@-26XQXmu7t3Na3e?ap=>R$u`AJ8x)=Iuo8vziG2iZ~=(;z^fwNso9ERCfa>qDl( z5qSCW+W(%5>$y#zNdvZ(`gJX`>6#(TDU=YH&sFRSClvF+R;_J$9 z)k?|Hs3R)M8NfRyFHet+7@>=PcZSk4{LMJzW72TEw1tFn(84@yN%4)QLj$Ck3>uhG z>*QC6qhTm5C@aV&I)~#S*l;LCY&Pp-;gr`OIb-3>B^Jb4P-nfB&h#7Le4IZ5Qt#e` zFc3l<3;GPGPF6N$QV!viyS)tp!ccIKxhP}I2yg)})`1Vsu2!~{dtkQ7Tq6)>3tMx* zg&Np4>-m;n$ROOUC0m_6V&(C4HhG?toT#00l9ZX6terCGj|4@H{eJoEgQh(vS-T+H zx;ZBYuM_tDNoh$|n`Ghc~k@ z0C6F{5f5LI;}-Uip7=(_X5q0i;)-ejaHND_!^Yd&K&Z>(;UoDS9#>af!O1p5@t(b7 zvh|~J;}uQy=HSe!QUO|Onxd44w{rUM6|*~Ni88);??i|ssw z!8%_lh&mSkK?!kwF@B`UL|E=?CXd&lb^s+JHSn{Hn9CYomZ$u64LU&;I z1^L*mfq8{I1z*f5+DRO&oE;<7L7ki;1b2uyZRTuUe)dq!tu|9};Ue8|!{61qZCgzk zJJzk$u5Z?E2uMkPei742S_&;9F2%!=!uo0eCtFM|U|W_Yr@3u9sWxIqzV^D#JL$Lj z%UNgY?|=D=CVljgP2gl3>JgQdSL(TkAJQZD+@sRftDV-!EP~Z>Qeb;CDPX(%8JlGN zl!qfE$hjkOtK6QYz3q31JJ9S{;tsMmdzuHBX@+&lOx(_FQE={R_A@e)@-5hPUb%H1 z-%i=GkJ)BR16_^1!p?UxwhfCvl%ph;moj@A8}4Cc_BOG?wx3@1O&KYvsTzLE&AR)! z7nE)6H8V3q`P&SzHr{PAH$_pjVYIRhKut}JTLlVf_@7CHoxR~)8-^AVm(6EpCYX$h zXTQnTS$)&$v}-3*3U2(XmM>rKl!meu%Z&218ZdC6PC5H*?Xl+|$EJF>&er?SJ*oY- z@1y+=++R;$dx@reF&&XCHgasruQuxh@SOxyRO9J8u@q;|LFuivJjZ2vC|*oupyj{Y5Wd59K%_mMnd=p%o!}q;DA46 zL0AAbOBiw!x$EP6z5FJQ-I!?jVZa5A7{4*VFFGG(=+dEQ>9QMcbmk0%ELywP`YPGs zRFRmh))}c<{LM-&nl;0Ts)sJCUkvh$hA zCAP4>h0L}5{=|Wo$JnT(2Y<@O)rbtEK28;4uDoq&kmsa@n1o^0ePw1Gcucl*5S#ii z?J)B=Re(+VzqL_UPi0xDj=SM@{po@~>fiU?ulxS>FFo+WtLoRkzxwpsMpF&%Vb@-x z`-c5PZ@u!0RxDfQNR?P$r`;~RMy1hoeXy#^wFltEF3XQ%cyqe2C9=1fGuKA9jn-lt z((KM>Wap$LYp%`Qf8KPH+mTUQQ|%n%8&Vh;ohTGTFS}4@O13oQvtqypdlX18%YgovGkuy{6lmA6 zlUweCd(D|TMYsL^CiUpqQ`_#agNh0YG|?2T9d_A87hZ9N3T>9xMUr&UDUGW_ZQ6Ix z>dG49P*#T_;?E=n%+`fX^euathT)Fg6%>*H5EOa&U78?qu;w{4W@zg^ecX1E>o2`j ze>~$1eKLN$E--})nMJqJnRFJ7fKZ{EiQ{K5TS(`@v(WfB9>OUj+wkQJ{G-+mSh)}J zHfwTvvetY!ON++Na(~pq=kw*eI*dD&6<6r%cc-a%;VRV|k->#Q2RrtJ1xL$gI!1}f z*3R9!D?2CG2wOy?YOL+Ox7*%{uj_BWT_;+*yKl9XTa-tUV&DU8xQhp5E>08hW_qY6SPBiNzNs}Snml14XD-}<^4DW04ylLs z(xH_}Nt!!hfyL%3B_rxi-G6O%@F#{V^#y45>LAp9j(5;m0EoeI zx9;8BX@?NGDL`0c&aGzCvel%A<>#b3W=DELom-NFwK0x&u`rei4>7y4bzYi&-8EVD zHdCCdFtb+q*(ut;Tbf$6%hE1g(iO>0H#rq?HYx5xmI^b|lGLYNs#474inhttz)opO zH`a?A6rVNbk0ZWmuKRYkGA7Njnms!{tV@b16dCH=DplRhe%-!(iaK`4Qq{*ZEY^mD zvF+`x>}~AXuZ=&ugx$>m0{=`NoBz zEyHdDaoN1i003dip$rCzGea7X_Hu;--eWF$RMn+bYCWK<23#=2{Uxu-cfO_huYBhI zAQUIv+V9>|11~?qDHGhD6K#{FrQ>F6%3W`3&5WgnpV`bk+Nkd-d#Ts4ySb~AsDtt; zt7zd$m!8w=5O>tccdLq1jixy5fA{Hn^R(eg&N8!2+=mg>qPM@)o6GN0bxDP~?$=K} zkK0xC?sfr>KP;KHp*_koAS@O?%aHeh`5$jSoK{351k+%aN=I(F{th&bf%!*$ioH|x*WU9TJOzE`CtXJ|ZT z25b)*NO{Oa*cNeKu1jAUo1F8~XPWi)IP1`>FWabRB50`4yg0D68 zsnL39zeS7_Fl58dA)Si54G7JoEduV3&_z5DwSinhvfvN9

QE1!w5sY0)&* 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%0A%deX7(W4znD4K zT|LwkAa+Vxx@&x+KHj?`_XJoYas>O0-HV|C zOA<3wklsp*Qd?pS4&b`t1vxZA0@U`Vs@TBiL_ChygcREQ<9Od`s{p_ z+dDNkU)7d}@O;i0*>`%bv0BR?$@b+CPJC&^W~xW$Tfpq)TrkAT-Ej}ii{z@6w-IuIKtf9!pKjYXN&eL zA<=y|1#rMzVRjQ+W3!JifR5ygGAWDtzy*02Mm}uWh4aJWn6*xmqKsI5P3v{#+vD$k z^h}-> z@=zw1u$0Hjb?;bsD4&P#B72A@uGrc{z6}u;AgsoSLYrK^*h5*a9>bxuw8Y=G&OvO; z;~xIoOz^#CE_Y(wVKX3#RId5>w&uV?4=`4 zKhqJattl?dPIeQrIDo0fHHEY6y_*%mTya%c9ndat3UElEz8N$1)cyAXTBfWpydKCwAZRHMiX2|JutY&fLge z>U|xj*S0x!urfO2s=n5*7me0$5} z%&PR(YMY;{?yd8j%uLS7*H`x5x=oHgHMz8BryM6czqYW}t@1TLrHy*E$<>$9w%V;j zj+K*V-)+>*!alb2z3n~Q((K%xd^uX$b9XJCFh*77Wp0)RfUwNgT?Xx?LoU8X?J`r9 zX0o$O>s)19ec;;JzB{zaRVTxZ-yQRFv^FhY1@;uDn{3X_(WFRg?a(gEWOc5VMRV1D zo9)!9YY$C*f3&-#GoHY%PMh85|MhxJN$aSAZ8Mc;WsFrD^=p%5vOM3_k!Ge^XR9|Y z!&qn?hwaRyOpWTT7oIo5*Xy9e4)fRaGQyexiN?}bf4Nu-M}J|WF1qP#85Y;0S1;%B zDO$5ys}{^r$GmLi8FJj{615KAKBHdkQ>310(wc4$7%>mtg*; z74Ee})mhxYOfwat(vX~5W!aQHG}q!Ryw;xmvg?#*VMpiJD&Opez3n&Q3F%Vk<@#U`%XfyRb@ZbM7T%!wcJKU~&?x}4D z3~+Ter=8fy3+K<*JFmY^!P;eyJ#^L||LAm==0a1p{Jn@vO;Eaq9sgF60B^%M9Pm1@eR(P4U2^6o4;6 z10Df?prv)Px&()T(`*WCkhuT%`VGq8rsMbg`}FbP-EGbxVZVF__$QDb$&3kvspNgg zayu2cHkZxpxn?G?a)PM>-~z8PWa2!Yi(@iS)pv`!~CLDc39vy z#taFQA!r3SP$&WOESP4*u_=L#f5fqAfCJX}pN$JQoYo^9dyP4x8_q1_wxr#(pLT|H ze9^{GhsTIUBiCyePqghT|X@qs#Sgj0y)WmlZJ3#0hf2_p+CY*S7 z2jbtJTggef1kJVlgj4QYRz6FFT=>O~OMe2;6P61`*ha(OHo}k0-#P$CmjCegLS))P zoe;v|VPW{9X#{9r~LSn=;V**0viMym624= zIj$cPBBpD!&DNUfOZ4e2uNWTO+f}WE>vE2(UsJf;tfEv^ntH#(@rP)yTTe85*9cVN z_vp49Ji>H72a26L&wev<88>_bbQCF>HFO|ACxoyt%EK;%z~Az#m$OE5(v90zX!N-cY4&>`8d)<{t`ha^ zzk?!UDyCgmS5&L16USRbx>ihEpwIvLy0Y5ktMmT-RA(}{xsHuS@W^t*E5vjo*B;Lh zyi{uX#5d6Y_HROi?4mOX3-9_1}jJ7$&(HaLMB$gV8Ebm)(e`nHA{zCK7yiYStntW{GMId9X< zN5?CxTPvj-K{Gq&tM!0xjUsN{HWDhcE ze2JlF;UMGwxP^t4#yXac0{CW^0_j-vMwW7aBppf|8w2Qgc2$tY&x%-?RxiHlB~|_g z9lu5lUhMGq7kG^<^4n#R%hbUDWAgz!NZ2jHqCN^40A{Q&aakGz0m8dF?Logl=5q-+ ztR8)W^5_FD5{uWS;~_E0^37PH&u@EO8SQgz#x7M}-wtZCLpOCDvYp!O*xg-+$RvAq z_iOda?{75<)f#at)V4=g{bTXSbqEVI%-p6h@t!yI)OoiUGRC^>U$v^V>(HaL+x5S3 zGN7icB?h`@P|Ol`6(GL=I*ZPs@hlhs@iGg-L4VGlP7@ zt#42SEaC?RVNG!%oD@8vPFAQ0iH{3|Cg9PuJRsENYY*R+##nE`?B&jXTrlSw`<-Z7 zaa0`#_43-Wjs6r=q&v;o*Cae>lRMY?bAzi9T1 z&rKK0u~Ad5wq1H?$Rp<{zh5U+tS*VWg>7Tt*4+Ov z+1Mr<wz-zV3fd}h%Z{27!I0D`eO4We<{fqdB2)B|z3tc4Q?$aIuF@S$F~0*)5y@6Bi=1T(U7O^M3BDN@uq9X?i8msaZW>m7|6rgUYdsC-4S zMxB1I7EYdQ{hVPcQ;FKQ>aMfL-J-UAyTnS`IJAhk0p7d$Sv`N{osLDLnsE4e&?U!f zr%MmB5m@f-OKc7VcIjEE?*JGN2nDuAXk+JiR2#$i{q1}qbVD*12ysCSkT0-vALr`| z;6r?#5EoK4=Hc7p!7pD|EF4YP2)pR*DOx&yj&inYqr5&HO;PIROdsM=sy@8(S$+1{ zYl_*VI_0syYR8lJbLF%IHi@_a9zEg)jeqr3lg7E$G1W>-%F#g&4ORDF4RDuT z*Tw#dM@xXtac}Drc0VBNy!p`Rj6e=I?4h#9gO`P*MIj1r0GZ7Uhd7~pkC`bl_M4D+ z;)XZ1@`O5Z#)Lfn%cqT(x$zKKXL3f0R!&~z*lfj`Qg=Cc$31&H?H7Wkw#w4X3Kp%@J%cXM*Gpy_1IaR0U8>G~`Z;-=)wPu> z)|OiDG_MLeo~=1}arj$#+nF5Zq#f7q(M?<~#zt}8Y+9dW^7w#kPu@4p%-}u@cJ(8_ zk+beD49m!ghCM7jZa?-1vqhHsp}>m2^@Hyk^9UJ@iN?lw*flrYAp&666U|&ZB-hJa z;@}2cs={4c;L3rq1_C2fjcA4QRw%7aw&pxD(PpjL9HuNWdogX2Qj(oUyyDXZdi&IS zv}P4occ&QxF3`3+57If~hPm|L2fjCP1AO_ycs+dV^)`Pi4apQ|Tn{+zU=6uA%%O*Wx$2GZ|uC=)?S{n>~CJ9~LVD-@qJUrV|#@GaLDhEt+nbxu_Gn zd9lgdtxSG~c+$JF$j^sCkhv&koTh+7ke-yxR)5ugf+`EkH23+Bou?0lbN(xztN&U1 zsolV>Yz7x=%sCHf)&~=uT&=MF%1v#fvqs;nu6y)#rF~!6Y{U)l`XvwO)!Xkg(<#$_ zc}BR;jVEin^AB>SQ~ce<8-{fy>V{<9x8v50@oykLEP#(|D&zgzr;X3;Vcn2*OSE4o zM8<*_zdu6@Uz=odwXO2E?WF8(ZJdWGIWtv}lq5~~>vQ_(zc1SC=MrxOT9r=x=VjXS zq9bEvZ64U{#09Y1?%VeYO&UAKNbFsi*;#EJtL`|skCVrn>dJ%|oH)RgK|>C1#Nf(g zh9Msb^9}Rz7I}&M4l_6?aNn}4?P2%@ZJ7(kqDFDb_Bq!N5S5v_Xw;V~oU>ecW+LKz z=yu2er+cL2WoX`upXi;TBb+J8kvQb)J|`Tj6Q8;)R?6muAB4C8mVPl`BlfvmD~pzx zG|4blU8=2i-B|~WILp~_l?5h`TUa}6n^S_^@5m{Ky<&2ezrlyhO)N8Csh>07Ta z?s!w#Hd8BB7c0|Dn+}6|Id^SRdWs5+*rQInSIZX6ao#0}x>e8ZH1va8l-*(De=vDd z;RhvdfR9JKr6-2oWL<+RGuhZsg$AB^g!cIR|EZ?5%DFRJ0uUIa`!)#qOd6DM5{HbHNt+(%{t&bV#wEt*Us!Erw)jMa5(84LfWmv2ZZMM=m9zE(t zjeq%-MptGeTL(UHmUPS~P|8(`Z1Cg|Z~t~276n@Zw$Wp01Wff{_r$u7RS zcvE*}t{-q2vI7EGIq566aVvj2`-c=8pf!*{kI?`0~@+ z>#Q+1smrc?T>dQywn*Xzc=Pgy_0lbOJJTr`Cxfp$+1TTd7PvCM8^Sgh{v0dL{(@P{ zRI#>91@o3`@NFl#g>$@56R&+rXiI#$w_2U|381B}@J3Vk-_ z-Iy!0Qd#M(+^)<{gZpm!u1uS)5N*|zuif7U#8&;vW^B7%wsMLRf3pu+JNualdiR|B zjg%E8Rg;W|6l&j-{!hn0eo3sLEf;?iSCnXH)YsR4{v)-u&&|`exBQrv;-dZPj~woilcr zGTY|H3fr>bXG7copFTKBkDd89W7Bc2%rg%6uFQ(+?>y_osth|tWn_j%*Pa+F>eg$nJcUuHec{N=w#^ z$Hu!g)~qi1N^6(nWG-7>zItnek-k&S{tce?7!PsfK z-;}PRnl%ls%)a{%)_(V#ZbVH{l??*qF`98zp_x}EQ*jxVEM99w9j>pwoZ8?r?AX4i z&K`SZb4LEV1SZP0h_(c&nz!S&atPh@l!K87XcV#AK>45uxuihsPa&qx<6Pum5>gEcY)5ev!llik7U_y@M~)!UfZuE0c|TX^GjYs4KQP zja)6zfIaqcE<+Xveu?mlC2oKjuYIhC4!_3aaG8-b)!wCQmC->%-~Wd??c6h#>X!+> wc;W_NX>sDcZ|I=wPts1O9uN!tC4=<;0ph$OER$k?L;wH)07*qoM6N<$f?jfmqyPW_ literal 0 HcmV?d00001