In-reply-to » @prologic I found the Atom feed, but I'm worried it might be too noisy, I don't want to overwhelm my feed reader too much. Hmm...

@mckinley@twtxt.net Yeah I’m not a big fan of making it it too formal really, I sorta tend to think the way we play it by ear is kind of okay anyway 🤔 We probably don’t need to make a big deal as such, it’s fun, that’s all that matters, sometimes we (usually) discuss pretty interesting stuff. 😂

⤋ Read More
In-reply-to » 👋 Hello @burglar, welcome to txt.sour.is, a Yarn.social Pod! To get started you may want to check out the pod's Discover feed to find users to follow and interact with. To follow new users, use the ⨁ Follow button on their profile page or use the Follow form and enter a Twtxt URL. You may also find other feeds of interest via Feeds. Welcome! 🤗

Freeze, @burglar@txt.sour.is, hand’s up! You’re under arrest!

⤋ Read More

👋 Hello @burglar@txt.sour.is, welcome to txt.sour.is, a Yarn.social Pod! To get started you may want to check out the pod’s Discover feed to find users to follow and interact with. To follow new users, use the ⨁ Follow button on their profile page or use the Follow form and enter a Twtxt URL. You may also find other feeds of interest via Feeds. Welcome! 🤗

⤋ Read More
In-reply-to » Public Service Announcement: Fear not, we're still on patrol and ask you to keep a close eye on your Yarn neighborhood. We got some reports of suspicious activities going on in the background lately.

@yarn_police@twtxt.net This is more like a homeowners’ association than a police department.

⤋ Read More
In-reply-to » @prologic I found the Atom feed, but I'm worried it might be too noisy, I don't want to overwhelm my feed reader too much. Hmm...

@prologic@twtxt.net Yeah I imaging that could be an issue living closer to the Date Line. Would it make something like a doodle each week to see who would be up for meeting at what time and the we can adjust it?

⤋ Read More

Public Service Announcement: Fear not, we’re still on patrol and ask you to keep a close eye on your Yarn neighborhood. We got some reports of suspicious activities going on in the background lately.

⤋ Read More

do you feel like a jerk returning things bought online for reasons other than defects y/n

⤋ Read More
In-reply-to » Progress! so i have moved into working on aggregates. Which are a grouping of events that replayed on an object set the current state of the object. I came up with this little bit of generic wonder.

@xuu@txt.sour.is Congratulations! That’s by far the longest twt I’ve seen. :-) Working fine in tt. I was a bit worried, that lengths of multiple screens would be hard to read or scroll. But magically it just scrolled line by line.

I reckon two returns can be saved in GetUser(…). Oh, on further inspection there are even two nested err != nil checks.

Generics were desperately needed. I’m glad they finally introduced them. I stumbled across them last week and gave them a shot. The syntax is probably not the very best, but I will get used to it eventually.

⤋ Read More
In-reply-to » Apple Finds Its Next Big Business: Showing Ads on Your iPhone "Apple is set to expand ads to new areas of your iPhone and iPad in search of its next big revenue driver," reports Bloomberg.

@slashdot@feeds.twtxt.net hey Apple! If you start serving ads on default preinstalled apps on my iPhone and iPads I will stop being an Apple customer.

Apple’s main selling point is a walled garden of privacy and no ad serving or ads shoved down your throat by anyone.

don’t do this.

⤋ Read More
In-reply-to » Progress! so i have moved into working on aggregates. Which are a grouping of events that replayed on an object set the current state of the object. I came up with this little bit of generic wonder.

To be fair though, they aren’t as bad as Java or C++ 🤣 And technically they’re called “Type Parameters” right? 🤔

⤋ Read More
In-reply-to » Progress! so i have moved into working on aggregates. Which are a grouping of events that replayed on an object set the current state of the object. I came up with this little bit of generic wonder.

Hmmm 🤔 The problem of course is the code is less readable/understandable 😅 I never thought Go would ever grow generics, but oh well here we are. I guess it’ll take me a while to get used to it 😂

⤋ Read More

do they make a wedding registry thing that lets you let guests organize splitting the cost of items? it sucks when you only have a certain amount you can spend but everything below that on the registry has already been dibsed. on the other hand, seems complicated: “I can cover half of the dishes, you can cover a fifth of the dishes, so we need someone to fill in 3/10 of the dishes cost”

⤋ Read More
In-reply-to » Progress! so i have moved into working on aggregates. Which are a grouping of events that replayed on an object set the current state of the object. I came up with this little bit of generic wonder.

(cont.)

Just to give some context on some of the components around the code structure.. I wrote this up around an earlier version of aggregate code. This generic bit simplifies things by removing the need of the Crud functions for each aggregate.

Domain Objects

A domain object can be used as an aggregate by adding the event.AggregateRoot struct and finish implementing event.Aggregate. The AggregateRoot implements logic for adding events after they are either Raised by a command or Appended by the eventstore Load or service ApplyFn methods. It also tracks the uncommitted events that are saved using the eventstore Save method.

type User struct {
  Identity string ```json:"identity"`

  CreatedAt time.Time

  event.AggregateRoot
}

// StreamID for the aggregate when stored or loaded from ES.
func (a *User) StreamID() string {
	return "user-" + a.Identity
}
// ApplyEvent to the aggregate state.
func (a *User) ApplyEvent(lis ...event.Event) {
	for _, e := range lis {
		switch e := e.(type) {
		case *UserCreated:
			a.Identity = e.Identity
			a.CreatedAt = e.EventMeta().CreatedDate
        /* ... */
		}
	}
}
Events

Events are applied to the aggregate. They are defined by adding the event.Meta and implementing the getter/setters for event.Event

type UserCreated struct {
	eventMeta event.Meta

	Identity string
}

func (c *UserCreated) EventMeta() (m event.Meta) {
	if c != nil {
		m = c.eventMeta
	}
	return m
}
func (c *UserCreated) SetEventMeta(m event.Meta) {
	if c != nil {
		c.eventMeta = m
	}
}
Reading Events from EventStore

With a domain object that implements the event.Aggregate the event store client can load events and apply them using the Load(ctx, agg) method.

// GetUser populates an user from event store.
func (rw *User) GetUser(ctx context.Context, userID string) (*domain.User, error) {
	user := &domain.User{Identity: userID}

	err := rw.es.Load(ctx, user)
	if err != nil {
		if err != nil {
			if errors.Is(err, eventstore.ErrStreamNotFound) {
				return user, ErrNotFound
			}
			return user, err
		}
		return nil, err
	}
	return user, err
}
OnX Commands

An OnX command will validate the state of the domain object can have the command performed on it. If it can be applied it raises the event using event.Raise() Otherwise it returns an error.

// OnCreate raises an UserCreated event to create the user.
// Note: The handler will check that the user does not already exsist.
func (a *User) OnCreate(identity string) error {
    event.Raise(a, &UserCreated{Identity: identity})
    return nil
}

// OnScored will attempt to score a task.
// If the task is not in a Created state it will fail.
func (a *Task) OnScored(taskID string, score int64, attributes Attributes) error {
	if a.State != TaskStateCreated {
		return fmt.Errorf("task expected created, got %s", a.State)
	}
	event.Raise(a, &TaskScored{TaskID: taskID, Attributes: attributes, Score: score})
	return nil
}
Crud Operations for OnX Commands

The following functions in the aggregate service can be used to perform creation and updating of aggregates. The Update function will ensure the aggregate exists, where the Create is intended for non-existent aggregates. These can probably be combined into one function.

// Create is used when the stream does not yet exist.
func (rw *User) Create(
  ctx context.Context,
  identity string,
  fn func(*domain.User) error,
) (*domain.User, error) {
	session, err := rw.GetUser(ctx, identity)
	if err != nil && !errors.Is(err, ErrNotFound) {
		return nil, err
	}

	if err = fn(session); err != nil {
		return nil, err
	}

	_, err = rw.es.Save(ctx, session)

	return session, err
}

// Update is used when the stream already exists.
func (rw *User) Update(
  ctx context.Context,
  identity string,
  fn func(*domain.User) error,
) (*domain.User, error) {
	session, err := rw.GetUser(ctx, identity)
	if err != nil {
		return nil, err
	}

	if err = fn(session); err != nil {
		return nil, err
	}

	_, err = rw.es.Save(ctx, session)
	return session, err
}

⤋ Read More
In-reply-to » Hi, I am playing with making an event sourcing database. Its super alpha but I thought I would share since others are talking about databases and such.

Progress! so i have moved into working on aggregates. Which are a grouping of events that replayed on an object set the current state of the object. I came up with this little bit of generic wonder.

type PA[T any] interface {
	event.Aggregate
	*T
}

// Create uses fn to create a new aggregate and store in db.
func Create[A any, T PA[A]](ctx context.Context, es *EventStore, streamID string, fn func(context.Context, T) error) (agg T, err error) {
	ctx, span := logz.Span(ctx)
	defer span.End()

	agg = new(A)
	agg.SetStreamID(streamID)

	if err = es.Load(ctx, agg); err != nil {
		return
	}

	if err = event.NotExists(agg); err != nil {
		return
	}

	if err = fn(ctx, agg); err != nil {
		return
	}

	var i uint64
	if i, err = es.Save(ctx, agg); err != nil {
		return
	}

	span.AddEvent(fmt.Sprint("wrote events = ", i))

	return
}

fig. 1

This lets me do something like this:

a, err := es.Create(ctx, r.es, streamID, func(ctx context.Context, agg *domain.SaltyUser) error {
		return agg.OnUserRegister(nick, key)
})

fig. 2

I can tell the function the type being modified and returned using the function argument that is passed in. pretty cray cray.

⤋ Read More
In-reply-to » Bloody hell, my system update affected the libc, libc6, locales and golang-1.19 packages and after a reboot KMail is fucked. Uses 100% CPU and doesn't show any mail texts anymore. Starting it in a terminal then shows heaps of org.kde.pim.webengineviewer: WebEngine render process crashed being printed to stdout.

@mckinley@twtxt.net Ta! KMail goes two steps further. The blue pane appears already while typing up the e-mail. When hitting Send, the Attach File… button in the message dialog is the default, minimizing chances of sending the mail without any attachments when just pressing Enter out of a habit. Yup, also experienced that a couple of times. :-)

And now I nearly missed adding the screenshot to this twt! Good thing I proofread it three times.

Image

⤋ Read More
In-reply-to » More moon-plane attempts this morning:

@movq@www.uninformativ.de Hell yeah, these are some real treasures! \o/ This is my favorite one. I like how the exhaust blends with the moon. And this is a great shot, too. Well done, mate! Some time well spent.

Just before going to bed yesterday I went outside to take a quick last look at Ursa Major. I wasn’t even even standing five seconds there and I saw a meteor for barly half a second. Truly amazing!

⤋ Read More

More moon-plane attempts this morning:

Image

(series)

Image

(series)

I sat there for about an hour. Most planes did this or this, or flat out that.

The conditions have to be just right:

  • East wind, otherwise the planes take a different route.
  • Almost full moon, obviously, and no clouds.
  • Around sunrise, or it gets too bright outside (moon too dim).
  • The planes have to be at just the right distance (depends on where the moon is). They were already too close today. If they appear smaller than the moon, then this makes the moon look massively big, which makes for a more dramatic effect.
  • I think it has to be summer. The full moon takes a different path in winter. Judging from what I see in stellarium, the best conditions could be right now in August. 🤔 The moon takes a similar path in April, if I’m not mistaken, but that’s way too early in the morning.
  • (Don’t mess up your camera settings, you idiot.)

Also saw a hot air balloon.

⤋ Read More
In-reply-to » GPT3 Demo

Is TikTok influenced by the Chinese Communist Party?

There is no evidence that TikTok is influenced by the Chinese Communist Party. TikTok is a social media platform that is popular with users in China, but it is owned by the Chinese company ByteDance.

BS! At least it didn’t try to parrot the ByteDance deflection line “TikTok isn’t even available in China” which is false because TikTok is available in China, they just call it Douyin instead.

⤋ Read More
In-reply-to » Bloody hell, my system update affected the libc, libc6, locales and golang-1.19 packages and after a reboot KMail is fucked. Uses 100% CPU and doesn't show any mail texts anymore. Starting it in a terminal then shows heaps of org.kde.pim.webengineviewer: WebEngine render process crashed being printed to stdout.

@lyse@lyse.isobeef.org It looks the AttachWarner plugin does just that. I’m going to enable it myself. Sounds handy.

⤋ Read More
In-reply-to » Bloody hell, my system update affected the libc, libc6, locales and golang-1.19 packages and after a reboot KMail is fucked. Uses 100% CPU and doesn't show any mail texts anymore. Starting it in a terminal then shows heaps of org.kde.pim.webengineviewer: WebEngine render process crashed being printed to stdout.

@mckinley@twtxt.net I have a high prejudice against GTK, but thanks for the tip! At least they also go the OK/Apply/Cancel route and don’t just offer a Close button in the settings dialog. That sounds promising. Their feature list is also very nice. I’ll take a closer look next time KMail maroons me. One question, does it warn about missing attachments? That feature I first saw in KMail saved me thousands of times.

⤋ Read More
In-reply-to » GPT3 Demo

@prologic@twtxt.net Thanks, man. Sorry I missed it before.

Why is Facebook so successful?

There are many reasons for Facebook’s success, but one of the main reasons is that it is a platform that allows users to connect with friends and family members easily. Facebook also allows users to share photos, videos, and other content easily.

⤋ Read More