Friday, November 21, 2025

Windows 10 SDK 10.0.20348.0 is gone

I was caught by surprise today after updating Visual Studio 2022 to version 17.14.11. All my projects failed to compile, because the SDK files disappeared. I first thought something broke with VS Code support, but then I saw that Visual Studio itself had the same problem.

Turns out the Windows SDK I was using – 10.0.20348.0 – was simply deprecated and removed in this update, according to here, and the release note itself. Indeed, Visual Studio Installer won’t show it anymore.

Apparently, now I’ll have to install a Windows 11 SDK, even if I’m running Windows 10. I hope this doesn’t break my stuff.

Wednesday, November 5, 2025

Non-movable and non-copyable C++20 classes

On my fantastic journey implementing WinLamb v2, I’m diving deep into C++20, grasping a lot of concepts I never understood before, and having a lot of fun along the way.

One of the things that I implemented was the idea of non-copyable and non-movable classes, at first, using macros. This felt inelegant, so I implemented P2895 paper with utility classes. It ultimately failed with the nested ListView classes, so I discarded the idea too.

My final solution was to = delete move constructor, which will prevent all copy and move. The hard rules are not particularly easy to memorize, so I’ll let them here for further reference:

  1. The two copy operations are independent. Declaring copy constructor does not prevent compiler to generate copy assignment and vice versa. (Same as in C++98.)
  2. Move operations are not independent. Declaring either one of them prevents the compiler to generate the other. (Different from copy operations.)
  3. If any of the copy operations is declared, then none of the move operations will be generated.
  4. If any of the move operations is declared, then none of the copy operations will be generated.
  5. If a destructor is declared, then none of the move operations will be generated. Copy operations are still generated for reverse compatibility with C++98.
  6. Default constructor generated only when no constructor is declared. (Same as in C++98.)

Example:

class Foo {
private:
	Foo(Foo&&) = delete; // non-copyable, non-movable
};

Friday, October 24, 2025

Ibanez Wizard profile history

Since I’m on the market for a “battle” RG guitar to play with bands, I reminded a change that happened to the fretboard width of Wizard necks, from 56 to 58mm. According to Rich, it happened back in 2005.

Digging a bit more, I found more information about the Wizard neck profile history, which I compiled in the table below:

Neck Width Thick Radius
Original Wizard 43/57mm 17/20mm 17"
Pre-2005
Super Wizard 43/56mm 17/19mm 17"
Wizard 43/56mm 18/20mm 17"
Post-2005
Super Wizard 43/58mm 17/19mm 17"
Wizard 43/58mm 18/20mm 17"

Monday, October 20, 2025

Using VSCode for C++ projects

For a long time I thought I only could use Visual Studio to write C++ programs on Windows, because MSVC toolchain requires some particular initializations before being able to run.

Turns out there is a way to smoothly run all the MSVC machinery from within VSCode. The answer is the same I found last year in automating MSVC builds: we need a .bat file to call MSVC’s own .bat, then we invoke VSCode executable right after.

call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
"C:\apps-portable\VS Code\Code.exe"

Save this .bat somewhere, and put a shortcut to it in your start menu, naming it “VSCode MSVC” or something like that.

To my surprise, multiple things work better in VSCode than in Visual Studio itself:

  • file navigation;
  • file creation and deletion;
  • code and comment folding;
  • keyboard shortcuts;
  • error reporting – VSCode highlights in red the files with errors, while in Visual Studio I have to build the project and look at the output to see which files are broken.

Monday, October 13, 2025

Perfect non-locking string winding

While searching my future Ibanez RG Prestige, I found this StewMac video of how to properly wind the strings around the tuning machines:

I remember having seen this technique before, but this time I’m keeping the reference.

Saturday, September 27, 2025

Single target dir for all Rust projects

Rust, just like C++, generates a lot of output files when you build an executable. Particularly, when writing my programs with WinSafe, I use the library straight from a sibling directory, so I can test any changes right away – the side effect is that all those output artifacts are generated repeatedly for each new program.

So I’ve just tested the target-dir global option for Cargo, which will use a single target directory for all projects. This would, in theory, prevent the constant rebuilding of WinSafe artifacts.

Since the output dir changed, I had to also change the deploy.sh scripts to point to the new location. Other than that, everything seemed to work as intended, and I’m pretty satisfied with the results.

This is now my global ~/.cargo/config.toml file:

# https://github.com/rust-lang/cargo/issues/3381#issuecomment-710388554
[net]
git-fetch-with-cli = true

# https://redd.it/1dua24f
# https://blog.rust-lang.org/2023/11/09/parallel-rustc.html
[build]
target-dir = "D:\\Stuff\\Core\\rs\\_target"
#rustflags = ["-Z", "threads=8"]
# Change default toolchain:
# rustup show
# rustup default nightly-x86_64-pc-windows-msvc
# rustup default stable-x86_64-pc-windows-msvc

As an extra benefit, when I want to clean the target directory, now I just need to delete the single _target one.

Monday, August 18, 2025

Previewing Go package documentation

While developing Windigo, I’m using the auto-generated docs at pkg.go.dev. It’s not perfect, but it’s something.

I didn’t know, however, a way to preview the generated docs while still developing the library.

Go 1.25 brought a new go doc option which allows us to preview the documentation by creating a temporary, virtual server. It downloads a whole bunch of packages, builds them, and then effectively displays the current docs:

go doc -http

This is being a game changer, I can now preview all the documentation instantly. Thanks to this guy who told me that.

Friday, August 15, 2025

Install PKCS#11 drivers, Linux

I need the PKCS#11 USB token at work, and every time I spin a new Linux VM, I need to install it again. But I never remember what needs to be done. So I’m documenting the steps here.

First, download the latest driver at GlobalSign, unzip and install it. The installation will probably fail because of missing dependencies; the second command will install them followed by the original package:

sudo dpkg -i foo.deb
sudo apt-get -f install

Once you reboot, the SafeNet icon will appear in the tray.

To install support for Brave browser, see here.

Sunday, August 10, 2025

Brave cookies whitelist

I’ve been wasting way too much time, multiple times, looking for Brave’s cookie whitelist setting. So I’ll just leave it here, for reference to my future self. I found the reference on this Reddit post.

The settings are buried in:

  • Settings
  • Privacy and security
  • Site and Shields Settings
  • Content
  • Additional content settings
  • On-device site data
  • Customized behaviors

Or, this direct link:

brave://settings/content/siteData

Monday, July 14, 2025

Goodbye Chrome

Today, Google Chrome officially disabled uBlock Origin extension. We can no longer enable it through any flags. I’ve been waiting for this moment to come for a while, and so it happened.

Today I finally uninstalled Google Chrome from my Windows computer.

Firefox is still my default browser, but I just installed Brave, which has the Chromium engine, because I have a feeling that it’s more performant than Firefox. However, I also have a feeling that Chrome itself is faster than Brave. Maybe Google has some code removed from Chromium and added only in Chrome, to intentionally make Chrome faster. Conspiracy theory, but who knows.

I used the portable version of Brave which felt strangely slow. I supposed that’s because I installed it on my D: drive, which is not SSD. Brave could not open magnet links, and so far, this new installation also cannot.

On my Android phone, I already have both Firefox and Brave. My issue with Brave is that it doesn’t support extensions, and SponsorBlock is become something I can’t live without.

Another issue is the disk space used by Chrome and Brave. My observations showed me that they top at somewhat 2.7 GB, which seems a lot. Coincidence or not, I also observed this for Firefox. My C: hard drive is running short these days, and until I buy myself a new computer, that’s all I have.

At last, I joined the bandwagon of the ex-Chrome users.

Thursday, June 26, 2025

Changing Chrome User Data location

By default, Google Chrome on Windows stores all its data in:

C:\Users\USERNAME\AppData\Local\Google\Chrome\User Data

This folder seems to top around 2.5 GB, as I tested both in Chrome and Brave.

When digging the portable version of Brave, I found that it uses the --user-data-dir command line switch to store the data somewhere else – that’s the whole point of being portable.

This command line switch, obviously, belongs to Chromium, and so to all its derivative browsers, like Chrome itself. Therefore, you can move Chrome’s User Data folder to any location. After moving the folder itself, you just have to pass the new location via the --user-data-dir command line switch, as explained in Chromium Docs:

"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --user-data-dir=D:\Stuff\ChromeUserData

This finding is also useful because it shows that the whole User Data folder can ba copied to a different computer.

I found a possible Chromium bug, however, when moving User Data to my D:\ drive. When a notification pops-up, clicking it will open another Chrome window, and this new window will point to the original User Data location. Which means native notifications are unusable.

Monday, June 23, 2025

Install PKCS#11 in Brave, Linux

As Chrome’s adoption of Manifest V3 approaches, I’ve been trying Brave more and more, even in my Android. Using it for work had me in trouble though, since unlike Firefox, it has no native support to PKCS#11 USB tokens.

After trying a few things, I gave up. But a few minutes ago I stumbled upon a website which I’ve seen before, probably when setting up Chrome, and to my surprise it worked for my Linux Mint. He uses the same SafeNet eToken 5110 I’ve got here.

modutil -dbdir sql:.pki/nssdb/ -add "eToken" -libfile /usr/lib/libeTPkcs11.so

I don’t know if it matters, but I ran the command above before installing Brave itself.

Friday, June 20, 2025

Cleaning Windows temp folder

As my SSD gets more and more stuffed, I’m searching for ways to remove the cruft from it. It’s a Windows 10 installation from 2018, which I have a feeling that it needs a fresh formatted install. But since I cannot afford that now, I just keep going.

Cleaning the temp folder manually is a cumbersome chore and also takes a lot of time. The batch script below, in the other hand, deletes all the files instantly:

echo Cleaning temp...
del /s /f /q %temp%\*
for /f %%f in ('dir /ad /b %temp%\') do rd /s /q %temp%\%%f
pause

A double click on the clean.bat file now can be done at any time, in no time.

Tuesday, May 27, 2025

Pinia sucks

Today I completely wiped away Pinia from a large Vue codebase at work. It was an immense effort, but I’m so pissed I didn’t mind working overtime.

The main reason to use Pinia is that you can inspect the state in DevTools – an idea taken from React –, but guess what. The extension only exists for Chrome now, and the current old Firefox version is broken. It looks like a project driven by amateurs, just like the horrible VSCode extension. And I’m not alone on this.

For the global stores, I’m simple using a reactive object, with functions and computed values inside – that’s what Pinia does anyway. I found this by digging into its source code. I also found that a computed inside a reactive makes the .value unnecessary, which is a merit of Vue’s reactivity system, which I still believe to be the best out there.

const state = reactive({
	loading: false,
	name: '',

	foo: computed(() => state.name + '.'),

	doAction(): {
		console.info('Hello');
	},
});

I really regret choosing Vue back in the day for this project. I should’ve choosen good ol’ React, because despite its flaws, it’s dependable.

Thursday, April 3, 2025

Lean Pinia stores

Three years ago – time files – I wrote a hack to remove the boilerplate fields from a Pinia store. It worked well.

This morning, writing work stuff, I wrote a lightweight wrapper to Pinia’s defineStore, with the primary intent to remove the manual string ID which needs to be given. After the initial TypeScript brouhaha, it went so well that I was able to fully integrate the boilerplate strip with Omit, which is a solution even less intrusive than the one I wroten 3 years ago.

import {_ActionsTree, _GettersTree, defineStore, DefineStoreOptions, Pinia, StateTree, Store, StoreGeneric} from 'pinia';

let nStore = 0;

type LeanStoreDef<Id extends string = string, S extends StateTree = StateTree, G = _GettersTree<S>, A = _ActionsTree> = {
	(pinia?: Pinia | null | undefined, hot?: StoreGeneric): Omit<Store<Id, S, G, A>,
		'$id' | '$dispose' | '$onAction' | '$patch' | '$reset' | '$state' | '$subscribe' | '_customProperties'>;
	$id: Id;
}

// eslint-disable-next-line @typescript-eslint/no-empty-object-type
export function newStore<Id extends string, S extends StateTree = {}, G extends _GettersTree<S> = {}, A = {}>(
	options: Omit<DefineStoreOptions<Id, S, G, A>, 'id'>,
): LeanStoreDef<Id, S, G, A> {
	return defineStore(('siorg-store-' + ++nStore) as Id, options);
}

Usage is just exactly what I had in mind:

const useNames = newStore({
	state: () => ({
		names: [] as string[],
	}),
	getters: {
		count: state => state.names.length,
	},
	actions: {
		add(name: string): void {
			this.names.push(name);
		},
	},
});

Tuesday, December 31, 2024

Zustand, devtools and immer wrapper, pt. 3

In another epiphany of the morning of this December 31, I enhanced my previous utility function to create Zustand stores, including devtools and immer middlewares:

import {create, StateCreator, StoreApi, UseBoundStore} from 'zustand';
import {devtools} from 'zustand/middleware';
import {immer} from 'zustand/middleware/immer';

type ZustandActions<T extends object, U extends object> = StateCreator<
	T,
	[['zustand/devtools', never], ['zustand/immer', never]],
	[['zustand/immer', never], ['zustand/devtools', never]],
	U
>;

/**
 * Creates a Zustand store with state, computed and actions.
 */
export function createStore<
	T extends object,
	U extends object,
	C extends Record<string, (s: UseBoundStore<StoreApi<T>>) => void>,
> (
	{
		state,
		computed = {} as C,
		actions = {} as ZustandActions<T, U>,
	}: {
		state: T;
		computed?: C;
		actions?: ZustandActions<T, U>;
	},
) {
	const store = create(
		devtools(
			immer(() => state),
			{name: Math.random().toString(36).slice(2), serialize: true},
		),
	);

	if (import.meta.env.DEV) {
		for (const name in computed) {
			if (!name.startsWith('use'))
				throw new Error(name + ' is a hook, and its name must start with the word "use".');
		}
	}

	return {
		use: store,
		...computed,
		...actions(store.setState, store.getState, store),
	};
}

The key improvement here is that computed functions will be 100% reactive, because they’re simple hooks attached to the store object – they work like ordinary hook functions:

const bearStore = createStore({
	state: {
		bears: 0,
	},
	computed: {
		useHasBears: () => bearStore.use(s => s.bears > 0),
	},
	actions: (set, get) => ({
		increasePopulation(): void {
			set(state => {
				++state.bears;
			});
		},
	}),
});

function App() {
	const bears = bearStore.use(s => s.bears);
	const hasBears = bearStore.useHasBears();

	return <div>
		<span>{bears} - {hasBears}</span>
		<button onClick={() => bearStore.increasePopulation()}>
			Change
		</button>
	</div>;
}

I’m in awe looking at such a small function yielding such a great usability.

Multiple className values in React, pt. 2

When dealing with an important React project at work, I was manipulating multiple CSS Modules class names with a function I wrote 2 and a half years ago, accepting an object for conditionals.

The early hours of the morning of this last day of the year brought me an idea for a shorter, simpler syntax that works better for imported CSS Modules names:

/**
 * Generates the `className` attribute with the given class names.
 *
 * @example
 * cn( 'abc' );
 * cn( 'abc', 'def' );
 * cn( 'abc', ['def', true] );
 */
export function cn(...items: (string | null | undefined | [string, boolean])[]): string {
	let fin = '';
	for (let i = 0; i < items.length; ++i) {
		const item = items[i];
		if (item === null || item === undefined) {
			continue;
		} else if (typeof item === 'string') {
			fin += item + ' ';
		} else if (Array.isArray(item) && item.length === 2) {
			if (typeof item[0] === 'string') {
				if (item[1]) fin += item[0] + ' ';
			} else {
				throw new Error(`cn() item #${i} is an invalid tuple: ${JSON.stringify(item)}`);
			}
		} else {
			throw new Error(`cn() item #${i} is invalid: ${JSON.stringify(item)}`);
		}
	}
	return fin.length ? fin.substring(0, fin.length - 1) : '';
}

And this new function covers all my current needs.

Friday, December 6, 2024

Download YouTube videos

These days I was transferring one of by band’s channel, and I needed to download a 1h34min long video. No web downloader worked properly.

While searching for an actual software, I found this Reddit post referring to a Python command line tool named yt-dlp. Basic usage is pretty straightforward:

yt-dlp.exe URL

My first try downloaded two files: MP4 and WEBM. The MP4 had no sound, and the WEBM was unplayable. My recently downloaded Vegas 22 didn’t seem to recognize this files. A warning message appeared, though:

WARNING: You have requested merging of multiple formats but ffmpeg is not installed.
The formats won't be merged

The repository README had an specific section labelled FFmpeg Static Auto-Builds, with a download link to Windows x64 binaries. The zip contains, among others, a bin directory with three executables. I extracted them in the same folder of the original executable – yt-dlp.exe –, and this time the download completed smoothly, with a single file with video and audio properly merged.

Excellent tool.

Monday, October 7, 2024

Goodbye my Universe

Today I finally parted ways with my long-time friend, my Ibanez Universe UV7BK green dots.

As far as I remember, I bought this guitar in 2008 amidst a craze of seven string guitars. I remember seeing an UV777BK on the TV and going nuts over that, even posting online at the old FCC forums. And by that time I joined a Dream Theater cover band, and I played solely this guitar. To this day, I still don’t know how I was able to play all that hard stuff on a seven string. Incredible young me.

The neck profile was truly great. I loved it. Pronounced shoulders, somewhat similar to the Suhr Modern Satin I had.

I remember trying to sell it 10 years ago or so, but I retreated.

After playing in a band where a seven string was demanded, and using a six string with a pitch shifter instead, I finally realized I don’t play sevens anymore. It must go. The original Ibanez wooden hardcase was wasted with mold, so I had to buy another one. Pretty bad fit, but anyway. The UV had grown mold in the neck too, but I cleaned. Maybe it will show up again in the future, who knows.

It was really hard to find someone to buy it. Professional sellers refused saying it’s hard to sell seven strings. In the end, I found someone to buy, and it posted it.

Goodbye, old friend.

Friday, July 26, 2024

Automating MSVC builds

While rewritting a few of my personal tools from Rust back to C++, I found myself willing to automate the build process. At first, I tried to invoke MSVC’s cl compiler directly, but it has proven to be absolute hell to do.

Eventually I stumbled upon the marvellous MSBuild tool, which is capable of understanding the .sln file and take all compiler and linker options from it:

msbuild foo.sln /p:Configuration=Release /p:Platform=x64

With that, I finally had the script to automate one build:

call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
set APP="vscode-font-patch"
msbuild %APP%.sln /p:Configuration=Release /p:Platform=x64
move /Y x64_Release\%APP%.exe "D:\Stuff\apps\_audio tools\"
rmdir /S /Q x64_Release
pause

Then it was time to automate the release build of all my listed projects. And I found out how awkward .bat syntax is. Loop syntax is particularly horrifying. In the end, I was able to cook a script to automate my C++ builds:

call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"

set APPS[0]="vscode-font-patch"

set "i=0"
:SymLoop
if not defined APPS[%i%] goto :EndLoop
call set APP=%%APPS[%i%]%%
cd %APP%
echo Building %APP%...
msbuild %APP%.sln /p:Configuration=Release /p:Platform=x64
move /Y x64_Release\%APP%.exe "D:\Stuff\apps\_audio tools\"
rmdir /S /Q x64_Release
cd ..

set /a "i+=1"
goto :SymLoop
:EndLoop
pause