User → can3p

Thu, 02 May 2024 17:05 → Ramen by can3p


Этот был неплох!

Sat, 27 Jan 2024 11:38 → Ramen by can3p



Bought in Asian market on Ams Noord

Thu, 17 Aug 2023 00:52 → Serenity by can3p

And this is why it's probably very different now since everything runs in it's own process etc. I've made a brief attempt to go through this part, here are the findings.

Thu, 17 Aug 2023 00:28 → Serenity by can3p

One more interesting bit from the video, here is more or less the snippet:

Core::EventLoop event_loop;

auto qt_event_loop_driver = Core::Timer::create_repeating(50, [&] {


return event_loop->exec()

There are multiple questions one may ask:

The answer to the second question is simple - there should be a global object somewhere and it's indeed there in form of EventLoopManager class that's implemented as a singleton per system.

So the whole sequence goes as the following:

Timer -> EventReceiver -> EventLoopManager

when an event loop is run it actually calls exec on EventLoopManager so even though it looks like you can have many event loops you actually cannot.

And EventLoopManager does the actual things described in the docs

Getting back to the first question: it was done most probably because the initial implementation had only one process and that was the easiest way to make resource loading work - make qt take a back seat and invoke it only to draw the window every now and then

Thu, 17 Aug 2023 00:12 → Serenity by can3p

Some hints in the first video on ladybird browser -

What web engine does is it generates a bitmap given the html it loaded and parsed given the view port dimensions and that's all to it. The rendering engine uses a layout tree that was built during the parsing phase to actually render content in the image.

Now, the rendered content has to be put in the window somehow and that has to be hooked up with QT. That works with Webview class inheriting from QAbstractScrollArea and that one in turn allows to right the behavior for all kinds of nice events including paintEvent which is used to take the bitmap from the engine and render it on the window. How qt does that? No idea, most probably it has it's own render tree for all the widgets and this is where paintEvent stems from. Inside of it Andreas uses QPainter class and that one probably knows how to actually put stuff into graphics memory

Wed, 16 Aug 2023 23:05 → Serenity by can3p

I'm watching Andreas' hacking session and I'm apparently lacking something essential:

Mon, 19 Jun 2023 04:51 → Product updates by can3p

Since last week it's possible to edit streams metadata!


This feature should allow to fix stream information easily or add new metadata fields easily

Mon, 19 Jun 2023 04:49 → Dev Notes by can3p

Last week I've released gogo. It only has the form handling component and does not show how to set up the app completely, but the form handling alone should showcase the efficiency of the approach. Server-side validation is not without it's downsides, however for the prototyping phase nothing could beat speed and consistency and both are provided.

Not all of the dabdab forms are handled this way, however the reason is purely historical, all new features are developed this way

Sat, 10 Jun 2023 14:00 → Dev Notes by can3p

Unexpected footgun with go templates: it's possible to define two blocks with the same name (which is fine), however one would silently override the other one even if they're both located in template that do not depend on each other in any way.

Dabdab has lost an ability to add notes and todo items to the messages because of that, but now everything is back

Tue, 02 May 2023 00:02 → Dev Notes by can3p

API implementation for dabdab was quite simple. I wasn't ready to implement a full-featured api with all the niceties, because there many security and convenience related questions, however a per stream api access was a rather trivial exercise.

Some of the reasons apis are hard to work with are

I've solved the first point by not requiring api keys in the first place - a share link with api access works like a slack hook that allows to post messages with a simple post and it was ok since the url was unique.

Second point is solved by generating a real curl call that can be used to post a message. And not only that, all the values in the payload are also generated to be random.

The remaining point was about testing. The usecase for such an api is some sort of automation that gathers data from time to time and user wants to store the data somewhere and render some nice graphs. I didn't want to run a cron and used sister service to trigger a webhook every now and that and the webhook post weather updates

Mon, 01 May 2023 02:00 → Product updates by can3p

Dabdab streams provide a natural place to store observations with optional metadata that can be used to render graphs or serve other purposes. This sounds like a great fit for any projects where you would like to record the data automatically, however right till this moment there was no api to use to integration.

From today dabdab has api! It's not global and works per stream on top of share concept and what's better it's zero configuration - no need to mess with api keys, you can copy an example from the share page and start pushing data right away!


Thu, 23 Feb 2023 01:17 → Dev Notes by can3p

More serious progress on dabdab:

I want more, to be precise, I want

I've found another reason for a slowdown on the home page - stimulus actually launches the component to render the timeline even though the element is hidden. It kind of makes sense, but I just don't see a clean way to avoid it

Wed, 22 Feb 2023 00:19 → Dev Notes by can3p

One more evening spent on optimizing the performance of

This time I've extracted all js related to visualisation into a separate js bundle + added a prefetch link tag to make sure this file is cached by browser. The size is still pathetic though, however this allowed me to return echarts since go package produces a really bad quality results.

As a next step I'm thinking about ditching uikit js components and rewrite few that matter to avoid bringing in 200 kb of useless code to the user

Tue, 21 Feb 2023 02:01 → Dev Notes by can3p

I was not totally happy with the frontend performance of dabdab and decided to spend an evening looking into it. Some of the changes:

The timeline package that I use is a real waste as well, it takes a whole bunch of dependencies with it that are worth of hunderds of kilobytes. The other offender is uikit framework, since many of the components that should be purely css like a grid for example, require js for no apparent reason.

From js side one potential fix is to use bundle chunking and load all the js only on the pages that need them. For example, symfony supports it, rails supports it too

Sun, 19 Feb 2023 01:34 → Dev Notes by can3p

With the change password form on settings I decided to formalize the pattern I use for the forms everywhere on the site. No surprise, the concept is the same as with django forms, less abstraction though - I'm not doing field types, automatic form generation and such. Every abstractions adds complexity, and at the moment it's not obvious whether it's worth it

Sat, 18 Feb 2023 16:50 → Dev Notes by can3p

The latest share stream feature required quite a few changes on the app to enable all the flexibility. Under the hood the same template is used to display a stream (or a message) no matter how it's being accessed. That's quite a lot of conditionals, but usually the problem is not with having conditional blocks but around having cryptic conditions that power them. I've seen it some many times - you open a template and see something like {{ if and .OneCondition (and .User .SecondCondition) (not .AnotherRandomCondition }}. The only feeling you get is the one of desperation since there is no reasonable way to change this condition without breaking things, especially if the template is used in several places.

The approach I took was to switch from ad hoc conditions to a capabilities based approach. For a given stream there is a set of flags which defines what a user can do with a stream - can they read? Can they add changes? Is it their own stream? With this approach the complexity in the templates goes back to a bearable level.

Another point to address is to synchronize the conditions in the template with the ones in the backend code. What I did in my case was I extracted all the code that calculates user capabilities into a single function that does all the calculations and use it both to control the behavior in the templates and the behavior on the backend. With that move the code became even simpler

Fri, 17 Feb 2023 01:51 → Product updates by can3p

Dabdab has received a major update on the stream sharing functionality. Not only you can create multiple share links, you can also control the functionality of the link:


Possible link types are:

The names are pretty self-explanatory, compared to the previous state it's now possible to give write access if you like! You may wonder why anyone would need a write-only link? One of the use cases is when you want to collect information from other people while keeping the collected information private. Dabdab has a contact form now which is pretty much just a shared stream with a write only access.

At the moment you will not get email updates on any messages posted this way, but another share type might be helpful. If you choose RSS a special private rss link will be created that you can use with your RSS reader or any other workflow to keep track of updates.

To make sure the functionality is not abused too much, there is a requirement for anonymous users to complete the captcha.

As part of the support form implementation the following changes have also been made:

Stay tuned for the updates about API!

Sun, 12 Feb 2023 00:45 → Dev Notes by can3p supports markdown with the help of goldmark. It's really hard to overestimate the usefulness of a decent parser. Since introducing image uploads I was really worried about hardcoding uploaded links into the message text. I assume message text almost immutable - it's weakly structured and any text updates will be quite painful.

What that means in practice - message text should contain as little representation details as possible and image urls is just one of such details. From now own any media upload will result in a simple <uuid>.png url, which will be properly resolved at the rendering time. The parser was really useful there since it's trivial to walk the parsed tree and update links if necessary

Wed, 08 Feb 2023 23:29 → Product updates by can3p

Here is another demo of the service!

Most of the features I've showcased are from the earlier update:

Image upload support has not been announced previously but it's there and you can add images in any way you like - copy/paste, drag'n'drop or click on the photo icon in the tool bar. In any way the picture will be uploaded to the service and added as a link to the message content.


Mon, 30 Jan 2023 00:43 → Dev Notes by can3p

As it turns out, a textarea element treats dropped files as strings instead of files and correct way to fix the situation is to simply use it's parent element

Thu, 26 Jan 2023 02:29 → Product updates by can3p

Today is a day of bigger updates!

Last but not least, dabdab supports stream shares from now on! If you have a private stream that you want to share with your friends you can share it. I've decided to experiment with share mechanics and now on dabdab you can create multiple share links for the same stream. In future users would be able to assign different capabilities to them and also revoke them individually. Imagine you have a wish list that you want to share with your friends once in a while but want to be able to close it down for parts of the group from time to time

Thu, 26 Jan 2023 00:17 → Dev Notes by can3p

What makes SPAs compelling is their tolerance to the latency. It's always possible to add a spinner, cache the state and cover backend deficiencies this way. It sounds just right, but at the same time what you really want to provide is a really slick experience to the user. When stated this way, any big latency should instead be exposed to force developers to act on it.

However, when the latency is always under control, it's very possible to use old school methods with page refresh which is less complex and allows to use the full power of libraries and resources on the backend

Mon, 23 Jan 2023 00:48 → Product updates by can3p

A minor update: new message input now has a set of buttons to help out with formatting! Nothing fancy like preview, however buttons should make it even easier to do messages on the go from mobile

Thu, 19 Jan 2023 01:37 → Dev Notes by can3p

Officially wasted an evening chasing a red herring of a simple markdown editor. There are very few projects out there and all of the drag a full blown markdown parser, code mirror, ton of styles and optionally the whole web font in order to draw an enhance textarea, which sounds totally not compatible with the idea of keeping dabdab as fast and as light as possible.

The ideal component for dabdab would be very similar to what github minus preview tab, since the whole idea of a toolbar would be to have the buttons that would remove the necessity to switch the keyboard on the phone in order to find symbols to render a quote or a bold font.

The other awesome feature github has is their image upload functionality, I want that as well

Wed, 11 Jan 2023 23:59 → Dev Notes by can3p

The concept of middlewares in gin is really powerful. Of course it's nothing exceptional, most of frameworks have it, but still. For example, custom error reporting is trivially implemented this way.

it's something like

r.Use(gin.CustomRecovery(func(c *gin.Context, err any) {
	userData := auth.GetUserData(c)

	admin.NotifyPageFailure(c, err, user)

The only limitation is that a beautiful error message that gin prints is compiles by private methods and is not passed to the callback. If you want the same data you'll probably do some copy/paste

Wed, 11 Jan 2023 02:04 → Product updates by can3p

One more small step forward, the registration is now open! The pricing information will come with more users on the platform

Tue, 10 Jan 2023 01:43 → Product updates by can3p

Small update: clicking on a lock item next to the stream name will toggle stream visibility with an obligatory confirm prompt

Thu, 29 Dec 2022 09:45 → Dev Notes by can3p

One of the interesting problems of every public service is that the amount of possible states a given user can land in grows exponentially over time. In many cases the easiest way to reproduce the situation is log in as this user. However it goes against privacy considerations of course. On dabdab private notes should be treated as private by developers as well.

An approach one could take is to allow to impersonate a user and fake all the content of the user while keeping the structure. If a user has a stream with three records, one of which has a youtube embed and the other has a list in it, generating some stream with the fake content which would have one message with embed and another one with a list should be enough for troubleshooting while keeping user data private.

Mon, 19 Dec 2022 16:14 → Dev Notes by can3p

Usage report so far: works really well with reading and travel notes, same efficiency as writing on the margins, however no need to digitize them afterwards and there is no difference between paper and electronic books

What’s really missing is some sort of offline support to make sure one could take notes on a plane for example

Thu, 15 Dec 2022 01:37 → Product updates by can3p

Hi! I've recorded the first demo of the service in order to show case basic features there, please check it out!

Features, mentioned in the video:

Load More (c) 2022 — 2023, / Contact us / Twitter