This feed omits posts by rms. Just 'cause.

Posted Fri Jun 23 01:07:13 2017 Tags:
Posted Thu Jun 22 06:36:03 2017 Tags:
Russian Priest Tells Men Not to Shave to 'Protect From Homosexuality'

Metropolitan Kornily, Primate of the Russian Orthodox Old Believer Church (RPSC), said that men with beards were less likely "corrupted" by same-sex relationships.

"God set down certain rules. The Lord created everyone with a beard. No man can resist his creator," Kornily told Russia's National News Service. "It's made a monstrous thing to see men's clothing and hairstyles changing."

Metropolitan Kornily also lamented that the beard's special status had "completely disappeared from the Catholic West."

Russian President Vladimir Putin was the first head of state to visit an Old Believer church in 350 years when he visited the RSPC Rogozhsky spiritual center in Moscow in May 2017.

National News Service:

"God gave us the rules: it is written that the Lord created everyone with a beard. And the Catholic West completely disappeared from this concept. But this is unequivocal: on icons we can not imagine Christ or any saint without a beard. A person should not resist his creator. Sodomy from this and it went: changing men's clothing, hairstyles".

@meakoopa: "That a person named 'Reality Winner' is ruining the life of someone named 'Beauregard Sessions' is how you know we live in a rough draft."

To that list we must now add "Metropolitan Kornily (Primate)".

Previously, previously, previously, previously, previously, previously, previously, previously, previously, previously.

Posted Mon Jun 19 18:39:36 2017 Tags:

I just released the first release candidate for libinput 1.8. Aside from the build system switch to meson one of the more visible things is that the helper tools have switched from a "libinput-some-tool" to the "libinput some-tool" approach (note the space). This is similar to what git does so it won't take a lot of adjustment for most developers. The actual tools are now hiding in /usr/libexec/libinput. This gives us a lot more flexibility in writing testing and debugging tools and shipping them to the users without cluttering up the default PATH.

There are two potential breakages here, one is that the two existing tools libinput-debug-events and libinput-list-devices have been renamed too. We currently ship compatibility wrappers for those but expect those wrappers to go away with future releases. The second breakage is of lesser impact: typing "man libinput" used to bring up the man page for the xf86-input-libinput driver. Now it brings up the man page for the libinput tool which then points to the man pages of the various features. That's probably a good thing, it puts the documentation a bit closer to the user. For the driver, you now have to type "man 4 libinput" though.

Posted Mon Jun 19 01:47:00 2017 Tags:
DNA Lounge update, wherein we're currently not doing deliveries, because Uber sucks.
Posted Thu Jun 15 05:48:44 2017 Tags:
Isn't that handy? Because I totally wanted to turn PasswordAuthentication back on, and allow logins from any account.

Thanks, Apple. You're a pal.

Previously, previously, previously, previously.

Posted Thu Jun 15 04:50:22 2017 Tags:

Please enjoy jwz mixtape 184.

Posted Wed Jun 14 19:38:22 2017 Tags:

This makes me think differently about all of these words.

Previously, previously.

Posted Wed Jun 14 06:45:02 2017 Tags:
This paper was long overdue. But software papers are not easy to write, particularly not follow up papers. That actually seems a lot easier for databases. Moreover, we already publish too much. However, the scholarly community does not track software citations (data citations neither, but there seems to be a bit more momentum there; larger user group?). So, we need these kind of papers, and just a version, archived software release (e.g. on Zenodo) is not enough. But, there it is, the third CDK paper (doi:10.1186/s13321-017-0220-4). Fifth, if you include the two papers about ring finding, also describing CDK functionality.

Of course, I could detail what this paper has to offer, but let's not spoil the article. It's CC-BY so everyone can readily access it. You don't even need Sci-Hub (but are allowed for this paper; it's legal!).

A huge thanks to all co-authors, John's work as release manager and great performance improvements as well as code improvement, code clean up, etc, and all developers who are not co-author on this paper but contributed bigger or smaller patches over time (plz check the full AUTHOR list!). That list does not include the companies that have been supporting the project in kind, tho. Also huge thanks to all the users, particularly those who have used the CDK in downstream projects, many of which are listed in the introduction of the paper.

And, make sure to follow John Mayfield's blog with tons of good stuff.
Posted Sat Jun 10 10:53:00 2017 Tags:

Colossal Cave Adventure, that venerable classic, is back and better than ever! The page for downloads is here.

The game is fully playable. It would be astonishing if it were otherwise, since it has been stable since 1995. One minor cosmetic change a lot of people used to the non-mainline variants will appreciate is that there’s a command prompt.

The most substantial thing Jason Ninneman and I have done to the code itself is that the binary is now completely self-contained, with no need for it to refer to an external adventure.text file. That file is now compiled to C structures that are linked to the rest of the game at build time.

The other major thing we’ve done is that the distribution now includes a pretty comprehensive regression-test suite. We do coverage analysis to verify that it visits most of the code. This clears the way to do serious code cleanup (gotos and stale FORTRAN idioms must die!) while being sure we’re not breaking things,

We gratefully acknowledge the support of the game’s original authors, Don Woods and Will Crowther.

Posted Mon Jun 5 19:46:08 2017 Tags:

I need a bit of hands-on time with someone who knows how to troubleshoot WordPress installations.

I recently had to upgrade my WordPress installation due to an exploit that inserted a malicious URL in one of my widgets. Since then, my spam filter has not been operating correctly. I am not sure whether Akismet is working very slowly or not working at all, but the net result is that I am having to approve every post by hand.

There is a suspicious thing visible from my admin account. It looks as though Akismet is installed twice.

I suspect the fix for this is something simple, but I don’t know what it is. Can anybody help?

Posted Mon Jun 5 10:54:44 2017 Tags:

Henry Spencer, upon reading my previous post, had this to say by email:

I won’t argue with Eric about the significance of that little event, but I do have to interject a few corrections about the historical details.

For this, I’ve got a couple of advantages over him. First, being somewhat of a packrat, I still have my notes from conferences 30+ years ago! (Not in digital form, alas.) And second, being the one who saved most of what we have of Usenet’s early days, I also have some relevant old Usenet postings to consult.

The precise date was 19 January 1984, in the second morning session of the Uniforum conference (a joint meeting of the Usenix Association and the /usr/group trade association). Kathleen Hemenway of Bell Labs gave a talk on work she and Helene Armitage had done: “A proposed syntax standard for UNIX system commands”. This was basically an attempt to codify and slightly tighten the rules already implemented several years earlier by AT&T’s getopt() library function.

As you might gather from that wording, getopt() wasn’t actually new then: it had existed within Bell for some time, but hadn’t made it out in any widely-available Unix release. In late 1981, I’d seen a Bell-internal Unix manual page describing it. I wanted it, and I couldn’t have it, so I wrote my own. It was indeed quite helpful, and on 11 Jan. 1982, I posted it to Usenet newsgroup net.sources. By the time of that conference, a fair number of people were using it.

Ms. Hemenway’s talk was mostly about the syntax issues, but she did mention that there were plans for enhancements to getopt() to help support the new spec. And during Q&A, she was indeed evasive about availability of the enhanced code — probably nobody had made any decisions about that. So I got up and said that I would upgrade my public-domain implementation to match any enhancements AT&T made. Didn’t seem like a big deal; to be honest, I was a bit surprised that it got cheers and applause. I guess a lot of people hadn’t yet grasped that we *had a choice* about this.

No…no, we hadn’t. And my having got the date wrong explains the particularly high anxiety about the Bell breakup; the consent decree would have taken effect not nine months previously but just eight days before.

Ever since, on the occasions that I remembered this before returning to a busy life, the second or third thought in my mind was always that I ought to find Henry and let him know what an influence he had on me in that moment.

Henry Spencer, you set an example that day for all of us, and we cheered you not for promising to write a few lines of code but because we heard the call behind the promise. The details grew dim in my memory, but the power of that example struck me again each time I recalled it. Value your craft and pursue excellence in it; share what you create; never fear to go up against a monopolist; be loyal to your peers in the work. This is how a hacker – how any kind of maker, really – does his duty to the future.

A lot of us have been trying to live out that lesson ever since. Thank you, Henry. I think the world owes you more than it knows for that inspiration.

Posted Mon Jun 5 01:01:06 2017 Tags:

Back in 2003, the pressure range value for Wacom pen tablets was set to 2048. That's a #define in the driver, but it shouldn't matter because we also advertise this range as part of the device description in the X Input protocol. Clients should be using that advertised min/max range and scale appropriately, in the same way as they should be doing this for the x/y axis ranges.

Fast-forward to 2017 and we changed the pressure range. New Wacom devices now use ~8000 levels, but we opted to just #define it in the driver to 65536 and be done with it. We now scale all models into that range, with varying granularity based on the physical hardware. It shouldn't matter because it's not tied to a reliable physical property anyway and the only thing that matters is the percentage of the max value (which is why libinput just gives you a [0, 1] range. Hindsight is a bliss.).

Slow-forward to 2017-and-a-bit and we received complaints that pressure handling is now broken. Turns out that some applications hardcoded the old 2048 range and now get confused, because virtually any pressure will now hit that maximum. Since those applications are largely proprietary ones and cannot be updated easily, we needed a workaround to this. Jason Gerecke from Wacom got busy and we now have a "Pressure2K" option available in the driver. If set, this option will scale everything into the 2048 range to make sure those applications still work. To get this to work, the following xorg.conf.d snippet is recommended:

Section "InputClass"
Identifier "Wacom pressure compatibility"
MatchDriver "wacom"
Option "Pressure2K" "true"
Put it in a file that sorts higher than the wacom driver itself (e.g. /etc/X11/xorg.conf.d/99-wacom-pressure2k.conf) and restart X. Check the Xorg.log/journal for a "Using 2K pressure levels" message, then verify it works by running xinput list "device name". xinput should show a range of 0 to 2048 on the third valuator.

$> xinput list "Wacom Intuos4 6x9 Pen stylus"
Wacom Intuos4 6x9 Pen stylus id=25 [slave pointer (2)]
Reporting 8 classes:
Class originated from: 25. Type: XIButtonClass
Buttons supported: 9
Button labels: None None None None None None None None None
Button state:
Class originated from: 25. Type: XIKeyClass
Keycodes supported: 248
Class originated from: 25. Type: XIValuatorClass
Detail for Valuator 0:
Label: Abs X
Range: 0.000000 - 44704.000000
Resolution: 200000 units/m
Mode: absolute
Current value: 22340.000000
Class originated from: 25. Type: XIValuatorClass
Detail for Valuator 1:
Label: Abs Y
Range: 0.000000 - 27940.000000
Resolution: 200000 units/m
Mode: absolute
Current value: 13970.000000
Class originated from: 25. Type: XIValuatorClass
Detail for Valuator 2:
Label: Abs Pressure
Range: 0.000000 - 2048.000000
Resolution: 1 units/m
Mode: absolute
Current value: 0.000000

Class originated from: 25. Type: XIValuatorClass
Detail for Valuator 3:
Label: Abs Tilt X
Range: -64.000000 - 63.000000
Resolution: 57 units/m
Mode: absolute
Current value: 0.000000
Class originated from: 25. Type: XIValuatorClass
Detail for Valuator 4:
Label: Abs Tilt Y
Range: -64.000000 - 63.000000
Resolution: 57 units/m
Mode: absolute
Current value: 0.000000
Class originated from: 25. Type: XIValuatorClass
Detail for Valuator 5:
Label: Abs Wheel
Range: -900.000000 - 899.000000
Resolution: 1 units/m
Mode: absolute
Current value: 0.000000

This is an application bug, but this workaround will make sure new versions of the driver can be used until those applications have been fixed. The option will be available in the soon-to-be-released xf86-input-wacom 0.35. The upstream commit is d958ab79d21b57141415650daac88f9369a1c861.

Edit 02/06/2017: wacom devices have 8k pressure levels now.

Posted Thu Jun 1 01:24:00 2017 Tags:

I excavated a bit of hacker history from old memories today. Not dead history either, but an important beginning of some large good things.

Here’s how it happened. I got email from a person requesting me to identify a source for the following allegedly famous quote: “All operating systems eventually turn into Unix”.

I told him that I’d never heard that quote as written but that it reminded me of a line by Henry Spencer: “Those who do not understand Unix are condemned to reinvent it, poorly.” This is of course a take on a well-known aphorism by Santayana.

I googled Henry Spencer’s name and some keywords to make sure I had the quote correct. The top hit, from which I verified the quote, was Henry’s Wikipedia page. I read it and something caught my eye – the assertion that Henry wrote his well-known and widely distributed regex package around 1987. And suddenly I remembered something.

Years ago I wrote Eminent Domains: The First Time I Changed History in which I mentioned Henry Spencer’s presence at the conference where I persuaded the NWG not to drop the functional domains in favor of a strict geographic system.

What I just remembered today is something else that happened at that conference that may have been as important, though in a less obvious way. It also pins the date to 1984, because I remember now that anxiety about what AT&T’s recent commercialization of Unix meant to us was very much in the air at that conference (IIRC the big announcement had happened in January or February). We were all worried that this meant the Bell Labs source code would no longer be shared with universities and research labs…as was indeed to become the case.

To fully understand this story you need to know that Henry was already a hugely respected figure in the tiny, not yet very conscious hacker culture of the time (there were, at a guess, somewhere around 500 of us then in the U.S. and Canada – maybe 700 worldwide). I knew him from USENET; I’d seen some of his code, in the relatively small amounts we passed around back then.

It also matters that the GNU Manifesto hadn’t been written yet – wouldn’t be until the following year, though I had some idea what was coming because Richard Stallman had discussed his plans with me at Boskone in February. (That was when I suggested to him that the flagship project for the FSF ought to be Emacs. Duh!) Stallman’s concept of “Free Software” was not yet part of the hacker zeitgeist,

So in October 1984 I was in a crowd of people watching a presentation by a woman from Bell Labs describing the then-new getopt(3) library, written by AT&T as a way to regularize the processing of command-line arguments in C programs. The custom up to then had been to write ad-hoc code for each application, leading to some odd and unpredictable variations in behavior.

Everybody thought this was a fine idea, and several people asked questions probing whether AT&T was going to let anyone else use the getopt code they had written. These questions related to the general anxiety about Unix source code distributions drying up.

Frustration mounted as the woman gave evasive answers which seemed to add up to “No, we refuse to commit to allowing general access to this code.” Which seemed to confirm everyone’s worst fears about what was going to happen to Unix source code access in general.

At which point Henry Spencer stands up and says (not in these exact words) “I will write and share a conforming implementation.” – and got a cheer from the assembled.

If you’re thinking “That’s not a big deal, we do this sort of thing all the time,” my actual point is that in October 1984 this was indeed a big deal. It took an actual imaginative leap for Henry Spencer to, in effect, say “Screw AT&T and its legalisms and evasions, if they’re going to cut off source access we hackers are gonna do it for ourselves.”

Yes, we had DECUS tapes and the Unix sources newsgroups on Unix already; Henry was building on that. But he got an actual cheer exactly because he was pushing forward, exposing the possibility of doing not just small projects and demos and quirky little tools but at competing with the likes of AT&T itself at software production.

Of course RMS was, as I was then one of the very few to already know, thinking along the same lines. But RMS’s was a more personal, ideological vision. Henry didn’t have any grand plan to save the world; he was just being a hacker, seeing where the solution to the problem posed by AT&T’s source-code lockdown had to lie, pointing it out just a bit sooner than anyone else, and putting his own skin and considerable reputation in the game.

So yeah. In retrospect I think this was a historically pivotal moment. A respected elder of our tiny tribe (so tiny that probably a substantial fraction of it was in the room listening) declared his independence from what AT&T chose to do about restricting its code. And they took that possibility home with them.

I’m put in mind of the historian Oswald Spengler’s notion that cultures are born at a moment of what Nietzsche called “transvaluation of all values”. Arguably this was one, rather like the one I semi-accidentally triggered in the late 1990s, at which the hacker culture woke up some – became aware of the possibilities implied by its existing folkways.

And there’s a more direct and personal aspect I had half-forgotten. I was a young, unknown programmer then – just 27, still figuring out what I wanted. I watched Henry make that promise. I heard the cheer, and felt the change in the air as culturally, we realized what the solution to AT&T fscking us over had to be.

And I thought “I want to be like that guy.”

Posted Fri May 26 20:29:42 2017 Tags:

TLDR: If you see devices like "xwayland-pointer" show up in your xinput list output, then you are running under a Wayland compositor and debugging/configuration with xinput will not work.

For many years, the xinput tool has been a useful tool to debug configuration issues (it's not a configuration UI btw). It works by listing the various devices detected by the X server. So a typical output from xinput list under X could look like this:

:: whot@jelly:~> xinput list
⎡ Virtual core pointer id=2 [master pointer (3)]
⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)]
⎜ ↳ SynPS/2 Synaptics TouchPad id=22 [slave pointer (2)]
⎜ ↳ TPPS/2 IBM TrackPoint id=23 [slave pointer (2)]
⎜ ↳ ELAN Touchscreen id=20 [slave pointer (2)]
⎣ Virtual core keyboard id=3 [master keyboard (2)]
↳ Virtual core XTEST keyboard id=5 [slave keyboard (3)]
↳ Power Button id=6 [slave keyboard (3)]
↳ Video Bus id=7 [slave keyboard (3)]
↳ Lid Switch id=8 [slave keyboard (3)]
↳ Sleep Button id=9 [slave keyboard (3)]
↳ ThinkPad Extra Buttons id=24 [slave keyboard (3)]
Alas, xinput is scheduled to go the way of the dodo. More and more systems are running a Wayland session instead of an X session, and xinput just doesn't work there. Here's an example output from xinput list under a Wayland session:

$ xinput list
⎡ Virtual core pointer id=2 [master pointer (3)]
⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)]
⎜ ↳ xwayland-pointer:13 id=6 [slave pointer (2)]
⎜ ↳ xwayland-relative-pointer:13 id=7 [slave pointer (2)]
⎣ Virtual core keyboard id=3 [master keyboard (2)]
↳ Virtual core XTEST keyboard id=5 [slave keyboard (3)]
↳ xwayland-keyboard:13 id=8 [slave keyboard (3)]
As you can see, none of the physical devices are available, the only ones visible are the virtual devices created by XWayland. On a Wayland session, the X server doesn't have access to the physical devices. Instead, it talks via the Wayland protocol to the compositor. This image from the Wayland documentation shows the architecture:
In the above graphic, devices are known to the Wayland compositor (1), but not to the X server. The Wayland protocol doesn't expose physical devices, it merely provides a 'pointer' device, a 'keyboard' device and, where available, a touch and tablet tool/pad devices (2). XWayland wraps these into virtual devices and provides them via the X protocol (3), but they don't represent the physical devices.

This usually doesn't matter, but when it comes to debugging or configuring devices with xinput we run into a few issues. First, configuration via xinput usually means changing driver-specific properties but in the XWayland case there is no driver involved - it's all handled by libinput inside the compositor. Second, debugging via xinput only shows what the wayland protocol sends to XWayland and what XWayland then passes on to the client. For low-level issues with devices, this is all but useless.

The takeaway here is that if you see devices like "xwayland-pointer" show up in your xinput list output, then you are running under a Wayland compositor and debugging with xinput will not work. If you're trying to configure a device, use the compositor's configuration system (e.g. gsettings). If you are debugging a device, use libinput-debug-events. Or compare the behaviour between the Wayland session and the X session to narrow down where the failure point is.

Posted Tue May 23 00:56:00 2017 Tags:

Colossal Cave Adventure was the origin of many things; the text adventure game, the dungeon-crawling D&D (computer) game, the MOO, the roguelike genre. Computer gaming as we know it would not exist without ADVENT (as it was known in its original PDP-10 incarnation).

Long ago, you might have played this game. Or maybe you’ve just heard stories about it, or vaguely know that “xyzzy” is a magic word, or have heard people say “You are in a maze of twisty little passages, all alike”,

Though there’s a C port of the original 1977 game in the BSD game package, and the original FORTRAN sources could be found if you knew where to dig, Crowther & Woods’s final version – Adventure 2.5 from 1995 – has never been packaged for modern systems and distributed under an open-source license.

Until now, that is.

With the approval of its authors, I bring you Open Adventure. And with it some thoughts about what it means to be respectful of an important historical artifact when it happens to be software.

This is code that fully deserves to be in any museum of the great artifacts of hacker history. But there’s a very basic question about an artifact like this: should a museum preserve it in a static form as close to the original as possible, or is it more in the right spirit to encourage the folk process to continue improving the code?

Modern version control makes this question easier; you can have it both ways, keeping a pristine archival version in the history and improving it. Anyway, I think the answer to the general question is clear; if heritage code like this is relevant at all, it’s as a living and functional artifact. We respect our history and the hackers of the past best by carrying on their work and their playfulness.

I’ve actually dealt with this question before, which is why Super Star Trek has both interface improvements and a -t option that invokes the original TTY interface in all its brutal simplicity. Open Adventure will have a similar option.

When Willie Crowther wrote the very first version in 1976 he was also writing firmware for the earliest generation of routers on the operational ARPANET – he was one of the most ingenious and capable programmers of his time. The code makes a fascinating study in how to push the limits of the primitive tools then available to him.

It’s very strange to the modern eye just to see a simulation like ADVENT written with no analogue even of C structures, let alone objects. But the FORTRAN Crowther wrote in didn’t have such things; game state was all global variables, a “feature” preserved in the mechanically translated C of 2.5. (Which, alas, is extremely ugly code full of gotos.)

It also looks odd, 40 years after the fact, to see the amount of code complexity devoted to space/time optimization so that (for example) you don’t have to re-parse the text master of the dungeon-defining database on every startup. That’s what you had to do then, when a room-filling minicomputer cranked many fewer instructions per second than the controller in your microwave oven.

Despite all the energy Crowther and Woods had to spend fighting ancient constraints, ADVENT was a tremendous imaginative leap; there had been nothing like it before, and no text adventure that followed it would be innovative to quite the same degree.

Thus, one of my goals moving forward will be to make the logical design of the dungeon simulation easier to understand for a modern reader. This will probably entail something parallel to what was done in the BSD Games port – gradually massaging the code into more idiomatic C. This reflects my judgment that it’s more important to make Crowther & Wood’s algorithmic thinking more visible than it is to, in any sense, preserve the details of their code.

It’s actually more difficult to decide how much to change their data structures. In idiomatic C one would collect all the saveable game state into a structure rather than leaving it as a mess of global variables that have to be saved and restored one at a time. And a lot of the strange bit-packing hacks in the database representation could probably be done away with today. But would doing that sort of thing obscure their achievement too much?

Probably not – and the baseline version will still be visible in the repository, after all. Likely what I’ll end up doing (if I can allocate the time) is cleaning up stuff like that and leaving comments explaining what it looked like in the FORTRAN original.

I don’t plan on any gameplay changes yet. Any such things will be reversible by the switch to restore historic behavior.

One thing I definitely plan is to modify the code so it can be regression-tested by capturing command logs, replaying them to the game and checking that the output is as expected – testing a full walkthrough should be possible. Matter of fact that needs to happen before anything else so that the correctness of changes can be verified.

This is not a strategy that would likely have occurred to anyone (well, maybe outside of a handful of people at Bell Labs) in 1977. Finding it thinkable depends on a mindset created by Unix pipes and redirection that was only gestating then.

Replay also busts one of Crowther & Woods’s original goals – thwarting attempts to get around obstacles in the game with any investment less than quitting and playing again. Towards this end they deliberately obscured the encoding of save files to make point tweaks of the game state difficult.

That, however, is a hack that fails the Kerckhoffs’s Law test – it’s useless or near useless in an environment where the “adversary” has the source code. When ADVENT (so called because PDP-10 filenames were limited to six characters of uppercase) was written, that was a pretty safe assumption, but today it will never be safe again. No harm, then, in dropping their obscurifying measures.

Source code obscurity is a “feature” from 1977 I miss less than even FORTRAN…

Posted Mon May 22 16:59:12 2017 Tags:

A marvellous thing has just occurred.

Colossal Cave Adventure, the original progenitor of the D&D-like dungeon-crawling game genre from 1977 and fondly remembered as ADVENT by those of us who played it on PDP-10s, is one of the major artifacts of hacker history.

The earliest version by Crowther and Woods (sometimes known as 350-point Adenture) was ported to C by Jim Gillogly in ’77 just after it first shipped. That has been part of the bsd-games collection forever.

What I have have just received Crowther & Wood’s encouragement to polish up and ship under a modern open-source license is not the Gillogly port; it’s Crowther & Woods’s last version from 1995. It has 18 years of work in it that the Gillogly version doesn’t.

I feel rather as though I’d been given a priceless Old Master painting to restore and display. Behooves me to be careful stripping off the oxidized varnish.

Posted Sun May 14 22:53:33 2017 Tags: