Which lines repeat most often in a stack trace?

I was looking at the stack trace of a stack overflow exception, and it’s looong (1172 lines). I wanted to just see which lines occurred most often. Easy enough with the right incantation of sort and uniq.

$ < stack.txt sort | uniq -c | sort -rh | head
Posted in Uncategorized | Leave a comment

Running Eclipse MAT on macOS

If you try to run Eclipse Memory Analyzer (MAT) out of the box on macOS, you’ll likely get an error that you need version 11 or above of Java, even if you have version 11 installed (say, with SDKMAN!).

You need to tell Eclipse MAT where to find this version of Java. Don’t edit the info.plist file, because then you’ll get an invalid code signature error.

Instead, you want to edit the /Applications/mat.app/Contents/Eclipse/MemoryAnalyzer.ini file. I added the following two lines to the top of my file:

-vm
/Users/lhochstein/.sdkman/candidates/java/current/bin

Worked like a charm. (Note that adding these to the bottom of the file didn’t work).

I also had to increase the size of the heap. I bumped it to 12GB, by editing the appropriate line in MemoryAnalyzer.ini to:

-Xmx12G

Final note: you may want to show Unreachable objects. I’m just going to copy-paste from this Stack Overflow answer.

  1. Close the snapshot
  2. Select the heap dump using Window > Heap Dump History right-click, Delete Index Files
  3. Select ‘Keep unreachable objects’ using Window > Preferences > Memory Analyzer
  4. Reopen the heap dump, which will reparse the heap dump.
  5. Select the Java Basics > GC Roots query.
  6. Select the ‘Unreachable Objects’ row.
  7. Run the ‘Show Retained Set’ query on that row.

Posted in Uncategorized | Leave a comment

Pasting HTML from the macOS clipboard

I like to write decision tables in Google Sheets. If you copy to the clipboard, it copies to HTML. Alas, pbpaste doesn’t support pasting HTML, and the text representation throws out too much info.

There’s a nice answer on Stack Overflow on how to do this in Swift.

Can combine this with tidy for nicer formatting:

./pbpaste-html | tidy -xml -q -i
Posted in Uncategorized | Leave a comment

WARNING: An illegal reflective access operation has occurred

If you’re running a newer version of the JDK (9 or greater), you might have started to see warnings that look like this:

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.codehaus.groovy.reflection.CachedClass (file:/Users/myname/.gradle/caches/modules-2/files-2.1/org.codehaus.groovy/groovy/2.5.11/4d8f25c5da08af46fb204fd493ec894699a3f4e8/groovy-2.5.11.jar) to method java.lang.Object.finalize()
WARNING: Please consider reporting this to the maintainers of org.codehaus.groovy.reflection.CachedClass
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

This warning is harmless, but annoying. From the groovy 2.5 release notes known issues

JDK9+ produces warnings with many libraries including Groovy due to some planned future restrictions in the JDK. Work is underway to re-engineer parts of Groovy to reduce/remove those warnings. Users wanting to hush the warnings as an interim measure may consider using the --add-opens escape clause offered by JDK9+. See commit 92bd96f (currently reverted) on the Groovy master branch for a potential list to add.

Groovy commit 92bd96f has the flags you can pass to the JVM to suppress the warnings, which I’ve reproduced below:

--add-opens=java.base/java.io=ALL-UNNAMED
--add-opens=java.base/java.lang=ALL-UNNAMED
--add-opens=java.base/java.lang.annotation=ALL-UNNAMED
--add-opens=java.base/java.lang.invoke=ALL-UNNAMED
--add-opens=java.base/java.lang.module=ALL-UNNAMED
--add-opens=java.base/java.lang.ref=ALL-UNNAMED
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED
--add-opens=java.base/java.math=ALL-UNNAMED
--add-opens=java.base/java.net=ALL-UNNAMED
--add-opens=java.base/java.net.spi=ALL-UNNAMED
--add-opens=java.base/java.nio=ALL-UNNAMED
--add-opens=java.base/java.nio.channels=ALL-UNNAMED
--add-opens=java.base/java.nio.channels.spi=ALL-UNNAMED
--add-opens=java.base/java.nio.charset=ALL-UNNAMED
--add-opens=java.base/java.nio.charset.spi=ALL-UNNAMED
--add-opens=java.base/java.nio.file=ALL-UNNAMED
--add-opens=java.base/java.nio.file.attribute=ALL-UNNAMED
--add-opens=java.base/java.nio.file.spi=ALL-UNNAMED
--add-opens=java.base/java.security=ALL-UNNAMED
--add-opens=java.base/java.security.acl=ALL-UNNAMED
--add-opens=java.base/java.security.cert=ALL-UNNAMED
--add-opens=java.base/java.security.interfaces=ALL-UNNAMED
--add-opens=java.base/java.security.spec=ALL-UNNAMED
--add-opens=java.base/java.text=ALL-UNNAMED
--add-opens=java.base/java.text.spi=ALL-UNNAMED
--add-opens=java.base/java.time=ALL-UNNAMED
--add-opens=java.base/java.time.chrono=ALL-UNNAMED
--add-opens=java.base/java.time.format=ALL-UNNAMED
--add-opens=java.base/java.time.temporal=ALL-UNNAMED
--add-opens=java.base/java.time.zone=ALL-UNNAMED
--add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.locks=ALL-UNNAMED --add-opens=java.base/java.util.function=ALL-UNNAMED --add-opens=java.base/java.util.jar=ALL-UNNAMED --add-opens=java.base/java.util.regex=ALL-UNNAMED --add-opens=java.base/java.util.spi=ALL-UNNAMED --add-opens=java.base/java.util.stream=ALL-UNNAMED --add-opens=java.base/java.util.zip=ALL-UNNAMED --add-opens=java.datatransfer/java.awt.datatransfer=ALL-UNNAMED --add-opens=java.desktop/java.applet=ALL-UNNAMED --add-opens=java.desktop/java.awt=ALL-UNNAMED --add-opens=java.desktop/java.awt.color=ALL-UNNAMED --add-opens=java.desktop/java.awt.desktop=ALL-UNNAMED --add-opens=java.desktop/java.awt.dnd=ALL-UNNAMED --add-opens=java.desktop/java.awt.dnd.peer=ALL-UNNAMED --add-opens=java.desktop/java.awt.event=ALL-UNNAMED --add-opens=java.desktop/java.awt.font=ALL-UNNAMED --add-opens=java.desktop/java.awt.geom=ALL-UNNAMED --add-opens=java.desktop/java.awt.im=ALL-UNNAMED --add-opens=java.desktop/java.awt.im.spi=ALL-UNNAMED --add-opens=java.desktop/java.awt.image=ALL-UNNAMED --add-opens=java.desktop/java.awt.image.renderable=ALL-UNNAMED --add-opens=java.desktop/java.awt.peer=ALL-UNNAMED --add-opens=java.desktop/java.awt.print=ALL-UNNAMED --add-opens=java.desktop/java.beans=ALL-UNNAMED --add-opens=java.desktop/java.beans.beancontext=ALL-UNNAMED --add-opens=java.instrument/java.lang.instrument=ALL-UNNAMED --add-opens=java.logging/java.util.logging=ALL-UNNAMED --add-opens=java.management/java.lang.management=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.rmi/java.rmi=ALL-UNNAMED --add-opens=java.rmi/java.rmi.activation=ALL-UNNAMED --add-opens=java.rmi/java.rmi.dgc=ALL-UNNAMED --add-opens=java.rmi/java.rmi.registry=ALL-UNNAMED --add-opens=java.rmi/java.rmi.server=ALL-UNNAMED --add-opens=java.sql/java.sql=ALL-UNNAMED

Note that this commit was ultimately reverted, which is why you’ve got to do it manually until the Groovy folks come up with a solution.

Posted in Uncategorized | Leave a comment

Unescaping strings of stack traces

I often find myself copying strings of Java stack traces which have escaped tabs and newlines (\t\n). Those aren’t fun to read. Here’s a quick Python script I rigged up to grab what’s on the clipboard and format it properly. I call it unescape:

#!/usr/bin/env python3
'''

Grab the string on the clipboard and print it to standard out,
interpreting tabs and newlines appropriately

'''
import subprocess
r = subprocess.run(["/usr/bin/pbpaste"], capture_output=True, encoding="unicode_escape")
print(r.stdout)

Posted in Uncategorized | Leave a comment

Stripping leading timestamp from GitHub Action logs

GitHub Action logs start with timestamps. To strip them with sed:

sed 's/^[0-9T:.-]\{27\}Z //'

Posted in Uncategorized | Leave a comment

Automating Slack status changes on macOS

In these days of everyone working from home, I really liked the approach to setting Slack status that Alex Hidalgo mentioned on Twitter:

I wanted to be able to change status from Alfred. Turns out there’s a handy Applescript bundle by Sam Knight that makes this easy. Here’s how I do it:

tell script "Slack"
	focus workspace "Netflix"
	set status "online" with icon ":wfh-up:"
end tell

I couldn’t get Alfred to invoke this Applescript directly (I imagine it has something to do with Security settings in Catalina), so I saved it to a file (up.scpt), and then invoked it in a workflow as a bash script, where the command was:

osascript ~/dev/slack-automation/up.scpt

My Alfred Slack status workflow looks like this:

Posted in Uncategorized | Leave a comment

Stomping a local git branch with the remote

When somebody rebases their PR, my local copy of that branch gets out of sync:

➜  keel git:(fix-paused-events) git status
On branch fix-paused-events
Your branch and 'luispollo/fix-paused-events' have diverged,
and have 8 and 16 different commits each, respectively.
  (use "git pull" to merge the remote branch into yours)

I just want my local copy to reflect the remote one.

I created a “stomp” alias that resets my local branch with the upstream:

[alias]
    stomp = !git reset $(git status -sb | cut -d'.' -f4 | awk '{print 
$1}') --hard

Posted in Uncategorized | Tagged | Leave a comment

J-Bob from the Little Prover

The Little Prover book references a companion proof assistant tool called J-Bob. I had a hard time getting it running using Racket’s Dracula package, here’s how to do it:

  1. Install Racket.
  2. Install the Dracula package for Racket. On macOS, I did:
    cd /Applications/Racket\ v6.10.1/bin
    sudo ./raco pkg install dracula
  3. Download ACL2. I ended up grabbing a pre-built binary gzipped tarball which was for 7.1, but the latest is 7.4 if you want to build from source. You can get the binaries at http://acl2s.ccs.neu.edu/acl2s/src/acl2/
  4. Unzip the ACL2 tarball somewhere, I put it in my home directory, so it ended up as ~/acl2-image-7.1-macosx.x86_64
  5. Launch the DrRacket IDE
  6. Menu: Language -> Choose Language -> Other Languages -> Dracula -> ACL2
  7. Menu: Dracula -> Change ACL2 Executable Path… -> Point it at the run_acl2 binary in the directory where you installed ACL2.
  8. In the top-left window, paste the following:
    (include-book "j-bob-lang" :dir :teachpacks)
    (include-book "j-bob" :dir :teachpacks)
    (include-book "little-prover" :dir :teachpacks)

    Note: Running these commands  in the REPL in the bottom-left window didn’t work for me.

  9. Click the “Run” button at the top-right of the Dr. Racket window.

You’re now set up to use J-Bob. Verify it worked by typing the following in the interpreter in the bottom-left window of Dr. Racket.

(J-Bob/step (prelude) '(car (cons 'ham '(cheese))) '())

The output should be:

(car (cons 'ham '(cheese)))

 

Posted in Uncategorized | Tagged , , , | Leave a comment

Generating Dash cheat sheets

I’m a big fan of the Dash documentation tool for macOS. In particular, I often create my own Dash cheat sheets to help me remember commands I frequently forget.

I make enough of these that I created a simple Go app named cheat to generate a skeleton cheat sheet. I also created an UltiSnips snippet to make it easier to generate categories and entries in cheat sheets.

snippet entry "cheatsheet entry"
entry do
    name '$1'
    notes <<-'END'
    \`\`\`
    $2
    \`\`\`
    END
end
endsnippet

snippet category "cheatsheet category"
category do
    id '$1'
end
endsnippet

On Neovim, this would go in ~/.config/nvim/UltiSnips/ruby.snippets

Posted in dash | Leave a comment