205B random strings and no 'Delphi'
2021-02-28 18:48 randomdelphi [permalink]
→ Delphi-PRAXiS: Can Delphi randomize string 'Delphi'?
Ah, that takes me back. A while ago at work I got someone baffled by this statement: It is said that a thousand monkeys banging away on keyboards could at some moment in infinite time produce the complete work of Shakespeare (and that the combined internet forums are a living counter-proof). Now if you search online you can find an XML download of the combined works of Shakespeare, so it's not hard to find the relative occurance of each letter of the alphabet. One can guess this will have rougly the same values per letter as the total of the English language. So, then, if you take 'random' by its definition, and the monkey's produce text at 1/26 probability for each letter in the alphabet, therefore they'll never reach a point in time where they (re)produce the works Shakespeare.
Now, I'm not a real philosopher, or a statistician, so my thesis could be complete fiction and based on nothing, but sometimes you really got to take a lesson from practice. In theory, in infinite time, it's ofcourse possible that something really really inherently possible could emerge out of a random system, but there are characteristigs to anything random, and there are exponential things at play that soon but experimantal set-ups like with the link above, that they probably would produce the expected outcome in a time-span that exceeds the number of years we've got left before the sun sheds its outer layers and devours the earth, complete with a set of silicon-based machines churning away at putting a series of random characters in sequence and comparing them of some neat stories of a long gone English playwright.
Good to know: don't do except on e:Exception do ... raise e;
2020-12-28 13:29 dontraisee [permalink]
Good to know. At work, I inherited a smaller project. It started firing access violation errors reading from 00000000 (that tells you there's a nil pointer involved somewhere) at some address that didn't put me somewhere in the source code when I did Search > Find address in the IDE...
I was lucky I got the program running in a debugger when this happens, and the root cause was something completely different. (An SQL unique index constraint violation if you're really interested.) I got that fixed soon enough, but that didn't explain where the access violation comes from.
I followed the exception with the debugger, and before the exception was handled by anything that outputs like a logger or an error display, sure enough an access violation happend, but the debugger didn't show me anywhere else in the source code than it was already debugging, strange.
It took me a long hard look at the code before I spotted it, but with some luck you'll be able to spot what's wrong faster. The original author had the strange habit of writing exception handlers like this:
try
//important stuff here
except
on e:Exception do
begin
//stuff to do in case of an exception here, (e.g. transaction rollback)
raise e;
end;
end;
And they were all over the place. Nothing bad about that per sé, with raising the exception again, you can centralise the actual exception handling on the 'highest level' where all the calls are made. But while you're able to raise a specific exception if you create a new one*, apparently there's a difference between raise e;
and raise;
at least in this Delphi version I was on. Delphi handles the destruction of exception objects for you, and apparently that throws something off and causes the nil access violation somewhere deep inside...
*: Fun fact: Did you know that the Delphi runtime system creates an EOutOfMemory exception instance at the start of your programs, just to have it ready when it actually runs out of memory anytime later? Forgot where I read about that though...
2020-12-18 16:26 invoicetemplates [permalink]
→ https://stackoverflow.com/questions/65348138/quickreport-on-delphi-sydney-10-4-1
Oh my, I didn't know. I guess we'll see this more and more with one-person open-source projects, that people stop with the project for all kinds of reasons.
But about reports, I've made this really elegant thing at work to script the design of a report with just a few basic commands (line, text, image, matrix, block, repeat...) that allows you to write what the report should look like, and make lots of small alterations later. If you really need your reports just right, I've always found a graphical designer to introduce minor artefacts that you sometimes need to work around...
I know there are tons of similar things out there, like TeX and PostScript, and even HTML or MetaFiles, but it was grown out of neccessity and suffered "dogfooding" from the very start, which shows in its design and execution. And thanks to SynPDF, (or "Print to PDF" for that matter) you can just exports PDF's with it as well. So I really should take some time and re-do it on my own time and open source it... If I can make it even better and cleaner, I might introduce the open-source version as a replacement at work! (... Oh-oh!) (... or was it this one?)
Carefull with Gogole Sheet CSV export
2020-06-26 14:18 ggggrgviz [permalink]
Ready for another story from the trenches? So image a Google Sheet made by someone else, with all kinds of dat in about 30 columns, of about a few thousand rows. Yes, it's a stretch to keep using Sheets for that, but this data will serve for the analysis for a decent application to manage this with... That probably won't be my team handling that project, but I had to do a quick cross reference of this data with the data in the database of one our current projects. The best way to do cross-checks is get the sheet into a table in the database to run queries. I guess you should be able to import a CSV pretty easily, right? I searched around and found this:
https://docs.google.com/spreadsheets/d/{key}/gviz/tq?tqx=out:csv&sheet={sheet_name}
Which I thought would provide the data in just the way ready for me to import. Wrong. The second column just happened to have codes for all of the items that are numeric for the first few hundreds of items, and then alphanumeric codes. At first I thought the CSV importer was fouling up, but I hadn't looked at the CSV data itself. Turns out this CSV exporter checks the first few lines (or perhaps even only the first one!), guesses the column is numeric, and then just exports an empty value for all non-numeric values in that column!
The code in that column was only in a number of cases needed to uniquely identify the items, so I first was looking for a reason why my cross-match was throwing duplicates in all of the wrong places. Ofcourse. Weep one tear for the time lost, then move on. Take solace in the wisdom gained.
I solved it by using the CSV from the Export menu. I only needed it once so I didn't get a URL for that.
2020-03-16 20:29 nottx [permalink]
→ Microsoft Teams goes down just as Europe logs on to work remotely — Verge
Tx wasn't down, especially the instance you host yourself.
I'll be there: Delphi Day 2019 - Brussels 9 May
2019-04-23 11:39 delphiday2019 [permalink]
I'll be there.
Local variables don't cost nothing!
2019-03-08 22:45 nocostvar [permalink]
O my god. I can't believe I have to keep explaining this. To a years-long colleague with some more years on the counter than me, the other day. He repeated a function call with the same arguments a few times in a few adjacent lines of code, with a guarantee in place that this will result the same value every time.
I asked him why. It couldn't be to have less typing: the extra var a:integer;
would replace far much more code it took for the repeated function calls. It couldn't be performance: even if the function would just be getting a value from a memory location, the call and return, building a stack frame and tearing it down it again, would end up in a multiple of the instructions the processor needs to work through.
I don't know who launched the idea the compiler should be smart enough to pick things like this out — what I read about Rust and other modern languages, I know research is actively looking at things like that — but as we currently have it, our good old trusted compiler doesn't. What is does do, and typically really well if we work a little with it, is mapping local variables onto the available registers of the CPU. In the best case no memory whatsoever is allocated for local variables.
Even if in theory some local variables get a temporary address on the stack, modern CPU's have multiple levels of cache so that the values don't even reach your DRAM silicon before you're function call completes. We're supposed to keep all functions and methods as short as possible, but even if we don't, the compiler knows if a local variable is only used for a short section of the code. So in some cases it's even better to have an extra local variable instead of re-using a local variable somewhere up front and then later near the end of a larger block, and still not pay with any performance of memory consumption...
So when in doubt, take an extra local var. It's what they're there for. It helps the compiler do better analysis. It helps you, now and later. All I need to do now is name them a little better. I know I have the nasty habit of things like var a,b,c,d,e,f,g:integer;
but I think I'm improving... Slowly...
PostgreSQL: update set from (join)*
2019-03-05 15:56 updatefrom [permalink]
In SQLServer schreef ik wel eens een query van de vorm:
update MyTable set Field1='Value1',Field2=3
from MyTable T1
inner join SomeOtherTable T2 on T2.Field3=T1.Field3
--eventueel nog joins
where T1.Field1='Value0'
Maar dan probeer je hetzelfde te doen in SQLite: noppes
Of in PostgreSQL, daar blijkt het wel te bestaan maar hij plakt de referentie naar de tabel van de update niet aan het gebruik van de tabel in je from of join. Omdat je zo dan eigenlijk geen velden van de tabel in de where hebt staan, doet hij de update op alle records, ongeacht je selectie. Maar dat is gemakkelijk op te lossen natuurlijk:
update MyTable set Field1='Value1',Field2=3
from MyTable T1
inner join SomeOtherTable T2 on T2.Field3=T1.Field3
where MyTable.MyPrimaryKeyField=T1.MyPrimaryKeyField --in de veronderstelling dat dit je primary key veld is natuurlijk
and T1.Field1='Value0'
Maar daar moet je dus wel zelf aan denken, lastig als je het anders gewoon was...
2019-02-03 21:51 rasphone [permalink]
Dit is er eentje om te onthouden. Ik had problemen met de VPN connectie naar het werk. Het is te zeggen, het werkte vlot en naar behoren op mijn vorige laptop. Ik koop me na x jaren eens een nieuwe laptop, neem de instellingen over, noppes. Waarom precies is me niet duidelijk aan de error. In de event log vind ik RasSstp die zegt dat het of een timeout of een certificaat-probleem is. Dus was ik al de certificate (stores! wist ik veel of het de computer of service of persoonlijke store is) aan het uitpluizen voor een eventueel verschil. Ik had zelfs al netsh ras set tracing * enabled
gevonden maar daar vond ik helemaal niets in terug... En dan kom ik plots toevallig langs deze (lap, vergeten de URL van waar ik het zag bij te houden):
C:\Users\%USERNAME%\AppData\Roaming\Microsoft\Network\Connections\Pbk\rasphone.pbk
Blijkt daar niet alleen precies inderdaad een cruciaal verschilletje te zitten in één van de honderden parametertjes daar, blijkt ook dat je gewoon extra files in die folder kan zetten en ze verschijnen auto-magisch in het netwerk-menu onder het icoon op de taakbalk. En voila, probleem geflikskts.
Another store from the trenches: GDI vs PDF
2018-07-06 18:31 gdipdf [permalink]
One of the great things about Delphi is this object-oriented way of manipulating things called the Visual Component Library. There's much more to it than that, but in a sense you could describe it as a wrapper around Windows API's. One of these is GDI, it's old but it's still there and used for graphics and text-layout. It was born, way back when, from the idea of What You See Is What You Get (WYSIWYG) taken even further and that the same program logic could work for display on screen and writing to a printer. Delphi's VCL declares the TCanvas class you can use to design the output, and wether you pass a Printer.Canvas, Screen.Canvas, Form.Canvas or Bitmap.Canvas shouldn't really matter. This works great for forms and reports.
But in the printing business, there's much more than forms and reports to put on paper. Over there the PDF reigns supreme. It performs a similar task, but originated out of a very different set of parameters. A big module we created of the production software at work generates them according to specifications. How this works is very different as the components that make up a PDF document are constructed one by one and this doesn't look like the work you normally would do with a TCanvas instance.
But now and again these two worlds need to bridge over to eachother. One day I had to keep automatic PDF archive copies of some reports, and discovered the great SynPDF project from the same people that created the mORMot framework. It offers a TCanvas instance (TPdfDocumentGDI.VCLCanvas
) that you can pass to code that knows what to with a TCanvas reference. It works great.
I haven't needed to think about crossing the two the other way round, but recently I noticed a collegue did, and he also found a simple straight-forward solution for the problem: You can just ask the PDF reader on the system to render a PDF to a printer. It's as simple as starting a process with:
"C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe" /n /t "<document to print>" "<printer name>"
or
"C:\Program Files (x86)\SumatraPDF\SumatraPDF.exe" -print-to "<printer name>" "<document to print>"
This works just great and even doesn't add too much code to your program. You may need to include the PDF viewer installer with your installer, but that's a minor issue and perhaps not even required as most people have a PDF reader installed by default.
Delphi project and subversion: set the build number to revision number
2018-06-09 09:37 dsvnbuild [permalink]
At work, we have a number of interrelated projects in a single subversion repository. We've agreed to change the build number in the project's version properties to the current revision number of your work folder. And specifically not the revision number you might predict your changes will land in when you commit them.
We're currently a rather small team so it may be tempting to assume you'll just get the next revision number, but we stress newcomers to ignore that urge. As long as we're a small team, this works manually, but if we grow we should move over to scripted version resource entries and commit hooks that update the build number automatically.
So with a major and minor version of 2.0 for example, and a release number of 8, the full version could look like "2.0.8.51873".
This way of working has a number of advantages.
The binaries that get used in production, but exert a bug in their behaviour, show with their full version number (and the previous version number from before the bug occurred) the vicinity of revision numbers that introduced the code change that may lay at the cause of the bug. To get the exact revision number, you need to look up the SVN log (or blame) of the .dof
or .dproj
file, but it's quite sure it's a number closely above the number in the version. We've stressed second line support personnel to list this number when reporting the bug, which helps when researching reproducibility.
But even long before that, when it happens two (or) more of us inadvertently make changes to the same project, we either started from the same revision number in the work folder and see when comitting that something has to get merged and it does so automatically or we get a merge conflict; or we started from different revision numbers and get a conflict right away or a message that we're over due for an update to or work folder.
As I said we're a small team for the moment and it rarely happens so it saves us an update task with risk of conflict before we commit, and in general we can split the work that needs to be done between us so we shouldn't make changes to the same projects.
Then again, if the team would ever grow to something like really big, we would probably have to switch to something else than subversion, or even repositories per project, who knows...
GMail: make the labels list compacter
2018-06-08 10:32 GMailLabelsCompacter [permalink]
If you remember from before, I have so much labels in GMail that I didn't like that the box to change the labels on a message with, is so small. Stylus to the rescue.
Now there's this new GMail design, and even in compact display, the list of labels on the left doesn' fit my screen. Also I don't like the font the subject line is rendered in. So a bit of inspection later, I add these lines to my overrides:
.z0 {
margin: 0px;
height: 32px;
padding: 0px 0px 0px 64px;
}
.z0>.L3{
height:24px;
}
.ha>.hP {
font-family: "PT Sans", sans-serif;
}
.aim {
height: 18px;
}
.J-N {
padding: 0px 12px 0px 32px;
}
.J-LC
{
padding: 0px 12px 0px 48px;
}
2018-03-01 22:07 nmdiesels [permalink]
→ VRT NWS: Gaan we onze afgedankte diesels naar Afrika sturen?
Zie, ik moet echt precies op het juiste moment om een benzine-wagen gevraagd hebben... Eind vorig jaar was het tijd voor een nieuwe lease-contract op het werk, dus dacht ik vragen staat vrij. Ik doe op vier jaar ocharme iets van een enkele omtrek om de aarde, dus geeft me asjeblief toch een wagen op benzine. Al was het omdat het inderdaad te voorspellen was dat dit jaar de dieselprijs (eindelijk!) de benzine-prijs zou inhalen. Daarnaast is er nog het kleine netelige feitje dat de wasem uit de pijp bij een dieselwagen blijkbaar behoorlijk wat smeerlapperij bevat. Ik zou niet zover gaan om dieselrijders te veroordelen voor deelname aan moord, maar jammer genoeg is er wel een relatie vast te stellen tussen luchtvervuiling en de sterftestatistieken.
Tot nu toe beklaag ik het me niet. Wel weet ik nu iets wat ik graag iets vroeger had geweten: Met een gemiddelde van 5,5 liter per honderd kilometer voor een diesel, en — voorlopig toch nog, dit nieuwe rijtuig moet zijn eerste 30 megameter nog volmaken — 7,5 bij een benzine-motor, is het omkeren van het verschil tussen diesel- en benzineprijs op slag verworden tot een psychologische grens. Wat niet wil zeggen dat heel misschien ik nog aan mijn gemiddelde rijstijl kan sleutelen om meer dan een grote 600 kilometer per tankbeurt er uit te krijgen.
Een heel klein iets waar ik mee zit, en ik niet direct weet aan wie ik het zou kunnen vragen is het volgende: Ik merk een klein verschilletje in gedrag van de aansturing bij het koppelen. Bij het versnellen en schakelen in de eerste drie versnellingen, lijkt de motor net even naar adem te happen voor het koppel zich aandient. Ik heb al geprobeerd of ik misschien het aankoppelpunt verkeerd inschat, of ik iets meer of net minder het gaspedaal moet geven net voor het koppelen, maar ik vond nog niet wat best werkt. Ik weet ook niet of het vanzelf zou verdwijnen als de motor wat is ingewerkt, of ik het spontaan onbewust leer vermijden, maar voorlopig is dat zo wat het enige wat me opvalt aan de wagen. Dat en dat ik goed het hoofd er bij hou om van die groene tuiten te nemen bij het tanken, niet meer die dikke zwarte. Zelfs die vind ik beter ruiken dan vroeger...
2017-09-07 11:00 fromthetrenches [permalink]
Here's another nice story 'from the trenches'. Packaging stations use a barcode scanner to scan the barcode on the items that need packaging. We were able to buy a batch of really good barcode scanners, second hand, but newer and better than those that we had. A notice came in from an operator: "with this new scanner, we get the wrong packaging material proposal." The software we wrote for the packaging stations, would check the database for the item which is the best suitable packaging material to package it in. It's a fairly complicated bit of logic that used the order and product details, linked to the warehouse stockkeeping and knows about the several exceptions required by postal services of the different destination countries.
So I checked the configuration of this station first. Always try to reproduce first: the problem could go away by itself, or exist 'between the user and the keyboard', or worse only happen intermittent depending on something yet unknown... Sure enough, product '30cm wide' would get a packaging proposal of the '40cm box' which is incorrect since it fits the '30cm box'. Strange. The station had the 'require operator packaging material choice confirmation' flag set to 1, so I checked with 0 and sure enough, it proposed the '30cm box' (with on-screen display, without operator confirm, just as the flag says)...
So into the code. Hauling the order-data and product-data from the live DB into the dev DB (I still thank the day I thought of this tool to reliably transport a single order between DB's). Opening the source-code for the packaging software, starting the debugger while processing the order, and... nothing. Nicely proposing the '30cm box' every time, with any permutation of the different flags (and there are a few, so a lot of combinations...)
Strange. Very strange. Going over things again and again, checking with other orders and other products, nothing. I declared the issue 'non-reproducable' an flagged it 'need more feedback', not really knowing of any would come from anywhere.
A short while later, a new notice from the same station: "since your last intervention, scanned codes concatenate". What, huh? I probably forgot to switch the 'require operator packaging material choice confirmation' back to 1, but how could that cause codes to concatenate? I went to have a look, and indeed, when a barcode is scanned (the device emulates keyboard signals for the digits and a press of 'Enter') the input-box would select-all, so the number is displayed, and would get overwritten by the next input. This station didn't. The caret was behind the numbers, and the next scan would indeed concatenate the next code into the input field.
Strange. Very strange. Into to the code first: there's a SelectAll call, but what could be wrong with that? And how to reproduce? What I did was write a small tool that displayed the exact incoming data from the keyboard, since it's apparently all about this scanner. Sure enough, the input was: a series of digits (those from the barcode), an 'Enter', and 'Arrow Down'. A-ha! These were second hand scanners, remember? God knows what these scanners were used for before, but if having the scanner send an extra 'arrow down' after each code, is the kludge it takes to solve some mystery problem in software out of your control, than that is what a fellow support engineer has to do... Got to have some sympathy for that. And the '40cm box' was indeed just below the '30cm box' in the list, so the arrow down would land in the packaging material selection dialog, causing the initial issue.
Download the manual for the scanners, scan the 'reset all suffixes to "CR"' configuration code, done.
(Update: got some nice comments on reddit)
HTML: label, no more "for" for me!
2017-04-13 22:44 htmllabelfor [permalink]
If only I had known sooner! I forgot where I picked this up, but apparently if you put <label>
around an <input>
, typically of type checkbox
or radio
, browsers automatically know the label is for that control. Before, I would write my <input id="x">
first, then a <label for="x">
after. To keep code neat, I would put it on a separate line, but the EOL inbetween would not be clickable to actuate the control. This is a really minor issue, but still. Now that I know you can just write this:
<label><input type="checkbox" name="Toggle1" value="1" checked="1" /> Toggle1: clicking text after a checkbox should toggle the checkbox!</label>
Because, there are two kinds of people: those that click the box to switch a checkbox, and those that click the text right of the checbox. You might not even know that you do, but you do don't you. If you're of the latter type, it's just one of those minor frustrations, that a click on the text-label sometimes doesn't do what you expect, and you have to:
But there you have it. Heaven has great UX. Here we need to make do with what we get. (And need to make sure it's the way we like it for those bits that we have control over.)
2017-03-24 21:57 boxer [permalink]
Drats. I thought I'll try something like Clover does, start with SetParent on any top-level window you could find with GetAncestor(GetForegroundWindow,GA_ROOT)
and see what it gives. There's this old default MDI child mechanic that starts working, so I thought this might just work. But it looks like over at Microsoft the Windows 10 team decided to cut some corners. The theming doesn't do it's modern stuff and reverts to Vista-style borders, and the newfangled calulator, for example, won't even take the SetParent nicely any more. Oh well. For the time I'm still on Windows 7 at work, I guess it'll come in handy there for the time being. Probably in about a week I'll know if this could work where other desktop-management tools failed or were too cumbersome or too invasive...
How does it work? Boxer starts with an empty window, and will show an icon over the top-right corner of other windows. Click that to 'box' the window. The top bar shows a tab for each boxed window. Right-click to open a menu with options to unbox or close, and drag to reorder. Multiple instances play nice with each-other and show 'boxing handles' next to eachother, the second instance labeled "A", the third "B", etc. To disable the boxing handles, right-click on the top bar to the right of all tabs.
Anyway, if you feel like having a try if you can do better, have a look at the code here. Download a binary here: Boxer.zip (209KB)
A story about two task-keeping-applications.
2017-03-18 17:22 s2tka [permalink]
Let me tell you a story of two task-keeping-applications. Once there was a team that was struggling to keep track of the work it was doing, had done, and still had to do. It was frustrating to work on the team, hard to schedule things, almost impossible to estimate when things where going to get done. And since clients are what they are, changing requirements and additional requests would cause much more disruption than expected of a team that calmly and firmly is determined to deliver the best of market solution.
An internal brainstorming-session about what to do about it, ended in two opposing visions about what decent issue-tracking should be about, and how a system that (co-!)operates with the team members should be structured internally, should behave, and which duties it should perform either by itself, or by effect of using its rules and restrictions correctly as designed.
In an attempt to get to the best solution, two teams were formed to develop each a project based on one of the two views. An evaluation would follow determining a winner, or if would it be possible to synergize the best parts of both into a single system.
A side note: from a managerial point of view this is a very tough decision. Allocating a lot of resources to work on internal structure, takes resources away of the work that brings in revenue, and such undertakings typically risk getting frivolous or spinning out of control. But I guess it's normal that all stop rowing to help keep the boat from sinking. So, apart from being intrinsically aware of the exceptionality of this opportunity, coordinators were given instructions to keep to a strict schedule in these projects and a determined focus on delivering a workable proof-of-concept quick. Sounds like a good work-ethic to apply generally, if you ask me.
A few weeks later progress was made, and the prototypes were already being used to keep track of the issues of these new task-keeping-applications and other projects. The main difference between design visions became apparent soon enough.
One application centered around the list of work items. Care was taken the entry form was extensive enough to have fields for all of the details about a work item, its categorization, its relation to the project, an outline of the projected outcome. An overview would show the current list, possibly filtered for those items assigned to you.
The other application was centered around getting information out of the system, especially structure and relation between items. Users would enter small specific reports, and add them to the best suitable node in a tree-structure, optionally marking relations with other items over branches. The overview showed an expandable structure starting at the root items. It also could have a filter applied, but would potentially show you an entirely different structure of the same data, when using a different relation type.
Having two working prototypes, attention gradually reverted back to the serious work and some of the frustrations of before were abated. After a few months an evaluation was undertaken.
One application had rendered itself useless. The first weeks of usage, a lot of entry happened, but without consensus about categorization, the list was enormous without a clear way of grouping relevant items. Duplicate entries and ambiguous task-descriptions were unresolved, causing confusion.
The other application was doing better. It needed work, but offered a good view of what had to get done.
Enough about the story. Reality, of course, is much more bleak. As no sane manager would make such a shift in resources of a troubled organization, the 'two teams' actually stand for the existing team using an off-the-shelf something badly administered on one side, and on the other side, well, just me, toiling on something potentially better, in my off-time.
I started — like many — with a plain text-file, then a spreadsheet. Then I took the step to design a database for it, but wanted something to do entry and retrieval with roughly the same ease-of-use that a spreadsheet would offer. Working with tree-structures for some other projects, I wanted a single structure to serve as the basis to store data in. Specifically with projects and tasks — as projects tend to have sub-projects, and tasks split into sub-tasks — using branches of a tree would enable to keep this distinction conveniently vague. If you add representation for entities like users and clients into this tree-structure, and relation between nodes over branches, you've got a richness to model much more of the world, and keep track of its changes, past and future.
From there it grew slowly, over years, into what it is now: tx. First versions suffered a notoriously bad interface, but I hope that has improved. For long I was its only user, but some cooperation features have been added since. What's left for me is to keep improving tx where possible, and demonstrating it to people what it's about.
Though entry and structure is important, where a task-keeping-system can really shine is helping to keep an overview. A cleverly designed filter can limit your view to exactly these items that are relevant to you, but in tx you get the additional option of having these items display with exactly those sections of the tree-structure they have in common. Also, I personally feel the most important items on any list, as long as it may be, should be on top. So when tx displays a list of items, they get ordered using their weight, determined by a combination of factors such as task-type and current status. As a task progresses from an active state to a final state, it may move down the list or even fade from view into an archival state.
And there's much, much more I could talk about, but it's all created out of necessity and designed adhering closely to a central vision of what a task-keeping-system should be and what it should be doing for you in order to be able to depend on it.
In conclusion, and for those people that — like me — skip long stories to the last paragraph, it's so very important that information systems succeed at keeping an up-to-date model of reality, and offer you the freedom and easy to update it's view of the world. Especially so with task-keeping software you depend on to keep track of the progress you make with projects, and to help stay on top of what's important. All of that served as the basis for developing tx.
2016-12-16 21:15 i1459bis [permalink]
I just noticed these went missing since I converted this website to a 'static blog' kind of thing. So I delved up the old backups and fetched these back from the old mdb, and put them up here.
The order is an order is an order.
2016-09-02 15:19 anorder [permalink]
Then there was the day I decided to redesign. I had a hard time explaining. Not only why I thought a redesign was needed, but what is was exactly that I would do differently in this new design.
There would be a small distance between the data of the orders and the rest. The design would center around the idea that an order is exactly just and only that, an order. A request from a customer to have us do something. The distince between order-data and the rest wouldn't be large, it would more be something like a conceptual demarkation. In practice the order-data would be insert-only. A new order is registered, and after that read-only. This is easily explained to you, but caused shockwaves over the entrenched toilers of the company.
So to get closer to the common root of a great number of small problems, I started a design with just this, drawing up a model of reality where this is the first fact to note: the fact that an order comes in. When, by whom and for what. Not that the order is accepted. Not if it is payed for or not. Not if it's covered by customer credit or not. Not that it's cancelled or completed. Register different facts in different tables. Back to the books. Back to the 16th century penwright toiling in candlelit accounting books.
I sometimes joked that serious companies would require a stamp and signature to transfer this or that between departments. And silently I hope some still do. And even if none are left, it's up to us to see the romance in it. It's man-made structure to guide a man-made process, but it's structure and process none the less. Things break down swiftly when those go.
2015-11-24 11:04 typesofinformation [permalink]
I |
---|
Life would be good if all we had was information. If only we could get all the information. We can't handle that much information, so we build systems to handle the information for us. Strange things happen when information comes in. Good systems are designed to handle these well. In designing information processing systems, you have to cater for the following.
U | R |
D | I |
---|
Some input signals contain no information. They are either damaged in transport, incomplete, or not of a correct form for the system to handle. Either report them to find out if repair is possible, or keep count of them to be able to report about the health of the system.
Some input signals come in twice, and contain the same information. Or do they? If possible try to have the last step in the chain report if an event did take place twice, or if it's an echo on the line. Sometimes a clerk does drop a pack of cards and enters them again just to be sure. Be ready to take only the new cards.
Some information is wrong. Us humans do make mistakes. The system sometimes doesn't know. It processes a signal, of the correct form, holding valid information. Then again, the fact that some information already in the system may be incorrect is also information.
Don't expect to get all information. There is always more.
uu | uk |
ku | U R D I |
More input is coming in. Sometimes we know how much input is still waiting to come in. We'll roughly know how much information there'll be added. In most cases it follows a measurable trend. In some cases it follows the business.
Information processing is one thing, but does it deliver the required new information? Is there more to mine out of the amassment? Sometimes the numbers can show what you need to know, but do you know where to look?
It's hard to design for things we don't know we don't know (yet). But it serves to be prepared. New things have a knack for looking a lot like something we have already. Sometimes they deserve a new module, sometime just a new category, but don't forget to put the existing items in a category also.
https://en.wikipedia.org/wiki/There_are_known_knowns
GMail: make the labels menu larger
2015-10-22 09:36 GMailLargerLabelsMenu [permalink]
When you don't like it: adapt it.
At work we've been switched to Google Mail for some time now, and to make sense of the mayhem that is the incoming torrent of e-mail, I've been using an extensive set of labels and sub-labels with nice colours and stuff.*
But the list of labels on the pop-up-menu if the 'move' and 'label' buttons is so small, only showing the first few labels, and I had to scroll most of the time.
Is there way to adapt this? It turns out there is. At first I read about user stylesheets, but these got removed from Google Chrome, but there's an extension that does the same: Stylus
Install this, and for URL's that start with "https://mail.google.com/mail/
", add this:
.aX1 {
max-height: 780px;
top: 92px !important;
}
.aX2 {
max-height: 780px;
top: 92px !important;
}
.aX1 .aXjCH {
max-height: 600px;
}
.aX2 .aXjCH {
max-height: 600px;
}
*: Extra tip: I was searching for something nice to prefix the label-names with that would cause them to get storted (alphabetically) at the end. In theory you could use "zzz " as prefix, but that's ugly. And assumes you'll never have an account named "zzz".
After a bit of searching around the unicode spec, I stumbled upon Bopomofo, so now i use ㄍ and ㄑ which apparently sort past 'z' and look pretty nice.
2015-10-16 22:24 tx [permalink]
tx started as a tool to keep track of things. From there it evolved into a new take on data, categorisation, oversight, structure, registration, evaluation...
To complete the configuration, set up a multi-user environment or tweak the project to your needs, it's advised to install and build from the source code.
To get started quickly with default configurations, download and install this easy installer. It has tx and xxm combined into a single executable (that conveniently launches the URL in the default browser at start-up), and a minimal database to get you started. Read more about configuring tx here.
Update: now also available as an NT-service. Installs to serve on HTTP port 80 by default, add argument Port=
to the service command line in the registry to configure an other port number.
The ongoing search for the best suitable font.
2014-10-03 18:50 i3078 [permalink]
There is something mesmerizingly strange about the font “PT Sans” (and “PT Sans Serif” and “PT Mono” for that matter, but in this specific case it’s about “PT Sans”).
For something at work I was looking for a font to use throughout a set of applications and a web-site to tie them together and set them apart from all of the other day-to-day work that people at work do. Therefore this font has a lot of requirements to conform to:
I have tested a large number of fonts for all of these. Some are too wide, some too narrow, some too ugly, some too frivolous. Some are bad at the default screen size. Some are too much just another Helvetica clone. A few were only missing a bold or italic version. I know what I’m asking for is a lot, but fonts that get close are generally of a certain age, further along than version ‘1.0’. It takes a lot of work to make a font, and a lot more of work to make a good font. It shows when the font has gotten a lot of care and attention.
From time to time I search the web for other fonts and go through a procedure to test them: make the website use the font, watch a number of pages with lists and common operations to see what they look like. If I like that, put the font up in an application and see if that looks good. Then run the application on the oldest workstation to see what it looks like.
I like to read about the story behind a font. Who made it, why was it made, what was it originally used for. (How come it’s made free for use?) There is so much there.
For now “PT Sans” is about the only font that fits all of my wishes the best. This is the strange thing about it. It appears to be made specifically for Cyrillic script, but the Latin are really good as well. It’s well balanced, does digits well, renders on screen resolution good. So by that logic there must have been a very large amount of work put into it. Based on a very rich set of knowledge on the subject. But I don’t find any record of that, or don’t know where to look for it.
But that’s it. The last few searches have not resulted in a better fit to my needs than “PT Sans”. The project is in development still, but is using “PT Sans” throughout. It’s looking great. Helping its little bit to make a splendid first impression to everyone I’ve demoed to up till now.
And look at that capital Q. Look at it.
How to turn on automatic logon in Windows XP
2010-02-18 08:28 i2872 [permalink]
Als ik deze nodig heb kan ik die natuurlijk nooit onthouden! Tijd om die hier toe te voegen dus:
Start+R (run) en dan: "control userpasswords2"
http://support.microsoft.com/kb/315231
2009-11-26 00:10 i2788 [permalink]
Er staat eigenlijk nog een hele hoop over TPS op wikipedia!
(ik lees trouwens verontrustende dingen over wikipedia...)