From ebbc293d80ea0e3190ccf9edaa82c1af598b2f43 Mon Sep 17 00:00:00 2001 From: JingMatrix Date: Tue, 1 Sep 2026 13:55:37 +0200 Subject: [PATCH 1/4] Let a long version name scroll instead of squeezing the row MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A repository hands back whatever the publisher wrote, and that is regularly something like 1.58.245-ai-ui-label+B520-20260828T1203Z-full. Drawn as a plain Text with no width of its own it took the whole row and left the date beside it one character wide, printed down the screen a character per line — which reads as a rendering fault rather than as a long name. The modules list already answers this: a fixed width, one line, and the part that does not fit scrolls past once. ScrollingLabel is that rule, in one place, so the store's three version lines — the badge on a list row, the tag on a release card, the install button's label — cannot each get it differently. The row's fixed parts are measured first and the version takes the remainder, so it is the version that gives way rather than the date. --- .../org/matrix/vector/ui/ScrollingLabel.kt | 39 ++++++++++ .../vector/ui/store/RepoDetailsScreen.kt | 72 ++++++++++++------- .../org/matrix/vector/ui/store/RepoScreen.kt | 12 +++- 3 files changed, 93 insertions(+), 30 deletions(-) create mode 100644 manager-ui/src/main/kotlin/org/matrix/vector/ui/ScrollingLabel.kt diff --git a/manager-ui/src/main/kotlin/org/matrix/vector/ui/ScrollingLabel.kt b/manager-ui/src/main/kotlin/org/matrix/vector/ui/ScrollingLabel.kt new file mode 100644 index 000000000..d9b2cfa04 --- /dev/null +++ b/manager-ui/src/main/kotlin/org/matrix/vector/ui/ScrollingLabel.kt @@ -0,0 +1,39 @@ +package org.matrix.vector.ui + +import androidx.compose.foundation.basicMarquee +import androidx.compose.material3.LocalTextStyle +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle + +/** + * A label that scrolls its own text past rather than taking the width of whatever sits beside it. + * + * Version names are written by whoever published the release, not by us, and a repository will hand + * back things like `1.58.245-ai-ui-label+B520-20260828T1203Z-full`. Left to wrap, one of those eats + * the whole row and squeezes its neighbour — a date, a chevron — into a column one character wide, + * which is unreadable in a way that looks like a rendering fault rather than a long name. + * + * So the rule the modules list already follows applies wherever a published version is drawn: the + * label is one line inside a bounded width, and the part that does not fit scrolls past once. The + * caller gives it that width — usually `Modifier.weight(1f, fill = false)`, which hands the row's + * fixed parts their natural size first and leaves this with the remainder. + */ +@Composable +fun ScrollingLabel( + text: String, + modifier: Modifier = Modifier, + style: TextStyle = LocalTextStyle.current, + color: Color = Color.Unspecified, +) { + Text( + text = text, + style = style, + color = color, + maxLines = 1, + softWrap = false, + modifier = modifier.basicMarquee(iterations = 1, repeatDelayMillis = 2_000), + ) +} diff --git a/manager-ui/src/main/kotlin/org/matrix/vector/ui/store/RepoDetailsScreen.kt b/manager-ui/src/main/kotlin/org/matrix/vector/ui/store/RepoDetailsScreen.kt index eed084206..a0dcb0f55 100644 --- a/manager-ui/src/main/kotlin/org/matrix/vector/ui/store/RepoDetailsScreen.kt +++ b/manager-ui/src/main/kotlin/org/matrix/vector/ui/store/RepoDetailsScreen.kt @@ -2,6 +2,7 @@ package org.matrix.vector.ui.store import org.matrix.vector.ui.R as UiR import org.matrix.vector.ui.ToggleRow +import org.matrix.vector.ui.ScrollingLabel import org.matrix.vector.ui.SheetHeading import org.matrix.vector.ui.sheetRowColors import org.matrix.vector.ui.theme.Mono @@ -462,17 +463,22 @@ private fun InstallBar( modifier = Modifier.size(18.dp), ) Spacer(Modifier.width(8.dp)) - Text( - when { - state.upgradable -> - stringResource( - if (state.sameVersion) UiR.string.store_badge_reinstall - else UiR.string.store_badge_update, - state.latest?.versionName.orEmpty(), - ) - state.installed != null -> stringResource(UiR.string.store_reinstall) - else -> stringResource(UiR.string.store_install) - } + // One line, whatever the version name is: a button that grows a second row + // to fit a build identifier moves the bar under the reader's thumb. + ScrollingLabel( + text = + when { + state.upgradable -> + stringResource( + if (state.sameVersion) UiR.string.store_badge_reinstall + else UiR.string.store_badge_update, + state.latest?.versionName.orEmpty(), + ) + state.installed != null -> + stringResource(UiR.string.store_reinstall) + else -> stringResource(UiR.string.store_install) + }, + modifier = Modifier.weight(1f, fill = false), ) } } @@ -658,27 +664,39 @@ private fun ReleaseCard( ) .padding(vertical = 4.dp), ) { - // The tag, not the name: it carries the version code, which is what actually decides - // whether the platform will accept this over what is installed. - release.tagName?.let { - Text(text = it, style = Mono, color = colors.onSurfaceVariant, maxLines = 1) - } - release.publishedAt.asRepositoryDate(locale)?.let { - if (release.tagName != null) { + // The tag and the date share what is left after the chevron, and the date is served + // first: it is a fixed handful of characters, while a tag is whatever the publisher + // wrote and is regularly longer than the screen. Measured the other way round the tag + // would push the date into a column one character wide. + Row(modifier = Modifier.weight(1f), verticalAlignment = Alignment.CenterVertically) { + // The tag, not the name: it carries the version code, which is what + // actually decides whether the platform will accept this over what is + // installed. + release.tagName?.let { + ScrollingLabel( + text = it, + style = Mono, + color = colors.onSurfaceVariant, + modifier = Modifier.weight(1f, fill = false), + ) + } + release.publishedAt.asRepositoryDate(locale)?.let { + if (release.tagName != null) { + Text( + text = " · ", + style = MaterialTheme.typography.labelSmall, + color = colors.outlineVariant, + ) + } Text( - text = " · ", - style = MaterialTheme.typography.labelSmall, - color = colors.outlineVariant, + text = it, + style = MaterialTheme.typography.labelMedium, + color = colors.onSurfaceVariant, + maxLines = 1, ) } - Text( - text = it, - style = MaterialTheme.typography.labelMedium, - color = colors.onSurfaceVariant, - ) } if (hasNotes) { - Spacer(Modifier.weight(1f)) Icon( Icons.Rounded.ExpandMore, contentDescription = disclose, diff --git a/manager-ui/src/main/kotlin/org/matrix/vector/ui/store/RepoScreen.kt b/manager-ui/src/main/kotlin/org/matrix/vector/ui/store/RepoScreen.kt index a8b2fbe8a..431484882 100644 --- a/manager-ui/src/main/kotlin/org/matrix/vector/ui/store/RepoScreen.kt +++ b/manager-ui/src/main/kotlin/org/matrix/vector/ui/store/RepoScreen.kt @@ -10,6 +10,7 @@ import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.SheetValue import androidx.compose.material3.rememberBottomSheetState import org.matrix.vector.ui.ChoiceRow +import org.matrix.vector.ui.ScrollingLabel import org.matrix.vector.ui.SheetHeading import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -401,6 +402,11 @@ private fun StoreRow(entry: StoreEntry, onClick: () -> Unit) { entry.latest?.versionName.orEmpty(), ), tint = colors.primary, + // The version name in this badge is the publisher's, and can be + // longer than the row. It takes what is left after the date rather + // than the other way round: the date is a fixed handful of + // characters and the badge is not. + modifier = Modifier.weight(1f, fill = false), ) entry.installed != null -> RowBadge( @@ -422,11 +428,11 @@ private fun StoreRow(entry: StoreEntry, onClick: () -> Unit) { } @Composable -private fun RowBadge(icon: ImageVector, text: String, tint: Color) { - Row(verticalAlignment = Alignment.CenterVertically) { +private fun RowBadge(icon: ImageVector, text: String, tint: Color, modifier: Modifier = Modifier) { + Row(modifier = modifier, verticalAlignment = Alignment.CenterVertically) { Icon(icon, contentDescription = null, modifier = Modifier.size(14.dp), tint = tint) Spacer(Modifier.width(4.dp)) - Text(text = text, style = MaterialTheme.typography.labelMedium, color = tint) + ScrollingLabel(text = text, style = MaterialTheme.typography.labelMedium, color = tint) } } From 3c949872356533ddce7d81c5e872ae3da411c2cb Mon Sep 17 00:00:00 2001 From: JingMatrix Date: Tue, 1 Sep 2026 13:55:37 +0200 Subject: [PATCH 2/4] Fill the dot on the build the version sheet is showing The dots in the version history are a radio group and were read as one, so the reader who tapped an older build found the hollow dot still against the row they were looking at and the filled one against a row they had left. The list was marking what is installed, which is a different fact. The fill now follows the selection and moves with the tap. Installed is still marked, twice over: the accent on its dot, and the word in the status column. --- .../matrix/vector/ui/update/VersionHistory.kt | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/manager-ui/src/main/kotlin/org/matrix/vector/ui/update/VersionHistory.kt b/manager-ui/src/main/kotlin/org/matrix/vector/ui/update/VersionHistory.kt index c3eb6a812..8389683db 100644 --- a/manager-ui/src/main/kotlin/org/matrix/vector/ui/update/VersionHistory.kt +++ b/manager-ui/src/main/kotlin/org/matrix/vector/ui/update/VersionHistory.kt @@ -32,7 +32,7 @@ import org.matrix.vector.ui.sheetRowColors /** * Where a version stands relative to the running build — the one distinction each row is marked by. * - * [Installed] is the build actually running (a filled dot, the accent). [Diverged] carries the same + * [Installed] is the build actually running (its dot wears the accent). [Diverged] carries the same * version number but was not made from this release — another branch, or a working tree with changes * — so it looks installed by the number alone and must be told apart. [Older] sits below the running * build. [None] is any other version (a newer one on offer, or a sibling channel's build). @@ -68,8 +68,10 @@ private val STATUS_WIDTH = 96.dp * name, date, channel and status, tapping one to switch the screen to it. * * A scrollable list rather than a dropdown, so an older build carries the same weight as the newest - * and nothing is hidden past an edge. The rows are marked the way an activity feed marks the commit - * you are on — a filled dot against hollow ones — so the running build is findable at a glance. + * and nothing is hidden past an edge. The dots are a radio group and behave like one: the filled + * one is the build the screen is showing, and it moves to whichever row is tapped. What is + * *installed* is a separate fact and is told separately — the dot's colour and the status word + * beside it — because the two rows are only the same one until the reader picks something else. * * Localised through [LocalDialogLocalizer] like every shared sheet: a sheet is its own window and * drops the host's in-app language override on the way in, so it is re-applied inside. @@ -99,9 +101,15 @@ fun VersionHistorySheet( supportingContent = { Text(item.subtitle, maxLines = 1, overflow = TextOverflow.Ellipsis) }, + // The filled dot is the row the screen is showing, because that is what a + // list of dots means everywhere else: tapping one moves it. The installed + // build is still marked, by the colour of its dot and by the word in the + // status column — reading it off the fill instead would leave the reader + // who has just tapped an older build with no dot against the row they are + // looking at, and a filled one against a row they are not. leadingContent = { Icon( - if (item.status == VersionStatus.Installed) Icons.Rounded.RadioButtonChecked + if (item.selected) Icons.Rounded.RadioButtonChecked else Icons.Rounded.RadioButtonUnchecked, contentDescription = null, tint = From 14c95e706f2b41bbc3a4f75d2472063a5fcecf6b Mon Sep 17 00:00:00 2001 From: JingMatrix Date: Tue, 1 Sep 2026 14:13:24 +0200 Subject: [PATCH 3/4] Draw the monochrome statue rather than fill it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A themed icon is one flat colour, and at that size a filled silhouette is a blob: the wing feathers and the drapery folds the statue is recognised by were punched out of it as twenty-five lines and lost anyway. The line drawing keeps them, because lines are all it is. Traced from the outline artwork, scaled onto the 350 viewport the solid one used and centred exactly where it was, so the launcher's themed icon and its coloured one stay the same statue at the same size. Weight and detail are set for the size the drawable is really drawn at, which is small in every use and large in none — 24 by 38 pixels in the status bar of a 420dpi phone, around 28dp on the home screen — so the tracing's hairlines are stroked up to six units and most contours are dropped. Which ones is decided by what a line does, not by its length: length alone deletes the statue, whose outline is a run of medium pieces rather than one long one. The outline is found first, by closing the ink over the gaps and filling from outside in, and kept whole. Only the interior thins, by region: the wing keeps its feathers, the skirt loses its folds. --- .../res/drawable/ic_statue_monochrome.xml | 40 +++++++++++++++---- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/daemon/src/main/res/drawable/ic_statue_monochrome.xml b/daemon/src/main/res/drawable/ic_statue_monochrome.xml index 7144f80d9..8d463f200 100644 --- a/daemon/src/main/res/drawable/ic_statue_monochrome.xml +++ b/daemon/src/main/res/drawable/ic_statue_monochrome.xml @@ -5,14 +5,38 @@ android:viewportWidth="350" android:viewportHeight="350"> - + + android:strokeColor="#FFFFFF" + android:strokeWidth="4.5" + android:strokeLineJoin="round" + android:strokeLineCap="round" + android:pathData="M212.4 50.9v.7c.1 0 .2 0 .3-.1l-.3-.6ZM188.2 29.7l-.5 .5 .5-.5ZM83.1 7.5l.5 .5-.5-.5ZM231.7 45.4v-.7c-.1 0-.2 0-.3 .1l.3 .6ZM235.5 45.4l.3-.6c-.1-.1-.2-.1-.3-.1v.7ZM246.3 51.6l-.3 .6c.1 .1 .3 .1 .4 .1l-.1-.7ZM258.6 66.3l.6-.2-.6 .2ZM260.2 157.1l.1 .7-.1-.7ZM217.7 47.6l-.4-.6 .4 .6ZM179.4 167.3l-.6-.3 .6 .3ZM168.1 177.7l.4 .6c.2-.1 .3-.3 .3-.6h-.7ZM168.4 172.9l-.6-.4 .6 .4ZM158.7 112.4v.7-.7ZM138.3 104l.4-.6c0 0-.1 0-.1-.1l-.3 .7ZM116.9 95.8l-.5 .4 .5-.4ZM33.5 38.3l.4 .6c.2-.2 .3-.3 .3-.5l-.7-.1ZM28.2 54.5l.4 .5c.3-.2 .4-.6 .2-.9l-.6 .4ZM43.1 73.7l.4-.6c-.1-.1-.2-.1-.3-.1l-.1 .7ZM73.1 78.5l.5-.5c-.2-.1-.4-.2-.6-.1l.1 .6ZM113.7 74.1l.3 .7-.3-.7ZM162.6 244.6l.2-.6c-.2-.1-.4 0-.6 .1l.4 .5ZM159.9 280.3l-.7-.2 .7 .2ZM164.8 344.3l-.7-.1 .7 .1ZM201.4 341.7l-.3-.6 .3 .6ZM237.1 345.3l-.2 .6 .2-.6ZM257.7 342.1l.4 .5c.1-.1 .2-.2 .2-.4l-.6-.1ZM262.6 318.1l.6 .4c.1-.1 .1-.2 .1-.4h-.7ZM265.7 284.9l.6 .2-.6-.2ZM265.7 252.9l.6 .3-.6-.3ZM266.3 238.9h-.7c0 .1 0 .2 .1 .3l.6-.3ZM263.4 185.8l-.6-.3 .6 .3ZM268 161.4l-.7-.1 .7 .1ZM142.9 188.8l-.3-.6 .3 .6ZM149 23.1l.4 .6c6-3.8 13.5-4.2 20.6-2.6 7.1 1.5 13.7 5.1 17.7 9.1l.5-.5 .4-.5c-4.2-4.2-11-7.9-18.3-9.5-7.3-1.6-15.3-1.2-21.7 2.9l.4 .5ZM188.2 29.7l-.5 .5c7.3 7.4 9.7 14.5 24.4 21.3l.3-.6 .2-.6c-14.3-6.7-16.4-13.4-24-21.1l-.4 .5ZM149 23.1l-.5 .5c8.2 10 17.4 15.3 26.5 18.9 4.6 1.8 9.2 3.2 13.6 4.5 4.4 1.3 8.7 2.5 12.7 4.1l.2-.7 .3-.6c-4.1-1.6-8.4-2.8-12.8-4.1-4.4-1.4-8.9-2.7-13.5-4.5-9-3.5-18-8.7-26-18.5l-.5 .4ZM149 23.1l.5-.4c-10.5-10.6-25.5-16.2-38.7-18.3-6.6-1.1-12.8-1.3-17.7-.8-2.4 .2-4.6 .6-6.4 1.2-1.7 .6-3.2 1.3-4.1 2.2l.5 .5 .5 .5c.7-.7 1.9-1.4 3.5-1.9 1.7-.5 3.7-.9 6.1-1.2 4.8-.4 10.9-.2 17.4 .8 13 2.2 27.7 7.7 37.9 17.9l.5-.5ZM83.1 7.5l-.5-.5c-.2 .3-.4 .6-.4 .9 0 .4 0 .7 .2 1 .3 .6 1 1.1 1.8 1.5l.3-.6 .4-.6c-.8-.4-1.2-.7-1.3-1-.1-.1-.1-.1-.1-.1 0 0 .1-.1 .1-.1l-.5-.5ZM84.5 9.8l-.3 .6c2.4 1.4 7.2 2.8 14.7 4l.1-.7 .1-.6c-7.5-1.2-12.1-2.6-14.2-3.9l-.4 .6ZM84.5 9.8l.2 .7c18.9-6.5 36.3 1 50.2 10.7 7 4.8 13 10.2 17.9 14.7 2.4 2.2 4.6 4.1 6.4 5.7 1.8 1.5 3.4 2.7 4.6 3.2l.3-.6 .3-.7c-1-.4-2.5-1.4-4.3-3-1.8-1.5-3.9-3.4-6.4-5.7-4.9-4.4-11-9.8-18-14.7-14.1-9.8-31.9-17.6-51.4-10.9l.2 .6ZM164.1 44.2l-.3 .6c2.9 1.2 20.5 8.3 31.5 12.4l.2-.7 .3-.6c-11-4.1-28.5-11.2-31.4-12.4l-.3 .7ZM220 46.3v.6c0 0 0 0 0 .1 .1 0 .2 0 .3 0 .2 0 .6 .1 1 .1 .7 .1 1.8 .2 3 .2 2.4 0 5.4-.2 7.7-1.3l-.3-.6-.3-.6c-2 .9-4.7 1.1-7.1 1.1-1.1 0-2.1-.1-2.9-.2-.4 0-.7 0-.9-.1-.1 0-.2 0-.3 0 0 0-.1 0-.2 0v.7ZM235.5 45.4l-.3 .6c3.4 1.6 6.3 3.5 10.8 6.2l.3-.6 .4-.6c-4.4-2.6-7.5-4.6-10.9-6.2l-.3 .6ZM235.5 45.4c0-.7 0-.7 0-.7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0-.1 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0-.1 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0-.1 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0-.1 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0-.1 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0-.1 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0-.1 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0-.1 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0-.1 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0-.1 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0-.1 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0-.1 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0-.1 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0-.1 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0-.1 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.1 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0v.7 .7c0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-.7ZM246.3 51.6l.1 .7c1.7-.3 3-.4 4-.1 1.1 .2 2 .8 2.8 1.7 .8 1 1.5 2.5 2.3 4.5 .8 2.1 1.6 4.7 2.4 8.1l.7-.2 .6-.2c-.8-3.3-1.6-6-2.4-8.1-.8-2.2-1.6-3.8-2.6-4.9-1-1.2-2.1-1.9-3.4-2.2-1.4-.3-2.9-.3-4.6 0l.1 .7ZM260.2 157.1l.7-.2c-2.2-5.4-3-9.3-3-12.5 0-3.2 .7-5.8 1.8-8.8 2.1-6 5.4-13.2 5.4-28.9h-.7-.7c0 15.5-3.2 22.5-5.3 28.5-1.1 3-1.9 5.8-1.9 9.2 0 3.4 .9 7.5 3.1 13l.6-.3ZM258.6 66.3l-.7 .2c.3 1.2 1.2 2.4 2.3 3.6 .5 .7 1.1 1.3 1.8 2 .6 .7 1.3 1.4 1.9 2.2 2.7 3 5.4 6.7 6.3 11.4l.7-.1 .6-.1c-.9-5.2-3.8-9.1-6.5-12.1-.7-.8-1.4-1.5-2-2.2-.7-.7-1.3-1.4-1.8-2-1-1.2-1.7-2.2-2-3.1l-.6 .2ZM270.9 85.6l-.7 .1c1 5.2-.2 11.9-6.3 20.6l.5 .4 .6 .4c6.2-9 7.6-16 6.5-21.6l-.6 .1ZM270.9 85.6l-.6-.3c-2.7 5.2-8.8 8-15.7 7.2-6.9-.8-14.5-5-19.8-13.5l-.6 .4-.6 .3c5.5 8.9 13.5 13.3 20.8 14.2 7.3 .8 14.1-2.1 17.1-8l-.6-.3ZM214.7 77.1l.6 .2c2.1-6.9-.2-15-4.3-20-2.1-2.5-4.6-4.3-7.4-4.7-2.9-.4-5.8 .6-8.5 3.4l.4 .5 .5 .5c2.5-2.6 5-3.4 7.4-3 2.3 .3 4.6 1.9 6.5 4.2 3.9 4.7 6 12.3 4.1 18.8l.7 .1ZM212.4 50.9c.3 .6 .3 .6 .3 .6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .1 0 0 0 0-.1 .1-.1 0 0 .2-.1 .3-.2 .4-.2 .8-.5 1.3-.8 1.1-.7 2.4-1.5 3.5-2.2l-.3-.6-.4-.6c-1.1 .7-2.5 1.5-3.5 2.2-.5 .3-1 .6-1.3 .8-.2 .1-.3 .2-.4 .3 0 0-.1 0-.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 .6ZM217.7 47.6l.3 .6c.6-.4 1.2-.7 1.6-1 .2-.1 .4-.2 .5-.2 0-.1 .1-.1 .1-.1 0 0 0 0 0 0 0 0 0 0-.1 0 0 0 0 0-.1 0v-.6-.7c-.1 0-.2 0-.3 0 0 0 0 0-.1 .1 0 0-.1 0-.2 .1-.1 0-.3 .1-.5 .3-.4 .2-1 .5-1.6 .9l.4 .6ZM217.7 47.6l-.4 .6c12.8 7.6 20.2 8.5 24.5 8.2 1.1-.1 2-.3 2.7-.4 .7-.2 1.2-.3 1.6-.3 .3-.1 .4 0 .4 0 0 0 .2 .2 .3 .9l.6-.1 .7-.2c-.1-.6-.3-1.2-.7-1.6-.4-.4-1-.5-1.5-.4-.5 .1-1.1 .2-1.7 .4-.7 .1-1.5 .3-2.5 .3-4 .3-11.1-.5-23.7-8l-.3 .6ZM247.4 56.5l-.6 .1c.1 .8-.1 1.3-.4 1.7-.4 .4-1.1 .7-2.1 .8-1.9 .3-4.9-.2-8.2-1.1-6.6-2-14.2-6.2-17.9-10.8l-.5 .4-.6 .4c4 5 11.9 9.2 18.6 11.3 3.4 1 6.5 1.5 8.8 1.2 1.2-.2 2.2-.6 2.9-1.3 .7-.7 .9-1.7 .7-2.9l-.7 .2ZM195.5 56.5l-.4-.5c-2.5 2.6-4.3 7.2-5.3 12-1 4.8-1.3 10-.8 13.7l.7-.1 .7-.1c-.6-3.5-.3-8.5 .7-13.2 1.1-4.7 2.8-9 4.9-11.3l-.5-.5ZM189.7 81.6l-.7 .1c.4 2.5 1.5 5.2 2.7 8 1.3 2.8 2.9 5.7 4.4 8.4 1.6 2.7 3 5.2 4.1 7.4 .5 1.1 .9 2 1.2 2.9 .3 .8 .4 1.5 .4 1.9l.7 .1h.7c0-.7-.2-1.6-.5-2.5-.3-.9-.8-1.9-1.3-3-1.1-2.2-2.6-4.8-4.1-7.5-1.5-2.7-3-5.5-4.3-8.3-1.3-2.7-2.3-5.3-2.6-7.6l-.7 .1ZM168.1 177.7h.7c0-.5-.1-1.1-.1-1.5 0-.5-.1-.9-.1-1.3-.1-.7 0-1.2 .3-1.6l-.5-.4-.6-.4c-.6 .7-.6 1.6-.6 2.5 0 .4 .1 .8 .1 1.3 .1 .5 .1 .9 .1 1.4h.7ZM168.4 172.9l.5 .4c.2-.2 .4-.4 .7-.6 .4-.2 .9-.5 1.4-.7 1-.5 2.3-1 3.5-1.5 1.3-.5 2.5-1 3.5-1.4 .5-.3 .9-.5 1.3-.7 .1-.1 .3-.3 .4-.4 .2-.1 .3-.3 .4-.5l-.7-.2-.6-.3c0 0 0 0 0 0-.1 .1-.2 .2-.3 .2-.2 .2-.6 .4-1.1 .6-.9 .5-2.1 .9-3.3 1.4-1.3 .5-2.6 1-3.7 1.5-.6 .3-1.1 .6-1.5 .8-.4 .3-.8 .6-1.1 1l.6 .4ZM201.3 123.2l-.6-.1c-.8 5-1.8 7.9-3 10.2-1.2 2.2-2.7 3.7-4.5 5.8-3.7 4.2-8.5 10.2-14.4 27.9l.6 .3 .7 .2c5.8-17.6 10.5-23.5 14.1-27.5 1.8-2 3.4-3.7 4.7-6.1 1.3-2.4 2.4-5.5 3.1-10.6l-.7-.1ZM201.3 123.2v-.7c-5.9 0-8.8-1.2-10.4-3.1-.8-.9-1.3-2.1-1.7-3.5-.4-1.4-.7-2.9-1-4.7l-.7 .1-.7 .2c.4 1.7 .7 3.4 1.1 4.8 .4 1.5 1 2.9 2 4 2 2.3 5.3 3.5 11.4 3.5v-.6ZM187.5 111.3l-.4-.5c-1.5 1.2-2.6 2-3.6 2.6-1.1 .6-2.2 .9-3.7 1.1l.1 .7 .1 .6c1.6-.2 2.9-.5 4.1-1.2 1.2-.6 2.4-1.5 3.8-2.7l-.4-.6ZM179.9 115.2l-.7-.1c-.2 2.4-1.1 4.1-2.3 5.1-1.3 1-2.8 1.4-4.3 .9-3.1-.8-6.6-4.8-6.9-13.5h-.6-.7c.3 9 3.8 13.8 7.8 14.9 2 .5 4 .1 5.5-1.2 1.6-1.3 2.6-3.4 2.9-6.1h-.7ZM158.7 112.4v-.7c-1 0-3.3-.4-5.1-1.9-1.8-1.5-3.3-4-2.6-8.5l-.7-.1-.7-.1c-.7 4.9 .9 8 3.1 9.8 2.2 1.7 4.8 2.2 6 2.2v-.7ZM138.3 104l.3-.7c-1.1-.5-2.1-1.3-2.8-3-.7-1.7-1.2-4.4-1.2-8.9h-.7-.7c0 4.6 .5 7.5 1.4 9.5 .8 2 2.1 3 3.4 3.7l.3-.6ZM133.9 91.4l-.6-.4c-3 4.3-6.2 6.3-8.9 6.8-2.7 .5-5.2-.5-7-2.5l-.5 .5-.5 .4c2.1 2.4 5 3.6 8.2 3 3.2-.6 6.6-2.9 9.8-7.4l-.5-.4ZM75.9 22v.7c3.1 0 10.1 .8 16.5 1.9l.2-.7 .1-.7c-6.5-1-13.6-1.8-16.8-1.8v.6ZM113.7 28.4h-.6c-.4 3.4 1.1 6.4 4.3 8.8 3.3 2.4 8.2 4.2 14.9 5.2l.2-.6 .1-.7c-6.7-1.1-11.4-2.8-14.3-5-3-2.1-4.2-4.7-3.9-7.6l-.7-.1ZM132.7 64.7l-.6-.2c-1.5 3-2 5.6-1.7 7.6 .3 2.2 1.5 3.7 3.4 4.5 1.8 .8 4.2 .9 7 .2 2.8-.6 6-2 9.4-4.1l-.4-.6-.3-.6c-3.4 2.1-6.4 3.4-9 4-2.6 .6-4.7 .5-6.2-.1-1.4-.6-2.3-1.8-2.6-3.5-.2-1.7 .2-4 1.6-6.9l-.6-.3ZM149.8 72.1l-.5-.5c-5.3 6-8 11.1-8.7 15.2-.7 4 .6 7 3.1 8.5 2.4 1.4 5.8 1 9.1-1 3.3-2.1 6.5-5.9 8.9-11.8l-.7-.2-.6-.3c-2.3 5.7-5.4 9.3-8.4 11.1-3 1.9-5.8 2-7.7 1-1.8-1.1-2.9-3.4-2.3-7.1 .6-3.7 3.1-8.6 8.3-14.4l-.5-.5ZM84.5 9.8v-.6c-8.9 .8-15 2-18.8 3.4-1.9 .7-3.3 1.4-4.2 2.2-.9 .8-1.3 1.7-1.2 2.7l.7-.1h.6c0-.4 .2-.9 .9-1.6 .7-.6 1.9-1.3 3.7-2 3.6-1.3 9.5-2.5 18.4-3.3l-.1-.7ZM61 17.4l-.7 .1c.1 1 .8 1.8 1.6 2.4 .9 .7 2.1 1.2 3.5 1.6 2.8 .9 6.5 1.4 10.6 1.2l-.1-.7v-.6c-3.9 .1-7.5-.3-10.1-1.2-1.3-.4-2.4-.9-3.1-1.4-.7-.5-1-1-1.1-1.4h-.6ZM61 17.4l-.3-.6c-9.1 3.4-15.9 6.2-20.4 9.4-4.6 3.3-7 6.9-7.5 12.1h.7l.7 .1c.4-4.7 2.6-8 6.9-11 4.4-3.1 10.9-5.9 20.1-9.3l-.2-.7ZM28.2 54.5l.6-.4c-2.2-3.4-2.5-5.7-1.6-7.8 .4-1.1 1.2-2.2 2.3-3.4 1.2-1.2 2.7-2.5 4.4-4l-.4-.6-.5-.5c-1.7 1.5-3.3 2.9-4.5 4.2-1.2 1.3-2.1 2.5-2.6 3.8-1.1 2.7-.5 5.5 1.7 9l.6-.3ZM28.2 54.5l-.4-.6c-3.1 2.2-5.2 4.4-6.1 6.6-1 2.3-.7 4.5 .7 6.4 1.4 1.9 3.9 3.5 7.3 4.8 3.5 1.2 7.9 2.1 13.4 2.7v-.7l.1-.7c-5.4-.5-9.7-1.4-13-2.6-3.3-1.2-5.5-2.7-6.7-4.3-1.1-1.6-1.3-3.2-.6-5.1 .8-1.8 2.7-3.9 5.7-6l-.4-.5ZM43.1 73.7l-.3 .6c5.4 3.2 9.8 5.1 14.4 5.9 4.7 .8 9.7 .4 16.1-1l-.2-.7-.1-.6c-6.3 1.3-11.1 1.7-15.5 1-4.5-.8-8.7-2.6-14-5.8l-.4 .6ZM73.1 78.5l-.4 .5c3.3 3.1 7.8 3.9 14.3 3 6.5-.9 15.2-3.4 27-7.2l-.3-.7-.2-.6c-11.8 3.8-20.3 6.3-26.7 7.1-6.4 .9-10.4 .1-13.2-2.6l-.5 .5ZM116.9 95.8l.5-.5c-2.9-3.1-3.9-8.9-1.1-15.1l-.6-.3-.7-.2c-3 6.5-1.9 12.9 1.4 16.5l.5-.4ZM115.7 79.9l.6 .3c2.4-5.1 7.5-10.6 16.7-14.8l-.3-.7-.3-.6c-9.4 4.4-14.8 10-17.4 15.6l.7 .2ZM113.7 74.1l.3 .7c0 0 0 0-.1 0 0 0 0 0 0 0 0 0 .1 0 .2 .1 .1 .2 .3 .5 .5 1 .3 1 .5 2.5 .4 4h.7l.7 .1c0-1.7-.1-3.3-.5-4.5-.2-.6-.5-1.1-.8-1.5-.4-.4-.9-.7-1.6-.5l.2 .6ZM140.8 232.1l.5-.5c-6.1-6.4-9.7-11.9-10.7-17.1-.9-5.1 .7-10.2 5.4-15.9l-.6-.5-.5-.4c-4.8 5.9-6.6 11.4-5.6 17.1 1 5.6 4.8 11.3 11 17.8l.5-.5ZM162.6 244.6l-.3 .7c6.2 2.4 9.1 3.4 11.6 3.8l.1-.7 .1-.7c-2.3-.3-5.1-1.2-11.3-3.7l-.2 .6ZM184.4 190.8l-.6-.2c-3.8 12.4-5.2 24-6.3 34-.5 4.9-1 9.4-1.6 13.4-.6 4-1.4 7.4-2.5 10.2l.6 .2 .7 .3c1.2-2.9 1.9-6.4 2.6-10.5 .6-4 1-8.5 1.6-13.5 1-9.9 2.5-21.4 6.2-33.7l-.7-.2ZM174 248.4l-.6-.1c-.9 4-3 8.6-5.6 13.9-2.6 5.3-5.7 11.2-8.6 17.9l.7 .2 .6 .3c2.9-6.6 5.9-12.5 8.6-17.8 2.6-5.3 4.7-10 5.6-14.2l-.7-.2ZM159.9 280.3l-.7-.2c-3.5 8.1-2.6 16.2-2.5 23.7 .2 7.5-.3 14.4-6.3 20.3l.5 .5 .4 .5c6.4-6.4 7-13.8 6.8-21.3-.1-7.7-1-15.4 2.4-23.2l-.6-.3ZM171.7 296.2h.6c-.7-15.7 1.4-23.5 5.7-30.3 2.2-3.4 4.9-6.6 8.2-10.5 3.3-3.9 7.2-8.3 11.5-14.3l-.6-.4-.5-.4c-4.3 5.9-8.1 10.4-11.4 14.2-3.3 3.8-6.1 7.1-8.4 10.7-4.5 7.1-6.6 15.2-5.8 31h.7ZM225.7 188.6l-.6-.3c-11.8 23.3-20 40.2-28.5 52l.5 .4 .6 .4c8.6-11.9 16.8-29 28.6-52.2l-.6-.3ZM150.9 324.6l-.5-.5c-.8 .8-1.3 1.6-1.2 2.5 .1 .9 .6 1.5 1.3 2.1 .6 .6 1.5 1.1 2.5 1.6 .5 .3 1 .6 1.5 .8 .6 .3 1.1 .6 1.7 .9 2.2 1.2 4.5 2.7 6 4.6 1.6 1.9 2.5 4.3 1.9 7.6l.7 .1 .7 .2c.6-3.7-.4-6.6-2.2-8.7-1.8-2.2-4.2-3.7-6.5-5-.5-.3-1.1-.6-1.6-.9-.6-.3-1.1-.5-1.6-.8-.9-.5-1.7-1-2.3-1.4-.5-.5-.7-.9-.7-1.2-.1-.3 .1-.7 .7-1.4l-.4-.5ZM231.4 284.9l-.7-.3c-3.3 6.9-6.3 13.7-9.1 20-2.8 6.3-5.3 12.2-7.7 17.3-2.4 5.2-4.7 9.6-6.8 12.9-2.1 3.3-4.1 5.4-6 6.3l.3 .6 .3 .6c2.2-1 4.4-3.4 6.6-6.8 2.1-3.4 4.4-7.8 6.8-13 2.4-5.1 5-11 7.8-17.4 2.8-6.3 5.8-13 9.1-19.9l-.6-.3ZM201.4 341.7l-.3-.6c-8.8 4.1-18 5.4-24.9 5.4-3.4 0-6.3-.3-8.2-.9-1-.2-1.7-.5-2.1-.8-.5-.3-.4-.4-.4-.3l-.7-.2-.7-.1c-.1 .8 .5 1.4 1.1 1.8 .6 .4 1.4 .7 2.5 1 2 .5 5 .9 8.5 .9 7.1 0 16.5-1.4 25.5-5.6l-.3-.6ZM201.4 341.7l-.1 .7c7 1.1 13.7 1.3 19.7 1.6 6.1 .3 11.5 .7 15.9 1.9l.2-.6 .2-.7c-4.6-1.3-10.2-1.7-16.2-2-6.1-.2-12.7-.5-19.6-1.6l-.1 .7ZM257.7 342.1l.6 .1c.5-2.8 .8-5.5 1.1-8 .4-2.5 .7-4.8 1-6.8 .7-4.1 1.5-7.1 2.8-8.9l-.6-.4-.5-.4c-1.6 2.1-2.4 5.4-3.1 9.5-.3 2-.6 4.3-.9 6.8-.3 2.5-.7 5.2-1.1 8l.7 .1ZM265.7 284.9l-.7-.2c-3.4 11.8-3 18.8-3 33.4h.6 .7c0-14.6-.3-21.5 3-33l-.6-.2ZM265.7 284.9l.6 .2c.5-1.5 .4-3.6 .1-6-.2-2.5-.6-5.4-1-8.4-.7-6-1-12.5 .9-17.5l-.6-.3-.7-.2c-2 5.3-1.6 12.2-.9 18.2 .3 3.1 .7 5.9 1 8.3 .2 2.5 .3 4.3-.1 5.5l.7 .2ZM265.7 252.9l.6 .3c1.1-2.9 1.8-5.3 2-7.7 .1-2.3-.3-4.5-1.4-6.9l-.6 .3-.6 .3c1 2.2 1.4 4.1 1.2 6.2-.1 2.2-.8 4.5-1.9 7.3l.7 .2ZM266.3 238.9h.7c-.3-20.4 2.4-32.4-3-53.3l-.6 .2-.7 .2c5.3 20.6 2.6 32.3 2.9 52.9h.7ZM263.4 185.8l.6 .3c1.4-3 2.2-5.4 1.8-7.7-.3-2.3-1.8-4.2-4.5-6.5l-.4 .6-.4 .5c2.5 2.1 3.7 3.9 4 5.6 .3 1.9-.3 3.9-1.7 6.9l.6 .3ZM260.9 172.5h.7v-1.4h-.7-.7v1.4h.7ZM260.9 171.1l.3 .6c.5-.2 1-.5 1.4-.8 .4-.3 .7-.8 .8-1.4 0-.5-.1-1.1-.5-1.7-.3-.7-.8-1.4-1.5-2.3l-.5 .4-.5 .4c.6 .9 1.1 1.5 1.3 2.1 .3 .5 .3 .8 .3 1 0 .1-.1 .3-.3 .5-.2 .1-.6 .3-1.1 .6l.3 .6ZM260.9 165.9l.5 .5c1.3-1.4 2.8-1.5 4.2-1.8 .7-.1 1.5-.3 2.1-.8 .6-.5 1-1.3 1-2.4h-.7l-.7-.1c0 .9-.2 1.3-.5 1.5-.3 .2-.7 .3-1.4 .5-1.3 .2-3.3 .4-5 2.1l.5 .5ZM268 161.4h.7c.1-1.4-.6-2.7-2-3.6-1.4-.9-3.5-1.4-6.5-1.3v.6l.1 .7c2.8-.1 4.6 .4 5.7 1.1 1 .7 1.4 1.6 1.3 2.4l.7 .1ZM239.1 78.1l-.5 .5c2.6 2.6 8 6.9 13.2 9.2 2.6 1.1 5.3 1.8 7.6 1.4 1.1-.2 2.2-.7 3.1-1.5 .9-.8 1.6-2 2.1-3.5l-.6-.2-.7-.2c-.4 1.3-1 2.2-1.7 2.9-.7 .6-1.5 1-2.5 1.1-1.9 .4-4.2-.2-6.7-1.3-5-2.1-10.3-6.3-12.8-8.9l-.5 .5ZM222.5 64l-.3 .6c12.9 6.6 20.6 12 26.5 15.6 5.8 3.6 9.9 5.5 15.4 4.5l-.1-.7-.1-.7c-5 .9-8.7-.7-14.5-4.2-5.8-3.6-13.7-9.1-26.6-15.7l-.3 .6ZM222.3 59.2l-.4 .6c8.3 5 15.8 9.5 22.1 12.9 3.1 1.7 5.9 3.1 8.3 4.2 2.5 1 4.5 1.7 6.2 1.9l.1-.7 .1-.7c-1.5-.2-3.4-.8-5.8-1.8-2.4-1-5.2-2.4-8.3-4.1-6.2-3.3-13.7-7.9-21.9-12.9l-.4 .6ZM222.3 59.2l-.5 .5c7.3 6.8 17 12.7 24.5 16.2 3.8 1.8 7.1 3.1 9.4 3.6 .5 .1 1.1 .2 1.5 .3 .4 0 .8 0 1.2-.1 .3-.1 .7-.3 .9-.7 .2-.5 .1-.9-.1-1.2l-.6 .3-.6 .3c.1 .2 0 .2 0 .1 .1-.1 .2-.1 .1-.1-.2 0-.4 0-.8 0-.3 0-.8-.1-1.3-.2-2.1-.5-5.3-1.7-9.1-3.5-7.5-3.5-17-9.3-24.1-16l-.5 .5ZM237.1 345.3l-.2 .6c.4 .2 1.1 .2 1.9 .3 .9 0 2.1 0 3.3 0 2.6-.1 5.7-.3 8.6-.9l-.1-.6-.2-.7c-2.8 .5-5.8 .7-8.3 .8-1.3 0-2.4 0-3.2 0-.9 0-1.4-.1-1.6-.2l-.2 .7ZM250.6 344.7l.1 .6c2.9-.5 5.7-1.3 7.4-2.7l-.4-.5-.5-.5c-1.4 1.1-3.9 1.9-6.8 2.4l.2 .7ZM249.4 297.2l-.3-.6c-9.2 4.7-14.6 16.9-14.9 27.7-.1 5.5 1 10.7 3.7 14.6 2.7 3.9 6.9 6.4 12.7 6.4v-.6-.7c-5.4 0-9.2-2.3-11.6-5.9-2.4-3.5-3.5-8.5-3.4-13.7 .3-10.6 5.5-22.2 14.1-26.6l-.3-.6ZM246.3 272.4l-.6-.2c-2 6.8-5.1 12.4-8.3 17.7-3.2 5.2-6.5 10.1-8.7 15.3-2.3 5.2-3.5 10.7-2.5 17.3 .9 6.5 4 14 10.3 23.2l.6-.4 .5-.4c-6.2-9-9.2-16.3-10.1-22.6-.9-6.2 .3-11.5 2.4-16.6 2.2-5 5.4-9.8 8.7-15.1 3.2-5.3 6.4-11 8.4-18l-.7-.2ZM92.6 23.9l-.2 .7c3 .5 6.7 .6 10.1 .8 3.6 .2 6.7 .5 8.7 1.2l.2-.7 .3-.6c-2.2-.8-5.6-1.1-9.1-1.3-3.5-.2-7.1-.3-9.9-.8l-.1 .7ZM111.4 25.9v-.7c-13.2 1.7-20.8 4.8-24.4 8.3l.5 .5 .5 .5c3.2-3.2 10.4-6.3 23.5-7.9l-.1-.7ZM87.5 34l.1-.7c-6.2-.8-11-1.1-15.5-.6-4.5 .4-8.8 1.6-14.1 3.5l.2 .6 .2 .7c5.3-1.9 9.5-3 13.8-3.5 4.4-.4 9-.2 15.2 .7l.1-.7ZM38.9 48.4h.6c0-1.5 .8-3.2 2.2-4.8 1.4-1.6 3.3-3.1 5.3-4.3 2.1-1.2 4.3-2 6.2-2.4 2-.4 3.6-.2 4.6 .5l.4-.6 .4-.5c-1.5-1-3.5-1.1-5.6-.7-2.2 .4-4.5 1.3-6.7 2.5-2.1 1.3-4.2 2.9-5.6 4.6-1.5 1.8-2.5 3.8-2.5 5.7h.7ZM87.5 34l-.5-.5c-1.3 1.3-2.1 2.7-2.4 4.1-.2 1.4 0 2.8 .6 4.1 1.3 2.5 4.1 4.7 7.6 6.1l.3-.6 .3-.7c-3.4-1.3-5.9-3.3-6.9-5.4-.6-1.1-.7-2.2-.5-3.3 .2-1 .8-2.2 2-3.3l-.5-.5ZM38.9 48.4h-.7c0 2.8 2.4 4.6 5.8 5.7 3.4 1.1 8.1 1.5 13.5 1.3 10.9-.3 24.5-3 35.9-7.6l-.3-.6-.3-.7c-11.1 4.6-24.6 7.2-35.3 7.5-5.3 .2-9.9-.2-13.1-1.2-3.3-1-4.9-2.5-4.9-4.4h-.6ZM102.6 49l-.2-.7c-11.9 4-23.7 6.7-33.9 8-10.3 1.2-18.9 1-24.6-.8l-.2 .6-.2 .6c6 2 14.8 2.2 25.1 .9 10.4-1.3 22.2-4 34.2-8l-.2-.6ZM132.5 41.8l-.1-.7c-6.7 .7-11 3.3-13 6.7-2 3.3-1.4 7.2 1.5 10.1l.5-.5 .5-.4c-2.5-2.5-2.9-5.8-1.3-8.6 1.6-2.8 5.5-5.3 11.9-6v-.6ZM121.4 57.4l-.5 .5c3.2 3.2 9 5.1 17.2 4l-.1-.7v-.7c-8 1.1-13.4-.8-16.1-3.5l-.5 .4ZM43.7 56.1l-.6 .3c3 6.8 11.6 11.5 24.8 12.4 13.2 .8 31.3-2.1 53.7-10.7l-.2-.7-.3-.6c-22.3 8.6-40.2 11.4-53.1 10.6-13-.9-20.9-5.4-23.6-11.6l-.7 .3ZM162.5 80.4h-.7c.2 5.9 .3 10.3 .6 14.8h.7l.7-.1c-.3-4.4-.5-8.9-.6-14.7h-.7ZM175.6 81.6l-.7-.2c-1.5 4.7-2.7 8.1-4.4 10.3-.8 1.1-1.8 1.8-2.9 2.3-1.2 .5-2.6 .6-4.5 .5v.7l-.1 .7c2 .1 3.6-.1 5.1-.6 1.4-.6 2.5-1.5 3.5-2.7 1.9-2.5 3.1-6.2 4.6-10.8l-.6-.2ZM175.6 81.6h-.7c.2 14.6 1.2 22 4.3 33.7l.7-.1 .6-.2c-3-11.7-4-18.9-4.2-33.4h-.7ZM231.1 109.6v.7c7.7-.2 13.3-1.6 18.3-2.7 5-1 9.4-1.6 14.9-.2l.1-.7 .2-.6c-5.8-1.5-10.4-.8-15.5 .2-5.1 1.1-10.5 2.5-18 2.7v.6ZM212.1 83.6l-.7 .1c.3 2.5 1.3 5.5 2.7 8.4 1.4 3 3.2 6 5.2 8.7 2 2.7 4.2 5.2 6.2 6.9 1 .8 2 1.5 2.9 2 1 .4 1.9 .7 2.7 .6v-.7l-.1-.6c-.5 0-1.1-.1-2-.5-.8-.4-1.7-1.1-2.6-1.9-1.9-1.6-4-3.9-6-6.6-1.9-2.6-3.7-5.6-5.1-8.5-1.4-2.9-2.3-5.6-2.5-7.9h-.7ZM218.2 130.5l-.1 .7c20.3 3.2 35.2-6 38-19.7l-.7-.2-.6-.1c-2.6 12.8-16.6 21.8-36.5 18.6l-.1 .7ZM182.7 178.1l.6 .1c1-9.2 8.4-24 22.9-40.9l-.5-.5-.5-.4c-14.6 17-22.2 32-23.2 41.7h.7ZM135.4 198.1l-.6 .3c1.7 4.2 4.1 7 7.2 8.3 3.1 1.3 6.7 1 10.7-.7 8.1-3.5 18.4-12.7 30.5-27.4l-.5-.5-.6-.4c-12.1 14.7-22.1 23.7-29.9 27-3.9 1.7-7.1 1.9-9.7 .8-2.6-1.1-4.8-3.6-6.4-7.6l-.7 .2ZM168.1 177.7l-.4-.5c-4.5 3.3-9.1 5.1-13.4 6.5-4.2 1.5-8.3 2.6-11.7 4.5l.3 .6 .4 .6c3.2-1.8 7.1-2.9 11.5-4.4 4.3-1.4 9.1-3.3 13.7-6.7l-.4-.6ZM142.9 188.8l-.3-.6c-3.6 2-6.4 4.8-7.8 9.7l.6 .2 .7 .2c1.3-4.5 3.9-7.1 7.2-8.9l-.4-.6ZM142.9 188.8l-.1 .7c7.9 2 14.2 2.4 20.4 .7 6.2-1.7 12.2-5.4 19.9-11.5l-.4-.6-.5-.5c-7.6 6.1-13.5 9.7-19.4 11.3-5.9 1.6-11.9 1.2-19.7-.8l-.2 .7ZM140.8 232.1h-.7c.2 3.5 1.8 6.9 4.2 9.7l.6-.5 .5-.4c-2.3-2.6-3.7-5.8-4-8.9l-.6 .1ZM144.9 241.3l-.6 .5c4.4 5 11.7 7.8 18.6 3.4l-.3-.6-.4-.5c-6.2 3.9-12.7 1.5-16.8-3.2l-.5 .4ZM144.9 241.3v.7c9.4-.5 17.4-3.8 22.9-10.4 5.5-6.6 8.4-16.3 7.8-29.7h-.6l-.7 .1c.5 13.1-2.4 22.5-7.6 28.7-5.2 6.3-12.8 9.4-21.9 10l.1 .6ZM209.8 140.6l-.5-.4c-5.4 7.2-8.8 15.8-9.1 37.5h.7l.6 .1c.4-21.6 3.8-29.9 8.9-36.7l-.6-.5ZM216.4 182.8l.6-.2c-6.5-16.7-11-28-6.5-41.7l-.7-.3-.6-.2c-4.7 14.3 0 26.1 6.6 42.7l.6-.3ZM225.7 188.6l-.6-.3c-8.7 22.5-17.1 40.7-23.3 54.8-3.1 7-5.7 13.1-7.4 18.2-1.7 5-2.6 9.2-2.4 12.4h.7 .7c-.2-3 .6-6.9 2.3-12 1.7-5 4.2-11 7.3-18.1 6.2-14.1 14.7-32.3 23.3-54.8l-.6-.2ZM260.9 172.5l-.1-.7c-2.7 .4-6.5 2.1-10.7 4.7-4.3 2.6-8.9 6.3-13.3 10.6-8.7 8.6-16.2 20-16.4 31.9h.7 .7c.1-11.3 7.4-22.5 16-31 4.3-4.2 8.8-7.8 13-10.4 4.1-2.6 7.8-4.1 10.2-4.5l-.1-.6ZM221.1 219l-.6-.3c-1.4 2.4-3.8 6.4-6.7 11.2-3 4.8-6.4 10.3-9.6 15.9-3.2 5.6-6.2 11.2-8.5 16.1-1.1 2.4-2 4.7-2.7 6.7-.6 1.9-1 3.7-1 5.1h.7 .7c0-1.2 .3-2.8 .9-4.7 .7-2 1.6-4.2 2.7-6.6 2.2-4.8 5.2-10.3 8.4-15.9 3.2-5.6 6.6-11.1 9.5-15.9 2.9-4.8 5.4-8.8 6.8-11.3l-.6-.3ZM238 216l-.6-.3c-4.7 8.5-11.4 16.1-18.8 24.6-7.4 8.5-15.4 17.9-22.8 30l.6 .3 .6 .4c7.3-12 15.3-21.3 22.7-29.8 7.3-8.5 14.1-16.2 18.9-24.9l-.6-.3ZM187.1 299.6l.6 .2c3-14.4 9.2-24.3 29.4-45.8l-.5-.5-.5-.4c-20.2 21.5-26.6 31.6-29.7 46.4l.7 .1ZM231.4 284.9l-.3-.6c-5 2.2-9.5 5.9-13.7 10.2-4.2 4.2-8 9.1-11.5 13.5-3.6 4.4-6.8 8.4-9.7 11-3 2.7-5.5 3.7-7.7 2.9l-.3 .6-.2 .6c3 1.2 6-.3 9.1-3 3-2.7 6.3-6.8 9.8-11.2 3.6-4.5 7.4-9.3 11.5-13.5 4.1-4.2 8.5-7.8 13.2-9.9l-.2-.6ZM239.8 220.4l-.7-.2c-7.8 33.9-13.7 52-30.7 80.9l.6 .3 .6 .4c17.1-29 23-47.3 30.9-81.3l-.7-.1Z" /> From 0d302f9185dfae091f86d7740a804435e37bc341 Mon Sep 17 00:00:00 2001 From: JingMatrix Date: Tue, 1 Sep 2026 15:37:44 +0200 Subject: [PATCH 4/4] Keep one implementation of the label that scrolls its own text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ScrollingLabel arrived beside three inline spellings of itself rather than in place of them: the module name in the list, the module name again in the scope screen's title, and the version inside UpdatableVersion. Each had decided for itself how long a name should keep moving — one pass after two seconds, one after three, three passes — which is four kinds of motion for one idea, and on the modules list two of them are on the same row. They all come through it now, and the pause and the number of passes are named constants in that one file, because nobody choosing a delay at a call site is thinking about the other four. The scope title's three passes settle to one with everything else; a title that goes over three times on a screen someone is working down is the reason the rule is worth having. The ellipsis goes where it was wrong: a marquee draws its text past the edge, so UpdatableVersion keeps TextOverflow.Ellipsis only on the branch that cannot scroll. ModulesScreen was importing basicMarquee and not using it. --- .../kotlin/org/matrix/vector/ui/ModuleRow.kt | 15 +++----- .../org/matrix/vector/ui/ScrollingLabel.kt | 38 ++++++++++++++----- .../org/matrix/vector/ui/UpdatableVersion.kt | 25 ++++++------ .../ui/screens/modules/ModulesScreen.kt | 1 - .../manager/ui/screens/modules/ScopeScreen.kt | 23 +++++------ 5 files changed, 56 insertions(+), 46 deletions(-) diff --git a/manager-ui/src/main/kotlin/org/matrix/vector/ui/ModuleRow.kt b/manager-ui/src/main/kotlin/org/matrix/vector/ui/ModuleRow.kt index ff9d1325e..367187a54 100644 --- a/manager-ui/src/main/kotlin/org/matrix/vector/ui/ModuleRow.kt +++ b/manager-ui/src/main/kotlin/org/matrix/vector/ui/ModuleRow.kt @@ -2,7 +2,6 @@ package org.matrix.vector.ui import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background -import androidx.compose.foundation.basicMarquee import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -182,16 +181,14 @@ fun ModuleRow( // The title's band. Both halves are fixed and both scroll, so however long a name or // version string becomes neither can reach the other. Row(verticalAlignment = Alignment.CenterVertically) { - Text( + ScrollingLabel( text = name, - style = MaterialTheme.typography.titleMedium, - fontWeight = FontWeight.SemiBold, + style = + MaterialTheme.typography.titleMedium.copy( + fontWeight = FontWeight.SemiBold + ), color = nameColor, - maxLines = 1, - overflow = TextOverflow.Clip, - modifier = - Modifier.weight(1f) - .basicMarquee(iterations = 1, repeatDelayMillis = 3_000), + modifier = Modifier.weight(1f), ) if (versionName.isNotBlank()) { Spacer(Modifier.width(10.dp)) diff --git a/manager-ui/src/main/kotlin/org/matrix/vector/ui/ScrollingLabel.kt b/manager-ui/src/main/kotlin/org/matrix/vector/ui/ScrollingLabel.kt index d9b2cfa04..6306a8b41 100644 --- a/manager-ui/src/main/kotlin/org/matrix/vector/ui/ScrollingLabel.kt +++ b/manager-ui/src/main/kotlin/org/matrix/vector/ui/ScrollingLabel.kt @@ -9,17 +9,35 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.TextStyle /** - * A label that scrolls its own text past rather than taking the width of whatever sits beside it. + * How long the text waits before it moves, and how many times it goes. * - * Version names are written by whoever published the release, not by us, and a repository will hand - * back things like `1.58.245-ai-ui-label+B520-20260828T1203Z-full`. Left to wrap, one of those eats - * the whole row and squeezes its neighbour — a date, a chevron — into a column one character wide, - * which is unreadable in a way that looks like a rendering fault rather than a long name. + * One pass, after a pause long enough to read the beginning of the line first. A label that keeps + * moving is a distraction on a screen someone is working on, and a label that starts moving the + * instant it appears is read from the middle. It says its piece once and settles. * - * So the rule the modules list already follows applies wherever a published version is drawn: the - * label is one line inside a bounded width, and the part that does not fit scrolls past once. The - * caller gives it that width — usually `Modifier.weight(1f, fill = false)`, which hands the row's - * fixed parts their natural size first and leaves this with the remainder. + * These live here and nowhere else. Two labels that scroll at different speeds on the same screen + * look like two kinds of thing, and nobody choosing a delay at a call site is thinking about the + * other four. + */ +private const val PASSES = 1 +private const val PAUSE_MS = 2_000 + +/** + * One line of text that scrolls itself rather than being cut short or taking a neighbour's width. + * + * The names this app draws are written by other people — a module's title, a package, a version + * name a repository hands back like `1.58.245-ai-ui-label+B520-20260828T1203Z-full` — and any of + * them can be longer than the row it lands in. Wrapping is not an option in a fixed row: the text + * eats its neighbour, and a date beside it ends up a column one character wide. Truncating is + * usually worse than it looks, because the tail is so often the part that tells two builds apart. + * + * So the line is one line inside whatever width the caller gives it — usually + * `Modifier.weight(1f, fill = false)`, which serves the row's fixed parts first and leaves this the + * remainder — and the part that does not fit scrolls past once. + * + * The whole of it is here so that it is one behaviour. Everything that scrolls a name in either + * manager comes through this: the modules list, the scope screen's title, a version with an update + * mark on it, and the three places the store prints a release's name. */ @Composable fun ScrollingLabel( @@ -34,6 +52,6 @@ fun ScrollingLabel( color = color, maxLines = 1, softWrap = false, - modifier = modifier.basicMarquee(iterations = 1, repeatDelayMillis = 2_000), + modifier = modifier.basicMarquee(iterations = PASSES, repeatDelayMillis = PAUSE_MS), ) } diff --git a/manager-ui/src/main/kotlin/org/matrix/vector/ui/UpdatableVersion.kt b/manager-ui/src/main/kotlin/org/matrix/vector/ui/UpdatableVersion.kt index 8439489ff..9c1cdf7e5 100644 --- a/manager-ui/src/main/kotlin/org/matrix/vector/ui/UpdatableVersion.kt +++ b/manager-ui/src/main/kotlin/org/matrix/vector/ui/UpdatableVersion.kt @@ -5,7 +5,6 @@ import androidx.compose.animation.core.animateFloat import androidx.compose.animation.core.infiniteRepeatable import androidx.compose.animation.core.rememberInfiniteTransition import androidx.compose.animation.core.tween -import androidx.compose.foundation.basicMarquee import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -50,7 +49,7 @@ fun UpdatableVersion( text: String, hasUpdate: Boolean, modifier: Modifier = Modifier, - /** Whether an over-long version scrolls past instead of being cut. */ + /** Whether an over-long version scrolls past, as [ScrollingLabel], instead of being cut. */ marquee: Boolean = false, style: TextStyle = Mono, color: Color = LocalContentColor.current, @@ -81,15 +80,17 @@ fun UpdatableVersion( ) Spacer(Modifier.width(5.dp)) } - Text( - text = text, - style = style, - color = if (hasUpdate) markColor else color, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - modifier = - if (marquee) Modifier.basicMarquee(iterations = 1, repeatDelayMillis = 2_000) - else Modifier, - ) + val ink = if (hasUpdate) markColor else color + // Ellipsised only where it cannot scroll: a marquee draws its own text past the edge, and + // an ellipsis on top of that is a full stop in the middle of a moving line. + if (marquee) ScrollingLabel(text = text, style = style, color = ink) + else + Text( + text = text, + style = style, + color = ink, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) } } diff --git a/manager/src/main/kotlin/org/matrix/vector/manager/ui/screens/modules/ModulesScreen.kt b/manager/src/main/kotlin/org/matrix/vector/manager/ui/screens/modules/ModulesScreen.kt index d5e71533a..3496443fe 100644 --- a/manager/src/main/kotlin/org/matrix/vector/manager/ui/screens/modules/ModulesScreen.kt +++ b/manager/src/main/kotlin/org/matrix/vector/manager/ui/screens/modules/ModulesScreen.kt @@ -73,7 +73,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.graphics.Color import androidx.compose.foundation.background -import androidx.compose.foundation.basicMarquee import androidx.compose.ui.draw.clip import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.stringResource diff --git a/manager/src/main/kotlin/org/matrix/vector/manager/ui/screens/modules/ScopeScreen.kt b/manager/src/main/kotlin/org/matrix/vector/manager/ui/screens/modules/ScopeScreen.kt index 94606d0a9..d6b76db81 100644 --- a/manager/src/main/kotlin/org/matrix/vector/manager/ui/screens/modules/ScopeScreen.kt +++ b/manager/src/main/kotlin/org/matrix/vector/manager/ui/screens/modules/ScopeScreen.kt @@ -41,7 +41,6 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.basicMarquee import androidx.compose.foundation.border import org.matrix.vector.ui.contextClickable import androidx.compose.foundation.shape.CircleShape @@ -112,6 +111,7 @@ import org.matrix.vector.ui.show import org.matrix.vector.manager.ui.components.PackageActionResult import org.matrix.vector.manager.ui.components.PackageActionSheet import org.matrix.vector.ui.SearchField +import org.matrix.vector.ui.ScrollingLabel import org.matrix.vector.ui.theme.Mono class ScopeViewModelFactory(private val packageName: String, private val userId: Int) : @@ -262,20 +262,15 @@ fun ScopeScreen( TopAppBar( title = { Column { - Text( + // The column is a fixed slice of one row, and module names are not. + // Rather than truncate the end of a name — often exactly the part that + // distinguishes two builds of the same module — it scrolls itself. + ScrollingLabel( text = state.moduleName, - style = MaterialTheme.typography.titleMedium, - fontWeight = FontWeight.SemiBold, - maxLines = 1, - softWrap = false, - // The column is a fixed slice of one row, and module names are not. - // Rather than truncate the end of a name — often exactly the part that - // distinguishes two builds of the same module — it scrolls itself. - // - // Finite, not endless: this is a screen someone sits on while working - // through a long list, and a title that never stops moving is a - // distraction. It says its piece and settles. - modifier = Modifier.basicMarquee(iterations = 3), + style = + MaterialTheme.typography.titleMedium.copy( + fontWeight = FontWeight.SemiBold + ), ) Text( text = packageName,