That's a very impressive story! I was hoping this post would get a bit more attention so I could read of more tales like this, but I guess this will have to do.
I assume that a robot capable of handling 400lb must have a pretty beefy power supply. You can probably get an intuitive sense of how much damage a robot can do to you by imagining what would happen if all of the power output was directed directly at your body (in the form of heat/electrical/kinetic). A tiny 5v motor might on a breadboard might be enough warm your hand up or fling a small pebble toward you, but a motor that requires one of those bigger 400v 3-phase 60A supplies can probably pull enough energy to melt iron or generate the same kinetic energy as some military ordnances.
The title of this post stood out to me because it's a fairly niche topic that I've been meaning to write a 'rant' post about myself. I think in a very 'pure' parsing theory sense, there is no real advantage to separating the lexer and the parser. I claim that any counter-argument is due to the limitations of individual software tools, and their inability to let up specify the grammar that we actually want.
If I recall correctly, the original historical reason for separating them was due to memory limitations on early mainframe computers. Actual source code would be fed into the 'lexer' and a stream of 'tokens' would come out the other end and then be saved to a file, which would then be fed into the next stage.
Having said this, you can ask "In practice, is there currently an advantage to separating the lexer and the parser with the tools we use now?" The answer is 'yes', but I claim that this is just a limitation of the tools we have available to us today. Tokens are usually described using a simple regular expression, whereas the parsing rules are 'context free', so worst-case complexity of parsing the two is not the same. If you pull tokens into the parser and just parse them as naive 'single-character parser items', then you end up doing more work than you would have otherwise since your parser is going to try all kinds of unlikely and impossible chopped up token combinations. The other big issue is memory savings. Turning every token into a (small) parse tree is going to increase memory usage 10-20x (depending on the length of your tokens).
Personally, I think there is a substantial need for more advanced ways of describing language grammars. The ideal model would be to have various kinds of annotations or modifiers that you could attach to grammar rules, and then the parser generator would do all sorts optimizations based on the constraints that these annotations imply. Technically, we already do this. It's called putting the lexer in one file, and the parser in another file. There is no good reason why we can't specify both using a more unified grammar model and let the parser generator figure out what to do about each rule to be as efficient as possible.
The computer science theory behind grammars seems to have peaked in the 1980s, and there doesn't seem to have been many new innovations that have made it into daily programming life since then.
One of the reasons that I stopped working on it was because of how slow it became, so I might be able to contribute to answering your question.
Initially, when the compiler was simpler, it was actually much faster. I was able to do some meaningful proof of concept demos with it like compiling a small microkernel, and compiling most of its own source code. Of course, the natural thing to do is to make it so that could cross-compile itself and run in the browser, and that's where it became terribly slow, which required more code to optimize, and the new code that was added to make it faster in the long term made it much slower in the short term.
To start with, if you think of a simple piece of code like this:
if ( 1 ) { putc('a'); }
This is only a 23 byte character program, so why should it be slow to compile? Well, the first stage of parsing this program involves tokenization. In this short program, I count 16 different 'tokens' (including the whitespace). If you want to have even the simplest data structure to describe one of your 'tokens', that only contains a single pointer to an offset in the program, then you will need to consume 16 pointers just for the tokens. On a 64 bit machine, you'll have 8 byte pointers, and 16 * 8 = 128 bytes, just for the pointers into the byte array of the program! And we haven't even started talking about the memory overhead of all the other things you'll need to describe about these tokens in your token object.
So, now we already have a memory overhead that is more than 5 times as big as the program, but we also have to build the parse tree, control flow graphs, linker objects etc. and you also have to pull in a mess of header files, bloated libraries etc. If you're wasteful with memory in the compiler, you can easily run out of memory from compiling a few megabytes of source code. Being more intelligent with memory management requires copying memory around a lot, which also adds to the latency.
So, now you need to think about optimizing your memory use, and do 'smarter' things that trade memory usage for CPU. Plus, you're likely to also start needing free/delete a lot from heap memory which is a system call and therefore slower than a call within your program. By the time you implement all this 'optimization', you compiler has become an incredibly complicated and bloated system that requires even more code to optimize all the opportunities for improvement.
A couple weeks ago I was working away in the terminal when all of a sudden, my USB camera turned on and its light started flashing at me indicating something had just started interacting with my webcam. I immediately assumed "Oh, that's probably just some hackers watching me through my web-cam.", so I looked through /var/log a bit and noticed that it had just re-detected all USB devices and two new users had just been added to my system:
Does anyone know what these new users are for, and why they were added just now instead of at install time? I googled a bit, but couldn't find any recent news about it.
Interesting, thank you for that analysis. From what I understand, the RCE exploit really needs two things to work: 1) The interpretation of the JNDI reference by log4j, and 2) The 'auto-execute loaded classes' (which I don't quite understand).
Is there any kind of low-level flag you can pass to Java or your environment to completely disable JNDI? I recall that there is a flag you can pass to log4j, but I can't see any reason why I would ever use JNDI anywhere in Java.
Also, do you have any additional insights on how exactly the mechanism for 2) works? From what I understand, this is a feature of Java itself?
I've been thinking about this since I saw it here on HN yesterday, and I can't help but entertain the idea that this might end up being 'the worst software security flaw ever'.
"(a) A general license is hereby issued authorizing commercial and industrial firms; research, educational, and medical institutions; and Federal, State, and local government agencies to receive, possess, use, and transfer uranium and thorium, in their natural isotopic concentrations and in the form of depleted uranium, for research, development, educational, commercial, or operational purposes in the following forms and quantities:
...
(2) No more than a total of 7 kg (15.4 lb) of uranium and thorium at any one time...
It may very well be the case that users more often click a link to unsubscribe directly on the site more than they click the 'unsubscribe' feature in the email client (I don't have any stats on that).
The original question remains though: How does the stated service here work when there is only a List-Unsubscribe: header and no web form?
I just checked a few newsletter emails in my inbox, and they all offer List-Unsubscribe: mailto: based unsubscription. From what I see, it is quite universal and more common than link-based unsubscription. Newsletter providers prefer not to use the url based unsubscription because some email providers will crawl the URLs in emails and automatically unsubscribe people without them knowing.
It's also possible that you're talking about a 'link' (a href) in the email body that goes to the newsletter provider's site and ask them a bunch of questions (why are you unsubscribing etc.). That's a different concept entirely.
From what I've seen, the email-based way is the primary unsubscription method in use today. Even when you use the gmail feature "Mark this as spam", depending on what you click, it will just send an email on your behalf to the to whatever is specified in the List-Unsubscribe: mailto: header.
How does this work from a technical perspective? If I forward mail to this service instead of clicking the 'unsubscribe' link, then how do they 'unsubscribe' me on my behalf? In order to complete the unsubscription process, the newsletter owner needs to receive an email (usually generated automatically by the mail client when clicking the 'unsubscribe link') that comes from the person being unsubscribed. If I outsource this process, this means that 'please-unsubscribe.com' will need to spoof emails from me on my behalf and send them the email specified in the List-Unsubscribe email header. If spoofed emails are not used and they come from 'please-unsubscribe.com' this won't be very actionable to the newsletter owner. From their perspective, they're now going to get 'unsubscribe' notifications that all come from an email at 'please-unsubscribe.com' which never signed up to the newsletter in the first place.
This all assumes that the newsletter unsubscription process is using the email based method instead of the link based method (which is a good assumption email-based is more common).
hah, because you care so much, I'll go ahead and make that change. It's probably better for SEO anyway. I made the change on my local copy. It will get pushed next time I re-build the site.
As the author of this blog post, I find this statement interesting. Can you expand upon the sentiments expressed in your statement? Also, by 'read this', do you mean just the blog post, or contents of the works by Jim Roskind?
Agreed on the point that there are better mental models out there. The difficulty is to make content that is simultaneously correct, but also not over-complicated. I finished off the post with a reference to Russ Cox's work so any sufficiently motivated individual will find the right models there.
You found a bug. The bug was: When I was computing the animation frames for the visual, after a backtracking event, I forgot to restore the 'progress' values for the PROGRESS nodes to what they were before the stack push took place. I think I fixed this issue, and I just pushed an update which should appear any second when the cache invalidates.