[HN Gopher] Making a music library without a SPA
___________________________________________________________________
Making a music library without a SPA
Author : todsacerdoti
Score : 217 points
Date : 2023-09-29 15:04 UTC (1 days ago)
(HTM) web link (begin.com)
(TXT) w3m dump (begin.com)
| Signez wrote:
| At first, I thought it was a good exercise (and it still is), but
| going through the result [0] made me more skeptical.
|
| It is... slow? I mean, Internet Explorer slow. Maybe I'm spoiled
| by the level of responsiveness of application-style web
| interfaces, but opening an album or returning to the library
| feels _slow_. Is it because I 'm browsing from Western Europe and
| the application is hosted in the USA?
|
| I'm used to browsing multi-page apps that don't pretend to be
| apps, and having a 500ms load time after a click is expected and
| feels right. But waiting the same time for a click in a page that
| looks like an app makes me uncomfortable. It's weird - is this
| the Uncanny Valley again?
|
| [0] : https://enhance-music.com
| BeefySwain wrote:
| Can you expand on what you mean by slow? For me everything
| loaded extremely fast.
| slotrans wrote:
| the main page loads fast but the interactions are slow, like
| there's some artificial delay
|
| the 500ms estimate above seems about right... it should be
| much faster. Navigating from one static page to another
| should be sub-100ms assuming the server is on the same
| continent
| [deleted]
| 38 wrote:
| I agree with other commenter, works fast for me.
| sexy_seedbox wrote:
| Yep, the site is very slow in Southeast Asia.
| meowtimemania wrote:
| This is what I got going from the main page to an album page:
|
| 55ms for html, 67ms for css, 15ms for webp image.
|
| I'm in bay area so it might be slower in other places
| beebeepka wrote:
| Runs slow, not loads slow. Also, what bay area. There must be
| thousands of bay areas on a planet covered by 2/3 water
| cdogl wrote:
| The one associated with this website.
| hcks wrote:
| What planet? There's billions out there too
| wizofaus wrote:
| Could be the cargo bay area of a huge alien star ship...
|
| (Btw from my own bay area of a certain SE Australian
| state it does feel a little laggy when navigating, but
| quite usable)
| eddythompson80 wrote:
| It's a bit US (and tech) centric, but Bay Area is short for
| the San Francisco Bay Area.
| layer8 wrote:
| This is where upper case actually makes a difference.
| Maybe that's what the parent was alluding to.
| Hrun0 wrote:
| Looks like the enhance-styles.css doesn't get cached properly
| and gets requested on every route. The browser then waits for
| 500ms for a response from a server, likely due to increased web
| traffic.
|
| An issue which could have been avoided by using a SPA :D
| donperignon wrote:
| So the solution to cache a resource it's to use an SPA? why
| not find the reason for this css not being cached and solve
| it?
| discordance wrote:
| Very fast for me.
| zelphirkalt wrote:
| And now imagine, that this approach was hyped to no end and
| suddenly everyone was building every web_app_ this way, maybe in
| some fancy framework for it ... is basically what happens in
| frontend land but the other way around, web_sites_ being build as
| SPAs.
| meiraleal wrote:
| In the source code I see a lot of JavaScript, usage of service
| workers (the tech behind web apps) and a not great general UX,
| besides an herculean work to make it work for 1% of the users in
| the world that navigate the web without JS enabled.
|
| The code quality is great and enhance framework is top notch
| quality, I'm happy to see this as I'm building something similar
| ("build your entire app with accessible HTML") but without making
| 1% of the users the main selling point.
| Alifatisk wrote:
| My only concern is not being able to share the state of the page
| with others.
|
| I feel like that is a necessity.
| arendtio wrote:
| Am I getting old? As far as I can tell, this is what we were
| doing before JS became the mighty weapon it is today (like
| pre-2005).
|
| So if you don't like JS, this is a pattern you might want to
| revive, but I can hardly believe, that we want to go back to that
| world as a standard for web development.
| meiraleal wrote:
| Not with this quality nor was it tried with modern tech. New
| times, new ways to do the same thing. I would prefer to code
| using this Enhance framework used by to develop this app than
| React.
| simonbarker87 wrote:
| If you look at things like htmx and the principles that
| underpin that many would say the past 15 years have been a
| holding pattern waiting for browser APIs to catch up and
| provide a decent front end experience.
|
| Personally I love working on in an "older" style way here the
| server just sends html to the browser and we don't need to
| built an app twice (once in the fronted and once in the back
| end).
|
| The real magic comes in having the older, full stack approach,
| sprinkling in JS as needed and then having modern CI/CD for
| deployments.
| pjmlp wrote:
| We not only want to in name of performance, the new folks are
| rediscovering gunpowder as we say back home, adding SSG and SSR
| to SPA frameworks.
| 38 wrote:
| damn, this is fucking awesome:
|
| https://enhance-music.com
|
| you can disable 3rd-party, 1st-party and even inline JavaScript,
| and it keeps working.
| high_priest wrote:
| I feel uneasy when everything goes blank on click and the back
| button doesn't get my a page higher in irder, but the previous
| song. :(
| revskill wrote:
| What i love about JS and AJAX is it "fixed" the "double submit"
| problem in pure MPA :))
| unlog wrote:
| It doesn't have a volume control, I really can't understand the
| point of these "minimal UIs" that don't have the very most basic
| needed _feature_.
| doublepg23 wrote:
| Shouldn't that be handled by the native platform?
|
| I have a thinkpad from 2008 with dedicated volume keys...
| unlog wrote:
| No, because I could be playing a game with its own volume,
| while also being in a webrtc call with someone on another
| tab. Volume control for a music player is no-brainer.
| promiseofbeans wrote:
| That's not a problem with the whole concept, it's just a
| problem with how they did it. Volume controls are built in to
| the native music player element
| unlog wrote:
| Yep, that's right. The "mini player" on Windows has exactly
| the same problem. Its a big box of 200x100~ pixels or so and
| it doesnt include a volume control, you have to exit the mini
| player. I do not understand the reasoning of such decisions,
| really. It maybe looks cute but It's pretty useless.
| zelphirkalt wrote:
| Not so long ago I had this problem on bandcamp too, but they do
| not attempt to run without JS at all. I regulated volume for
| the website in my OS instead. However, when it switches to the
| next track, it would blast off my ears again. This issue is not
| limited to websites like the one linked here.
| llIIllIIllIIl wrote:
| Removing JavaScript from your frontend means you have one less
| application, build system, dependencies and oncall schedule to
| maintain. Love to the authors, wonderful job.
| meiraleal wrote:
| You can just remove the build system and most dependencies from
| a JS app. Modern JS is great if you are ok to serve 85-90% of
| world audience.
| LeoPanthera wrote:
| I remember back in the 90s, web pages could have persistent music
| by using a frameset. Put the player in one frame, and the browser
| in the other frame.
|
| Frames were generally a bad idea, but I always wondered what
| exactly was wrong with this one. Seems like a reasonable idea,
| and you wouldn't even need Javascript!
| Gigachad wrote:
| What's the issue with using JS? Seems like the perfect tool for
| the job here.
| notatoad wrote:
| the biggest problem, at least for me, is that it breaks links -
| you can only link to the frameset, not the actual page, and the
| url doesn't change on navigation.
|
| unless you start doing javascript address bar manipulations, in
| which case you've got both an SPA and frames.
| LeoPanthera wrote:
| Is this really that different to javascript applications
| where the state does not alter the URL? Which seems to be
| most of them.
| gherkinnn wrote:
| Interesting exercise. It explores the upper bounds of what can be
| done this way and proves that forms and links don't need to be an
| SPA monstrosity.
|
| But comparing this to the linked Astro version [0], Astro wins
| hands down. It feels faster, URL works, and behaves more
| predictably.
|
| Turns out a music player is best built using SPA-y tech. And it
| is possible not to build a monstrosity along the way. These so-
| called island architectures are right on the money. It is server
| first, but breaking out of it and building some client side
| interaction is seamless when required.
|
| 0 - https://astro-records.pages.dev/
| benbristow wrote:
| Those albums sound a bit different! :)
| hcks wrote:
| Can we stop using expressions such as "SPA monstrosity" when
| this "unbloated HMTL" website breaks copying links, the back
| button, the address bar, don't cache ressources properly, etc
| etc
| jbreckmckye wrote:
| Give it a couple of years, people will bemoan the
| "Frankenstein" of partial server rendering, pine for the
| "consistency" of SPAs instead.
| jadbox wrote:
| The Astro version feels just like a SPA to me.
| sitzkrieg wrote:
| consider it browserwreck feature complete /s
| hrisng wrote:
| I agree. They did a very cool exercise. But let be honest here,
| most of the users today would not put up with a UX like that.
| Even for a tech person who is used to some very hostile UX day
| in and day out, I would still not use that if I have the
| option.
| meiraleal wrote:
| The Astro one is indeed not a SPA. But the original one is a
| SPA composed of multiple iframes. It is like old AJAX hacks.
| codeptualize wrote:
| To me this article and demo shows why we use SPA's, and how much
| modern frameworks actual do for you. It's hard to not see a whole
| lot of very basic problems in this demo that any modern framework
| would solve out of the box.
|
| The "SPA bad" arguments are also largely outdated. Most apps that
| are build now are at least hybrid, with some SSR getting best of
| both worlds, urls and navigation are solved, accessibility is
| improving with better component libraries linters and best
| practices, automatic bundle splitting, highly optimized caching
| of static assets, build tools with hot reloading as a standard
| option, static exports, etc etc.
|
| Getting a good Lighthouse score is not the flex it used to be
| (referring to the enhance movies demo), my all-JS Next.js app
| scores 100's without even trying.
|
| The only potential argument would be users not having JS enabled,
| which is not relevant to most apps and use cases. In most cases
| you do not want to degrade the experience of most (but more
| likely all) of your users, and with SSR you can have it all.
|
| Obviously build for your audience and use cases and apply
| technology that makes sense and I welcome experimentation with
| alternative approaches, but saying "spa bad" is imo not very
| productive.
| CSSer wrote:
| When I started in the industry, progressive enhancement as a
| concept was the theme du jour. As SPAs have gained prominence,
| I've sadly watched the drive to improve them and sometimes
| pushback against them morph this concept as it's taught to
| newcomers into "No JS" or "low JS" as a side effect. It lacks
| nuance.
|
| For example, your menus should work without JS but that doesn't
| mean they should work _as well_ as or _exactly the same way as_
| they do with JS disabled. There are many features and patterns
| that a11y /screenreader users (which I recognize I'm somewhat
| lumping in with the "I disable JS for X reason(s) crowd here)
| appreciate that are still impossible without JS. I've surprised
| people on a couple occasions by showing them how much JS is
| actually used to create many of the WAI-ARIA menu proof of
| concepts[0], for example.
|
| I think the "a11y is easy" crowd, well intentioned as it may
| be, is also partially to blame for this. I've read articles
| with titles like "How to do X with CSS only" that gloss over
| many UX downsides to the chosen approach.
|
| The sad reality is that a11y users represent another audience
| with a different set of formed expectations one needs to cater
| to, and fulfilling those expectations is not free more often
| than some would care to admit, especially when you consider how
| complex the differences in approaches between screen readers
| can be. This isn't an excuse to not help those users, but I
| have wondered before if we would be doing better if we were
| more scathing in our commentary on vendor standards as it
| relates to this. Who knows? Perhaps I'm naive.
|
| [0]
| https://www.w3.org/WAI/ARIA/apg/patterns/menubar/examples/me...
| RecycledEle wrote:
| SPA = Single Page Application
| meiraleal wrote:
| Correction: this is a SPA. Only even more over engineered than a
| nextjs or gatsby one.
| padjo wrote:
| It stops playing when I press the back button. I dunno if that's
| really working with the web platform.
| high_priest wrote:
| Now this looks greatx but xhe main reason I have been sticking to
| SPA frameworks is to persist and dynamically swap components like
| SiteMaps, Table of Contents, Cart lookups and chat windows. Is a
| similiar solution, based on iFrames going to replace this for me?
| toastal wrote:
| May as well go back to the original frames
| IceDane wrote:
| Lol is this really what you want to show the world?
|
| If you're going to take this trite stance, what you demo has to
| be really good.. and it's really not. The first I see is really
| bad FOUC which is weird when this should be mostly static html.
| Interacting with the website is then super janky: there is a
| noticeable delay when using the music player, it seems to "lag"
| when playing, and clicking on albums flashes the cover full
| screen for a second and then shows me the page.
|
| Lots of stuff like that. All in all, this is not the sort of
| thing I would want to put out there with this sort of message. I
| wouldn't want to hire a company that takes this sort of stance
| and then delivers garbage.
| zagrebian wrote:
| I browse the the web on desktop with JavaScript disabled by
| default. The demo works. I don't even need to know what
| enhancement are added with JavaScript. The basic HTML version is
| perfectly fine.
| abdellah123 wrote:
| Going through the docs, nothing there about how to edit state?
| renancouto wrote:
| Everything comes at a cost, in this case it was deep linking.
| Even though back and forward buttons work, navigating to an album
| won't update the URL which won't allow sharing and will be bad
| for search engines since all navigation points to the same URL.
| tgv wrote:
| That's fairly easy to fix (in principle; I don't know what
| their backend is; it might require JS).
|
| But there's so little value in the navigation, that I'm not
| surprised it works as an "MPA" (even though it feels janky).
| And that's all not done by JavaScript. The player, the
| animation, etc. still requires it. TBH, I don't see the point
| of this demonstration.
| tethys wrote:
| Just a side note: It bothers me a bit that most audio player
| interfaces make it unnecessarily difficult to navigate within a
| title. This here is a good example: The waveform extends across
| the entire width of the window and could be wonderfully used to
| jump precisely to the desired spot (Soundcloud does this
| comparatively well). Instead, I only have an extremely narrow bar
| here, where a few pixels of movement mean a jump of several
| seconds.
| montag wrote:
| It's also common to see a seek bar that is too thin and hard to
| click.
|
| This one is 19px tall: https://chiptune.app
| insin wrote:
| People tend to blame SPAs/JavaScript (instead of the people
| holding them) for breaking the address bar, the back button and
| the ability to open links in a new tab, but this does all three
| of those.
| zelphirkalt wrote:
| Does it? Or is playing another track conceptually a new page?
| asddubs wrote:
| IMO a new page is when you explicitly click something and
| most of the page changes
| [deleted]
| [deleted]
| sanitycheck wrote:
| Yeah, I just tried it and it's horrible!
|
| I'm all for making things work without JS, but demonstrating
| that my experience can be equally bad with plain HTML+CSS
| doesn't feel like an improvement.
|
| Anyway we can have SPAs with a working back button and a
| working address bar with sufficient competence and motivation.
| Links in a new tab would work if all the state was in the URL,
| but messy URLs are unfashionable these days.
| promiseofbeans wrote:
| The problem I see here is that it's not linkable - I can't see my
| current location in the url bar, which means I can't share it to
| other people. Maybe you could fix this with some JS?
|
| Cool idea though.
| [deleted]
| RockRobotRock wrote:
| Very opinionated, but the end result is beautiful. Looks like
| Apple Music.
| jwells89 wrote:
| Love to see this, and hope that things like it become more
| practical as the HTML standard develops further. While there's
| nothing wrong with JS in itself, the less that's required the
| better from several angles -- the big ones for me are less
| required dev work, less need for miles-long lists of
| dependencies, and better likelihood that the various components
| of the app are implemented consistently well since they're the
| responsibility of web engine maintainers instead of random
| library devs.
|
| For me personally web front end as a platform becomes
| progressively more interesting as HTML includes more robust
| widgets and functionality.
| zerbinxx wrote:
| Devil's advocacy here (and I know this is overwrought and
| beaten to absolute death here and abroad daily) but is a large
| dependency tree really that bad?
|
| Most modern backend development assumes a ton of dependency
| management, tech like Docker has proven for at least 10 years
| that it can be manageable in production at scale. While I get
| that browser compatibility can be a pain in a way that the
| backend doesn't have to reckon with I don't really see why
| dependency management for something like React should be a
| decision factor for front end.
|
| That's also not to insinuate that we should just do it (SPA +
| massive amounts of JS) because browsers can handle it or that
| there are zero downsides to JS dependency management, but
| rather that the positives and negatives of zero-JS solutions
| should be adjudicated on things like developer experience and
| speed of delivery.
| jwells89 wrote:
| I'm not an HTML purist, JS is fine, but I prefer to use it
| only where it's necessary.
|
| The main thing that's bad about massive dependency trees in
| my mind is that it makes them difficult to keep a mental map
| of, which makes for pain when things go awry. Most of the
| work I do is on iOS apps which is a generally more "batteries
| included" environment, and there most dependencies only go a
| level or two deep, which is reasonable to reason about and
| makes it more practical to track down problems. iOS apps also
| just don't need as many dependencies in the first place.
|
| It's not practical for web front end to require as few
| dependencies as e.g. iOS, but I think it's a worthwhile
| endeavor to push that line as far as it can go so it's more
| practical to develop a complex low-dependency web app.
| zelphirkalt wrote:
| Large dependency trees are usually not about using docker or
| not. That is rarely a dependency of the code itself. The
| complaint about large dependency trees is about hundreds or
| even thousands of dependencies of the code itself, where you
| could get away with maybe tens, if you write trivial code
| (left pad ...) yourself and avoided needlessly adding more
| stuff on top. Every time one adds a dependency, one should
| feel a little sting and make an uncomfortable face and
| remember, that this dependency might make things badly
| maintainable, difficult to upgrade, or vulnerable. Always ask
| oneself things like: "Did I read the code of that dependency
| and its dependencies? Do I really know what this code does?"
| and of course if one does now lock down that dependency to
| exactly one version, one would have to consider these things
| every time one upgrades dependencies.
|
| Now for a throwaway web app maybe one does not need to care.
| But then one should also label it as such. A throwaway,
| nothing to be taken as a good example. Definitely not
| production ready code.
| exabrial wrote:
| Absolutely beautiful and a relief of fresh of air from the
| dumpster fire that is SPAs.
| wg0 wrote:
| We're again swinging to the extremes.
| danjac wrote:
| I built a podcast library/player[1] using HTMX and Alpine, using
| Django as the backend. It has an audio player that would stay
| open and keep playing while the user navigates around the page.
| This is quite easy to do with HTMX.
|
| It's pretty simple - it's just for my own needs - but it works
| quite well. You can go far these days before needing an SPA.
|
| [1] https://github.com/danjac/radiofeed-app
| jddj wrote:
| I have to ask, partly because I went around this same circle in
| my head when evaluating htmx and deciding that it was cool
| enough but I didn't want every interaction to be a server round
| trip.
|
| What do you get from combining htmx with alpine that you
| wouldn't get more simply from just alpine?
|
| The way I saw it was that I'd end up with some state in the
| client, some on the server, some in json, some in html, my
| server would have to know how to render some components, the
| client others.. and for what benefit? Alpine can fairly easily
| do everything htmx does and it's one less framework to send to
| the user, one less thing independently watching and acting on
| the dom, one less dependency to manage, etc.
| danjac wrote:
| Alpine is just used for pure client lightweight interactions,
| such as toggling a menu (if CSS was insufficient) or (in this
| case) handling the audio player controls. Of course, I could
| even go more lightweight, and just use vanilla JS in such
| cases, but as both libraries are pretty small anyway it was
| easier to manage client DOM interactions with Alpine.
|
| There's no JSON in this site: the only pure non-HTML
| interaction is a "ping" where the audio player posts the
| latest play time of an episode every few seconds while
| running, so that if the user switches to another device, or
| closes the tab, they get the latest runtime of the last
| episode they were listening to.
|
| In terms of performance, I found there wasn't much difference
| between this approach and an SPA. For example, if I navigate
| from page A to page B in a React app, I still need to fetch
| JSON or GraphQL data for that new page, perhaps including
| multiple round trips to the server depending on the API
| design. With HTMX, I can just fetch a small HTML snippet: for
| example, if I click a "Subscribe" button, it just returns
| some new HTML showing "Unsubscribe" and updated URL or
| whatever. Sure you can do that with plain Alpine, but HTMX
| makes it easier to reason about state, which I'd need to
| otherwise manage client side (e.g. keeping a tally of all my
| subscribed podcasts).
|
| HTMX also provides solutions for things like updating state
| in multiple places: for example you if you have a shopping
| cart, and you want to update not only the cart itself but a
| counter widget in the navbar, you can do "out of band"
| responses that can insert snippets of content outside the
| main target. Again, totally doable with Alpine, but more work
| for me.
|
| And not every interaction has to be a server round-trip, you
| can certainly push work to the client side if needed, and use
| Alpine or vanilla JS or even React if you want: in a work
| project for example, we had most of the site in HTMX, but
| used React for a dashboard page with lots of complex
| interactive graphs and whatnot.
|
| As I said, it was a pretty simple app, certainly not as
| complex as Spotify. But given that the often repeated example
| of when to use an SPA is "running an audio player while
| navigating around the site", it makes me wonder why the need
| to reach for React or other SPA framework for even simpler
| needs.
| jddj wrote:
| Thanks, that was helpful and got me thinking.
|
| Indeed just using vanilla js was something that occurred to
| me, or drawing clear boundaries around where things happen
| which it sounds like you've done here. In the end I decided
| it wasn't going to be long before I wanted to do some basic
| sorting or filtering or something of nontrivial objects on
| the client and that was where my brain decided it was more
| effort than it was worth for whatever I was trying to
| prototype.
|
| I've largely settled at the moment on alpine multipage apps
| with traditional json rest APIs behind them and some light
| serverside templating for the initial loads, and the only
| thing so far that makes me reach for something heavier is
| if there's a lot of user-defined content and I want to feel
| confident of being able to run under a strict CSP.
|
| But it sounds like you landed on something that makes sense
| as well so thanks for the explanation.
| pier25 wrote:
| Zero JS makes sense in some cases but this seems more code
| golfing than a real product that users would love.
|
| I totally agree bloated SPAs are terrible and in most cases an
| MPA is the best option. But a bit of JS is certainly fine when it
| makes for a better experience. Even HN uses a bit of JS.
|
| And what's the point of having all this bandwidth and CPU power
| available if we're not going to use it? (even one tiny bit)
| thewakalix wrote:
| > With our 'zero JavaScript' happy paths now covered, we can
| have a little more fun when JavaScript is available in the
| browser.
| gherkinnn wrote:
| JS is available in the browser unless someone knowingly
| disables it. It is a standard.
| chrismorgan wrote:
| JS will fail to execute _a lot_ more often than most people
| realise, e.g. due to poor network conditions, particularly
| if hosted on a different origin (first-party JS is far more
| reliable, and inline JS the most reliable).
| pier25 wrote:
| > _e.g. due to poor network conditions_
|
| Do you have any metrics on this? Seems like an extremely
| rare edge case.
|
| Anecdotally, I haven't experienced it in years.
| o11c wrote:
| The (semi-old) UK stats said 1.1% failure rate, but
| somebody more recent said it had increased to 3%.
|
| That's a lot.
| gherkinnn wrote:
| Somebody said is a bad source. 3% failure seems too high
| given nearly everything requires JS.
| flagrant_taco wrote:
| There's a huge gap between some JS and Spas though. The
| question for me is always where data is rendered to markup, not
| whether it uses JS in the browser at all.
| masklinn wrote:
| > And what's the point of having all this bandwidth and CPU
| power available if we're not going to use it? (even one tiny
| bit)
|
| It's there when you need it? Using less bandwidth and cpu means
| using less battery.
| ptx wrote:
| TL;DR: They used an iframe for the content.
|
| But this brings with it the navigation issues that were the
| reason we abandoned frames: The URL in location bar no longer
| reflects the location of the specific page, so it can't be
| bookmarked easily. Also, when opening in a link in a new tab, we
| get the reverse of this problem in that the other frames are
| lost.
|
| You could solve this with JavaScript that updates the location, I
| suppose, but then the result is essentially an SPA.
| whoiscroberts wrote:
| Where are my HTMX people?
| htamas wrote:
| This is interesting as a demo, but I'm curious how would this
| solution handle chunking up songs for better performance (think
| long podcast episodes or higher quality audio), or a DRM like
| Widevine.
|
| Without these, the farthest you could go on this path is a unique
| way to show off some indie work.
|
| I remember one of my favourite bands in my teenage years (think
| early 2000s) had a website where they let you listen to their
| albums. I wanted to listen to them on my mp3 player so we figured
| out we can just look up the URLs of the mp3s from the HTML and
| download it.
| katspaugh wrote:
| Nice write up and a refreshing take on building websites w/o
| relying too much on JS! Great experimental music too.
|
| I've run out of free space on soundcloud, and Bandcamp is
| incredibly slow to upload files. So I might as well just fork
| this project and host the audio library myself. Kudos Cole!
| colordrops wrote:
| Wait, can you just upload arbitrary files to SoundCloud? Is
| there no copyright check?
| katspaugh wrote:
| I was talking about the "music" I make, so I don't know.
___________________________________________________________________
(page generated 2023-09-30 23:02 UTC)