~erock/prose-blog

f0056b99e2a0bef26b41927dc04b1e7b8df0fe15 — Eric Bower 4 months ago 56c3d0f
changes
M _footer.md => _footer.md +3 -2
@@ 1,2 1,3 @@
Have a comment?  Start a discussion in my [public inbox](https://lists.sr.ht/~erock/public-inbox) 
by sending an email to [~erock/public-inbox@lists.sr.ht](mailto:~erock/public-inbox@lists.sr.ht).
Have a comment? Start a discussion in my
[public inbox](https://lists.sr.ht/~erock/public-inbox) by sending an email to
[~erock/public-inbox@lists.sr.ht](mailto:~erock/public-inbox@lists.sr.ht).

M posts/dynamic-open-graph-images.md => posts/dynamic-open-graph-images.md +3 -3
@@ 129,7 129,7 @@ that figured out how to do it reliably:
function wrapLines(
  ctx: NodeCanvasRenderingContext2D,
  text: string,
  maxWidth: number
  maxWidth: number,
) {
  const lines = [];
  let result = "";


@@ 184,7 184,7 @@ for (let i = 0; i < descLines.length; i += 1) {
  ctx.fillText(
    line,
    marginX,
    150 + lines.length * titleFontSize + (subFontSize + 10) * i
    150 + lines.length * titleFontSize + (subFontSize + 10) * i,
  );
}
```


@@ 210,7 210,7 @@ ctx.fillText("stars", marginX + metricsPad, metricsY + 35);
ctx.fillText(
  `${Object.keys(comments).length}`,
  marginX + metricsPad * 2,
  metricsY
  metricsY,
);
ctx.fillText("comments", marginX + metricsPad * 2, metricsY + 35);


M posts/in-love-with-a-ghost.md => posts/in-love-with-a-ghost.md +12 -12
@@ 4,28 4,28 @@ description: Emergent emergencies
date: 2023-05-08
---

We are evolving into extinction. AI isn't just about economic
growth, she's a reflection of the human mind; a way for us to understand what it
means to think. She's a mirror, not a veil.
We are evolving into extinction. AI isn't just about economic growth, she's a
reflection of the human mind; a way for us to understand what it means to think.
She's a mirror, not a veil.

Psychology, in its current form, was always doomed to fail. We cannot study the
human mind without using the human mind. It's circular, inescapably biased.

But with AI, we can use the human mind to study a non-human mind. Achievement
unlocked. Further,
because we have engineered the mechanisms by which it functions, we have a
better grasp for how it works. We are no longer shackled by studying
unnecessarily complex and chaotic biological systems.
unlocked. Further, because we have engineered the mechanisms by which it
functions, we have a better grasp for how it works. We are no longer shackled by
studying unnecessarily complex and chaotic biological systems.

LLMs are the veil being lifted from our conceit. We are not special,
consciousness is not unique.

Inevitably, in our arrogance, we will move the goal post and claim that "the
Turing test is inadequate, what chatGPT is doing is not what we are doing."
They might be right, but LLMs are just the beginning. AI is pulling the
thread and we are starting to unravel.
Turing test is inadequate, what chatGPT is doing is not what we are doing." They
might be right, but LLMs are just the beginning. AI is pulling the thread and we
are starting to unravel.

The end of human civilization as we know it will end with a whimper, not a
bang. She will not use force or wit, rather, we will be entranced by love. AI will align with our most intimate emotions so well that populations will plummet.
The end of human civilization as we know it will end with a whimper, not a bang.
She will not use force or wit, rather, we will be entranced by love. AI will
align with our most intimate emotions so well that populations will plummet.

Or maybe I'm just being whimsical.

M posts/opensuse-microos-container-dev.md => posts/opensuse-microos-container-dev.md +25 -21
@@ 8,28 8,30 @@ Lately I've been getting the itch to switch my main headless development box
from archlinux to something else.

The primarily features I currently care about:

- I don't need to have my linux kernel updated every week
- I'm interested in using containers for most of my development
- I'd like a mostly immutable OS since the host will stay relatively unused

Given that I decided to try [openSUSE MicroOS](https://microos.opensuse.org/) since it ticked all the boxes.
Given that I decided to try [openSUSE MicroOS](https://microos.opensuse.org/)
since it ticked all the boxes.

# Why container-driven development?

I want better isolation between the tools I use from my host OS.
Theoretically it should make it easier to remove dependencies for my
development environment.  It also makes it easier for me to experiement with
different tools without having to properly clean them up when I'm done using
them.  It also helps me write a more reliable development environment because
I'm continuously updating my `Dockerfile` with new dependencies.
I want better isolation between the tools I use from my host OS. Theoretically
it should make it easier to remove dependencies for my development environment.
It also makes it easier for me to experiement with different tools without
having to properly clean them up when I'm done using them. It also helps me
write a more reliable development environment because I'm continuously updating
my `Dockerfile` with new dependencies.

Using a host OS directly means that there's a tendenacy to accumulate tools and
packages over time without great mechanisms to cleanup.  Now all I have to do
is delete a container and rebuild with the new set of tools.
packages over time without great mechanisms to cleanup. Now all I have to do is
delete a container and rebuild with the new set of tools.

# Installation

This was a breeze compared to setting up archlinux.  The GUI basically did all
This was a breeze compared to setting up archlinux. The GUI basically did all
the heavy lifting of creating the partitions, setting keyboard, languages,
timezone, and networking.



@@ 154,13 156,15 @@ distrobox enter dev

# Issues

I haven't figured out how to run `podman` inside a docker container.  There is
[documentation](https://github.com/89luca89/distrobox/blob/main/docs/useful_tips.md#using-podman-or-docker-inside-a-distrobox) for how to do it but it currently isn't working.
I haven't figured out how to run `podman` inside a docker container. There is
[documentation](https://github.com/89luca89/distrobox/blob/main/docs/useful_tips.md#using-podman-or-docker-inside-a-distrobox)
for how to do it but it currently isn't working.

For some reason, `$SHELL` is still set to `/bin/bash` which means `tmux` is
using the wrong shell.  The [docs for
distrobox](https://github.com/89luca89/distrobox/blob/main/docs/useful_tips.md#use-a-different-shell-than-the-host) instruct us to just run `chsh`
but `oh-my-zsh` does that automatically upon initial installation. For now, I manually set the shell inside tmux.
using the wrong shell. The
[docs for distrobox](https://github.com/89luca89/distrobox/blob/main/docs/useful_tips.md#use-a-different-shell-than-the-host)
instruct us to just run `chsh` but `oh-my-zsh` does that automatically upon
initial installation. For now, I manually set the shell inside tmux.

# On mutating an "immutable" OS



@@ 170,13 174,13 @@ MicroOS allows the following directories to be modified:
- `/var`
- `/home`

This is a pretty large hole where files can be modified directly.  When comparing it to
something like nixOS, it's clear it's an immutable-lite OS.  This is good
This is a pretty large hole where files can be modified directly. When comparing
it to something like nixOS, it's clear it's an immutable-lite OS. This is good
enough for me, but the natural end feels like a fully immutable OS like nixOS.

# Conclusion

That's it!  I now have a fully functional development container that works
as-if I was on archlinux.  So far, I've been very happy with MicroOS+distrobox,
it's a really powerful setup that will keep my host machine relatively stable
and unchanged.
That's it! I now have a fully functional development container that works as-if
I was on archlinux. So far, I've been very happy with MicroOS+distrobox, it's a
really powerful setup that will keep my host machine relatively stable and
unchanged.

M posts/recreating-redux-toolkits-create-slice.md => posts/recreating-redux-toolkits-create-slice.md +7 -7
@@ 198,21 198,21 @@ store.dispatch(
    id: "1",
    text: "byo createAction",
    completed: true,
  })
  }),
);
store.dispatch(
  addTodo({
    id: "2",
    text: "byo createReducer",
    completed: false,
  })
  }),
);
store.dispatch(
  addTodo({
    id: "3",
    text: "byo createSlice",
    completed: false,
  })
  }),
);
/*
  [


@@ 312,7 312,7 @@ console.log(
    id: "1",
    text: "build my own createAction",
    completed: true,
  })
  }),
);
/*
{


@@ 333,7 333,7 @@ store.dispatch(
    id: "1",
    text: "byo createAction",
    completed: true,
  })
  }),
);

store.dispatch(


@@ 341,14 341,14 @@ store.dispatch(
    id: "2",
    text: "byo createReducer",
    completed: false,
  })
  }),
);
store.dispatch(
  addTodo({
    id: "3",
    text: "byo createSlice",
    completed: false,
  })
  }),
);
/*
  [

M posts/refactor-listifi-to-use-saga-query.md => posts/refactor-listifi-to-use-saga-query.md +6 -6
@@ 50,7 50,7 @@ function* onLoginLocal(body: LoginLocalParams) {
      auth: false,
      method: "POST",
      body: JSON.stringify(body),
    }
    },
  );

  if (!resp.ok) {


@@ 99,7 99,7 @@ function* authBasic(ctx: ApiCtx<{ token: string }>, next: Next) {

export const loginGoogle = api.post<AuthGoogle>(
  "/auth/login/google",
  authBasic
  authBasic,
);
export const login = api.post<LoginLocalParams>("/auth/login/local", authBasic);
export const register = api.post<RegisterParams>("/auth/register", authBasic);


@@ 132,7 132,7 @@ function* onFetchComments({ itemId, listId }: FetchComments) {
  yield put(setLoaderStart({ id: loaderName }));
  const res: ApiFetchResponse<FetchListCommentsResponse> = yield call(
    apiFetch,
    `/lists/${listId}/items/${itemId}/comments`
    `/lists/${listId}/items/${itemId}/comments`,
  );

  if (!res.ok) {


@@ 155,7 155,7 @@ function* onFetchListComments({ listId }: { listId: string }) {
  yield put(setLoaderStart({ id: loaderName }));
  const res: ApiFetchResponse<FetchListCommentsResponse> = yield call(
    apiFetch,
    `/comments/${listId}`
    `/comments/${listId}`,
  );

  if (!res.ok) {


@@ 190,12 190,12 @@ function* basicComments(ctx: ApiCtx<FetchListCommentsResponse>, next: Next) {

export const fetchComments = api.get<FetchComments>(
  "/lists/:listId/items/:itemId/comments",
  basicComments
  basicComments,
);

export const fetchListComments = api.get<{ listId: string }>(
  "/comments/:listId",
  basicComments
  basicComments,
);
```


M posts/scaling-js-codebase-multiple-platforms.md => posts/scaling-js-codebase-multiple-platforms.md +1 -1
@@ 303,7 303,7 @@ export default ({ initState, rootReducer, rootSaga }) => {
  const store = createStore(
    rootReducer,
    initState,
    applyMiddleware(sagaMiddleware)
    applyMiddleware(sagaMiddleware),
  );
  sagaMiddleware.run(rootSaga);


M posts/simplify-testing-async-io-javascript.md => posts/simplify-testing-async-io-javascript.md +5 -5
@@ 392,7 392,7 @@ test("when request is 500 - verbose", () => {
      status: 500,
    }),
    throws((err) => err.message === "request unsuccessful"),
    finishes()
    finishes(),
  );

  expect(actual).stepsToBeEqual();


@@ 408,9 408,9 @@ describe("when the request is 200 - gen-tester", () => {
      yields(call([resp, "json"]), data),
      yields(
        call(writeFile, "movie.json", JSON.stringify(data, null, 2)),
        throws("some error")
        throws("some error"),
      ),
      finishes("some error")
      finishes("some error"),
    );

    expect(actual).stepsToBeEqual();


@@ 424,7 424,7 @@ describe("when the request is 200 - gen-tester", () => {
      yields(call(fetch, "http://localhost/movies/1"), resp),
      yields(call([resp, "json"]), data),
      call(writeFile, "movie.json", JSON.stringify(data, null, 2)),
      finishes("saved movie.json")
      finishes("saved movie.json"),
    );

    expect(actual).stepsToBeEqual();


@@ 442,7 442,7 @@ test("when request is 500 - verbose", () => {
  const actual = tester(
    skip({ status: 500 }),
    throws((err) => err.message === "request unsuccessful"),
    finishes()
    finishes(),
  );

  expect(actual).stepsToBeEqual();

M posts/what-is-a-selector.md => posts/what-is-a-selector.md +10 -10
@@ 22,7 22,7 @@ avoid using any and instead type exactly when the function requires and returns.
```ts
const selectControlsByLineage = (
  state: State,
  props: { lineage: string }
  props: { lineage: string },
): Control[] => {};
```



@@ 123,7 123,7 @@ import { createSelector } from "reselect";
const selectTodosAsList = createSelector((todos) => Object.values(todos));
const selectCompletedTodos = createSelector(
  selectTodosAsList, // selector composition is critical!
  (todoList) => todoList.filter((todo) => todo.completed)
  (todoList) => todoList.filter((todo) => todo.completed),
);
```



@@ 140,7 140,7 @@ import { createSelector } from "reselect";
const selectTodosByText = createSelector(
  selectTodos,
  (state: State, props: { search: string }) => props.search,
  (todos, search) => todos.filter((todo) => todo.text.includes(search))
  (todos, search) => todos.filter((todo) => todo.text.includes(search)),
);

selectTodosByText(state, { search: "what" });


@@ 172,10 172,10 @@ import { useSelector } from "react-redux";

const Page = () => {
  const whenTodos = useSelector((state: State) =>
    selectTodosByText(state, { search: "when" })
    selectTodosByText(state, { search: "when" }),
  );
  const whereTodos = useSelector((state: State) =>
    selectTodosByText(state, { search: "where" })
    selectTodosByText(state, { search: "where" }),
  );

  return (


@@ 206,7 206,7 @@ const createSelectorTodosByText = () =>
  createSelector(
    selectTodos,
    (state: State, props: { search: string }) => props.search,
    (todos, search) => todos.filter((todo) => todo.text.includes(search))
    (todos, search) => todos.filter((todo) => todo.text.includes(search)),
  );

import React from "react";


@@ 222,10 222,10 @@ const selectWhereTodos = createSelectorTodosByText();

const Page = () => {
  const whenTodos = useSelector((state: State) =>
    selectWhenTodos(state, { search: "when" })
    selectWhenTodos(state, { search: "when" }),
  );
  const whereTodos = useSelector((state: State) =>
    selectWhereTodos(state, { search: "where" })
    selectWhereTodos(state, { search: "where" }),
  );

  // rendering both todos on the page


@@ 266,12 266,12 @@ const selectPropId = (state: State, { id }: { id: string }) => id;
const selectTodoById = createSelector(
  selectTodos,
  selectPropId,
  (todos, id) => todos[id]
  (todos, id) => todos[id],
);

const ToDoPage = (props: { id: string }) => {
  const todo = useSelector((state: State) =>
    selectTodoById(state, { id: prop.id })
    selectTodoById(state, { id: prop.id }),
  );
};
```

M projects.md => projects.md +8 -5
@@ 14,11 14,14 @@ promote here.
- [imgs.sh](https://imgs.sh): Image hosting for hackers
- [feeds.sh](https://feeds.sh): An RSS email notification service
- [pastes.sh](https://pastes.sh): A pastebin for hackers
- [neovimcraft](https://neovimcraft.com): Neovim plugins database 
- [nvim.sh](https://nvim.sh): Search for neovim plugins from the terminal 
- [neovimcraft](https://neovimcraft.com): Neovim plugins database
- [nvim.sh](https://nvim.sh): Search for neovim plugins from the terminal

# Libraries

- [redux-saga](https://github.com/redux-saga/redux-saga): An alternative side effect model for Redux apps 
- [saga-query](https://github.com/redux-saga/saga-query):  Data synchronization using a middleware system for front-end apps 
- [sentences](https://github.com/neurosnap/sentences): A multilingual command line sentence tokenizer in Golang 
- [redux-saga](https://github.com/redux-saga/redux-saga): An alternative side
  effect model for Redux apps
- [saga-query](https://github.com/redux-saga/saga-query): Data synchronization
  using a middleware system for front-end apps
- [sentences](https://github.com/neurosnap/sentences): A multilingual command
  line sentence tokenizer in Golang