20,173 Matching Annotations
  1. Nov 2022
    1. Why was the SIGSTOP-ed process not responding to SIGTERM? Why does the kernel keeps it in the same state? Why did it get killed the moment it received the SIGCONT signal? If it was because of the previous SIGTERM signal, where was it kept until the process resumed?
    2. SIGSTOP and SIGKILL are two signals that cannot be caught and handled by a process.
    1. Synchronously waiting for the specific child processes in a (specific) order may leave zombies present longer than the above-mentioned "short period of time"
    2. When a process loses its parent, init becomes its new parent. init periodically executes the wait system call to reap any zombies with init as parent.
    3. or just an uncommon decision to not reap children (see example)
    4. Zombie processes should not be confused with orphan processes: an orphan process is a process that is still executing, but whose parent has died. When the parent dies, the orphaned child process is adopted by init (process ID 1). When orphan processes die, they do not remain as zombie processes; instead, they are waited on by init.
    5. The result is that a process that is both a zombie and an orphan will be reaped automatically.
    6. The term zombie process derives from the common definition of zombie — an undead person. In the term's metaphor, the child process has "died" but has not yet been "reaped". Also, unlike normal processes, the kill command has no effect on a zombie process.
    7. This occurs for the child processes, where the entry is still needed to allow the parent process to read its child's exit status: once the exit status is read via the wait system call, the zombie's entry is removed from the process table and it is said to be "reaped".
    1. Tini fixes by "forwarding signals": if you send a signal to Tini, then it sends that same signal to your child process (Jenkins in your case).
    2. A second problem is that once your process has exited, Bash will proceed to exit as well. If you're not being careful, Bash might exit with exit code 0, whereas your process actually crashed (0 means "all fine"; this would cause Docker restart policies to not do what you expect). What you actually want is for Bash to return the same exit code your process had.
    3. Note that you can address this by creating signal handlers in Bash to actually do the forwarding, and returning a proper exit code. On the other hand that's more work, whereas adding Tini is a few lines in your Dockerfile.
    4. In other words, if you use Bash to run Jenkins, and then run docker stop, then Jenkins will never see the stop command!
    5. Now, Bash actually does the same thing (reaping zombies), so you're probably wondering: why not use Bash as PID 1?
    6. When a zombie is created (i.e. which happens when its parent exits, and therefore all chances of it ever being waited by it are gone), it is reparent to init, which is expected to reap it (which means calling wait on it).
    7. In other words, someone has to clean up after "irresponsible" parents that leave their children un-wait'ed, and that's PID 1's job.
    8. Have lost their parent (i.e. their parent exited as well), which means they'll never be waited on by their parent.

      He's supposedly defining a zombie process, but here ends up defining an orphan process, conflating the two.

    9. Now, unlike other processes, PID 1 has a unique responsibility, which is to reap zombie processes.
    1. According to the Unix process model, the init process -- PID 1 -- inherits all orphaned child processes and must reap them. Most Docker containers do not have an init process that does this correctly. As a result, their containers become filled with zombie processes over time.
    1. A low-level approach is to fork twice, running the desired process in the grandchild, and immediately terminating the child. The grandchild process is now orphaned, and is not adopted by its grandparent, but rather by init.
    2. The process group mechanism in most Unix-like operating systems can be used to help protect against accidental orphaning, where in coordination with the user's shell will try to terminate all the child processes with the "hangup" signal (SIGHUP), rather than letting them continue to run as orphans.
    3. In a Unix-like operating system any orphaned process will be immediately adopted by an implementation-defined system process: the kernel sets the parent to this process
    4. Even though technically the process has a system process as its parent, it is still called an orphan process since the process that originally created it no longer exists.
    5. its jobs (internal representation of process groups)
    1. An init system does not have to be heavyweight. You may be thinking about Upstart, Systemd, SysV init etc with all the implications that come with them. You may be thinking that full system needs to be booted inside the container. None of this is true. A "full init system" as we may call it, is neither necessary nor desirable.
    2. Let's look at a concrete example. Suppose that your container contains a web server that runs a CGI script that's written in bash. The CGI script calls grep. Then the web server decides that the CGI script is taking too long and kills the script, but grep is not affected and keeps running. When grep finishes, it becomes a zombie and is adopted by the PID 1 (the web server). The web server doesn't know about grep, so it doesn't reap it, and the grep zombie stays in the system.
    3. That is, instead of properly reaping adopted processes, it's probably expecting another init process to do that job, and rightly so.
    4. In every day language, people consider "zombie processes" to be simply runaway processes that cause havoc. But formally speaking -- from a Unix operating system point of view -- zombie processes have a very specific definition. They are processes that have terminated but have not (yet) been waited for by their parent processes.
    5. The problems that we solved are applicable to a lot of people. Most people are not even aware of these problems, so things can break in unexpected ways (Murphy's law). It's inefficient if everybody has to solve these problems over and over.
    1. Mono doesn't have that glyph, so what you're seeing is that that symbol is being used from another font to be able to show something
    1. To check whether the music symbol ♫ is being displayed in a string (if it is not being displayed on some devices), you can try measuring the string width; if width == 0 then the symbol is absent.
    2. Checking is done on the entire fallback chain, not just the immediate font referenced." So if you only want to know if it's in the Typeface you specified, this won't work.
    3. I have a custom font which is displaying the box character.
    4. I want to check if the String I am about to display can be displayed by my custom font.
    5. If it cannot then I want to use the standard Android font (which I know can display the characters)
    6. I can't find a method to check if my Typeface can display a particular String though.
    1. Glyph 0 must be assigned to a .notdef glyph. The .notdef glyph is very important for providing the user feedback that a glyph is not found in the font. This glyph should not be left without an outline as the user will only see what looks like a space if a glyph is missing and not be aware of the active font’s limitation.
    2. It is recommended that the shape of the .notdef glyph be either an empty rectangle, a rectangle with a question mark inside of it, or a rectangle with an “X”
    1. You need .notdef, unicode value undefined: microsoft.com/typography/otspec/recom.htm Characters are assigned in blocks of the same kind. Most blocks have some unassigned points at the end to start the next block on a round number. These points allow Unicode Consortium to add new glyphs to a block. New glyphs don't come into existence often. See typophile.com/node/102205. Maybe you can ask your question in the Typophile forum. They can tell you more about how this exactly works and how to render .notdef
    2. I wasn't aware of 'missing character glyph', some Googling suggests that U+0000 can/should be used for missing characters in the font. However in at least one font I've tested with U+0000 is rendered as whitespace while missing characters are rendered as squares (similar to U+25A1).
    3. I want to be able to detect if the font used can display a certain character or not
    4. However after doing a bit of testing I see that this character is not used to represent missing glyphs on either my Windows 7 computer or the Android phone I've tested with (Motorola Atrix).
    5. The Unicode replacement character sounds promising when reading about it on Wikipedia: It is used to indicate problems when a system is not able to render a stream of data to a correct symbol. It is most commonly seen when a font does not contain a character, but is also seen when the data is invalid and does not match any character
    1. Some software attempts to hide this by translating the bytes of invalid UTF-8 to matching characters in Windows-1252 (since that is the most likely source of these errors), so that the replacement character is never seen.
    2. Thus the replacement character is now only seen for encoding errors, such as invalid UTF-8.
    3. At one time the replacement character was often used when there was no glyph available in a font for that character. However, most modern text rendering systems instead use a font's .notdef character, which in most cases is an empty box (or "?" or "X" in a box[5]), sometimes called a "tofu" (this browser displays 􏿾). There is no Unicode code point for this symbol.
    4. Consider a text file containing the German word für (meaning 'for') in the ISO-8859-1 encoding (0x66 0xFC 0x72). This file is now opened with a text editor that assumes the input is UTF-8. The first and last byte are valid UTF-8 encodings of ASCII, but the middle byte (0xFC) is not a valid byte in UTF-8. Therefore, a text editor could replace this byte with the replacement character symbol to produce a valid string of Unicode code points. The whole string now displays like this: "f�r".
    5. 2.^ Grey areas indicate non-assigned code points 3.^ Black areas indicate noncharacters (code points that are guaranteed never to be assigned as encoded characters in the Unicode Standard)
    6. The replacement character � (often displayed as a black rhombus with a white question mark) is a symbol found in the Unicode standard at code point U+FFFD in the Specials table. It is used to indicate problems when a system is unable to render a stream of data to a correct symbol.[4] It is usually seen when the data is invalid and does not match any character:
    7. Since the replacement is the same for all errors this makes it impossible to recover the original character. A better (but harder to implement) design is to preserve the original bytes, including the error, and only convert to the replacement when displaying the text. This will allow the text editor to save the original byte sequence, while still showing the error indicator to the user.
    1. No, there is no “glyph not found” character. Different programs use different graphic presentations. An empty narrow rectangle is a common rendering, but not the only one. It could also be a rectangle with a question mark in it or with the code number of the character, in hexadecimal, in it.
    2. The glyph-not-found character is specified by the font engine and by the font; there is no fixed character for it.
    3. While there are many great answers regarding the "glyph not found" glyph, that won't help you actually detect it, as the text string in code will still have the character regardless of the font used to render it.
    4. By the way, I am not talking about � (replacement character). This one is displayed when a Unicode character could not be correctly decoded from a data stream. It does not necessarily produce the same glyph:
    5. replacement glyph
    6. missing glyph
    7. replacement glyph missing glyph interpretable but unrenderable character
    8. There is no standardized look/glyph, it’s up to the implementation
    9. U+25A1 □ WHITE SQUARE may be used to represent a missing ideograph

      apparently distinct from: Unicode replacement character (U+FFFD)

    10. I have rolled back your edit to Jukka K. Korpela's answer. Please include that information in this answer and/or add a comment to the other answer.
    11. Why not just include the information there and delete this answer?
    12. Then don’t use the phrase “replacement character”, because a) it’s not a character at all, and b) it’s specifically not the character with the Unicode name REPLACEMENT CHARACTER, and c) people easily get confused with issues like this.
    13. it does not have a fixed glyph, though fonts that contain it tend to use very similar glyphs
    1. SVG 1.1 (a W3C Recommendation): The altglyph element provides detailled control over the glyphs used to render particular character data.
    2. anchestor
    3. A character exists, but the glyph to display it isn't available.
    4. The character does not exist. Proposed solutions include encoding the character, markup for individual characters, and Private Use Codepoints.
    5. The character exists in Unicode/ISO 10646, but not in the character encoding used for the document. In this case, use Numeric Character References (NCRs, example: 噸).
    6. However, in some cases, there may be something missing:
    1. Grepping has the problem of "false positives": The output of a pip list | grep NAME would match on any module which name contains "NAME", e.g. also match "some_other_NAME". While pip3 show MODULENAME only matches on complete matches.
    1. To become an international superhero, fork this gist, make a shell-runable node.js application font-to-regexp.js that just takes your font file(s?) on the command line, invokes ttx for you on it(them), loads the result with jsdom, runs fontRange on it and prints the regexp to stdout, instead of doing the above steps manually. Oh, and brag about it in the comments here, of course, so other people find it too!
    1. Note that ttx is part of the fonttools mentioned in the accepted answer. It's a Python script, so it's also available on Mac and Linux.
    2. I've edited the title slightly to make the intent of the question more obvious.
    3. But these two questions are interwoven (and you’ll find many answers to the wrong question in the Answers section).
    4. $ python checkfont.py /usr/share/fonts/**/DejaVuSans.ttf 65 12622 # a ㅎ
    5. The script takes as arguments the font path and optionally code points / characters to search for:
    6. Here is a method using the fontTools Python library (which you can install with something like pip install fonttools):
    1. Type designers usually do not create new characters, i.e. the meanings of those pictures, or, more technically put, ‘the smallest component of written language that has semantic value.’ We don’t invent alphabets, we merely re-interpret existing ones.
    2. Type designers create new glyphs, i.e. pictures representing characters.
    3. Characters versus glyphs
    4. A glyph can also represent more than one character at once. Take an f_f_f ligature as an example. It represents three f characters in a row. Ligatures do not have Unicodes, because the separate characters already have codes and the the fact that it’s a ligature does not change the meaning of its parts.
    5. What if you want to share the same glyph shape between two Unicode values? There are a few situation where you would need that. E.g., the symbol increment U+2206 and the Greek letter Delta U+0394 should look the same. There is a similar issue with Ohm U+2126 and Omega U+03A9. Or, you are creating an all-caps font. Or you simply want to reuse the same space glyph for both the space U+0020 and non-breaking space U+00A0.
    6. Well, actually, some ligatures do have legacy codes, but solely for backwards compatibility with outdated encodings from the long-gone, dark ages of eight-bit computing. E.g. f_f can have the U+FB00 LATIN SMALL LIGATURE FF code point. If ‘eight-bit’ does not tell you anything, please erase everything you read within these parentheses from your memory immediately, keep calm and continue reading.
    1. Characters are logical text units identified by Unicode codepoints, whereas glyphs are graphical font units. The distinction between character and glyph is critical to understanding FontLab, and fonts in general.
    2. A Glyphset is the glyph repertoire of a font, i.e. all glyphs present in the font. The old term for this repertoire was “character set”, but it is misleading because in modern font technology, a font is a collection of glyphs, not a collection of characters.
    1. I know this is older but I'm surprised by the "Is redrawing 110K glyphs (with metrics and kerning and combining attributes and hinting) too hard?" I used to do typography. A plain, unoriginal typeface with 255 straightforward latin-# oriented letters is at least a couple days of work; probably a couple weeks; couple months for truly good work. 110K is the equivalent of 400+ faces with much harder metrics and such. 15,000 hours of work or drastically more; so at least 7 or so years. So, kinda hard.
    1. That’s fine and dandy if you’re running in production and have a publicly accessible address such as your domain name but what about during development?You can’t just tell Stripe to access http://localhost because that address isn’t publicly accessible to the internet.
    2. When developing real world applications you tend to run into certain road blocks such as:How do I test webhooks locally?How can I show a demo of my site to a client?How can I develop a web app that uses subdomains on localhost?How can I test Let’s Encrypt without a domain name?
    3. Lucky for us, it’s super easy to use subdomains in development nowadays. http://lvh.me is a free service that resolves itself along with all subdomains to localhost.
    1. Unless you are the maintainer of lvh.me, you can not be sure it will not disappear or change its RRs for lvh.me. You can use localhost.localdomain instead of localhost, by adding the following lines in your hosts file: 127.0.0.1 localhost localhost.localdomain ::1 localhost localhost.localdomain This is better than using lvh.me because: you may not always have access to a DNS resolver, when developing
    1. scale: 3 means 3 of those digits come after the decimal point (surely it should be the other way round, scale for how big the number is and precision for its decimal places?):
    1. Sidekiq uses all of the data structures Redis provides: lists, sorted sets, hashes.
    2. If you want a queueing system that uses X, use a queuing system that uses X! Sidekiq's mantra is simple and efficient. Redis is both. Abstracting data storage is neither.
    1. Played for free during the first few days of the game's release. For its current price to content ratio, I can't justify spending $30 for four modes of play (minus one since I rarely play local multiplayer). Battle Royale is dead on arrival as a result of being locked behind such a wall.
    2. this game really needs to go free-to-play (just for the battle royale mode) in order to not be immediately DOA. the fact that even during a free weekend on launch day lobbies are still barely filling up is very concerning for this game's future.
    1. If you want it to automatically check/fix lint errors like this, I would recommend setting up https://github.com/gabyx/githooks in your dev environment. We have a pre-commit hook that automatically runs rubocop for any changed files whenever you try to do a commit. I find it helpful anyway. (Nick prefers a VS Code extension that actually runs it every time he saves a file, which is oftener than I prefer but works for him.)
    1. I don't see why this is a false positive
    2. that return is definitely inside the transaction block, and will cause exactly the sort of unwind that has changed behaviour. (To me, such a "rescue and then return" pattern is exactly the case one should worry about the most!)

      .

    1. It may not seem like the obvious behaviour for return, but perhaps it is a safe assumption to make in general to think of return as aborting the method yielding to the block.

      Interesting possible convention:

    2. def with_something prepare yield on_success end any return, break or throw would skip the on_success code. Skipping over the on_success code also seems quite reasonable when the block calls break and throw. It may not seem like the obvious behaviour for return, but perhaps it is a safe assumption to make in general to think of return as aborting the method yielding to the block. It might be desirable to discourage the use of return in this way for transactions to keep the code clearer, but that would also affect the use of break which seems like a reasonable way to abort a transaction from within the transaction block.
    3. Can you refactor your code so that instead of returning from within the transaction block you set a variable and then return outside of the block?
    4. Is there a recommended way to patch Rails to disable this behavior? We are blocked on upgrading to 7 because of this.

      .

    5. I just spent a day dismantling a model, trying to find the cause of the silent rollback - taking out every association, every validation, every callback, whittling down all the code in the transaction, only to finally discover that it was return true that was the cause of it all. Or yes, an exception!
    6. I think I had expected that existing rails developers would discover this problem in existing code through the deprecation warning to avoid a nasty surprise. I'm worried about my future kids learning Rails and writing perfectly looking Ruby code just to learn the hard way that return is sometimes a nono! Jokes aside, I think that no one expected that the deprecation will turn into silent rollbacks. This is a very controversial change, pretty much everyone taking part in the discussion on the deprecation PR raised some concerns about the potential consequences of this change. The only thing that was making it easier to swallow was the promise of making it clear to the user by throwing an exception after the rollback.
    1. I fail to understand how this is such a low priority. Code review is one of the most basic and critical portions of development lifecycle, and prior to discovery of this ticket I literally had to roll an entire other repository manager just to perform that correctly when I discovered entire directories of changes had been omitted from the Gitlab generated MR. We actually found that in order to get the change set fix to apply reliably, that it is required to add "?w=1" to the url even after updating the white space setting.
    2. FYI these kind of limits bugs are very confusing for users.
    3. Just a repro datapoint. Lost my mind and 1.5 days trying to figure this out on our gitlab server. Unchecking checkbox worked around it.
    1. Expected behavior this code should be ignored. Actual behavior this code is flagged.

      This issue is a correct usage of 'false positive"

  2. Oct 2022
    1. Not sure why every review is positive when the game is like this. I mean, it technically works and can be completed, so there's that. But the implementation is not great.
    2. The "developer" here, Dnovel/My Way Games is a serial Russian asset flipper. This Russian "Developer" consistently uses a paid/fake review service for all of his games and asset flips, to create false positive review impressions, in an attempt to mislead gamers.This is basically a scam, and your instinct to question the fake positive review score is spot on.
    1. The audio department is mostly comprised of a track of piano elevator music and some sound effects which were taken from freesound.org, mostly without adhering to the Creative Commons licene:A pile of wood - https://freesound.org/people/jorickhoofd/sounds/178740/ - BY-4.0PickupBook1.wav - https://freesound.org/people/jomse/sounds/428666/ - BY-3.0Ambience, Seaside Waves, Close, A.wav - https://freesound.org/people/InspectorJ/sounds/400632/ - BY-4.0Whistling antarctic blizzard - https://freesound.org/people/stormpetrel/sounds/173096/ - BY-NC-3.0campfire_01.wav - https://freesound.org/people/matucha/sounds/170247/ - BY-4.0Windy Window.wav - https://freesound.org/people/Pedaling%20Prince/sounds/338952/ - BY-3.0The "BY-NC" license doesn't allow commercial exploitation, by the way, so this is a clear copyright violation.

      .

    1. Capybara.register_driver(:cuprite) do |app| Capybara::Cuprite::Driver.new( app, { window_size: [1200, 800], inspector: true, url_blacklist: ['https://www.google-analytics.com/analytics.js', 'https://www.google-analytics.com/', 'https://js-agent.newrelic.com', 'https://www.googletagmanager.com', 'https://cdnjs.cloudflare.com', 'http://fonts.googleapis.com', 'https://use.fontawesome.com', 'https://bam.nr-data.net', 'http://connect.facebook.net', 'http://static.ak.facebook.com', 'https://s-static.ak.facebook.com', 'https://www.facebook.com', 'http://ajax.googleapis.com'], debug: true, browser_options: { 'no-sandbox' => nil, 'headless' => nil, 'blink-settings' => 'imagesEnabled=false' }, timeout: 20, logger: $stdout, process_timeout: 20 } ) end
    1. a little flaw (Google translation can not find the translation of the word "瑕疵", so can only use the word "flaw" instead)

      annotation meta: may need new tag: no exact translation in other language

    1. so this means that there are no documentation telling you that this is the way you have to do it anywhere so naturally a lot of devs do not know about this, unless they ask about it by luck or of curiousity.

      annotation meta: may need new tag: how could they know / how would one find out?

    1. As a kid, I had cobbled together a version of “me” using parts from different sets, but it never looked exactly right (though I did have two lightsabers and a hoverboard, which is definitely just like the real me).
    1. Just as a breadcrumb here for future readers (I found this thread when I was searching), it seems Cuprite has support for non-headless now (via Ferrum). headless: false in the options does the trick. And thanks for your work on Cuprite.
    2. @route @twalpole as a community I think we're super grateful for your work on a CDP alternative to chromedriver/selenium, poltergeist etc. I do think collaboration could be very valuable though, although it would likely mean abandoning one of the projects and teaming up on the other, you both obviously have very deep knowledge of CDP and therefore would get a load more done than any of us "end users" trying to wade in there. The status for us on our Rails project is that Apparition fails with a ton of errors, they all seem related to handling timing events (accept_prompt doesn't work, opening new windows seems problematic etc etc etc) whereas Cuprite only rails with a cookie gem we're using (easy fixed) and doesn't support drag_to yet. So to me Cuprite seems more complete, but I don't know much about the internals.
    3. As both projects are written by 2 different people independently there's huge difference in the code. I don't think I have time or wish to merge them because it's huge amount of work. The common thing between them is only CDP that's all. Though Cuprite is already stable and supports all features that Capybara requires, we run tests and do many cools things with it in production.
    4. As a history mark, when back then I asked Thomas if he started to work on CDP, he said yes but never finished it, so I started this project from scratch which by now feels completed. After releasing it I only yesterday realized that he open-sourced his project and keeps working on it. I think it just feels hard to throw everything you have written to trash, but I wasn't proposed at the beginning to work together on common project and this is the reason Cuprite had began. Though since this project is completed I see no sense to work on something else especially for me, the only difference would be in Ruby implementation which is boring as you can do things in a different manner and CDP has issues too so the difference could be only how we workaround them.
    5. And yeah, you two should probably gang up :)
    6. what is the difference? and why do you write it from scratch?
    7. Haven't really looked through your code, so not sure what the difference is - I would guess not too much. I told you about my version when we were discussing the issues you were having on cuprite -- It was 70+ percent done so I released it and finished up most of the rest. I guess one difference is that you appear to be aiming at bleeding edge Chromium, whereas I'm more focused on things working on Chrome release since I think that's more important for people to test with (no customer is going to be running Chromium alpha).
    8. I also was surprised to see 2 "kind of similar" new drivers both targeting CDP I wonder if joining forces ultimately would be a good idea?
    1. Multiplying two objects will merge them recursively: this works like addition but if both objects contain a value for the same key, and the values are objects, the two are merged with the same strategy.

      Unfortunately, it doesn't merge/concatenate arrays. Sometimes that's what you want (you want the 2nd value to override the 1st but sometimes not.

      If you want it to concatenate instead, here are some workarounds:

      1. https://stackoverflow.com/questions/53661930/jq-recursively-merge-objects-and-concatenate-arrays

      2. If you only need/want to concatenate for some fixed list of keys, you could do it more simply like this (but could get repetitive to repeat for each key you want it for):

      ⟫ jq -n '[{hosts: ["a"]}, {hosts: ["b"]}] | .[]' | jq -s '.[0] * .[1] * {hosts: (.[0].hosts + .[1].hosts)}' { "hosts": [ "a", "b" ] }

    1. Test.new.test { puts "Hi!" }
    2. The problem is that the caller may write yield instead of block.call. The code I have given is possible caller's code. Extended method definition in my library can be simplified to my code above. Client provides block passed to define_method (body of a method), so he/she can write there anything. Especially yield. I can write in documentation that yield simply does not work, but I am trying to avoid that, and make my library 100% compatible with Ruby (alow to use any language syntax, not only a subset).

      An understandable concern/desire: compatibility

      Added new tag for this: allowing full syntax to be used, not just subset

    3. Unfortunately this is not what I am looking for. I know I can call block this way, but I need to use yield. b variable was used only to indicate that block is actually given.
    4. You cannot use yield inside a define_method block. This is because blocks are captured by closures, observe: def hello define_singleton_method(:bye) { yield } end hello { puts "hello!" } bye { puts "bye!" } #=> "hello!"
    5. This breaks the TIMTOWTDI rule
    1. grammar Parser { rule TOP { I <love> <lang> } token love { '♥' | love } token lang { < Raku Perl Rust Go Python Ruby > } } say Parser.parse: 'I ♥ Raku'; # OUTPUT: 「I ♥ Raku」 love => 「♥」 lang => 「Raku」 say Parser.parse: 'I love Perl'; # OUTPUT: 「I love Perl」 love => 「love」 lang => 「Perl」
    2. Definable grammars for pattern matching and generalized string processing

      annotation meta: may need new tag: "definable __"?

    1. I'm afraid you missed the joke ;-) While you believe spaces are required on both sides of an em dash, there is no consensus on this point. For example, most (but not all) American authorities say /no/ spaces should be used. That's the joke. In writing a line about "only one way to do it", I used a device (em dash) for which at least two ways to do it (with spaces, without spaces) are commonly used, neither of which is obvious -- and deliberately picked a third way just to rub it in. This will never change ;-)
    2. This text has a line which has an ortographical typo in it. Please look at this line of text from the Zen of Python: There should be one-- and preferably only one --obvious way to do it.

      first sighting: ortographical

    3. I'm sorry, but syntax is part of poetry, too.
    1. Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Complex is better than complicated. Flat is better than nested. Sparse is better than dense. Readability counts. Special cases aren't special enough to break the rules. Although practicality beats purity. Errors should never pass silently. Unless explicitly silenced. In the face of ambiguity, refuse the temptation to guess. There should be one– and preferably only one –obvious way to do it.[a] Although that way may not be obvious at first unless you're Dutch. Now is better than never. Although never is often better than right now.[b] If the implementation is hard to explain, it's a bad idea. If the implementation is easy to explain, it may be a good idea. Namespaces are one honking great idea – let's do more of those!
    2. The formatting of the dashes in this line and the final is purposely inconsistent, in reference to the varying formatting conventions.[6]
    1. It's really not always a better user experience to keep things in one browser... What if they are in a sign-up or check-out flow in your SPA, and at the last step they need to agree to some conditions in an external page? Unless you use a modal, opening in a new window would really be preferable to the user completely losing context and having to go through the whole process again.
    1. It acts as a black hole null object, allowing arbitrarily deep method chains.

      If that's what it does, then perhaps the name should reflect that in the name!

    2. For any message that has not explicitly allowed or expected, the double will return itself.

      If that's what it does, then perhaps the name should reflect that in the name!

    3. to make the double "loose"

      If that's what it does, then perhaps the name should reflect that in the name!

    4. Null object doubles

      as_loose_object or as_black_hole or allow_any_message would have been better names.

      "null" makes it sound like nil, which you can't send any (almost) message to! So it sounds like it does the opposite (disallows random messages) of what it does (allows random messages).