1. 2

    Note that this was based upon OpenBSD 4.6.

    1. 10

      If you want proper as in “canonical”, John Gruber’s original is your best choice. It is effectively the definition of markdown. But markdown has moved on beyond Gruber’s original vision, mostly without him. Still, his original vision in collaboration with Aaron Swartz is still very usable, especially for blogging.

      Once you move beyond the original Perl code, you have numerous choices. Here are a few:

      And there’s no shortage of online converters and other versions.

      I’ve used pandoc for years. It doesn’t just convert markdown to html. It converts from multiple formats to multiple formats, including various slide formats as well as PDF. It supports Python and Haskell scripts, as well as Lua scripting. The Lua scripting is very interesting because it manipulates the AST in memory as opposed to Python and Haskell where pandoc marshalls the AST to a JSON representation, pipes it to the script, and then receives the output.

      Lowdown is interesting because it’s a fork of hoedown. @kristaps went through it and added a proper AST representation internally as well as pledge and privilege separating it. He doesn’t expose the AST (yet?), but it’s fast and efficient.

      Multimarkdown is a good choice if you want to stay in Markdown but target more than one output format. Like pandoc, mmd can export to several slide formats and pdf by way of LaTeX.

      Lastly, the lua and awk versions are noted above because I like little languages that do so much. ;-)

      For most of what markdown was originally designed for, text files converted to HTML, you almost can’t go wrong. Where you’re going to find your choices both expanded and somewhat complicated is when you move beyond basic markdown and start trying to write slides, documentation, books, or use add-on features like tables.

      I’d suggest start with basic markdown as described on Gruber’s Markdown page, pick one of the simpler converters like his Perl script, and see whether you need anything beyond that. Then look at Pandoc and Multimarkdown. If you don’t need more features but want more speed, then look at Lowdown.

      1. 2

        lowdown does have its library exposed! pkg_add lowdown, man 3 lowdown.

        1. 1

          Thanks for the detailed answer!

        1. 3

          pkg_locate doesn’t find any of these. It does, however, find pelican and my own, sblg. I’ve also heard a lot about Roman’s ssg.

            1. 4

              How about “learn javascript” instead of any of its countless frameworks? It’s pretty easy to write compliant vanilla javascript without jumping through per-browser hoops. Same goes with CSS and HTML—maybe learn those too?

              Though these days, I guess I’d rather suggest people write typescript.

              1. 4

                This doesn’t solve a contention problem: it merely notifies folks when the jakes are in use.

                (A “bathroom contention problem” would probably be solved by some straightforward modelling and controlled distribution of coffee.)

                1. 11

                  “Unfortunately, the fundamentalist FOSS mentality we encountered on Reddit is still alive and well.” Ok, so this “fundamentalist” attitute, according to the article, is from comments like “This is going to be a very hard sell being a proprietary closed source system to Linux users, many use Linux because they have bought into the idea of open source. Good luck with it anyway”. I understand that this article is just a closed-source product promo (whose claim to fame is interoperating with… another closed-source product), but name-calling folks (probably like myself) who use open source “fundamentalists” is wrong, especially when they give feedback as quoted.

                  Then we have, “we don’t store or process data online — strictly between you and your mail server”, but, “users can turn off what little data collection we do”. Um… pick one.

                  1. 1

                    i guess they meant “unfortunately for us proprietary software programmers who want to exploit users.”

                  1. 3

                    If anybody feels like having some weekend fun, BCHS is always wanting for articles on using these tools! (I use scan-build all the time, though I swear mostly by AFL and valgrind.)

                      1. 1

                        Sorry, too late to edit it now as well. I wonder if a moderator can change it

                      1. 0

                        I propose having several API releases with absolutely nothing in them so that browsers can catch up with the “extremely exciting” eye cancer already there. See caniuse browser scores for more. Also, I would like a pony.

                        1. 3

                          If you would like to criticise this API or web APIs in general, could you please do it in some sort of constructive manner? I have no idea what your comment was about, other than that you seem angry about something.

                        1. 9

                          Many of the author’s experiences speaking with senior government match my own.

                          However, there’s one element that I think is very easily lost in this conversation, and which I want to highlight: there is no group I spend more time trying to convince of the importance of security than other software engineers.

                          Software engineers are the only group of people I’ve ever had push back when I say we desperately need to move to memory safe programming languages. All manner of non-engineers, when I’ve explained the damages wrought by C/C++, and how nearly every mass-vulnerability they know about has a shared root cause, generally understand why this is an important problem, and want to discuss ideas about how do we resolve this.

                          Engineers complain to me that rewriting things is hard, and besides if you’re disciplined in writing C and use sanitizers and fuzzers you’ll be ok. Rust isn’t ergonomic enough, and we’ve got a really good hiring pipeline for C++ engineers.

                          If we want to build software safety into everything we do, we need to get engineers on board, because they’re the obstacle.

                          1. 11

                            People don’t even use sanitizers and fuzzers, so I’m not sure why you would expect them to rewrite in Rust. It’s literally 1000x less effort.

                            As far as I can tell, CloudFlare’s CloudBleed bug would have been found if they compiled with ASAN and fed about 100 HTML pages into it. You don’t even have to install anything; it’s built right into your compiler! (both gcc and Clang)

                            I also don’t agree that “nearly every mass vulnerability has a shared root cause”. For example, you could have written ShellShock in Rust, Python, or any other language. It’s basically a “self shell-code injection” and has very little to do with memory safety (despite a number of people being confused by this.)

                            The core problem is the sheer complexity and number of lines of unaudited code, and the fact that core software like bash has exactly one maintainer. There are actually too many people trying to learn Rust and too few people maintaining software that everybody actually uses.

                            In some sense, Rust can make things worse, because it leads to more source code. We already have memory-safe languages: Python, Ruby, JavaScript, Java, C#, Erlang, Clojure, OCaml, etc.

                            Software engineers should definitely spend more time on security, and need to be educated more. But the jump to Rust is a non-sequitur. Rust is great for kernels where the above languages don’t work, and where C and C++ are too unsafe. But kernels are only a part of the software landscape, and they don’t contain the majority of security bugs.

                            I would guess that most data breaches these days have nothing to do with memory safety, and have more to do with bugs similar to the ones in the OWASP top 10 (e.g. XSS, etc.)


                            Edit: as another example, Mirai has nothing to do with memory safety:


                            All it does it try default passwords, which gives you some idea of where the “bar” is. Rewriting software in Rust has nothing to do with that, and will actually hurt because it takes effort and mindshare away from solutions with a better cost/benefit ratio. And don’t get me wrong, I think Rust has its uses. I just see people overstating them quite frequently, with the “why don’t more people get Rust?” type of attitude.

                            1. 2

                              There were languages like Opa that tried to address what happened on web app side. They got ignored just like people ignore safety in C. Apathy is the greatest enemy of security. It’s another reason we’re pushing the memory-safe, higher-level languages, though, with libraries for stuff likely to be security-critical. The apathetic programmers do less damage on average that way. Things that were code injections become denial of service. That’s an improvement.

                            2. 2

                              not only software engineers, almost the entire IT industry has buried it’s head in the sand and is trying desperately hard to hide from the problem, because “security is too hard”. We are pulling teeth to get people to even do the minimal upgrades to things. I recently had a software vendor refusing to support anything other than TLS 1.0. After many exchanges back and forth, including an article from Microsoft(and basically every other sane person) saying they were dropping all support of older TLS protocols because of their insecurity, they finally said, OK we will look into it. I’m sure we all have stories like this.

                              If you can’t even bother to take the minimum of steps to upgrade your security stacks after more than a decade,(TLS1.0 released in 1999 and TLS 1.2 is almost exactly a decade old now) because it’s “too hard”, trying to get people to move off of memory unsafe languages like C/C++ is a non-starter.

                              But I agree with you, and the author.

                              1. 2

                                I would like to use TLS 1.3 for an existing product. It’s in C and Lua. The current system is network driven using select() (or poll() or epoll() depending upon the platform). The trouble I’m having is finding a library that is easy, or even a bit complicated but sane to use. The evented nature means I an notified when data comes in, and I want to feed this to the TLS library instead of having the TLS library manage the sockets for me. But the documentation is dense, the tutorials only cover blocking calls, and that’s when they’re readable! Couple this with the whole “don’t you even #$@#$# think of implementing crypto” that is screamed from the roof tops and no wonder software engineers steer away from this crap.

                                I want a crypto library that just handles the crypto stuff. Don’t do the network, I already have a framework for that. I just need a way to feed data into it, and get data out of it, and tell me if the certificate is good or not. That’s all I’m looking for.

                                1. 2

                                  OpenBSD’s libtls.

                                  1. 2

                                    TLS 1.3 is not quite ready for production use, unless you are an early adopter like Cloudfare. Easy to use API’s that are well-reviewed are not there yet.

                                    Crypto Libraries: OpenBSD’s libtls like @kristapsdz mentioned, or libsodium/nacl or OpenSSL. If it’s just for your internal connections and don’t actually need TLS, just talking to libsodium or NaCL for an encrypted stream of bytes is probably your best bet, using XSalsa20+Poly1305. See: https://latacora.singles/2018/04/03/cryptographic-right-answers.html

                                    TLS is a complicated protocol(TLS1.3 reduces a LOT of complexity, it’s still very complicated).

                                    If you are deploying to Apple, Microsoft or OpenBSD platforms, you should just tie to the OS provided services, that provide TLS. Let them handle all of that for you(including the socket). Apple and MS platforms have high-level API’s that will do all the security crap for you. OpenBSD has libtls.

                                    On other platforms(Linux, etc), you should probably just use OpenSSL. Yes it’s a fairly gross API, but it’s pretty well-maintained nowadays(5 years ago, it would not qualify as well maintained.). The other option is libsodium/NaCL.

                                    1. 1

                                      Okay, fine. Are there any crypto libraries that are easy to use for whatever is current today? My problem is: a company that is providing us information today via DNS has been invaded by a bunch of hipster developers [1] who drunk the REST Kool-Aid™ so I need a way to make an HTTPS call in an event driven architecture and not blow our Super Scary SLAs with the Monopolistic Phone Company (which would case the all-important money to flow the other way), so your advice to let OS provided TLS services control the socket is a non-starter.

                                      And for the record, the stuff I write is deployed to Solaris. For reasons that exceed my pay grade.

                                      So I read the Cryptographic Right Answers you linked to and … okay. That didn’t help me in the slightest.

                                      The program I’m working on is in C, and not written by me (so it’s in “maintenance mode”). It works, and rewriting it from scratch is probably also a non-starter.

                                      Are you getting a sense of the uphill battle this is?

                                      [1] Forgive my snarky demeanor. I am not happy about this.

                                      Edit: further clarification on what I have to work with.

                                      1. 1

                                        I get it, it sucks sometimes. I’m guessing you are not currently doing any TLS at all? So you can’t just upgrade the libraries you are currently using for TLS, whatever they are.

                                        In my vendor example, the vendor already implemented TLS (1.0) and then promptly stopped. They have never bothered to upgrade to newer versions of TLS. I don’t know the details of their implementation, obviously, since it’s closed-source; but unless they went crazy and wrote their own crypto code, upgrading their crypto libraries is probably all that’s required. I’m not saying it’s necessarily easy to do that, but this is something everyone should do at least once every decade, just to keep the code from rotting a terrible death anyways. TLS 1.2 becomes a decade old standard next month.

                                        I don’t work on Solaris platforms (and haven’t in at least a decade, so you are probably better off checking with other Solaris people). Oracle might have a TLS library these days, I have no clue. I tend to avoid Oracle land whenever possible. I’m sorry you have to play in their sandbox.

                                        I agree the Crypto right-answers page isn’t useful for you, since you just want TLS, It’s target is for developers who need more than TLS. I used it here mostly as proof of why I recommended XSalsa20+Poly1305 for symmetric encryption. Again, you know you need TLS, so it’s a non-useful document for you at this point.

                                        Event driven IO is possible with OpenSSL, but it’s not super easy see: https://www.openssl.org/docs/faq.html#PROG11. Then again, nothing around event driven IO is super easy. Haproxy and Nginx both manage to do it, and are both open-source implementations of TLS, so you have working code you can go examine. Plus it might give you access to developers who have done event driven IO with TLS. I haven’t ever written that implementation, so I can’t help with those specifics.

                                        OpenSSL is working on making their API’s easier to use, but it’s a long, slow haul, but it’s definitely a known problem, and they are working on it.

                                        As for letting the OS do the work for you, you are correct there are definitely use-cases where it won’t work, and it seems you fit the bill. For most applications, letting the OS do it for you is generally the best answer, especially around Crypto which can be hard to get right, and of course only applies to the platforms that offer such things(Apple, MS, etc). Which is why I started there ;)

                                        Anyways, good luck! Sorry I can’t just point to a nice easy example, for you. Maybe someone else around here can.

                                        1. 1

                                          I’m not even using TCP! This is all driven with UDP. TCP complicates things but is manageable. Adding a crap API between TCP and my application? Yeah, I can see why no one is lining up to secure their code.

                                          1. 1

                                            I think there is a communication issue here.

                                            The vendor you are connecting with over HTTPS supports UDP packets on a REST API interface? really? Crazier things have happened I guess.

                                            I think what you are saying is you are doing DNS over UDP for now, but are being forced into HTTPS over TCP?

                                            DNS over UDP is very far away from a HTTPS rest API.

                                            Anyways, for being an HTTPS client, against a HTTPS REST API over TCP, you have 2 decent options:

                                            Event driven/async: use libevent, example code: https://github.com/libevent/libevent/blob/master/sample/https-client.c

                                            But most people will be boring, and use something like libcurl (https://curl.haxx.se/docs/features.html) and do blocking I/O. If they have enough network load, they will setup a pool of workers.

                                            1. 2

                                              Right now, we’re looking up NAPTR records over DNS (RFC-3401 to RFC-3404). The summary is that one can query name information for a given phone number (so 561-555-5678 is ACME Corp.). The vendor wants to switch to a REST API and return JSON. Normally I would roll my eyes at this but the context I’m working in is more realtime—as in Alice is calling Bob and we need to look up the information as the call is being placed! WE have a hard deadline with the Monopolistic Phone Company to provide this information [1].

                                              We don’t use libevent but I’ll look at the code anyway and try to make heads and tails.

                                              [1] Why are we querying a vendor this for? Well, it used to be in house, but now “we lease this back from the company we sold it to - that way it comes under the monthly current budget and not the capital account.” (at least, that’s my rational for it).

                                              1. 2

                                                Tell me how it goes. Fwiw, you might want to take a quick look at mbed TLS. Sure it wants to wrap a socket fd in its own context and use read/write on it, but you can still poll that fd and then just call the relevant mbedtls function when you have data coming in. It does also support non-blocking operation.

                                                https://tls.mbed.org/api/net__sockets_8h.html#a2ee4acdc24ef78c9acf5068a423b8c30 https://tls.mbed.org/api/net__sockets_8h.html#a03af351ec420bbeb5e91357abcfb3663


                                                https://tls.mbed.org/kb/how-to/mbedtls-tutorial (non-blocking io not covered in the tutorial but it doesn’t change things much)

                                                I’ve no experience with UDP (yet – soon I should), but if you’re doing that, well, mbedtls should handle DTLS too: https://tls.mbed.org/kb/how-to/dtls-tutorial (There’s even a note relevant to event based i/o)

                                                We use mbedtls at work in a heavily event based system with libev. Sorry, no war stories yet, I only got the job a few weeks ago.

                                                1. 1

                                                  Right, let’s add MORE latency for a real-time-ish system. Always a great idea! :)

                                1. 6

                                  Note: not about manpages.

                                    1. 20
                                        Spread out?
                                      1. 1

                                        no ahahahha

                                      1. 1

                                        Are there any benchmarks for this?

                                        1. 2

                                          Only thing I see is the the performance graph on the author’s page here: https://kristaps.bsd.lv/kcgi/

                                          1. 1

                                            I’ve long wanted to update these with some good measurements against, say, PHP. (And on OpenBSD, too.) It’s important to have a solid measure of the performance trade-off between CGI with a compiled binary and the FastCGI clones (Python’s, PHP’s, etc.) alongside the security benefits of ephemeral processes.

                                            1. 1

                                              Wow. Thanks for that.

                                              15msec response sounds like an eternity. My server responds in micros over loopback, so what’s going on?

                                              Is there an easy way to test this?

                                          1. 6

                                            I was so happy in thinking that somebody wrote a performant tsc implementation.

                                            % time tsc --outFile foo.js foo.ts 
                                                0m01.93s real     0m02.68s user     0m00.49s system


                                            % cat foo.ts
                                            module Shapes {
                                                export class Rectangle {
                                                    constructor (public height: number, public width: number) { }
                                            1. 1

                                              Cryptocurrencies are certainly a… textured subject of economics. But to answer the author’s question of, “How does a non-mathematician judge these things?”, well, for starters, perhaps by engaging reputable sources. Such as, say, one of those mathematicians, or perhaps an economist qualified to navigate the subject matter. The author, however, does not appear to be one of either. How did he judge?

                                              1. 2

                                                This is such a nightmare, but that’s ok, because it’s a subset of the larger CalDAV nightmare. (Inconsistent formats, inconsistent standards implementations, etc.) In kcaldav, I ended up parsing and ignoring rrules, and just fetching all entries on collection requests because computing recurrences within intervals is complicated. Let the client sort it out.

                                                Whenever I get back to this (unfortunately, “it just works” for my tiny calendar, which is the enemy of “make it work better”), I’ve scratched the surface (in datetime.c) with a way to bisect recurring intervals from a rule until on falls within a duration, and simply bound durations below to, say, the daily or hourly level. Either way, I’d need to pull ever rrule from the database and run this routine.

                                                If you’re interested in dirtying your hands with CalDAV, it’s all there, but certainly not easy.

                                                1. 7

                                                  Why not just directly write man(7), which is all this tool produces? Or use the existing perlpod, pandoc, docbook, lowdown, rst2man, or any other tool doing exactly the same thing from diverse formats?

                                                  Because I’m sure the world needs more opaque, un-indexable manpages.

                                                  (Edit: to clarify, use mdoc(7).)

                                                  1. 5

                                                    Author here. Did you even read the blog post? I answered all of these questions.

                                                    perlpod is built on a mountain of perl, and pandoc on a mountain of haskell. lowdown is a Markdown implementation, and Markdown and roff are mutually exclusive. RST and roff are mutually exclusive. I spoke about docbook directly in my article (via asciidoc, which is a docbook frontend). I also directly addressed mdoc.

                                                    Man pages are already being indexed. If you search the web for “man [anything]” you’ll find numerous websites which scrape packages and convert the roff into HTML.

                                                    1. 1

                                                      Thanks for your hack. It’s a good candidate for a port in my little os.

                                                      A couple of question:

                                                      • have you considered to avoid the bold markers around man page refs as you already have the parentheses to identify the reference?
                                                      • also section titles have conventional names: what about omitting the starting sharp to mark them as titles?
                                                      • what about definition lists? (I know they are an HTML thing, but they can be useful to describe options for example)
                                                      • I know tables are the most difficult format to express in a readable source form, but what alternatives did you considered and why you discarded them?

                                                      And btw… Thanks again!

                                                      1. 2

                                                        Glad you like it!

                                                        have you considered to avoid the bold markers around man page refs as you already have the parentheses to identify the reference?

                                                        This is an interesting thought. https://todo.sr.ht/~sircmpwn/scdoc/12

                                                        also section titles have conventional names: what about omitting the starting sharp to mark them as titles?

                                                        I’m not fond of this idea. Given that lots of man pages will need to have section titles which fall outside of the conventinoal names, and that I want all headers to look the same, this isn’t the best design imo.

                                                        what about definition lists? (I know they are an HTML thing, but they can be useful to describe options for example)

                                                        man pages do “definition lists” with borderless tables, which are possible to write with scdoc like this

                                                        |[ *topic*
                                                        :[ definition
                                                        |  *topic
                                                        :  definition
                                                        # etc

                                                        I know tables are the most difficult format to express in a readable source form, but what alternatives did you considered and why you discarded them?

                                                        The main approach I’ve seen elsewhere is trying to use something resembling ascii art to make tables look like tables in the source document. I’ve never been fond of this because you then have to do annoying edits when updating the table to keep all of the artsy shit intact, which in addition to being just plain annoying can also bloat your diffs, lead to more frequent merge conflicts, etc.

                                                        An alternative some formats have used is to make aligning your columns optional, but still using an artsy-fartsy kind of style. I figure that if you’re going to make aligning the columns optional you no longer have any reason to require a verbose format like that. So I invented something more concise.

                                                        Also, the troff preprocessor used for tables supports column alignment specifiers and various border styles, which I wanted to expose to the user in a concise way. Other plaintext table formats often have this feature but never concise.

                                                        1. 1

                                                          man pages do “definition lists” with borderless tables

                                                          Do you think you could render something like this with scdoc in a source-readable way http://man7.org/linux/man-pages/man8/parted.8.html (see section OPTIONS and COMMAND)?

                                                          The main approach I’ve seen elsewhere is trying to use something resembling ascii art to make tables look like tables in the source document.

                                                          Actually it was what I was thinking about. You propose a good point, but my counter argument is that manual pages are (hopefully) read more often then they are written. But I admit that my goal is people using cat to read manual pages by default, so I can see how in a more conventional system using Troff the people most often read a rendered page, thus the annoyance is pointless. OTOH, it should be relatively easy to write a tool that take scdoc document as input and output another scdoc document where tables are automatically aligned, removing the annoyance to align the cells while writing.

                                                          Having said that, I find your table syntax nice.
                                                          I wonder if one could nest tables (I mean put a table in a cell). Also, you organize the table by rows, but given the format, some table might benefit from being organized by column.

                                                          1. 2

                                                            Do you think you could render something like this with scdoc in a source-readable way http://man7.org/linux/man-pages/man8/parted.8.html (see section OPTIONS and COMMAND)?

                                                            You don’t actually even need tables for this. scdoc preserves your indent. https://sr.ht/I0g7.txt

                                                            I wonder if one could nest tables (I mean put a table in a cell). Also, you organize the table by rows, but given the format, some table might benefit from being organized by column.

                                                            I think nested tables is a WONTFIX. Also not sold on column-oriented tables. IMO man pages should be careful to keep their tables fairly narrow to stay within 80 characters.

                                                            1. 1

                                                              Wow, that’s really readable!

                                                              Fine for nested tables. Just to be sure I explained what I meant by column-oriented (that just like nested tables might or might not be a good idea): suppose you want to create something like

                                                              English    Italian    Swahili
                                                              Hello!     Ciao!      Habari?
                                                              Tour       Viaggio    Safari
                                                              Lion       Leone      Simba

                                                              You might prefer a syntax like

                                                              |[ English
                                                              :[ Hello!
                                                              :[ Tour
                                                              :[ Lion
                                                              |[ Italian
                                                              :[ Ciao!
                                                              :[ Viaggio
                                                              :[ Leone
                                                              |[ Swahili
                                                              :[ Habari?
                                                              :[ Safari
                                                              :[ Simba

                                                              Or even, for such a simple table (that I don’t know if actually exists in a man page, so…), you could put each column (or row) in the same line:

                                                              |[ English :[ Hello! :[ Tour :[ Lion
                                                              |[ Italian :[ Ciao! :[ Viaggio :[ Leone
                                                              |[ Swahili :[ Habari? :[ Safari :[ Simba

                                                              (that a tool could easily turn into:

                                                              |[ English :[ Hello!  :[ Tour    :[ Lion
                                                              |[ Italian :[ Ciao!   :[ Viaggio :[ Leone
                                                              |[ Swahili :[ Habari? :[ Safari  :[ Simba


                                                              Ok… now I’ve really annoyed you enough for a single night… good work!

                                                    2. 5

                                                      Because you cannot have progress without research.

                                                      Now troff is not readable in source form.
                                                      This is better in this regard. You are right about indexing, but the project have a very short log. I guess we can talk about it with the author, and see what he think about that.

                                                      Maybe he like the idea, and add it. Or he doesn’t, and will not add it.
                                                      You will always be able to fork it and fine tune to you need.

                                                      I’m grateful to hackers who challenge the status quo.

                                                      1. 4

                                                        While mdoc(7) is great (thanks for that!) , I think your questions are answered on the page. I think lowdown is probably the closest to what u/SirCmpwn was aiming for (no dependencies, man output), maybe they hadn’t seen it?

                                                        Man formatting is inscrutable to the un-trained eye (most people), and we need to acknowledge the popularity of markdown is related to its ease of reading/writing.

                                                        1. 4

                                                          I think your questions are answered on the page. I think lowdown is probably the closest to what u/SirCmpwn was aiming for (no dependencies, man output), maybe they hadn’t seen it?

                                                          groff (as installed on every Linux distribution that uses groff for man pages, which is basically all of them, and macOS) has had native support for mdoc for at least a decade. If you install an mdoc man page and then man $thepage, you get exactly what you expect.

                                                      1. 3

                                                        I aspire to handle criticism (and praise) as well as the author. (See the comments below the article.) Well done.