Children aren’t worried about the future. Young people aren’t worried about the future; they’re worried about us: us leading them into the future we envision
Jack Ma — Oct 2017, keynote speech at Alibaba Cloud’s Computing Conference in Hangzhou
Category: condescending
Zij bestaan voor ons. Wij bestaan niet voor hen.
Because …
A QEventLoop is a heavy dependency. Not every worker thread wants to require all its consumers to have one. This renders QueuedConnection not always suitable. I get that signals and slots are a useful mechanism, also for thread-communications. But what if your worker thread has no QEventLoop yet wants to wait for a result of what another worker-thread produces?
QWaitCondition is often what you want. Don’t be afraid to use it. Also, don’t be afraid to use QFuture and QFutureWatcher.
Just be aware that the guys at Qt have not yet decided what the final API for the asynchronous world should be. The KIO guys discussed making a QJob and/or a QAbstractJob. Because QFuture is result (of T) based (and waits and blocks on it, using a condition). And a QJob (derived from what currently KJob is), isn’t or wouldn’t or shouldn’t block (such a QJob should allow for interactive continuation, for example — “overwrite this file? Y/N”). Meanwhile you want a clean API to fetch the result of any asynchronous operation. Blocked waiting for it, or not. It’s an uneasy choice for an API designer. Don’t all of us want APIs that can withstand the test of time? We do, yes.
Yeah. The world of programming is, at some level, complicated. But I’m also sure something good will come out of it. Meanwhile, form your asynchronous APIs on the principles of QFuture and or KJob: return something that can be waited for.
Sometimes a prediction of how it will be like is worth more than a promise. I honestly can’t predict what Thiago will approve, commit or endorse. And I shouldn’t.
Colleague tells me I write blogs in chats while I explain how to write a producer-consumer
I’m at home now. I don’t do non-public unpaid work. So let’s blog the example I’m making for him.
workplace.h
#ifndef Workplace_H #define Workplace_H #include <QObject> #include <QFuture> #include <QWaitCondition> #include <QMutex> #include <QStack> #include <QList> #include <QThread> #include <QFutureWatcher> class Workplace; typedef enum { WT_INSERTS, WT_QUERY } WorkplaceWorkType; typedef struct { WorkplaceWorkType type; QList<int> values; QString query; QFutureInterface<bool> insertIface; QFutureInterface<QList<QStringList> > queryIface; } WorkplaceWork; class WorkplaceWorker: public QThread { Q_OBJECT public: WorkplaceWorker(QObject *parent = NULL) : QThread(parent), m_running(false) { } void run() Q_DECL_OVERRIDE; void pushWork(WorkplaceWork *a_work); private: QStack<WorkplaceWork*> m_ongoing; QMutex m_mutex; QWaitCondition m_waitCondition; bool m_running; }; class Workplace: public QObject { Q_OBJECT public: explicit Workplace(QObject *a_parent=0) : QObject (a_parent) {} bool insert(QList<int> a_values); QList<QStringList> query(const QString &a_param); QFuture<bool> insertAsync(QList<int> a_values); QFuture<QList<QStringList> > queryAsync(const QString &a_param); private: WorkplaceWorker m_worker; }; class App: public QObject { Q_OBJECT public slots: void perform(); void onFinished(); private: Workplace m_workplace; }; #endif// Workplace_H
workplace.cpp
#include "workplace.h" void App::onFinished() { QFutureWatcher<bool> *watcher = static_cast<QFutureWatcher<bool>* > ( sender() ); delete watcher; } void App::perform() { for (int i=0; i<10; i++) { QList<int> vals; vals.append(1); vals.append(2); QFutureWatcher<bool> *watcher = new QFutureWatcher<bool>; connect (watcher, &QFutureWatcher<bool>::finished, this, &App::onFinished); watcher->setFuture( m_workplace.insertAsync( vals ) ); } for (int i=0; i<10; i++) { QList<int> vals; vals.append(1); vals.append(2); qWarning() << m_workplace.insert( vals ); qWarning() << m_workplace.query("test"); } } void WorkplaceWorker::pushWork(WorkplaceWork *a_work) { if (!m_running) { start(); } m_mutex.lock(); switch (a_work->type) { case WT_QUERY: m_ongoing.push_front( a_work ); break; default: m_ongoing.push_back( a_work ); } m_waitCondition.wakeAll(); m_mutex.unlock(); } void WorkplaceWorker::run() { m_mutex.lock(); m_running = true; while ( m_running ) { m_mutex.unlock(); m_mutex.lock(); if ( m_ongoing.isEmpty() ) { m_waitCondition.wait(&m_mutex); } WorkplaceWork *work = m_ongoing.pop(); m_mutex.unlock(); // Do work here and report progress sleep(1); switch (work->type) { case WT_QUERY: { // Report result here QList<QStringList> result; QStringList row; row.append("abc"); row.append("def"); result.append(row); work->queryIface.reportFinished( &result ); } break; case WT_INSERTS: default: { // Report result here bool result = true; work->insertIface.reportFinished( &result ); } break; } m_mutex.lock(); delete work; } m_mutex.unlock(); } bool Workplace::insert(QList<int> a_values) { WorkplaceWork *work = new WorkplaceWork;; QFutureWatcher<bool> watcher; work->type = WT_INSERTS; work->values = a_values; work->insertIface.reportStarted(); watcher.setFuture ( work->insertIface.future() ); m_worker.pushWork( work ); watcher.waitForFinished(); return watcher.result(); } QList<QStringList> Workplace::query(const QString &a_param) { WorkplaceWork *work = new WorkplaceWork; QFutureWatcher<QList<QStringList> > watcher; work->type = WT_QUERY; work->query = a_param; work->queryIface.reportStarted(); watcher.setFuture ( work->queryIface.future() ); m_worker.pushWork( work ); watcher.waitForFinished(); return watcher.result(); } QFuture<bool> Workplace::insertAsync(QList<int> a_values) { WorkplaceWork *work = new WorkplaceWork; work->type = WT_INSERTS; work->values = a_values; work->insertIface.reportStarted(); QFuture<bool> future = work->insertIface.future(); m_worker.pushWork( work ); return future; } QFuture<QList<QStringList> > Workplace::queryAsync(const QString &a_param) { WorkplaceWork *work = new WorkplaceWork; work->type = WT_QUERY; work->query = a_param; work->queryIface.reportStarted(); QFuture<QList<QStringList> > future = work->queryIface.future(); m_worker.pushWork( work ); return future; }
The rules of scuba diving
- First rule. You must understand the rules of scuba diving. If you don’t know or understand the rules of scuba diving, go to the second rule.
- The second rule is that you never dive alone.
- The third rule is that you always keep close enough to each other to perform a rescue of any kind.
- The forth rule is that you signal each other and therefor know each other’s signals. Underwater, communication is key.
- The fifth rule is that you tell the others, for example, when you don’t feel well. The others want to know when you emotionally don’t feel well. Whenever you are insecure, you tell them. This is hard.
- The sixth rule is that you don’t violate earlier agreed upon rules.
- The seventh rule is that given rules will be eclipsed the moment any form of panic occurs, you will restore the rules using rationalism first, pragmatism next but emotional feelings last. No matter what.
- The eighth rule is that the seventh rule is key to survival.
These rules make scuba diving an excellent learning school for software development project managers.
RE: Bye Facebook
Wim made a stir in the land of the web. Good for Wim that he rid himself of the shackles of social media.
But how will we bring a generation of people, who are now more or less addicted to social media, to a new platform? And what should that platform look like?
I’m not a anthropologist, but I believe human nature of organizing around new concepts and techniques is that we, humans, start central and monolithic. Then we fine-tune it. We figure out that the central organization and monolithic implementation of it becomes a limiting factor. Then we decentralize it.
The next step for all those existing and potential so-called ‘online services’ is to become fully decentralized.
Every family or home should have its own IMAP and SMTP server. Should that be JMAP instead? Probably. But that ain’t the point. The fact that every family or home will have its own, is. For chat, XMPP’s s2s is like SMTP. Postfix is an implementation of SMTP like ejabberd is for XMPP’s s2s. We have Cyrus, Dovecot and others for IMAP, which is the c2s of course. And soon we’ll probably have JMAP, too. Addressability? IPv6.
Why not something like this for social media? For the next online appliance, too? Augmented reality worlds can be negotiated in a distributed fashion. Why must Second Life necessarily be centralized? Surely we can run Linden Lab’s server software, locally.
Simple, because money is not interested in anything non-centralized. Not yet.
In the other news, the Internet stopped working truly well ever since money became its driving factor.
ps. The surest way to corrupt a youth is to instruct him to hold in higher esteem those who think alike than those who think different. Quote by Friedrich Nietzsche.
Asynchronous undoable and redoable APIs
Combining QFuture with QUndoCommand made a lot of sense for us. The undo and the redo methods of the QUndoCommand can also be asynchronous, of course. We wanted to use QFuture without involving threads, because our asynchronosity is done through a process and IPC, and not a thread. It’s the design mistake of QtConcurrent‘s run method, in my opinion. That meant using QFutureInterface instead (which is undocumented, but luckily public – so it’ll remain with us until at least Qt’s 6.y.z releases).
So how do we make a QUndoCommand that has a undo, and that has a redo method that returns a asynchronous QFuture<ResultType>?
We just did that, today. I’m very satisfied with the resulting API and design. It might have helped if QUndoStack would be a QUndoStack<T> and QUndoCommand would have been a QUndoCommand<T> with undo and redo’s return type being T. Just an idea for the Qt 6.y.z developers.
Making something that is ‘undoable editable’ with Qt
Among the problems we’ll face is that we want asynchronous APIs that are undoable and that we want to switch to read only, undoable editing, non-undoable editing and that QML doesn’t really work well with QFuture. At least not yet. We want an interface that is easy to talk with from QML. Yet we want to switch between complicated behaviors.
We will also want synchronous mode and asynchronous mode. Because I just invented that requirement out of thin air.
Ok, first the “design”. We see a lot of behaviors, for something that can do something. The behaviors will perform for that something, the actions it can do. That is the strategy design pattern, then. It’s the one about ducks and wing fly behavior and rocket propelled fly behavior and the ostrich that has a can’t fly behavior. For undo and redo, we have the command pattern. We have this neat thing in Qt for that. We’ll use it. We don’t reinvent the wheel. Reinventing the wheel is stupid.
Let’s create the duck. I mean, the thing-editor as I will use “Thing” for the thing that is being edited. We want copy (sync is sufficient), paste (must be aysnc), and edit (must be async). We could also have insert and delete, but those APIs would be just like edit. Paste is usually similar to insert, of course. Except that it can be a combined delete and insert when overwriting content. The command pattern allows you to make such combinations. Not the purpose of this example, though.
Enough explanation. Let’s start! The ThingEditor, is like the flying Duck in strategy. This is going to be more or less the API that we will present to the QML world. It could be your ViewModel, for example (ie. you could let your ThingViewModel subclass ThingEditor).
class ThingEditor : public QObject { Q_OBJECT Q_PROPERTY ( ThingEditingBehavior* editingBehavior READ editingBehavior WRITE setEditingBehavior NOTIFY editingBehaviorChanged ) Q_PROPERTY ( Thing* thing READ thing WRITE setThing NOTIFY thingChanged ) public: explicit ThingEditor( QSharedPointer<Thing> &a_thing, ThingEditingBehavior *a_editBehavior, QObject *a_parent = nullptr ); explicit ThingEditor( QObject *a_parent = nullptr ); Thing* thing() const { return m_thing.data(); } virtual void setThing( QSharedPointer<Thing> &a_thing ); virtual void setThing( Thing *a_thing ); ThingEditingBehavior* editingBehavior() const { return m_editingBehavior.data(); } virtual void setEditingBehavior ( ThingEditingBehavior *a_editingBehavior ); Q_INVOKABLE virtual void copyCurrentToClipboard ( ); Q_INVOKABLE virtual void editCurrentAsync( const QString &a_value ); Q_INVOKABLE virtual void pasteCurrentFromClipboardAsync( ); signals: void editingBehaviorChanged (); void thingChanged(); void editCurrentFinished( EditCurrentCommand *a_command ); void pasteCurrentFromClipboardFinished( EditCurrentCommand *a_command ); private slots: void onEditCurrentFinished(); void onPasteCurrentFromClipboardFinished(); private: QScopedPointer<ThingEditingBehavior> m_editingBehavior; QSharedPointer<Thing> m_thing; QList<QFutureWatcher<EditCurrentCommand*> *> m_editCurrentFutureWatchers; QList<QFutureWatcher<EditCurrentCommand*> *> m_pasteCurrentFromClipboardFutureWatchers; };
For the implementation of this class, I’ll only provide the non-obvious pieces. I’m sure you can do that setThing, setEditingBehavior and the constructor yourself. I’m also providing it only once, and also only for the EditCurrentCommand. The one about paste is going to be exactly the same.
void ThingEditor::copyCurrentToClipboard ( ) { m_editingBehavior->copyCurrentToClipboard( ); } void ThingEditor::onEditCurrentFinished( ) { QFutureWatcher<EditCurrentCommand*> *resultWatcher = static_cast<QFutureWatcher<EditCurrentCommand*>*> ( sender() ); emit editCurrentFinished ( resultWatcher->result() ); if (m_editCurrentFutureWatchers.contains( resultWatcher )) { m_editCurrentFutureWatchers.removeAll( resultWatcher ); } delete resultWatcher; } void ThingEditor::editCurrentAsync( const QString &a_value ) { QFutureWatcher<EditCurrentCommand*> *resultWatcher = new QFutureWatcher<EditCurrentCommand*>(); connect ( resultWatcher, &QFutureWatcher<EditCurrentCommand*>::finished, this, &ThingEditor::onEditCurrentFinished, Qt::QueuedConnection ); resultWatcher->setFuture ( m_editingBehavior->editCurrentAsync( a_value ) ); m_editCurrentFutureWatchers.append ( resultWatcher ); }
For QUndo we’ll need a QUndoCommand. For each undoable action we indeed need to make such a command. You could add more state and pass it to the constructor. It’s common, for example, to pass Thing, or the ThingEditor or the behavior (this is why I used QSharedPointer for those: as long as your command lives in the stack, you’ll need it to hold a reference to that state).
class EditCurrentCommand: public QUndoCommand { public: explicit EditCurrentCommand( const QString &a_value, QUndoCommand *a_parent = nullptr ) : QUndoCommand ( a_parent ) , m_value ( a_value ) { } void redo() Q_DECL_OVERRIDE { // Perform action goes here } void undo() Q_DECL_OVERRIDE { // Undo what got performed goes here } private: const QString &m_value; };
You can (and probably should) also make this one abstract (and/or a so called pure interface), as you’ll usually want many implementations of this one (one for every kind of editing behavior). Note that it leaks the QUndoCommand instances unless you handle them (ie. storing them in a QUndoStack). That in itself is a good reason to keep it abstract.
class ThingEditingBehavior : public QObject { Q_OBJECT Q_PROPERTY ( ThingEditor* editor READ editor WRITE setEditor NOTIFY editorChanged ) Q_PROPERTY ( Thing* thing READ thing NOTIFY thingChanged ) public: explicit ThingEditingBehavior( ThingEditor *a_editor, QObject *a_parent = nullptr ) : QObject ( a_parent ) , m_editor ( a_editor ) { } explicit ThingEditingBehavior( QObject *a_parent = nullptr ) : QObject ( a_parent ) { } ThingEditor* editor() const { return m_editor.data(); } virtual void setEditor( ThingEditor *a_editor ); Thing* thing() const; virtual void copyCurrentToClipboard ( ); virtual QFuture<EditCurrentCommand*> editCurrentAsync( const QString &a_value, bool a_exec = true ); virtual QFuture<EditCurrentCommand*> pasteCurrentFromClipboardAsync( bool a_exec = true ); protected: virtual EditCurrentCommand* editCurrentSync( const QString &a_value, bool a_exec = true ); virtual EditCurrentCommand* pasteCurrentFromClipboardSync( bool a_exec = true ); signals: void editorChanged(); void thingChanged(); private: QPointer<ThingEditor> m_editor; bool m_synchronous = true; };
That setEditor, the constructor, etc: these are too obvious to write here. Here are the non-obvious ones:
void ThingEditingBehavior::copyToClipboard ( ) { } EditCurrentCommand* ThingEditingBehavior::editCurrentSync( const QString &a_value, bool a_exec ) { EditCurrentCommand *ret = new EditCurrentCommand ( a_value ); if ( a_exec ) ret->redo(); return ret; } QFuture<EditCurrentCommand*> ThingEditingBehavior::editCurrentAsync( const QString &a_value, bool a_exec ) { QFuture<EditCurrentCommand*> resultFuture = QtConcurrent::run( QThreadPool::globalInstance(), this, &ThingEditingBehavior::editCurrentSync, a_value, a_exec ); if (m_synchronous) resultFuture.waitForFinished(); return resultFuture; }
And now we can make the whole thing undoable by making a undoable editing behavior. I’ll leave a non-undoable editing behavior as an exercise to the reader (ie. just perform redo() on the QUndoCommand, don’t store it in the QUndoStack and immediately delete or cmd->deleteLater() the instance).
Note that if m_synchronous is false, that (all access to) m_undoStack, and the undo and redo methods of your QUndoCommands, must be (made) thread-safe. The thread-safety is not the purpose of this example, though.
class UndoableThingEditingBehavior : public ThingEditingBehavior { Q_OBJECT public: explicit UndoableThingEditingBehavior( ThingEditor *a_editor, QObject *a_parent = nullptr ); protected: EditCellCommand* editCurrentSync( const QString &a_value, bool a_exec = true ) Q_DECL_OVERRIDE; EditCurrentCommand* pasteCurrentFromClipboardSync( bool a_exec = true ) Q_DECL_OVERRIDE; private: QScopedPointer<QUndoStack> m_undoStack; }; EditCellCommand* UndoableThingEditingBehavior::editCurrentSync( const QString &a_value, bool a_exec ) { Q_UNUSED(a_exec) EditCellCommand *undoable = ThingEditingBehavior::editCurrentSync( a_value, false ); m_undoStack->push( undoable ); return undoable; } EditCellCommand* UndoableThingEditingBehavior::pasteCurrentFromClipboardSync( bool a_exec ) { Q_UNUSED(a_exec) EditCellCommand *undoable = ThingEditingBehavior::pasteCurrentFromClipboardSync( false ); m_undoStack->push( undoable ); return undoable; }
Perfection
Perfection has been reached not when there is nothing left to add, but when there is nothing left to take away.
Merkel bashing
It seems to be the new sport of nitwit moronic world leaders like Trump and Erdogan to bash Frau Merkel.
It makes me respect her more.
Duck typing
Imagine you have a duck. Imagine you have a wall. Now imagine you throw the duck with a lot of force against a wall. Duck typing means that the duck hitting the wall quacks like a duck would.
ps. Replace wall with API and duck with ugly stupid script written by an idiot. You can leave quacks.
Binaries in git, release numbering, Git-Flow and Scrum at the CIA
Funny how even the software developers at the CIA have problems with idiots who want to put binaries in git. They also know about Git-Flow, my preferred git branching workflow. I kind of wonder how come, if they know about Git-Flow, we see so few leaked NSA and CIA tools with correct semver versioning. Sometimes it’s somewhat okayish, like you can see here. But v1.0-RC3 is not really semver if you see how they got there here. To start with, your alpha versions start with 0.0.x. So where are all those versions under 0.0.x that happened before release candidate 3? 1.0, 1.1-beta, 1.0-phase2, 1.0-beta1-, 1.0-beta-7. WTF guys. That’s not a good versioning scheme. Just call it 0.0.1, 0.0.2, 0.1.0, 0.1.1, 0.1.2 for the betas. And when the thing sees first usage, start calling it 1.0.0, 1.0.1, 1.0.2, 1.1.0, 1.1.1, 1.2.0 etc. What’s wrong with that? And how are all these words like alha-1, beta-2, phase2, etc any better? Maybe just fire your release maintainer! Admittedly for that 2.0.x series they at least tried to get it right.
The point is that packaging tools can be configured to let other packages depend on these version numbers. In x.y.z the x number has implications on API incompatibility whereas the y number can be used for compatible feature additions.
I can imagine that different malwares, exploits, rootkits, intrusion tools they develop would pose incompatibilities with each other, and that for example the NSA and CIA want to share libraries and link without having to recompile or repackage. So versioning to indicate ABI and API compatibility wouldn’t be a bad idea. Let’s hope in the next round of massive leaks we see them having learned good software development processes and practices.
They are doing Scrum sprints and do retrospectives, though. That’s not so bad.
Beste VRT, over PGP
PGP, Pretty Good Privacy, is niet enkel te koop op Het Internet; het is zowel gratis als dat het open source is. Dat wil zeggen dat iedereen op deze planeet de broncode van PGP kan downloaden, compileren en aanpassen en dat iedereen het op een telefoon kan zetten.
Velen gebruiken dan ook zulke encryptiesoftware voor allerlei redenen. Vaak zonder dat ze het door hebben (https websites, de diensten van je bank, online aankopen, Whatsapp berichten, en zo verder). Soms hebben ze het wel door (dat zijn dan vaak techneuten).
Enkelingen doen dat om hun communicatie over criminele plannen te versleutelen. Maar velen anderen doen dat om hun bedrijfsgegevens, privacy, persoonlijke data en zo verder te beveiligen. Er zouden ook overheden zijn, naar het schijnt, zoals de onze, bijvoorbeeld, die het veelvuldig gebruiken. Volgens geruchten gebruiken alle militairen het. Ik ben er van overtuigd dat jullie werkgever, de VRT, het ook heel veel gebruikt en zelfs oplegt. Een beetje serieus journalist gebruikt het tegenwoordig ook voor, laat ik hopen, alles.
PGP is niet illegaal. Het versleutelen van berichten is niet illegaal. Dat de politie het daarom niet meer kan lezen, is op zichzelf niet illegaal. Er staat in onze Belgische wetgeving helemaal niets over het illegaal zijn van het versleutelen van berichten. Er staat in onze Belgische wetgeving helemaal niets over het illegaal zijn van bv. software zoals PGP.
Versleutelen van berichten bestaat ook al eeuwen. Nee, millennia. Misschien zelfs wel al tienduizenden jaren. Kinderen doen het en leren het. Misschien niet op al te professionele manier. Maar sommige kinderlijk eenvoudige encryptietechnieken zijn theoretisch onkraakbaar. Zoals bv. de one time pad
Sterker nog, onze Belgische universiteiten staan over de hele wereld bekend om haar wiskundigen die zich met cryptografie bezig houden. De wereldwijd belangrijkste encryptiestandaard, Rijndael, werd door Leuvense studenten ontwikkeld. Die PGP software gebruikt die encryptiestandaard, ook. Het staat tegenwoordig bekend als de Advanced Encryption Standard, AES, en wordt oa. militair vrijwel overal ingezet.
Dat een aantal mensen van het gerecht en de politie het lastig vinden dat een aantal criminelen gebruik maken van software zoals PGP, betekent op geen enkele manier dat het gebruik van en het voorzien van telefoons met PGP, op zichzelf, illegaal is. Helemaal niet. Het is dus vrij onnozel om in jullie journaal te laten uitschijnen als zou dat wel het geval zijn. Dat is het niet. Zeker in extreme tijden zoals nu is het gevaarlijk wanneer de media zoiets doet uitschijnen. Straks maakt men de gewone burger weer bang over allerlei dingen, en dan gaat de politiek domme eisen stellen zoals het verbieden van encryptie.
Het versleutelen van berichten is een erg belangrijk onderdeel, in de technologie, om die technologie veilig en betrouwbaar te laten werken. Het ontbreken van de mogelijkheid om berichten en gegevens te versleutelen zou werkelijk catastrofale gevolgen hebben.
Het zou ook geen enkele crimineel weerhouden toch één en ander te encrypteren. Encryptie verbieden zou letterlijk alleen maar de onschuldige burger schaden. De crimineel zou er net voordeel uit halen; de crimineel wordt het daardoor plots veel eenvoudiger gemaakt om bij onschuldige burgers (die geen encryptie meer kunnen gebruiken) digitaal in te breken.
Denk in deze extreme tijden goed na wat je in jullie mediakanaal, het nationale nieuws, doet uitschijnen. Als techneut vind ik het bijzonder onverantwoordelijk van jullie. OOK en vooral wanneer de bedoeling was om het nieuws zo dom mogelijk te brengen. Alsof onze burgers het niet zouden aankunnen om correct geïnformeerd te worden over deze materie.
Gewoën, op teevee
Aanmaakblokskensnaft
Er is iets waar ik mij al een tijdje onwaarschijnlijk druk in maak: Aanmaakblokskens.
Er bestaat een bepaald merk aanmaakblokskens die geen ECO label hebben (dus hun marketingjongens hebben de moeite niet gedaan om de drukker van het kartonneke te vragen er ECO bij te frommelen). Die blijken kei goed te werken. Want daar zit, vermoedelijk, gewoon naft of zo in. Dus, dat werkt. Logisch.
Daarnaast heb je ongelofelijk veel andere merken die niet werken. Je moet er letterlijk twintig tot dertig seconden een vlam op houden. Daardoor heb je meer aanstekergas nodig, verbrand je vaker je vingers en maak je je handen sneller vuil aan de kachel. Met andere woorden, die werken niet.
Dingen die niet werken verkopen na een tijd niet goed.
Dus nu ligt er in tal van supermarkten een te veel aan zogenaamde ecologische aanmaakblokjes, en een te kort aan dat goeie merk. Dat merk dat dus wel werkt.
Nu vraag ik me af: die paar milligram naft, of wat er ook in die goeie blokskens zit, is dat nu zo erg om dat op te fikken als je in je wagen vijftig liter van dat spul tankt? Ik bedoel: een keer draaien met uw stuur op de parking van de supermarkt en je hebt al een paar jaar aanmaakblokjesnaft verbruikt.
Ik wilde het toch maar even kwijt.
Pretending to think like heads of CIA and NSA
“Meeting with intel officials ‘constructive,’ hacking had ‘absolutely no effect’ on election. There was no tampering whatsoever with voting machines,” Trump said.
“There had been attempts to hack the Republican National Committee (RNC). However, thanks to the Comittee’s strong hacking defenses, they all failed” Trump said.
“America’s safety and security is a number one priority”, Trump said. He will appoint a team to draft plans on how to repel any cyber attacks on the US in the future. However, he added, “the methods, tools and tactics” of enforcing cyber security would not be made public. “That will benefit those who seek to do us harm,” Trump said.
The king is dead, long live the king.
Linux is right now what Linux right now is
It certainly isn’t the desktop. But nonetheless, it’s all over the place.
Heb besloten Katleen Gabriels wat te helpen
Dat mag he. Ik ben niet eens betaald door Lannoo. Ik vind wel dat ze dat ondertussen eens mogen doen hoor.
Dus. Wat is er gaande?
Haar boek, Onlife, hoe de digitale wereld je leven bepaalt, is gisteren verkozen tot Liberales Boek van het jaar 2016. De jury bestond uit filosofe Tinneke Beeckman, Liberales-kernlid Dirk Verhofstadt, Liberales-voorzitter Claude Nijs, deMens.nu-voorzitter Sylvain Peeters en Liberales-kernlid Koert Van Espen.
Ze nodigt ons allemaal van harte uit op de huldigingsavond op donderdag 26 januari 2017 om 20 uur, in het Liberaal Archief (Kramersplein 23) te Gent. Het programma ziet er als volgt uit:
Eerst wordt het Liberales-boek Theorieën over rechtvaardigheid. De John Rawlslezingen (redactie Dirk Verhofstadt) voorgesteld.
Daarna volgt de voorstelling van het boek De keuze van D66 (redactie Daniël Boomsma), met een toespraak door Vlaams parlementslid Mathias De Clercq.
Vervolgens interviewt Koert Van Espen haar over Onlife.
En na al dat voedsel voor de geest zal de ambrozijn rijkelijk vloeien tijdens de nieuwjaarsreceptie.
De toegang is gratis, maar inschrijven is verplicht via info@liberales.be.
Ja, ik vind toch wel dat de Linux community aanwezig moet zijn. Vorige keer was ik daar alleen. Wanneer komt de rest van planet.grep.be me eens steunen? We kunnen er een leuke avond van maken. Toch?!
Met vriendelijke groeten,
De philip. Niet diene die het altijd over philip-conspiracies heeft. Diene andere, die daar in mee gaat.
Weinig tijd
Zij die oordelen over al waar weinig tijd voor is, nemen hun tijd om na te kijken of de voorstellers wel hun tijd genomen hebben.
Boeiende politiek-rechterlijke avond
Maar, rechters moeten de wet uitvoeren. Niet zelf proberen wetten te maken. De scheiding der machten geldt in alle richtingen.
Imperator Bart heeft een punt.