The diffoscope maintainers are pleased to announce the release of diffoscope
version 185. This version includes the following changes:
[ Mattia Rizzolo ]
* Fix the autopkgtest in order to fix testing migration: the androguard
Python module is not in the python3-androguard Debian package
* Ignore a warning in the tests from the h5py package that doesn't concern
diffoscope.
[ Chris Lamb ]
* Bump Standards-Version to 4.6.0.
I upgraded my first servers from buster to bullseye over the weekend and it
went very smoothly, so big thank you to all the debian developers who
contributed your labor to the bullseye release!
This morning, however, I hit a snag when the first windows users tried to login.
It seems like a putty bug (see update below).
First, the user received an error related to algorithm selection. I didn t
record the exact error and simply suggested that the user upgrade.
Once the user was running the latest version of putty (0.76), they received a new error:
Server refused public-key signature despite accepting key!
The server log seems to agree with the client returned message: first the key
was accepted, then it was refused.
We re-generated a new key. We turned off the windows firewall. We deleted all
the putty settings via the windows registry and re-set them from scratch.
Nothing seemed to work. Then, another windows user reported no problem (and
that user was running putty version 0.74). So the first user downgraded to 0.74
and everything worked fine.
Update
Wow, very impressed with the responsiveness of putty devs!
And, who knew that putty is available in debian??
Long story short: putty version 0.76 works on linux and, from what I can tell,
works for everyone except my one user. Maybe it s their provider doing some
filtering? Maybe a nuance to their version of Windows?
Nearly 4 weeks after contracting COVID-19 I am finally able to return to work
Yes I have had both Jabs (my 2nd dose was back in June), and this knocked me for six. I spent most of the time in bed, and only started to get up and about 10 days ago.
I passed this on to both my wife and daughter (my wife has also been double jabbed), fortunately they didn t get it as bad as me and have been back at work / school for the last week. I also passed it on to a friend at the UK Debian BBQ, hosted once again by Sledge and Randombird, before I started showing symptoms. Fortunately (after a lot of PCR tests for attendees) it doesn t look like I passed it to anyone else
I wouldn t wish this on anyone.
I went on holiday back in August (still in England) thinking that having both jabs we would be fine. We stayed in self catering accommodation and we spent our time outside, we visited open air museums, walked around gardens etc, however we did eat out in relatively empty pubs and restaurants.
And yes we did all have face masks on when we went indoors (although obviously we removed them whilst eating).
I guess that is when I caught this, but have no idea exactly when or where.
Even after vaccination, it is still possible to both catch and spread this virus. Fortunately having been vaccinated my resulting illness was (statistically) less bad than it would otherwise have been.
I dread to think how bad I would have been if I had not already been vaccinated, I suspect that I would have ended up in ICU. I am still very tired, and have been told it may take many more weeks to get back to my former self. Other than being overweight, prior to this I have been in good health.
If you are reading this and have NOT yet had a vaccine and one is available for you, please, please get it done.
Debian Reunion Hamburg 2021, we still have free beds
We still have some free slots and beds available for the "Debian Reunion
Hamburg 2021" taking place in Hamburg at the venue of the 2018 & 2019 MiniDebConfs
from Monday, Sep 27 2021 until Friday Oct 1 2021, with
Sunday, Sep 26 2021 as arrival day.
So again, Debian people will meet in Hamburg.
The exact format is less defined and structured than previous years, probably
we will just be hacking from Monday to Wednesday, have talks on Thursday and
a nice day trip on Friday.
Please read https://wiki.debian.org/DebianEvents/de/2021/DebianReunionHamburg and
if you intend to attend, please register there. If additionally you would
like to stay on site (in a single room or shared with one another person),
please mail me.
I'm looking forward to this event, even though (or maybe also because) it will
be much smaller than last years. I suppose this will lead to more personal
interactions and more intense hacking, though of course it is to be seen
how this works out exactly!
In this blog post, I will cover a few related but also different topics around X2Go - the GNU/Linux based remote computing framework.
Introduction and Catch Up
For those, who haven't come across X2Go, so far... With X2Go [0] you can log into remote GNU/Linux machines graphically and launch headless desktop environments, seamless/published applications or access an already running desktop session (on a local Xserver or running as a headless X2Go desktop session) via X2Go's session shadowing / mirroring feature.
Graphical backend: NXv3
For several years, there was only one graphical backend available in X2Go, the NXv3 software. In NXv3, you have a headless or nested (it can do both) Xserver that has some remote magic built-in and is able to transfer the Xserver's graphical data to a remote client (NX proxy). Over the wire, the NX protocol allows for data compression (JPEG, PNG, etc.) and combines it with bitmap caching, so that the overall result is a fast and responsive desktop experience even on low latency and low bandwidth connections. This especially applies to X desktop environments that use many native X protocol operations for drawing windows and widget onto the screen. The more bitmaps involved (e.g. in applications with client-side rendering of window controls and such), the worse the quality of a session experience.
The current main maintainer of NVv3 (aka nx-libs [1]) is Ulrich Sibiller. Uli has my and the X2Go community's full appreciation, admiration and gratitude for all the work he does on nx-libs, constantly improving NXv3 without breaking compatibility with legacy use cases (yes, FreeNX is still alive, by the way).
NEW: Alternative Graphical Backend: X2Go Kdrive
Over the past 1.5 years, Oleksandr Shneyder (Alex), co-founder of X2Go, has been working on a re-implementation of an alternative, less X11-dependent graphical backend. The underlying Xserver technology is the kdrive part of the X.org server project. People on GNU/Linux might have used kdrive technology already: The Xephyr nested Xserver uses the kdrive implementation.
The idea of the X2Go Kdrive [2] implementation in X2Go is providing a headless Xserver on the X2Go Server side for running X11 based desktop sessions inside while using an X11-agnostic data protocol for sending the graphical desktop data to the client-side for rendering. Whereas, with NXv3 technology, you need a local Xserver on the client side, with X2Go Kdrive you only need a client app(lication) that can draw bitmaps into some sort of framebuffer, such as a client-side X11 Xserver, a client-side Wayland compositor or (hold your breath) an HTMLv5 canvas in a web browser.
X2Go Kdrive Client Implementations
During first half of this year, I tested and DEB-packaged Alex's X2Go HTMLv5 client code [3] and it has been available for testing in the X2Go nightly builds archive for a while now.
Of course, the native X2Go Client application has X2Go Kdrive support for a while, too, but it requires a Qt5 application in the background, the x2gokdriveclient (which is still only available in X2Go nightly builds or from X2Go Git [4]).
X2Go and Remmina
As currently posted by the Remmina community [5], one of my employees has been working on finalizing an already existing draft of mine for the last couple of months: Remmina Plugin X2Go. This project has been contracted by BAUR-ITCS UG (haftungsbeschr nkt) already a while back and has been financed via X2Go funding from one of their customers. Unfortunately, I never got around really to finalizing the project. Apologies for this.
Daniel Teichmann, who has been in the company for a while now, but just recently switched to an employment model with considerably more work hours per week, now picked up this project two months ago and achieved awesome things on the way.
Daniel Teichmann and Antenore Gatta (Remmina core developer, aka tmow) have been cooperating intensely on this, recently, with the objective of getting the X2Go plugin code merged into Remmina asap. We are pretty close to the first touchdown (i.e. code merge) of this endeavour.
Thanks to Antenore for his support on this. This is much appreciated.
Remmina Plugin X2Go - Current Challenges
The X2Go Plugin for Remmina implementation uses Python X2Go (PyHoca-CLI) under the bonnet and basically does a system call to pyhoca-cli according to the session settings configured in the Remmina session profile UI. When using NXv3 based sessions, the session window appears on the client-side Xserver and immediately gets caught by Remmina and embedded into the Remmina frame (via Xembed protocol) where its remote sessions are supposed to appear. (Thanks that GtkSocket is still around in GTK-3). The knowing GTK-3 experts among you may have noticed: GtkSocket is obsolete and has been removed from GTK-4. Also, GtkSocket support is only available in GTK-3 when using its X11 rendering backend.
For the X2Go Kdrive implementation, we tested a similar approach (embedding the x2gokdriveclient Qt5 window via Xembed/GtkSocket), but it seems that GtkSocket and Qt5 applications don't work well together and we did not succeed in embedding the Qt5 window of the x2gokdriveclient application into Remmina, so far. Also, this would be a work-around for the bigger problem: We want, long-term, provide X2Go Kdrive support in Remmina, not only for Remmina running with GTK-3/X11, but also when Remmina is used natively on top of Wayland.
So, the more sustainable approach for showing an X2Go Kdrive based X2Go session in Remmina would be a GTK-3/4 or a Glib-2.0 + Cairo based rendering client provided as a shared library. This then could be used by Remmina for drawing the session bitmaps into the Remmina session frame.
This would require a port of the x2gokdriveclient Qt code into a non-Qt implementation. However, we are running out of funding to make this happen at the moment.
More Funding Needed for this Journey
As you might guess, such a project as proposed is a project that some people do in their spare time, others do it for a living.
I'd love to continue this project and have Daniel Teichmann continue his work on this, so that Remmina might soon be able to provide native X2Go Kdrive Client support.
If people read this and are interested in supporting such a project, please get in touch [6]. Thanks so much!
light+love
Mike (aka sunweaver)
[0] https://wiki.x2go.org/
[1] https://github.com/ArcticaProject/nx-libs
[2] https://code.x2go.org/gitweb?p=x2gokdrive.git;a=tree
[3] https://code.x2go.org/gitweb?p=x2gohtmlclient.git;a=tree
[4] https://code.x2go.org/gitweb?p=x2gokdriveclient.git;a=tree
[5] https://remmina.org/x2go/
[6] https://das-netzwerkteam.de/
Another small release of the tidyCpp package arrived on CRAN overnight. The packages offers a clean C++ layer (as well as one small C++ helper class) on top of the C API for R which aims to make use of this robust (if awkward) C API a little easier and more consistent. See the vignette for motivating examples.
The Protect class now uses the default methods for copy and move constructors and assignment allowing for wide use of the class. The small NumVec class now uses it for its data member.
The NEWS entry (which I failed to update for the releases) follows.
Changes in tidyCpp version 0.0.5 (2021-09-16)
The Protect class uses default copy and move assignments and constructors
The diffoscope maintainers are pleased to announce the release of diffoscope
version 184. This version includes the following changes:
[ Chris Lamb ]
* Fix the semantic comparison of R's .rdb files after a refactoring of
temporary directory handling in a previous version.
* Support a newer format version of R's .rds files.
* Update tests for OCaml 4.12. (Closes: reproducible-builds/diffoscope#274)
* Move diffoscope.versions to diffoscope.tests.utils.versions.
* Use assert_diff in tests/comparators/test_rdata.py.
* Reformat various modules with Black.
[ Zbigniew J drzejewski-Szmek ]
* Stop using the deprecated distutils module by adding a version
comparison class based on the RPM version rules.
* Update invocations of llvm-objdump for the latest version of LLVM.
* Adjust a test with one-byte text file for file(1) version 5.40.
* Improve the parsing of the version of OpenSSH.
[ Benjamin Peterson ]
* Add a --diff-context option to control the unified diff context size.
(reproducible-builds/diffoscope!88)
Colson Whitehead's latest novel, Harlem Shuffle, was always going to be widely reviewed, if only because his last two books won Pulitzer prizes. Still, after enjoying both The Underground Railroad and The Nickel Boys, I was certainly going to read his next book, regardless of what the critics were saying indeed, it was actually quite agreeable to float above the manufactured energy of the book's launch.
Saying that, I was encouraged to listen to an interview with the author by Ezra Klein. Now I had heard Whitehead speak once before when he accepted the Orwell Prize in 2020, and once again he came across as a pretty down-to-earth guy. Or if I were to emulate the detached and cynical tone Whitehead embodied in The Nickel Boys, after winning so many literary prizes in the past few years, he has clearly rehearsed how to respond to the cliched questions authors must be asked in every interview. With the obligatory throat-clearing of 'so, how did you get into writing?', for instance, Whitehead replies with his part of the catechism that 'It seemed like being a writer could be a cool job. You could work from home and not talk to people.' The response is the right combination of cute and self-effacing... and with its slight tone-deafness towards enforced isolation, it was no doubt honed before Covid-19.
Harlem Shuffle tells three separate stories about Ray Carney, a furniture salesman and 'fence' for stolen goods in New York in the 1960s. Carney doesn't consider himself a genuine criminal though, and there's a certain logic to his relativistic morality. After all, everyone in New York City is on the take in some way, and if some 'lightly used items' in Carney's shop happened to have had 'previous owners', well, that's not quite his problem. 'Nothing solid in the city but the bedrock,' as one character dryly observes. Yet as Ezra pounces on in his NYT interview mentioned abov, the focus on the Harlem underworld means there are very few women in the book, and Whitehead's circular response ah well, it's a book about the criminals at that time! was a little unsatisfying. Not only did it feel uncharacteristically slippery of someone justly lauded for his unflinching power of observation (after all, it was the author who decided what to write about in the first place), it foreclosed on the opportunity to delve into why the heist and caper genres (from The Killing, The Feather Thief, Ocean's 11, etc.) have historically been a 'male' mode of storytelling.
Perhaps knowing this to be the case, the conversation quickly steered towards Ray Carney's wife, Elizabeth, the only woman in the book who could be said possesses some plausible interiority. The following off-hand remark from Whitehead caught my attention:
My wife is convinced that [Elizabeth] knows everything about Carney's criminal life, and is sort of giving him a pass. And I'm not sure if that's true. I have to have to figure out exactly what she knows and when she knows it and how she feels about it.
I was quite taken by this, although not simply due to its effect on the story it self. As in, it immediately conjured up a charming picture of Whitehead's domestic arrangements: not only does Whitehead's wife feel free to disagree with what one of Whitehead's 'own' characters knows or believes, but that Colson has no problem whatsoever sharing that disagreement with the public at large. (It feels somehow natural that Whitehead's wife believes her counterpart knows more than she lets on, whilst Whitehead himself imbues the protagonist's wife with a kind of neo-Victorian innocence.) I'm minded to agree with Whitehead's partner myself, if only due to the passages where Elizabeth is studiously ignoring Carney's otherwise unexplained freak-outs.
But all of these meta-thoughts simply underline just how emancipatory the Death of the Author can be. This product of academic literary criticism (the term was coined by Roland Barthes' 1967 essay of the same name) holds that the original author's intentions, ideas or biographical background carry no especial weight in determining how others should interpret their work. It is usually understood as meaning that a writer's own views are no more valid or 'correct' than the views held by someone else. (As an aside, I've found that most readers who encounter this concept for the first time have been reading books in this way since they were young. But the opposite is invariably true with cinephiles, who often have a bizarre obsession with researching or deciphering the 'true' interpretation of a film.) And with all that in mind, can you think of a more wry example of how freeing (and fun) nature of the Death of the Author than an author's own partner dissenting with their (Pulitzer Prize-winning) husband on the position of a lynchpin character?
The 1964 Harlem riot began after James Powell, a 15-year-old African American, was shot and killed by Thomas Gilligan, an NYPD police officer in front of 10s of witnesses. Gilligan was subsequently cleared by a grand jury.
As it turns out, the reviews for Harlem Shuffle have been almost universally positive, and after reading it in the two days after its release, I would certainly agree it is an above-average book. But it didn't quite take hold of me in the way that The Underground Railroad or The Nickel Boys did, especially the later chapters of The Nickel Boys that were set in contemporary New York and could thus make some (admittedly fairly explicit) connections from the 1960s to the present day that kind of connection is not there in Harlem Shuffle, or at least I did not pick up on it during my reading.
I can see why one might take exception to that, though. For instance, it is certainly true that the week-long Harlem Riot forms a significant part of the plot, and some events in particular are entirely contingent on the ramifications of this momentous event. But it's difficult to argue the riot's impact are truly integral to the story, so not only is this uprising against police brutality almost regarded as a background event, any contemporary allusion to the murder of George Floyd is subsequently watered down. It's nowhere near the historical rubbernecking of Forrest Gump (1994), of course, but that's not a battle you should ever be fighting.
Indeed, whilst a certain smoothness of affect is to be priced into the Whitehead reading experience, my initial overall reaction to Harlem Shuffle was fairly flat, despite all the action and intrigue on the page. The book perhaps belies its origins as a work conceived during quarantine after all, the book is essentially comprised of three loosely connected novellas, almost as if the unreality and mental turbulence of lockdown prevented the author from performing the psychological 'deep work' of producing a novel-length text with his usual depth of craft. A few other elements chimed with this being a 'lockdown novel' as well, particularly the book's preoccupation with the sheer physicality of the city compared to the usual complex interplay between its architecture and its inhabitants. This felt like it had been directly absorbed into the book from the author walking around his deserted city, and thus being able to take in details for the first time:
The doorways were entrances into different cities no, different entrances into one vast, secret city. Ever close, adjacent to all you know, just underneath. If you know where to look.
And I can't fail to mention that you can almost touch Whitehead's sublimated hunger to eat out again as well:
Stickups were chops they cook fast and hot, you re in and out. A stakeout was ribs fire down low, slow, taking your time.
[ ]
Sometimes when Carney jumped into the Hudson when he was a kid, some of that stuff got into his mouth. The Big Apple Diner served it up and called it coffee.
More seriously, however, the relatively thin personalities of minor characters then reminded me of the simulacrum of Zoom-based relationships, and the essentially unsatisfactory endings to the novellas felt reminiscent of lockdown pseudo-events that simply fizzle out without a bang. One of the stories ties up loose ends with: 'These things were usually enough to terminate a mob war, and they appeared to end the hostilities in this case as well.' They did? Well, okay, I guess.
The corner of 125th Street and Morningside Avenue in 2019, the purported location of Carney's fictional furniture store. Signage plays a prominent role in Harlem Shuffle, possibly due to the author's quarantine walks.
Still, it would be unfair to characterise myself as 'disappointed' with the novel, and none of this piece should be taken as really deep criticism. The book certainly was entertaining enough, and pretty funny in places as well:
Carney didn t have an etiquette book in front of him, but he was sure it was bad manners to sit on a man s safe.
[ ]
The manager of the laundromat was a scrawny man in a saggy undershirt painted with sweat stains. Launderer, heal thyself.
Yet I can't shake the feeling that every book you write is a book that you don't, and so we might need to hold out a little longer for Whitehead's 'George Floyd novel'. (Although it is for others to say how much of this sentiment is the expectations of a White Reader for The Black Author to ventriloquise the pain of 'their' community.)
Some room for personal critique is surely permitted. I dearly missed the junk food energy of the dry and acerbic observations that run through Whitehead's previous work. At one point he had a good line on the model tokenisation that lurks behind 'The First Negro to...' labels, but the callbacks to this idea ceased without any payoff. Similar things happened with the not-so-subtle critiques of the American Dream:
Entrepreneur? Pepper said the last part like manure. That s just a
hustler who pays taxes.
[ ]
One thing I ve learned in my job is that life is cheap, and when things start getting expensive, it gets cheaper still.
Ultimately, though, I think I just wanted more. I wanted a deeper exploration of how the real power in New York is not wielded by individual street hoodlums or even the cops but in the form of real estate, essentially serving as a synecdoche for Capital as a whole. (A recent take of this can be felt in Jed Rothstein's 2021 documentary, WeWork: Or the Making and Breaking of a $47 Billion Unicorn and it is perhaps pertinent to remember that the US President at the time this novel was written was affecting to be a real estate tycoon.). Indeed, just like the concluding scenes of J. J. Connolly's Layer Cake, although you can certainly pull off a cool heist against the Man, power ultimately resides in those who control the means of production... and a homespun furniture salesman on the corner of 125 & Morningside just ain't that. There are some nods to kind of analysis in the conclusion of the final story ('Their heist unwound as if it had never happened, and Van Wyck kept throwing up buildings.'), but, again, I would have simply liked more.
And when I attempted then file this book away into the broader media landscape, given the current cultural visibility of 1960s pop culture (e.g. One Night in Miami (2020), Judas and the Black Messiah (2021), Summer of Soul (2021), etc.), Harlem Shuffle also seemed like a missed opportunity to critically analyse our (highly-qualified) longing for the civil rights era. I can certainly understand why we might look fondly on the cultural products from a period when politics was less alienated, when society was less atomised, and when it was still possible to imagine meaningful change, but in this dimension at least, Harlem Shuffle seems to merely contribute to this nostalgic escapism.
tl;dr
dgit clone sourcepackage gets you the source code, as a git tree, in ./sourcepackage. cd into it and dpkg-buildpackage -uc -b.
Do not use: "VCS" links on official Debian web pages like tracker.debian.org; "debcheckout"; searching Debian's gitlab (salsa.debian.org). These are good for Debian experts only.
If you use Debian's "official" source git repo links you can easily build a package without Debian's patches applied.[1]
This can even mean missing security patches. Or maybe it can't even be built in a normal way (or at all).
OMG WTF BBQ, why?
It's complicated. There is History.
Debian's "most-official" centralised source repository is still the Debian Archive,
which is a system based on tarballs and patches. I invented the Debian source package format in 1992/3 and it has been souped up since, but it's still tarballs and patches.
This system is, of course, obsolete, now that we have modern version control systems, especially git.
Maintainers of Debian packages have invented ways of using git anyway, of course.
But this is not standardised.
There is a bewildering array of approaches.
The most common approach is to maintain git tree containing a pile of *.patch files,
which are then often maintained using quilt. Yes, really, many Debian people are still using quilt,
despite having git! There is machinery for converting this git tree containing a series of patches, to an "official" source package. If you don't use that machinery, and just build from git, nothing applies the patches.
[1]
This post was prompted by a conversation with a friend who had wanted to build a Debian package,
and didn't know to use dgit. They had
got the source from salsa via a link on tracker.d.o, and built .debs without Debian's patches.
This not a theoretical unsoundness, but a very real practical risk.
Future is not very bright
In 2013 at the Debconf in Vaumarcus, Joey Hess, myself, and others, came up with a plan to try to improve this which we thought would be deployable. (Previous attempts had failed.)
Crucially, this transition plan does not force change onto any of Debian's many packaging teams,
nor onto people doing cross-package maintenance work.
I worked on this for quite a while, and at a technical level it is a resounding success.
Unfortunately there is a big limitation. At the current stage of the transition, to work at its best, this replacement scheme hopes that maintainers who update a package will use a new upload tool. The new tool fits into their existing Debian git packaging workflow and has some benefits, but it does make things more complicated rather than less (like any transition plan must, during the transitional phase). When maintainers don't use this new tool, the standardised git branch seen by users is a compatibility stub generated from the tarballs-and-patches. So it has the right contents, but useless history.
The next step is to allow a maintainer to update a package without dealing with tarballs-and-patches at all. This would be massively more convenient for the maintainer, so an easy sell. And of course it links the tarballs-and-patches to the git history in a proper machine-readable way.
We held a "git packaging requirements-gathering session" at the Curitiba Debconf in 2019. I think the DPL's intent was to try to get input into the git workflow design problem. The session was a great success: my existing design was able to meet nearly everyone's needs and wants. The room was obviously keen to see progress. The next stage was to deploy tag2upload. I spoke to various key people at the Debconf and afterwards in 2019 and the code has been basically ready since then.
Unfortunately, deployment of tag2upload is mired in politics. It was blocked by a key team because of unfounded security concerns; positive opinions from independent security experts within Debian were disregarded. Of course it is always hard to get a team to agree to something when it's part of a transition plan which treats their systems as an obsolete setup retained for compatibility.
Current status
If you don't know about Debian's git packaging practices (eg, you have no idea what "patches-unapplied packaging branch without .pc directory" means), and don't want want to learn about them, you must use dgit to obtain the source of Debian packages.
There is a lot more information and detailed instructions in dgit-user(7).
Hopefully either the maintainer did the best thing, or, if they didn't, you won't need to inspect the history.
If you are a Debian maintainer, you should use dgit push-source to do your uploads.
This will make sure that users of dgit will see a reasonable git history.
edited 2021-09-15 14:48 Z to fix a typo
Some time ago I looked briefly at an Envertech data logger
for small scale photovoltaic setups. Turned out that PV inverter are kinda
unreliable, and you really have to monitor them to notice downtimes and defects.
Since my pal shot for a quick win I've cobbled together another Python script
to query the portal at
www.envertecportal.com, and report
back if the generated power is down to 0. The script is currently run on a vserver
via cron and reports back via the system MTA. So yeah, you need to have something
like that already at hand.
Script and Configuration
You've to provide your PV systems location with latitude and longitude so the
script can calculate
(via python3-suntime)
the sunrise and sunset times. At the location we deal with we expect to generate
some power at least from sunrise + 1h to sunet - 1h. That is tunable via the
configuration option toleranceSeconds.
Retrieving the stationId is a bit ugly because it's not provided via any API,
instead it's rendered serverside into the website. So I just logged in on the
portal and picked it up by looking into the page source.
www.envertecportal.com API
I guess this is some classic in the IoT land, but neither the documentation
provided on the portal frontpage as docx, nor the API docs at port 8090 are complete and correct. The few bits I gathered via the
Firefox Web Developer Tools are:
Login https://www.envertecportal.com/apiaccount/login - POST, sent userName and
pwd containing your login name and password. The response JSON is very explicit if
your login was not successful and why.
Store the session cookie called ASP.NET_SessionId for use on all subsequent
requests.
Retrieve station info https://www.envertecportal.com/ApiStations/getStationInfo -
POST, sent ASP.NET_SessionId and stationId with the ID of the station. Returns
a JSON with an object named Data. The field Power contains the currently
generated power as a float with two digits (e.g. 0.01).
Logout https://www.envertecportal.com/apiAccount/Logout - POST, sent
ASP.NET_SessionId.
Some Surprises
There were a few surprises, maybe they help others dealing with an Envertech setup.
The portal truncates passwords at 16 chars.
The "Forget Password?" function mails you back the password in plain text
(that's how I learned about 1.).
The login API endpoint reporting the exact reason why the login failed is somewhat
out of fashion. Though this one is probably not a credential stuffing target because
there is no money to make, so don't care.
The data logger reports the data to www.envertecportal.com at port 10013.
There is some checksuming done on the reported data, but the system is not replay
safe. So you can sent it any valid data string at a later time and get wrong data
recorded.
People at forum.fhem.de
decoded some values but could not figure out the checksuming so far.
This is the fifth and final post in a series about the interface description language Candid.
If you made it this far, you now have a good understanding of what Candid is, what it is for and how it is used. For this final post, I ll put the spotlight on specific aspects of Candid that are maybe surprising, or odd, or quirky. This section will be quite opinionated, and could maybe be called what I d do differently if I d re-do the whole thing .
Note that these quirks are not serious problems, and they don t invalidate the overall design. I am writing this up not to discourage the use of Candid, but merely help interested parties to understand it better.
References in the wire format
When the work on Candid began at DFINITY, the Internet Computer was still far away from being a thing, and many fundamental aspects about it were still in the air. I particular, there was still talk about embracing capabilities as a core feature of the application model, which would be implemented as opaque references on the system level, likely building on WebAssembly s host reference type proposal (which only landed recently), and could be used to model access permissions, custom tokens and many other things.
So Candid is designed with that in mind, and you ll find that its wire format is not just a type table and a value table, but actually
a triple (T, M, R), where T ( type ) and M ( memory ) are sequences of bytes and R ( references ) is a sequence of references.
Also the wire format for values of function service tyeps have an extra byte to distinguish between public references (represented by a principal and possible a method name in the data part), and these opaque references.
Alas, references never made it into the Internet Computer, so all Candid implementations simply ignore that part of the specification. But it s still in the spec, and if it confused you before, now you know why.
Hashed field names
Candid record and variant types look like they have textual field names:
type T = record syndactyle : nat; trustbuster: bool
But that is actually only true superficially. The wire format for Candid only stores hashes of field names. So the above is actually equivalent to
type T = record 4260381820 : nat; 3504418361 : bool
or, for that matter, to
type T = record destroys : bool; rectum : nat
(Yes, I used an english word list to find these hash collisions. There aren t that many actually.)
The benefit of such hashing is that the messages are a bit smaller in most (not all) cases, but it is a big annoyance for dynamic uses of Candid. It s the reason why tools like dfx, if they don t know the Candid interface of a service, will print the result with just the numerical hash, letting you guess which field is which.
It also complicates host languages that derive Candid types from the host language, like Motoko, as some records (e.g. record trustbuster: bool; destroys : int ) with field name hash collisions can not be represented in Candid, and either the host language s type system needs to be Candid aware now (as is the case of Motoko), or serialization/deserialization will fail at runtime, or odd bugs can happen.
(More discussion of this issue).
Tuples
Many languages have a built-in notion of a tuple type (e.g. (Int, Bool)), but Candid does not have such a type. The only first class product type is records.
This means that tuples have to encoded as records somehow. Conveniently(?) record fields are just numbers after all, so the type (Int, Bool) would be mapped to the type
record 0 : int; 1 : bool
So tuples can be expressed. But from my experience implementing the type mappings for Motoko and Haskell this is causing headaches. To get a good experience when importing from Candid, the tools have to try to reconstruct which records may have been tuples originally, and turn them into tuples.
The main argument for the status quo is that Candid types should be canonical, and there should not be more than one product type, and records are fine, and there needs to be no anonymous product type. But that has never quite resonated with me, given the practical reality of tuple types in many host languages.
Argument sequences
Did I say that Candid does not have tuple types? Turns out it does, sort of. There is no first class anonymous product, but since functions take sequences of arguments and results, there is a tuple type right there:
func foo : (bool, int) -> (int, bool)
Again, I found that ergonomic interaction with host languages becomes relatively unwieldy by requiring functions to take and return sequences of values. This is especially true for languages where functions take one argument value or return one result type (the latter being very common). Here, return sequences of length one are turned into that type directly, longer argument sequences turn into the host language s tuple type, and nullary argument sequences turn into the idiomatic unit type. But this means that the types (int, bool) -> () and (record 0: int, 1: bool ) -> () may be mapped to the same host language type, which causes problems when you hope to encode all necessary Candid type information in the host language.
Another oddity with argument and result sequences is that you can give names to the entries, e.g. write
without breaking clients, this does not have the effect you think it has and will likely break.
My suggestion is to never put names on function arguments and result values in Candid interfaces, and for anything that might be extended with new fields or where you want to name the arguments, use a single record type as the only argument:
This allows you to add and remove arguments more easily and reliably.
Type shorthands
The Candid specification defines a system of types, and then adds a number of syntactic short-hands . For example, if you write blob in a Candid type description, it ought to means the same as vec nat8.
My qualm with that is that it doesn t always mean the same. A Candid type description is interpreted by a number of, say, consumers . Two such consumers are part of the Candid specification:
The specification that defines the wire format for that type
The upgrading (subtyping) rules
But there are more! For every host language, there is some mapping from Candid types to host language types, and also generic tools like Candid UI are consumers of the type algebra. If these were to take the Candid specification as gospel, they would be forced to treat blob and vec nat8 the same, but that would be quite unergonomic and might cause performance regressions (most language try to map blob to some compact binary data type, while vec t tends to turn into some form of array structure).
So they need to be pragmatic and treat blob and vec nat8 differently. But then, for all practical purposes, blob is not just a short-hand of vec nat8. They are different types that just happens to have the same wire representations and subtyping relations.
This affects not just blob, but also tuples (record blob; int; bool ) and field names , as discussed above.
The value text format
For a while after defining Candid, the only implementation was in Motoko, and all the plumbing was automatic, so there was never a need for users to to explicitly handle Candid values, as all values were Motoko values. Still, for debugging and testing and such things, we eventually needed a way to print out Candid values, so the text format was defined ( To enable convenient debugging, the following grammar specifies a text format for values ).
But soon the dfx tool learned to talk to canisters, and now users needed to enter Candid value on the command line, possibly even when talking to canisters for which the interface was not known to dfx. And, sure enough, the textual interface defined in the Candid spec was used.
Unfortunately, since it was not designed for that use case, it is rather unwieldy:
It is quite verbose. You have to write record , not just . Vectors are written vec ; instead of some conventional syntax like [ , ]. Variants are written as variant error = " " with braces that don t any value here, and something like #error " " might have worked as well.
With a bit more care, a more concise and ergonomic syntax might have been possible.
It wasn t designed to be sufficient to create a Candid value from it. If you write 5 it s unclear whether that s a nat or an int16 or what (and all of these have different wire representations). Type annotations were later added, but are relatively unwieldy, and don t cover all cases (e.g. a service reference with a recursive type cannot be represented in the textual format at the moment).
Not really the fault of the textual format, but some useful information about the types is not reflected in the type description that s part of the wire format. In particular not the field names, and whether a value was intended to be binary data (blob) or a list of small numbers (vec nat8), so pretty-printing such values requires guesswork. The Haskell library even tries to brute-force the hash to guess the field name, if it is short or in a english word list!
In hindsight I think it was too optimistic to assume that correct static type information is always available, and instead of actively trying to discourage dynamic use, Candid might be better if we had taken these (unavoidable?) use cases into account.
Custom wire format
At the beginning of this post, I have a Candid is list. The list is relatively long, and the actual wire format is just one bullet point. Yes, defining a wire format that works isn t rocket science, and it was easiest to just make one up. But since most of the interesting meat of Candid is in other aspects (subtyping rules, host language integration), I wonder if it would have been better to use an existing, generic wire format, such as CBOR, and build Candid as a layer on top.
This would give us plenty of tools and libraries to begin with. And maybe it would have reduced barrier of entry for developers, which now led to the very strange situation that DFINITY advocates for the universal use of Candid on the Internet Computer, so that all services can smoothly interact, but two of the most important services on the Internet Computer (the registry and the ledger) use Protobuf as their primary interface format, with Candid interfaces missing or an afterthought.
Sideways Interface Evolution
This is not a quirk of Candid itself, but rather an idiom of how you can use Candid that emerged from our solution for record extensions and upgrades.
Consider our example from before, a service with interface
service add_user : (record login : text; name : text ) -> ()
where you want to add an age field, which should be a number.
The official way of doing that is to add that field with an optional type:
service add_user : (record login : text; name : text; age : opt nat ) -> ()
As explained above, this will not break old clients, as the decoder will treat a missing argument as null. So far so good.
But often when adding such a field you don t want to bother new clients with the fact that this age was, at some point in the past, not there yet. And you can do that! The trick is to distinguish between the interface you publish and the interface you implement. You can (for example in your documentation) state that the interface is
service add_user : (record login : text; name : text; age : nat ) -> ()
which is not a subtype of the old type, but it is the interface you want new clients to work with. And then your implementation uses the type with opt nat. Calls from old clients will come through as null, and calls from new clients will come through as opt 42.
We can see this idiom used in the Management Canister of the Internet Computer. The current documented interface only mentions a controllers : vec principal field in the settings, but the implementation still can handle both the old controller : principal and the new controllers field.
It s probably advisable to let your CI system check that new versions of your service continue to implement all published interfaces, including past interfaces. But as long as the actual implementation s interface is a subtype of all interfaces ever published, this works fine.
This pattern is related to when your service implements, say, http_request (so its implemented interface is a subtype of that common interface), but does not include that method in the published documentation (because clients of your service don t need to call it).
Self-describing Services
As you have noticed, Candid was very much designed assuming that all parties always have the service type of services they want to interact with. But the Candid specification does not define how one can obtain the interface of a given service, and there isn t really a an official way to do that on the Internet Computer.
That is unfortunate, because many interesting features depend on that: Such as writing import C "ic:7e6iv-biaaa-aaaaf-aaada-cai" in your Motoko program, and having it s type right there. Or tools like ic.rocks, that allow you to interact with any canister right there.
One reason why we don t really have that feature yet is because of disagreements about how dynamic that feature should be. Should you be able to just ask the canister for its interface (and allow the canister to vary the response, for example if it can change its functionality over time, even without changing the actual wasm code)? Or is the interface a static property of the code, and one should be able to query the system for that data, without the canister s active involvement. Or, completely different, should interfaces be distributed out of band, maybe together with API documentation, or in some canister registry somewhere else?
I always leaned towards the first of these options, but not convincingly enough. The second options requires system assistance, so more components to change, more teams to be involved that maybe intrinsically don t care a lot about this feature. And the third might have emerged as the community matures and builds such infrastructure, but that did not happen yet.
In the end I sneaked in an implementation of the first into Motoko, arguing that even if we don t know yet how this feature will be implemented eventually, we all want the feature to exist somehow, and we really really want to unblock all the interesting applications it enables (e.g. Candid UI). That s why every Motoko canister, and some rust canisters too, implements a method
__get_candid_interface_tmp_hack : () -> (text)
that one can use to get the Candid interface file.
The name was chosen to signal that this may not be the final interface, but like all good provisional solutions, it may last longer than intended. If that s the case, I m not sorry.
This concludes my blog post series about Candid, for now. If you want to know more, feel free to post your question on the DFINTY developer forum, and I ll probably answer.
The Glasgow Haskell Compiler (GHC) has support for user-supplied rewrite rules,
which applied during one of the compiler optimisation stages. An example rule is
-# RULES
"streamFilter fuse" forall f g xs.
streamFilter f (streamFilter g xs) = streamFilter (f.g) xs
#-
I spent some time today looking at these more closely.
In order for rewrite rules to be applied, optimisation needs to be enabled. This
conflicts with interactive use of GHC, so you can't explore these things in GHCi.
I think rewrite rules are enabled by default (with optimisation), but you can ask
for them explicitly. When investigating these it's also useful to ask ghc to
always recompile, otherwise you have to change the source or manually remove .hi
or .o files (etc.) between invocations.
A starting set of command-line options to use then, are
-O -fenable-rewrite-rules -fforce-recomp
GHC runs several compilation stages, and the source program is transformed into
several different languages or language dialects as it goes. Before the phase
where rewrite rules are applied, some other optimisations take place, and the
source gets desugared. You can see the results of the desugaring by passing the
argument -ddump-ds. Here's an example program
main = print (unStream (streamFilter (>3) (streamFilter (<10)
(mkStream [0..20]))))
And here's what it looks like after the first pass optimisation and desugaring:
(Note: I used -dsuppress-all and -dsuppress-uniques to improve the clarity
of the above output. See Suppressing unwanted
information for further details).
Those short-hand sections ((<3)) in the input program are expanded to
something quite a lot longer. Out of curiosity I tried it again with plain
lambdas, not sections, and the result was smaller
main
= print
($fShow[] $fShowInteger)
(unStream
(streamFilter
(\ x -> > $fOrdInteger x 3)
(streamFilter
(\ x -> < $fOrdInteger x 10)
(mkStream (enumFromTo $fEnumInteger 0 20)))))
Rewrite rules happen after this. Once they're done (and several other passes),
the program is translated into an intermediate representation called Tiny
Core. This language
faintly resembles the input Haskell. GHC will output the Tiny Core program
if you supply the argument -ddump-simpl. Here's (most) of the program in Tiny
Core (I've substituted some constants for clarity):
main = hPutStr' stdout main1 True
main1 = $fShowInteger_$cshowList (catMaybes1 (main_go 0)) []
main_go
= \ x ->
case gtInteger# x 20 of
DEFAULT ->
case ltInteger# x 10 of
DEFAULT -> main_go (plusInteger x 1);
1# ->
case gtInteger# x 3 of
DEFAULT -> main_go (plusInteger x 1);
1# -> : (Just x) (main_go (plusInteger x 1))
;
1# -> []
After Tiny Core, GHC continues to translate the program into other forms
(including STG, CMM, ASM) and you can ask GHC to dump those representations too,
but this is all downstream from the rewrites so not relevant to them.
The rewrite rule at the top of this blog post is never applied: It doesn't get
a chance, because the function it operates on (streamFilter) is inlined by
GHC. GHC can detect this in some circumstances (-Winline-rule-shadowing). You
instruct GHC to report on which rules fired with -ddump-rule-firings and can
see before-and-after snippets of Tiny Core for each rule applied with
-ddump-rule-rewrites.
I played around with adding -# NOINLINE functionName #- pragmas to disable
inlining various functions to try and provoke a situation where the above rule
could match, but it was a losing battle: GHC's built-in optimisations are just
too good. But, it's also moot: the outcome I want (the filters to be fused) is
happening, it's just the built-in rewrite rules are achieving it,
once striot's functions
have been inlined away.
We re in the process of upgrading to Debian 11 (bullseye). If you come across any issues, feel free to raise them on the #debian-social IRC channel on oftc (also accessible via Matrix) and we ll look into it as soon as we have a chance.
We re aware that live streaming isn t currently working on our PeerTube instance, we have had some issues with this relatively new feature before, although at the moment we seem to be affected by upstream issue #4390.
In the aftermath of my report of Facebook censoring mentions of the open-source social network Mastodon, there was a lot of conversation about whether or not this was deliberate.
That conversation seemed to focus on whether a human speficially added joinmastodon.org to some sort of blacklist. But that s not even relevant.
OF COURSE it was deliberate, because of how Facebook tunes its algorithm.
Facebook s algorithm is tuned for Facebook s profit. That means it s tuned to maximize the time people spend on the site engagement. In other words, it is tuned to keep your attention on Facebook.
Why do you think there is so much junk on Facebook? So much anti-vax, anti-science, conspiracy nonsense from the likes of Breitbart? It s not because their algorithm is incapable of surfacing the good content; we already know it can because they temporarily pivoted it shortly after the last US election. They intentionally undid its efforts to make high-quality news sources more prominent twice.
Facebook has said that certain anti-vax disinformation posts violate its policies. It has an extremely cumbersome way to report them, but it can be done and I have. These reports are met with either silence or a response claiming the content didn t violate their guidelines.
So what algorithm is it that allows Breitbart to not just be seen but to thrive on the platform, lets anti-vax disinformation survive even a human review, while banning mentions of Mastodon?
One that is working exactly as intended.
We may think this algorithm is busted. Clearly, Facebook does not. If their goal is to maximize profit by maximizing engagement, the algorithm is working exactly as designed.
I don t know if joinmastodon.org was specifically blacklisted by a human. Nor is it relevant.
Facebook s choice to tolerate and promote the things that service its greed for engagement and money, even if they are the lowest dregs of the web, is deliberate. It is no accident that Breitbart does better than Mastodon on Facebook. After all, which of these does its algorithm detect keep people engaged on Facebook itself more?
Facebook removes the ban
You can see all the screenshots of the censorship in my original post. Now, Facebook has reversed course:
We also don t know if this reversal was human or algorithmic, but that still is beside the point.
The point is, Facebook intentionally chooses to surface and promote those things that drive engagement, regardless of quality.
Clearly many have wondered if tens of thousands of people have died unnecessary deaths over COVID as a result. One whistleblower says I have blood on my hands and President Biden said they re killing people before walking back his comments slightly . I m not equipped to verify those statements. But what do they think is going to happen if they prioritize engagement over quality? Rainbows and happiness?
This is the forth post in a series about the interface description language Candid.
Now for something completely different: How does Candid interact with the various host languages, i.e. the actual programming languages that you write your services and clients in?
There are two facets to that question:
How is the Candid interface represented inside the language?
Some languages with rich type systems can express all relevant information about a Candid method or service within its own type system, and then the concrete serialization/deserialization code can be derived from that type (e.g. using type classes in Haskell, Traits in Rust, or built into the compiler in Motoko).
Other languages have a less rich type system (e.g. C), no type-driven generic programming or are simply dynamically typed. In these cases, the Candid type has to be either transformed into specific code for that service by some external tool (e.g. JavaScript and TypeScript) or the Candid description has to be parsed and interpreted at runtime.
Either approach will give rise to a type mapping between the Candid types and the host language types. Developers will likely have to know which types correspond to which, which is why the Candid manual s section on types explicitly lists that.
How is the Candid interface description produced and consumed?
This is maybe the even more important question; what comes first: The code written in the host language, or the Candid description. There are multiple ways to tackle this, all of which have their merits, so I let s look at some typical approaches.
Generating candid from the host language
In many case you don t care too much about the interface of your service, and you just want to write the functionality, and get the interface definition for free. This is what you get when you write Motoko services, where the compiler calculates the Candid interface based on the Motoko types of your actor methods, and the build tool (dfx) puts that Candid file where it needs to go. You can thus develop services without ever writing or even looking at Candid type definitions.
The Candid library for Rust supports that mode as well, although you have to add some macros to your program to use it.
A downside of this model is that you have only indirect control over the generated Candid. Since it is type-driven, whenever there is more than one sensible Candid type for a given host language type, the translation tool has to make a choice, and if that does not suit you, that can be a problem.
In the case of Motoko we were able to co-design it with Candid, and their type systems are similar enough that this works well in practice. We have a specification of Candid-Motoko-type-mappings, and the type export from from Motoko to Candid is almost surjective. (Almost, because of Candid s float32 type, which Motoko simply does not have, and because of service types with methods names that are not valid Motoko identifiers.)
Checking host language against Candid
The above works well when you (as the service developer) get to define the service s interface as you go. But sometimes you want to develop a service that adheres to a given Candid interface. For example, in order to respond to HTTP requests in an Internet Computer service, you should provide a method http_request that implements this interface (simplified):
type HeaderField = record text; text; ;
type HttpRequest = record
method: text;
url: text;
headers: vec HeaderField;
body: blob;
;
type HttpResponse = record
status_code: nat16;
headers: vec HeaderField;
body: blob;
;
service :
http_request: (request: HttpRequest) -> (HttpResponse) query;
Here, a suitable mode of operation is to generate the Candid description of the service that you built, and then compare it against this expected interface with a tool that implements the Candid subtyping relation. This would then complain if what you wrote was not compatible with the above interface. The didc check tool that comes with the Rust library can do that. If your service has to implement multiple such pre-defined interfaces, its actual interface will end up being a subtype of each of these interfaces.
Importing Candid
If you already have a Candid file, in particular if you are writing a client that wants to talk to an existing service, you can also import that Candid file into your language. This is a very common mode of operation for such interface descriptions languages (e.g. Protobuf). The details depend a lot on the host language, though:
In Motoko, you can import typed actor references: Just write import C "canister:foo" where foo is the name of another canister in your project, and your build tool (dfx) will pass the Candid interface of foo to the Motoko compiler, which then translates that Candid service type into a Motoko actor type for you to use.
The mapping from Candid types to Motoko types is specified in IDL-Motoko.md as well, via the function i( ).
The vision was always that you can import a reference to any canister on the Internet Computer this way (import C "ic:7e6iv-biaaa-aaaaf-aaada-cai"), and the build tool would fetch the interface automatically, but that has not been implemented yet, partly because of disagreement about how canisters expose their interface (see below). The Motoko compiler is ready, though, as described in its build tool interface specification.
What is still missing in Motoko is a way to import a Candid type alone (without a concrete canister reference), to use the types somewhere (in function arguments, or to assert the type of the full canister).
The Rust library does not support importing Candid, as far as I know. If you write a service client in Rust, you have to know which Rust types map to the right Candid types, and manually get that right.
For JavaScript and TypeScript, the didc tool that comes with the Rust library can take a Candid file and produce JS resp. TS code that gives you an object representing the service with properly typed methods that you can easily interact with.
With the Haskell Candid library you can import Candid inline or from a file, and it uses metaprogramming (Template Haskell) to generate suitable Haskell types for you, which you can encode/decode at. This is for example used in the test suite of the Internet Identity, which executes that service in a simulated Internet Computer environment.
Generic and dynamic use
Finally, it s worth mentioning that Candid can be used generically and dynamically:
Since Canisters can indicate their interface, a website like ic.rocks that enumerates Canisters can read that interface, and provide a fully automatically generated UI for them. For example, you can not only see the Candid interface of the Internet Identity canister at https://ic.rocks/principal/rdmx6-jaaaa-aaaaa-aaadq-cai, but actually interact with it!
Similarly, during development of a service, it is very useful to be able to interact with it before you have written your actual front-end. The Candid UI tool provides that functionality, and can be used during local development or on-chain. It is also integrated into the Internet Computer playground.
Command line tools like dfx allow you to make calls to services, even without having their actual Candid interface description around. However, such dynamic use was never part of the original design of Candid, so it is a bit rough around the edges the textual format is a bit unwieldy, you need to get the types right, and field name in the responses may be missing.
Do you want to know why field names are missing then? Then check out the next and final post of this series, where I discuss a number of Candid s quirks.
This release is the culmination of a project that I've been wanting to do
for two years, but nearly all the work was done in the past week. That
experience made me rethink some of my skepticism, but I'll get to that
part of the story later.
In March of 1999, I got tired of writing HTML by hand and wrote a small
program called spin that implemented a macro language that translated into
HTML. This makes it one of the oldest programs for which I have a
continuous development history, predating podlators by three months. I think only News::Gateway (now very dormant) and Term::ANSIColor (still under active development but very stable) are
older, as long as I'm not counting orphaned packages like
newsyslog.
I've used spin continuously ever since. It's grown features and an
ecosystem of somewhat hackish scripts to do web publishing things I've
wanted over the years: journal entries like this one, book reviews, a
simple gallery (with some now-unfortunate decisions about maximum image
size), RSS feeds, and translation of lots of different input files into
HTML. But the core program itself, in all those years, has been one
single Perl script written mostly in my Perl coding style from the early
2000s before I read Perl Best Practices.
My web site is long overdue for an overhaul. Just to name a couple of
obvious problems, it looks like trash on mobile browsers, and I'm using
URL syntax from the early days of the web that, while it prompts some
nostalgia for tildes, means all the URLs are annoyingly long and embed
useless information such as the fact each page is written in HTML. Its
internals also use a lot of ad hoc microformats (a bit of RFC 2822 here, a
text-based format with significant indentation there, a weird
space-separated database) and are supported by programs that extract
meaning from human-written pages and perform automated updates to them
rather than having a clear separation between structure and data.
This will be a very large project, but it's the sort of quixotic personal
project that I enjoy. Maintaining my own idiosyncratic static site
generator is almost certainly not an efficient use of my time compared to,
say, converting everything to Hugo. But I have
3,428 pages (currently) written in the thread macro language, plus
numerous customizations that cater to my personal taste and interests,
and, most importantly, I like having a highly customized system that I
know exactly how to automate.
The blocker has been that I didn't want to work on spin as it existed. It
badly needed a structural overhaul and modernization, and even more badly
needed a test suite since every release involved tedious manual testing by
pouring over diffs between generations of the web site. And that was
enough work to be intimidating, so I kept putting it off.
I've separately been vaguely aware that I have been spending too much time
reading Twitter (specifically) and the news (in general). It would be one
thing if I were taking in that information to do something productive
about it, but I haven't been. It's just doomscrolling. I've been
thinking about taking a break for a while but it kept not sticking, so I
decided to make a concerted effort this week.
It took about four days to stop wanting to check Twitter and forcing
myself to go do something else productive or at least play a game instead.
Then I managed to get started on my giant refactoring project, and holy
shit, Twitter has been bad for my attention span! I haven't been able to
sustain this level of concentration for hours at a time in years.
Twitter's not the only thing to blame (there are a few other stressers
that I've fixed in the past couple of years), but it's obviously a huge
part.
Anyway, this long personal ramble is prelude to the first release of
DocKnot that includes my static site generator. This is not yet the full
tooling from my old web tools page;
specifically, it's missing faq2html, cl2xhtml, and cvs2xhtml. (faq2html
will get similar modernization treatment, cvs2xhtml will probably be
rewritten in Perl since I have some old, obsolete scripts that may live in
CVS forever, and I may retire cl2xhtml since I've stopped using the GNU
ChangeLog format entirely.) But DocKnot now contains the core of my site
generation system, including the thread macro language, POD conversion (by
way of Pod::Thread), and RSS feeds.
Will anyone else ever use this? I have no idea; realistically, probably
not. If you were starting from scratch, I'm sure you'd be better off with
one of the larger and more mature static site generators that's not the
idiosyncratic personal project of one individual. It is packaged for
Debian because it's part of the tool chain for generating files
(specifically README.md) that are included in every package I
maintain, and thus is part of the transitive closure of Debian main, but
I'm not sure anyone will install it from there for any other purpose. But
for once making something for someone else isn't the point. This is my
quirky, individual way to maintain web sites that originated in an older
era of the web and that I plan to keep up-to-date (I'm long overdue to
figure out what they did to HTML after abandoning the XHTML approach)
because it brings me joy to do things this way.
In addition to adding the static site generator, this release also has the
regular sorts of bug fixes and minor improvements: better formatting of
software pages for software that's packaged for Debian, not assuming every
package has a TODO file, and ignoring Autoconf 2.71 backup files when
generating distribution tarballs.
You can get the latest version of DocKnot from CPAN as App-DocKnot, or
from its distribution page. I know I
haven't yet updated my web tools page to reflect this move, or changed the
URL in the footer of all of my pages. This transition will be a process
over the next few months and will probably prompt several more minor
releases.
Cisco pyATS is a framework for network automation and testing. It
includes, among other things, an open-source multi-vendor set of
parsers and models, Genie Parser. It features 2700 parsers for
various commands over many network OS. On the paper, this seems a
great tool!
>>> fromgenie.conf.baseimportDevice>>> device=Device("router",os="iosxr")>>> # Hack to parse outputs without connecting to a device>>> device.custom.setdefault("abstraction", )["order"]=["os","platform"]>>> cmd="show route ipv4 unicast">>> output="""... Tue Oct 29 21:29:10.924 UTC...... O 10.13.110.0/24 [110/2] via 10.12.110.1, 5d23h, GigabitEthernet0/0/0/0.110... """>>> device.parse(cmd,output=output) 'vrf': 'default': 'address_family': 'ipv4': 'routes': '10.13.110.0/24': 'route': '10.13.110.0/24', 'active': True, 'route_preference': 110, 'metric': 2, 'source_protocol': 'ospf', 'source_protocol_codes': 'O', 'next_hop': 'next_hop_list': 1: 'index': 1, 'next_hop': '10.12.110.1', 'outgoing_interface': 'GigabitEthernet0/0/0/0.110', 'updated': '5d23h'
First deception: pyATS is closed-source with some exceptions. This
is quite annoying if you run into some issues outside Genie Parser.
For example, although pyATS is using the ssh command, it cannot
leverage my ssh_config file: pyATSresolves hostnames before
providing them to ssh. There is no plan to open source
pyATS.
Then, Genie Parser has two problems:
The data models used are dependent on the vendor and OS,
despite the documentation saying otherwise. For
example, the data model used for IPv4 interfaces is different
between NX-OS and IOS-XR.
The parsers rely on line-by-line regular expressions to extract
data and some Python code as glue. This is fragile and may break
silently.
To illustrate the second point, let s assume the output of show ipv4
vrf all interface is:
Loopback10 is Up, ipv4 protocol is Up
Vrf is default (vrfid 0x60000000)
Internet protocol processing disabled
Loopback30 is Up, ipv4 protocol is Down [VRF in FWD reference]
Vrf is ran (vrfid 0x0)
Internet address is 203.0.113.17/32
MTU is 1500 (1500 is available to IP)
Helper address is not set
Directed broadcast forwarding is disabled
Outgoing access list is not set
Inbound common access list is not set, access list is not set
Proxy ARP is disabled
ICMP redirects are never sent
ICMP unreachables are always sent
ICMP mask replies are never sent
Table Id is 0x0
Because the regular expression to parse an interface name does not
expect the extra data after the interface state, Genie Parser
ignores the line starting the definition of Loopback30 and parses
the output to this structure:1
While this bug is simple to fix, this is an uphill battle. Any
existing or future slight variation in the output of a command could
trigger another similar undetected bug, despite the extended test
coverage. I have reported and fixed several other silent parsing
errors: #516, #529, and #530. A more robust alternative
would have been to use TextFSM and to trigger a warning when some
output is not recognized, like Batfish, a configuration analysis
tool, does.
In the future, we should rely on YANG for data extraction, but it
is currently not widely supported. SNMP is still a valid possibility
but much information is not accessible through this protocol. In the
meantime, I would advise you to only use Genie Parser with caution.
As an exercise, the astute reader is asked to write the code
to extract the IPv4 from this structure.
This Perl module converts POD documents to thread, the macro language I
use for my static site builder (about which, more in another software
release coming up shortly). This release fixes a whole ton of
long-standing problems.
Remove support for parsing CVS $Id$ strings and emitting
\id commands.
Stop wrapping output text.
Fix internal section links.
Fix conversion of nested =over blocks.
Fix conversion of =over blocks without an =item.
Fix links to headings containing markup.
Fix metacharacter escaping in headings, contents, and navbar.
Fix handling of =for thread and =begin thread.
Fix non-breaking spaces in navbar section names.
Fix internal links whose anchors are wrapped.
Output the document before erroring out if POD errors were seen.
Suppress \signature if the input document was empty.
Add bugtracker, homepage, and repository package metadata.
In brief, a lot of the POD implementation was previously done by chasing
bugs rather than testing comprehensively, as reflected by the 65% code
coverage in the previous release. The test suite now achieves about 95%
code coverage (most of the rest is obscure error handling around
encoding) and cleans up a bunch of long-standing problems with internal
links.
I had previously punted entirely on section links containing markup, and
as a result the section links shown in the navigation bar or table of
contents were missing the markup and headings containing thread
metacharacters were mangled beyond recognition. That was because I was
trying to handle resolving links using regexes (after I got rid of the
original two-pass approach that required a driver script). This release
uses Text::Balanced instead, the same parsing module used by my static
site generator, to solve the problem (mostly) correctly. (I think there
may still be a few very obscure edge cases, but I probably won't encounter
them.)
The net result should hopefully be better conversion of my software
documentation, including INN documentation, when I regenerate my site
(which will be coming soon).
You can get the latest release from CPAN or from the
Pod::Thread distribution page.
Update: Facebook has reversed itself over this censorship, but I maintain that whether the censorship was algorithmic or human, it was intentional either way. Details in my new post.
Last November, I made a brief post to Facebook about Mastodon. Mastodon is an open-source and open social network, which is decentralized and all about user control instead of corporate control. I ve blogged about Mastodon and the dangers of Facebook before, but rarely mentioned Mastodon on Facebook itself.
Today, I received this notice that Facebook had censored my post about Mastodon:
Wonder with me for a second what this one-off post I composed myself might have done to trip Facebook s filter . and it is probably obvious that what tripped the filter was the mention of an open source competitor, even though Facebook is much more enormous than Mastodon. I have been a member of Facebook for many years, and this is the one and only time anything like that has happened.
Why they decided today to take down that post I have no idea.
In case you wondered about their sincerity towards stamping out misinformation which, on the rare occasions they do something about, they deprioritize rather than remove as they did here this probably answers your question. Or, are they sincere about thinking they re such a force for good by connecting the world s people? Well, only so long as the world s people don t say nice things about alternatives to Facebook, I guess.
Well, you might be wondering, Why not appeal, since they obviously made a mistake? Because, of course, you can t:
Indeed I did tick a box that said I disagreed, but there was no place to ask why or to question their action.
So what would cause a non-controversial post from a long-time Facebook member that has never had anything like this happen, to disappear?
Greed. Also fear.
Maybe I d feel sorry for them if they weren t acting like a bully.
Edit: There are reports from several others on Mastodon of the same happening this week. I am trying to gather more information. It sounds like it may be happening on Twitter as well.
Edit 2: And here are some other reports from both Facebook and Twitter. Definitely not just me.
Edit 3: While trying to reply to someone on Facebook, that was trying to defend Facebook, I mentioned joinmastodon.org and got this:
Anyone else seeing it?
Edit 4: It is far more than just me, clearly. More reports are out there; for instance, this one and that one.
I had this nightmare where I had a very, very important confcall.
I joined with Chrome. Chrome said Failed to access your microphone -
Cannot use microphone for an unknown reason. Could not start audio source.
I joined with Firefox. Firefox chose Monitor of Built-in Audio Analog Stereo
as a microphone, and did not let me change it. Not in the browser, not in
pavucontrol.
I joined with the browser on my phone, and the webpage said This meeting needs
to use your microphone and camera. Select *Allow* when your browser asks for
permissions. But the question never came.
I could hear people talking. I had very important things to say. I tried typing
them in the chat window, but they weren't seeing it. The meeting ended. I was
on the verge of tears.
Tell me, Mr. Anderson, what good is a phone call when you are unable to speak?
Since this nightmare happened for real, including the bit about tears in the
end, let's see that it doesn't happen again. I should now have three working
systems, which hopefully won't all break again all at the same time.
Fixing Chrome
I can reproduce this reliably, on Bullseye's standard Chromium
90.0.4430.212-1, just launched on an empty profile, no extensions.
The webpage has camera and microphone allowed. Chrome doesn't show up in the
recording tab of pulseaudio. Nothing on Chrome's stdout/stderr.
JavaScript console has:
Logger.js:154 2021-09-10Txx:xx:xx.xxxZ [features/base/tracks] Failed to create local tracks
Array(2)
DOMException: Could not start audio source
I had the similar problem once with chromium.
i could solve it by switching in preferences->microphone-> from "default" to "intern analog stereo".
Opening the little popup next to the microphone/mute button allows choosing
other microphones, which work. Only "Same as system (Default)" does not work.
Fixing Firefox
I have firefox-esr 78.13.0esr-1~deb11u1. In Jitsi, microphone selection is
disabled on the toolbar and in the settings menu. In pavucontrol, changing the
recording device for Firefox has no effect. If for some reason the wrong
microphone got chosen, those are not ways of fixing it.
What I found works is to click on the camera permission icon, remove microphone
permission, then reload the page. At that point Firefox will ask for permission
again, and that microphone selection seems to work.
Relevant bugs: on Jitsi and
on Firefox. Since this
is well known (once you find the relevant issues), I'd have appreciated Jitsi
at least showing a link to an explanation of workarounds on Firefox, instead of
just disabling microphone selection.
Fixing Jitsi on the phone side
I really don't want to preemptively give camera and microphone permissions to
my phone browser. I noticed that there's the Jitsi app on F-Droid
and much as I hate to use an app when a website would work, at least in this
case it's a way to keep the permission sets separate, so I installed that.
Fixing pavucontrol?
I tried to find out why I can't change input device for FireFox on pavucontrol.
I only managed to find an Ask Ubuntu question with no answer
and a Unix StackExchange question with no answer.