Категория: In English @en

Logrotate creates empty compressed log files

Case study: After some changes I’ve noticed logrotate flushes the main log (as it should) but all gzipped archived copies it creates are empty (20b). Logrotate destroys logs instead of preserving them.
You had one job, logrotate!

Turns out my logrotate file looked like this:

/var/log/httpd/*_log /custompath/log/*_log {
create ...

And the latter had been symlinked to the former.

It made sense when I wrote that. Cover all the bases. But the way logrotate works, it first scans all paths for files that need rotating and then applies rotation to them all.

So if I have /custompath/log/error_log reflected as /var/log/httpd/error_log, logrotate notices two files in need of rotation. It then compresses the first one, replaces it with empty log (create), then compresses the second one (now empty) and replaces the first .gz with an empty archive.

Nice job, logrotate. Make sure the collected filenames resolve to unique files? Nope. Maybe at least don’t overwrite already existing gzips? Nope.

Anki — How to review regularly

Here’s what helps me review regularly:

  • I study when there are no better things to do. When I commute it’s either reading or drilling. It’s easier to resist temptation when there’s less temptation.
  • I have a pact with myself that I will keep review counts low by whatever means necessary (even moving learned cards back to new), but in exchange I have to review all cards every day.

This way I have less temptation + less frustration ("I’m not going to finish these 1000 cards anyway") + more motivation ("Gotta review these 300 cards faster and have more time for reading").

It’s all about the balance of incentives. It sucks more to betray my routine, miss my usual satisfaction when I finish the reviews and pile up work for tomorrow than it is to drill an always manageable number of cards then feel good and have fun.

As for game-like elements, there’s "% learned" (overall progress), "review %" (today’s performance). Increasing both feels good because better scores == less cards to repeat tomorrow == less reviews in the coming days and in the long run == more time for reading.

Fix Logitech MK520 Mouse Middle Button

I’ve changed two sets of Logitech MK520 Wireless Keyboard+Mouse sets and while otherwise they’re great, the middle mouse button starts to fail after 6-8 months of use. Pretty annoying.

Turns out there’s an easy way to fix this:

  1. Remove the batteries, unscrew and remove the cover.
  2. Find the middle-button push thingie on the board. The thingie is held together by 4 black dots at the corners. Take a small screwdriver and carefully destroy these.
  3. The thingie will come apart. Remove its square cover, the button layer and the conductive layer.
  4. Clean the conductive layer carefully. If it’s black in the middle that’s why it doesn’t work. Scrub off that black until the middle is of uniform metallic color. Also clean the base under it.
  5. Assemble the thingie back as it were. Insert the battery and test the middle button.
  6. Very carefully use a toothpick to put just a tiny bit of glue at each of the four corners of the thingie where the remains of the black dots are. Have some more toothpicks and some napkins ready to remove excessive glue quickly. You don’t want to glue the whole button together!
  7. Assemble the mouse back.

Takes around 30-60 minutes and probably less if you know what you’re doing.

Mercurial local per-repo .hgignore

What do you do if you need to ignore some local files, but would prefer not to commit that rule to everyone in .hgignore?
(E.g. you’ve created a folder in the repo for your own needs)

There’s a global .hgignore which you can configure from %PROFILE%\hgrc, but using it to list all exceptions from everywhere is ugly.

Turns out you can add per-repository .hgignore overrides this way too! Edit repo’s hgrc:
ignore = .hg/.hgignore-local

It wouldn’t be committed as it’s inside .hg, and it would be parsed in addition to repo’s normal .hgignore.

Solved: Delphi XE3 64-bit debugger fails to run


Delphi XE3 sometimes fails to run 64-bit applications under a debugger. Code would compile, but the part where Delphi switches to debug layout never happens, Delphi just pops a message saying "Cannot run the debugger".

32-bit debugging continues to work normally, and so does "Run without debugging".

The funny part is that this happens irregularly. Sometimes the first attempt would succeed, and then the debugger would run all the time in all instances of Delphi. But if it fails the first time then it would always fail even if you restart Delphi.

I also noticed that the earlier I launch Delphi + debugger, the higher is the chance it would run (and then continue working). It seemed like there was something I was doing or the computer was doing sometime after boot that broke the debugger if I hadn’t launched it yet.


Stop the "Internet connection sharing" service and restart Delphi.

What might have contributed:

– Uninstalling older versions of Delphi on the same PC.
– Disabling Windows Firewall
– Disabling Windows Defender

(Diagnostics process)

Diagnostics process:

Looking at the successful and failed debugger launches with Process Monitor, in both cases Delphi runs a remote debugger. But on the successful run it’s dbkw64_17_0.exe (64 bit) while failed runs spawn rmtdbg170.exe (32 bit). Both are Delphi debuggers, but I suspected that the second one is only supposed to be used for 32 bit debugging.

Further investigation showed that in both cases dbkw64_17_0.exe launches initially, but in the second case it terminates shortly afterwards. Delphi then tries to connect to it through TCP, unable to do so, and restarts it automatically. But the code that does the restart probably wasn’t updated to 64 bit and launches 32-bit rmtdbg170.exe instead.

Anyway, the problem lies in the initial instance of dbkw64_17_0.exe terminating. Comparing Process Monitor logs, both successful and failed runs load the libraries and then work with winsock. Stack in the final calls indicates ws2_32.dll‘s socket() is running – the debugger is probably trying to open it’s command socket for listening – after which failed instance abruptly terminates (Thread Exit, Process Exit). I figured socket() probably returns with an error.

Using rohitab’s Api Monitor I tried to find out the error code, but this didn’t work out. Api Monitor successfully traced all the calls until roughly WSAStartup(), but no further – the last bunch of calls just before the termination always got lost, perhaps the injected driver wasn’t being able to send it back to the main app in time before the application terminated.

Then I opened dbkw64_17_0.exe for debugging in Visual Studio. I set a breakpoint to {,,ws2_32.dll}socket, caught the execution there and studied what happens step by step. Turns out, socket() was successful. It was followed by setsockopt call, also successful (to know which functions we were stepping into, I used VS’s standard ability to load Windows DLL symbols from Microsoft servers). Then dbkw64_17_0.exe called bind() which failed.

My initial guess was that someone else occupied the port it needed. Checking bind() parameters at MSDN, I looked into RDX, RCX, R8, R9 registers which host parameters in x64 calls, namely the memory referenced by RCX, which kept the requested family and port number. It turned out to be 0xC0F3 but it was unoccupied.

I then traced the call to bind() and from the internal call to WSPBind() got the error code: 0x1D27, that is 10013 (WSAEACCES: Permission denied. An attempt was made to access a socket in a way forbidden by its access permissions).

This code has no single specific reason for it. From the internet it looks like it appears when some driver or network-related service misbehaves. I tried stopping network related services one by one, until finally bind() succeeded. The infringing service was "Internet connection sharing (ICS)". As long as I stop this service, the debugger launches normally, and so long as ICS is running, the debugger would not start.

The reason why sometimes the debugger would run and then run always, is probably that ICS hadn’t yet been started or did not yet harm the network stack at the time. If the debugger run at that point, it would bind the socket, and for whatever reason binding at that port would then continue working later. But if the debugger was initially launched after the harm has been done, it wouldn’t be able to bind to the port neither once nor at all.

Sale rankings are not indicative of popularity

Sales might not be indicative of the anime’s popularity, as understood by those who watch anime regularly.

E.g. if asked what were the best animes that you watched, what most otaku would say.

First of all, there’s a large number of people which only stay in the anime for 1-2 years (and even more who only watch less than 10 series). They will vote for Shingeki no Kyoujin because that’s what they watched and it was good. But if you watched anime for the last 10 years, you wouldn’t necessarily say Kyoujin was the best that you’ve seen (even though it’s OK).

So even other reasons aside, sales mostly show “what was hip at the time it came out”, not “what was etched into the hearts of long-time fans the most”.

Now, if you look at the list, there’s only Gundam SEED in the top 10 which can’t be considered relatively modern (let’s say modern era starts with 2006 Haruhi / Geass). There’s only SEED, FMP and Initial D in the top 30!

Even if you count “Modern” from 2009 / Bake, there’s only SEED, 00, Macross F, Geass, Haruhi, FMP, Lucky Star and Initial D (10 slots total) which haven’t been made in the last 5 years.

Modern animes are disproportionately present in the top sale charts.

It’s not that anime has gotten just that much better. Delivery prices, channels and anime popularity vary. Perhaps anime DVDs cost more or weren’t as widely available, or it wasn’t as common at the time to buy them, or economy was worse, or anime in general had less fanbase.

Recent animes also have a better potential fanbase. Older otaku may still vote for them, while younger otaku will not, in general, watch lots of older animes, and even if they do, there’s usually no way to buy one (increasing the sales).

HOWTO: Assign checkable TAction to TSpeedButton

To make TSpeedButton work with TAction.Checked when it’s a singular option (either On or Off), make sure that at design-time:

SpeedButton.Action = Action
SpeedButton.GroupIndex = 0
SpeedButton.AllowAllUp = true
Action.GroupIndex = 0
Action.AutoCheck = true //only if you need AutoCheck

Then add this to FormCreate:

SpeedButton.GroupIndex := 17; //any non-used group index

SpeedButtons are linked to Actions through TSpeedButtonActionLink. It only updates their Down property if AllowAllUp is set and SpeedButton.GroupIndex property is NOT 0.

But when Action is linked, SpeedButton.GroupIndex gets rewritten by Action.GroupIndex on load.

And if Action.GroupIndex is 0 because it’s a singular option, then no matter what you put into SpeedButton.GroupIndex at design-time, it’s going to be rewritten with 0 at load, so TSpeedButtonActionLink does not update Down property.

The simplest solution is to set SpeedButton.GroupIndex to something in FormCreate.

How to maybe fix Gigabyte RF-G90B and certainly void your warranty

Disclaimer, read first. I have no qualifications to give any advice on this topic. I give no assurances or guarantees of any kind. This article is not meant to serve as an instruction, it’s just a description of what I did. Whatever you do, do it at your own risk, after properly studying and following safety measures.

I have a Gigabyte GZ-G90B1 Power Bank which seems to be more commonly known as RF-G90B. It’s also appears to be the same as Enerpad MG-9000 which is the brand name for Samyatech contents (board + cells imported from Japan, or so they say). So Gigabyte just sells that.

I haven’t used it for a while and when I tried to use it, it appeared dead. No matter if I tried to charge it, use it to charge mobile, press the button and/or hold it, the device wouldn’t react and lights would stay off.

As I’ve already lost my receipt I had no hope for replacement, so I unscrewed it (there’s a single screw). The box wouldn’t open at first because the cells are glued to both halves of it, but there’s no way around it but to pull. I detached the chip from the cells and then attached it back. This seems to have rebooted the chip and it started working.

If you cannot start Windows Live Marketplace

If you cannot start Windows Live Marketplace or games dependent on Windows Live even after completely reinstalling it, and you’re having the following errors:

  1. Application crash when starting Windows Live Marketplace with "FileNotFoundException" or "MethodNotFoundException" or something.
  2. Errors related to "msidcrl40.dll" in your %UserProfile%\AppData\Local\Microsoft\GFWLive\Logs.

Then this may help you.

  1. Uninstall Windows Live and all of its components (usually there are two: Microsoft Windows Live Runtime and Microsoft Windows Live Marketplace)
  2. Uninstall Windows Live Essentials or just Windows Essentials (same thing)
  3. Go to C:\Program Files\Common Files\Microsoft Shared\ and check that there’s no Windows Live subfolder or that it’s empty or whatever. Delete it if not empty. If some apps do not let you delete some files, rename those files and delete after restart.
  4. Restart
  5. Download and install Games for Windows Live 3.5, web setup will do. Check if the folder mentioned above is now present again and with files. If not, download wllogin_64.msi (or _32) and run it.
  6. All should work. Run Marketplace and check.

The folder Microsoft Shared\Windows Live is created by the thing that’s installed by wllogin_64.msi (Windows Live Login Helper or something). That thing is automatically installed with Windows Essentials, and it seems that it’s a newer version which lacks some function which is needed for Games for Windows Live. It is also automatically installed by GFWL 3.5 installed, but it won’t install it if it finds newer version (installed by Essentials), so reinstalling just GFWL doesn’t help.

I included that step where you may install the thing manually because GFWL 3.5 install may be stubborn and skip it anyway for whatever reason. If it so does, download and install manually.

pyoperalink: certificate verify failed

If you’re trying to use pyoperalink and you’re getting certificate verification errors:

httplib2.SSLHandshakeError: [Errno 1] _ssl.c:507: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

That might be because libhttpd2’s root certificate list is too short (I don’t know why).

Quick solution: Download this cacert.pem and save as Python\Lib\libhttpd2\cacerts.txt or Python\Lib\site-packages\libhttp2\cacerts.txt. You’ll need administrator privileges and make a backup of cacerts.txt beforehand.

Ostensible explanation: Certificates are chained: there’s a handful of root certificates which are used to sign site certificates or second-layer certificates and so on. Open auth.opera.com and study the certificate (in Opera you have to click the green placard in the address bar). At the time of writing the topmost certificate in its chain is "DigiCert High Assurance EV CA-1".

Open cacerts.txt. This is the root certificates libhttpd2 understands. Search for "DigiCert" or "Digi": no matches. Thus, libhttpd2 does not trust the "DigiCert High Assurance". It has to be added to this list. "Quick solution" does this by replacing the file with a longer list of trusted certificates extracted from the list at mozilla.org. You can use any other list in compatible format which contains root certificates you need. (You should study the source before copying it because I may be malevolent or mistaken myself).