vankuik.nl

Latest weblog entries

2024-05-31 Microsoft Excel shortcut key

When I'm in Microsoft Excel on macOS, I often want to clean up and delete rows. The online documentation is weird, and mentions a non-working shortcut key. To delete a row with the keyboard, navigate to the row, then press Shift-Space, then Control-Minus. This works on macOS Sonoma 14.5 with Microsoft Excel 16.81.

2023-12-01 Unable to use public key authentication for ssh login on Raspberry Pi

TL;DR: Raspberry Pi OS will reject rsa keys, use another type of key, and copy it to the Pi:

  % ssh-keygen -t ecdsa
  % ssh-copy-id .ssh/id_ecdsa.pub <pi-hostname>

Explanation is as follows. Recently I installed a Raspberry Pi 4, and I flashed the SD card with the Raspberry Pi Imager. I used the default OS (which is titled "Raspberry Pi OS, a port of Debian Bookworm"). I wanted to use passwordless login to ssh, i.e. public key authentication. So I copied my existing public key to the Raspberry Pi with ssh-copy-id. However when accessing the Pi over ssh, I still had to enter my password.

This had me stumped for a while. In the end, I turned on debug logging:

  % sudo vim /etc/ssh/sshd_config

Then add the following line:

  LogLevel DEBUG3

Restart SSH daemon and follow logs:

  % sudo systemctl restart sshd
  % journalctl -f

Try and log in with your old RSA key, and you'll see the following log message:

  Dec 01 09:27:53 HL46528028 sshd[2025]: debug3: mm_answer_keyallowed: publickey authentication test: RSA key is not allowed

What you need to do, is generate a new key with a different type:

  % ssh-keygen -t ecdsa

The default is to save they keypair in the ~/.ssh directory and call it id_ecdsa and id_ecdsa.pub. Copy the public key to the Raspberry:

  % ssh-copy-id .ssh/id_ecdsa.pub <pi-hostname>

Now enjoy passwordless login:

  % ssh <pi-hostname>

Of course don't forget to remove the LogLevel line from the sshd configuration, and restart the daemon.

2023-09-18 SwiftUI Separate toolbar

In SwiftUI, it's easy to just keep coding and dump everything in one view. Toolbars especially are "bulky", they take up a lot of lines, and are not regular views so syntax-wise, they're a bit of a bother to separate away. Here's an example of a bottom toolbar, to help you split up those big views.

    struct MainView: View {
        var body: some View {
            Color.blue
                .ignoresSafeArea(edges: [.top, .leading, .trailing])
                .toolbar {
                    ActionToolbar()
                }
        }
    }
    struct ActionToolbar: ToolbarContent {
        var body: some ToolbarContent {
            ToolbarItem(placement: .bottomBar) {
                 Spacer()
             }
            ToolbarItem(placement: .bottomBar) {
                Button(action: { print("Plus") }) {
                    Image(systemName: "plus.app.fill")
                        .resizable()
                        .scaledToFit()
                }
            }
        }
    }

2023-08-30 Coordinator in preview

When you're using the Coordinator pattern in a SwiftUI project, you'll find yourself sometimes wanting to preview the initial start of a "flow" of screens. But that's quite a bit of work because inside the coordinator, some boilerplate code needs to be present, to wrap the SwiftUI view in a UIHostingController.

This bit of code is useful to plunk in the utilities folder of your project, and use in the preview section of your SwiftUI view.

    private class PreviewViewController: UIViewController {
        private let coordinator: NavigationControllerCoordinator
        init(coordinator: NavigationControllerCoordinator) {
            self.coordinator = coordinator
            super.init(nibName: nil, bundle: nil)
        }
        required init?(coder: NSCoder) {
            fatalError()
        }
        override func viewDidLoad() {
            guard let navigationController = self.navigationController as? NavigationController else {
                return
            }
            title = "Preview"
            var configuration = UIButton.Configuration.filled()
            configuration.title = "Start"
            self.view = UIButton(configuration: configuration, primaryAction: UIAction(handler: {_ in
                navigationController.present(self.coordinator.navigationController, animated: true)
                self.coordinator.start()
            }))
        }
    }
    struct PreviewCoordinator: UIViewControllerRepresentable {
        let coordinator: NavigationControllerCoordinator
        typealias UIViewControllerType = NavigationController
        func makeUIViewController(context: Context) -> NavigationController {
            let viewController = PreviewViewController(coordinator: coordinator)
            return NavigationController(rootViewController: viewController)
        }
        func updateUIViewController(_ uiViewController: NavigationController, context: Context) {}
    }

Use as follows;

    struct NetworkScanQRView_Previews: PreviewProvider {
        static var previews: some View {
            PreviewCoordinator(coordinator: NetworkScanQRCoordinator.mocked)
        }
    }

More...

Weblog Archive

[[Weblog_entries_2024?]]

Weblog entries 2023

Weblog entries 2022

Weblog entries 2021

Weblog entries 2020

Weblog entries 2019

Weblog entries 2018

Weblog entries 2017

Weblog entries 2016

Weblog entries 2015

Weblog entries 2014

Weblog entries 2013

Weblog entries 2012

Weblog entries 2011

Weblog entries 2010

Weblog entries 2009

Weblog entries 2008

Weblog entries 2007

Weblog entries 2006

Weblog entries 2005

Weblog entries 2004

All weblog entries

Articles

Articles, chronologically (latest first). This is pretty old stuff.

Scribblings

Not yet finished. Maybe will never be finished. Maybe they'll get deleted. Who knows?

Programming:

System administration:

Others:

Files: