Thursday, May 30, 2019

Exotherm - Mercuric

This morning I got emails saying that a FICS computer account had been created for me. It's named "mercuric", my second choice because "exotherm" wasn't available. (It appears available to me, and I've logged in as guest with it even today, but maybe there's something else going on.) I added the ability to post seeks and set appropriate variables, then uploaded it to my server. It can successfully log in and play games, though it eventually loses connection - I'll need to set up some way to automatically restart it when needed.

Wednesday, May 29, 2019

Exotherm - Evaluator tweaks

I recently adjusted Exotherm's position evaluator a little more. To help it avoid losing in preventable ways in the endgame, I made it value check by rook or queen, which tend to lead to explosions. To encourage it to develop more pieces in the opening, I made it slightly value the possibility of targeting more open squares. I also adjusted the pawn balance evaluator to be less likely to needlessly sacrifice a rook for a pawn.

There's still no updates on FICS's provisioning of a computer account for Exotherm.

Tuesday, May 28, 2019

Exotherm - Memory conservation

The virtual server that I'll hopefully be able to run Exotherm on has only 1 GB of RAM. I've noticed that Exotherm uses a sizable fraction of that, so if I want my server to be able to continue doing more important things, I'll need to be careful about memory usage. I noticed that the "think" module keeps board objects for all positions in the tree even after they've been evaluated, stopping the GC from collecting them. So I adjusted it to set them to None when no longer needed, allowing the GC to make progress even in the middle of a think if necessary.

Monday, May 27, 2019

Exotherm - Preparing for deployment

My previous attempt at making Exotherm note positions that led to loss worked poorly because the information was rediscovered a half move too late. Today I added similar logic to the part of the bot that relays the decided move to the server. If the evaluator found that the bot is doomed, the outer code records that the previous move the bot made is bad. This measure has no depth limit because it will only add at most one entry per game, so I'm not too worried about storage space.

I also made the bot willing to accept draws in some circumstances. It now keeps track of how many moves have occurred since an explosion or pawn move. When its opponent makes a draw offer, it will accept if no progress has been made for several moves and there is little material still existing.

These are the last changes I wanted to make to Exotherm, so after testing them I sent in my application for a computer account. They've approved the deployment of my engine - now I'm waiting for the username to be approved and the account provisioned.

Sunday, May 26, 2019

Exotherm - Hardcoded responses

After some testing today I determined that Exotherm's new ability to record the moves that led to unexpected certain doom is not working as well as I hoped. It seems like the doom is detected a half-move too late in the very common 1. Nf3 trap. It looks like I would need something more sophisticated for Exotherm to make any progress in the general case. As a temporary measure, I added a configuration section for "hardcoded" responses to recognized positions. Currently I'm only manually configuring 1. ...f6 as the response to the knight threat, but once Exotherm is deployed I would monitor for other repeatable traps.

Saturday, May 25, 2019

Microsoft deprecated the File History API

I was looking back at the File History API that I had worked with previously and noticed that the new header files are saying it's deprecated. FhCfg.h has instructions like #pragma deprecated(IFhConfigMgr) and functions in FhSvcCtl.h are have notes like:
__declspec(deprecated("FhServiceOpenPipe is deprecated and might not work on all platforms. For more info, see MSDN."))

I'm looking at header files from the SDK for Windows 10 build 17134 (version 1803), while the version from build 10240 (version 1507, the original Windows 10) does not have the notices. Weirdly, there does not seem to be any mention of this deprecation in the documentation of those functions nor anywhere on MSDN that I could find by searching.

Friday, May 24, 2019

The Exotherm draw problem

I'm hoping to deploy Exotherm to the FICS relatively soon. There is a problem I'd like to address first, though. It plays poorly in the endgame and usually thinks it's doing much better than it is. It walks various pieces all around the board without making any progress. I would like to have it accept draws if it detects no progress has been made after some time. Playing it would be much more enjoyable if one didn't have to go all the way to draw by repetition or 50 moves when the bot can't figure out what to do.

Thursday, May 23, 2019

Exotherm - Learning

Previously Exotherm tended to fall for opening traps because a move looked good to it but actually led to certain doom deeper in the tree. Before releasing it, I wanted to make it avoid at least the most common mistakes. Today I added some code to the evaluator that uses and maintains a list of positions known to be won/lost. These notes are limited to a certain depth from the start of the game to avoid clogging up the list with deep positions that will never be seen again. The main bot code saves the list as part of the configuration file.

Wednesday, May 22, 2019

Listening for HTTP requests in PowerShell

I recently needed to test that an application made a reasonable HTTP request, so I wanted a convenient way to listen for requests and see the contents. It turns out the .NET Framework has an HttpListener class, so PowerShell can do the job. This sets up a listener on port 8080, waits for a connection, and prints the body:

$listener = [System.Net.HttpListener]::new()
$listener.Prefixes.Add('http://localhost:8080/')
$listener.Start()
$ctx = $listener.GetContext() # waits for connection
[System.IO.StreamReader]::new($ctx.Request.InputStream).ReadToEnd()
$listener.Close()

Tuesday, May 21, 2019

If a class mysteriously doesn't match, consider the loader

Recently I needed to load some Java class files from disk and see if they had certain annotations. I successfully got the classes loaded, but getAnnotation never found an annotation of my specified type. Confusingly, the full list provided by getAnnotations was of the expected size and the annotation class names were as expected, but the classes didn't compare equal to the target class. Eventually I realized the problem: the annotation class was loaded again from disk, and that copy was distinct from the one loaded into my application because they came from different classloaders. The solution was to prevent the duplicate load by providing a parent classloader (e.g. the current class's loader) to the URLClassLoader.

Saturday, May 18, 2019

Launching Internet Explorer without quotes mangling

One user was employing some batch commands to launch Internet Explorer to a specified URL. They found that this worked fine the first launch, but if the strategy was used again while the first IE instance was still running, the second instance misinterpreted quotes in the command line as part of the URL and failed to load the page.

This can be worked around by preventing Internet Explorer from "merging" frame processes and sessions. Supplying -nosessionmerging -noframemerging on the command line allowed multiple instances to be launched without mangled quotes breaking the URL.

Friday, May 17, 2019

Policy Plus - Similar language ADML loading

A Policy Plus issue was filed today suggesting a change to the ADML loading procedure. Previously it tried to find an ADML in the user's display language but fell back to English (en-US) if needed. However, some languages have several dialects that are of course more similar to each other than to US English. So I made the loader look for ADML files in directories with the same language (e.g. de) before falling all the way back to en-US.

Thursday, May 16, 2019

Getting the real current screen resolution from the command line

Getting the real current screen resolution, as shown in the display settings and as desired by this Super User question, is surprisingly tricky to do programmatically. Some ways get the maximum resolution supported by the display and others produce wrong results on high-DPI screens. The most reliable way seems to be GetDeviceCaps. In SprintDLL:
call user32.dll!GetDC /return native /into hdc (native 0)
call gdi32.dll!GetDeviceCaps /return int (slotdata hdc, int 118)
call gdi32.dll!GetDeviceCaps /return int (slotdata hdc, int 117)

The first call returns the width, the second gets the height. Or in PowerShell:
Add-Type @"
using System;
using System.Runtime.InteropServices;
public class PInvoke {
    [DllImport("user32.dll")] public static extern IntPtr GetDC(IntPtr hwnd);
    [DllImport("gdi32.dll")] public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
}
"@
$hdc = [PInvoke]::GetDC([IntPtr]::Zero)
[PInvoke]::GetDeviceCaps($hdc, 118) # width
[PInvoke]::GetDeviceCaps($hdc, 117) # height

Wednesday, May 15, 2019

The Robolectric JUnit runner doesn't support @ClassRule

I noticed yesterday that JUnit test suites run under Robolectric using @RunWith(RobolectricTestRunner.class) do not execute rules annotated with @ClassRule. I was hoping to allow some functionality to be packaged up into a rule so I could cleanly use it in many projects, but Robolectric just doesn't support class rules yet. Instead I'm creating an abstract class with @BeforeClass and @AfterClass methods, then making test suite classes inherit from that.

Tuesday, May 14, 2019

Extending the SprintDLL File History example

A while back I showed in a Super User answer how to use my utility SprintDLL to configure File History from script. I just noticed a comment on this blog from someone who would like to do something similar but with different File History settings. (The comment was posted several months ago - sorry for the long wait!) I don't recall off the top of my head how I figured out all the parts of that script, and it could be neat to show how to put this together, so I'm writing this live as I investigate. We'll see how this goes.

First we'll need a test environment that can be easily reverted. I'm using a Hyper-V virtual machine running Windows 10 Home. While I wait for it to do all the Windows updates, I create the FileHistory$ share that the current script assumes, download SprintDLL v1.2, and copy the existing script from my old answer into a file. I also copy the same script into a text editor on my real machine in case we need to revert the VM.

After a little Windows Update troubleshooting and a lot of waiting, the VM is all updated. I take a checkpoint. To make sure we have a solid starting point, I try the existing script:

SprintDLL run filehistory.sprint

Sure enough, it enables File History, setting it to keep backups until space is needed and make them at the default rate of once per hour. Our goal now is to save copies every three hours and keep them for three months.

Previously I used SetLocalPolicy to set the retention policy, so let's look there again now. It's not very specific, so let's click through to the FH_LOCAL_POLICY_TYPE enum's documentation. It has one value to set the frequency, one for the "retention type", and one for the retention age. Clicking through to FH_RETENTION_TYPES, we find one value that never deletes old backups (the default, to keep "forever"), one to keep until space is needed (what my previous script used), and one that's "age based." The FH_LOCAL_POLICY_TYPE documentation also shows what the "numeric parameter" (second argument to SetLocalPolicy) means for each policy type: time in seconds for frequency, time in days for retention. So it looks like we need to make these calls:

fh->SetLocalPolicy(FH_RETENTION_TYPE, FH_RETENTION_AGE_BASED)
fh->SetLocalPolicy(FH_FREQUENCY, 10800)
fh->SetLocalPolicy(FH_RETENTION_AGE, 90)

Here's the most similar call from my old script:
// fh->SetLocalPolicy(FH_RETENTION_TYPE, FH_RETENTION_UNLIMITED)
newslot native setLocalPolicy
copyslot setLocalPolicy = vtbl field 9
call funcat setLocalPolicy /call thiscall /return uint (slotdata fhPtr, int 1, int 1)

Only the last one needs to be copied/changed - the previous two just get the function address and the first is a comment. FH_RETENTION_AGE_BASED is right after FH_RETENTION_UNLIMITED in the enum documentation, so I'm going to guess we should change that last 1 to a 2:
// fh->SetLocalPolicy(FH_RETENTION_TYPE, FH_RETENTION_AGE_BASED)
newslot native setLocalPolicy
copyslot setLocalPolicy = vtbl field 9
call funcat setLocalPolicy /call thiscall /return uint (slotdata fhPtr, int 1, int 2)

FH_FREQUENCY is the very first entry in its enum documentation, so it's probably value 0. (If that turns out to be wrong, we could probably dig up some H file from the SDK to look it up.) We already have the function address, so after the existing call we just need another call and a helpful comment:
// fh->SetLocalPolicy(FH_FREQUENCY, 10800)
call funcat setLocalPolicy /call thiscall /return uint (slotdata fhPtr, int 0, int 10800)

FH_RETENTION_AGE is right after FH_RETENTION_TYPE, so it's probably value 2.
// fh->SetLocalPolicy(FH_RETENTION_AGE, 90)
call funcat setLocalPolicy /call thiscall /return uint (slotdata fhPtr, int 2, int 90)

We're ready to test! I copy the script into the VM and run it:

Function at 140706149603792 returned 0
Function at 140706149608592 returned 0
Function at 140706149607024 returned 0
Function at 140706149607024 returned 0
Function at 140706149607024 returned 0
Function at 140706149607520 returned 0
Function at 140706149604096 returned 0
FhServiceOpenPipe returned 0
FhServiceReloadConfiguration returned 0
FhServiceClosePipe returned 0

Promising! Let's check out the File History control panel:


Hmm, File History was enabled and we got our frequency set, but not the retention time. Out of curiosity I check an XML configuration file in %localappdata%\Microsoft\Windows\FileHistory\Configuration (mentioned in the Super User question I answered), and it does seem to have received the setting:


I wonder if my guess of 30 days per month doesn't match Windows's idea, causing it to fail to match any of the entries in the "keep saved versions" dropdown and thereby show the default in the UI. I try setting it to "3 months" using the UI and checking the configuration file again. Interestingly, the <MinimumRetentionAge> value has now changed to 3. Maybe the documentation is wrong/outdated? I revert the VM and make a small change to the script:
// fh->SetLocalPolicy(FH_RETENTION_AGE, 3)
call funcat setLocalPolicy /call thiscall /return uint (slotdata fhPtr, int 2, int 3)

The output in the console after running the script is the same. Let's see what the control panel looks like now:


There we go! Apparently the retention age parameter is specified in months, not days.

The full, corrected script is available in a Gist.

Monday, May 13, 2019

runtimeClasspath doesn't exist on Android source sets

Recently I was trying to adapt a Gradle/IntelliJ-based testing tool to an Android app module. It used sourceSets.main.runtimeClasspath and the test counterpart to assemble the classpath, but that doesn't seem to exist for Android, even using android.sourceSets instead of just sourceSets. Getting the full classpath from script seems to be tough, but in this case I really only needed my test suites to be included. So I just specified the path to those:

"${project.getRootDir()}/app/build/intermediates/javac/debugUnitTest/compileDebugUnitTestJavaWithJavac/classes"

Saturday, May 4, 2019

Adding line spacing to TextView in the presence of BackgroundColorSpan

One of my Android app's screens involves TextViews displaying text formatted with BackgroundColorSpan. That one view displays multiple lines by separating rows with newline characters. I found that the background color from one line came into contact with that of the next, an effect which looked poor. Adding line spacing in the layout XML made this worse - the background color took up the spacing and was therefore different between outer and middle lines.

I ended up fixing it by using a newline-space-newline sequence instead of just a newline to separate rows. That entire sequence of three characters is formatted with a RelativeSizeSpan to be a fifth the height of the main font. (Excluding either newline from the span makes the blank line full-height.) For padding, I also include the full sequence at the start of the string and a two-character newline-space sequence at the end.