Beeminder Forum

Announcing Trak, an alternative to TagTime

Hi everyone,

Just wanted to announce my alternative TagTime implementation that I call Trak!

You can download it here:

Trak is a (currently Mac-only) GUI implementation of TagTime, which I hope will make stochastic time tracking a lot more user friendly.

At this time, Trak looks kind of like this:

When you need to enter a data point, Trak will make your screen flash white (by default), which should make it both really obvious and unintrusive that you need to enter data.

Entering data can be done efficiently using a keyboard shortcut (by default Option+Space, but you can also change that), and Trak will even show you suggestions as you typed based on your previous activity.

As much as I think using Trak should be a great experience for TagTime users, it is currently very experimental (for all I know it might not even start properly on your computer), so please let me know if you have any feedback or questions, either on this thread or through the feedback form in Trak itself.

Hope you guys like it!

PS: Apologies for the fact that the dmg is quite big. I will try to make it smaller in the future, but this is unfortunately due to important libraries that I am using, such as PySide.

PPS: Trak might take a while to start initially, give it a second before giving up.


Excited to try this!

But it won’t open for me:

Something about PySide i guess:

16.03.06 Sun 3:05:21.678 PM _main[46266]:   Referenced from: /Volumes/Trak/
16.03.06 Sun 3:05:21.678 PM _main[46266]:   Reason: image not found

Thanks, just the type of thing I was afraid of :stuck_out_tongue: . I’ll try to look into this.

Ok I just pushed a version that I think will work (same link as before). Looks like it was due to this py2app bug:

Hopefully the hacky workaround I used will do the trick (I double checked with dtruss and I think it should). Let me know if you still can’t run it (especially if the error changed)

Oh, one important thing that I forgot to mention: multiple tags (‘tag1,tag2’) are largely unsupported (though they are high on my priority list) except for the beeminder integration which does split tags on commas.

1 Like

No luck yet. Same popup, with a different error in the console, if I’m copying the right part:

Aaaaaah, dependency hell!

Ok I think I fixed this one too. Just tried on another macbook than my own (something I should have done a while ago) and it seemed to run properly. Can you try now (same link as before)?

Thanks for your help and your patience!

1 Like

It runs! And it’s incessantly saying “what are you doing? – 1 entries to log” but I don’t see a way to enter anything.

Alright, good. It’s saying 1, not -1, right (if it’s showing a negative number that’s certainly a problem)?

You can enter things either by clicking on the empty entry in the main ui (a text box will appear), or by pressing the global shortcut, which will show an edit dialog (see settings, by default it should be option+space - note that it might conflict with software like Alfred if they are set up with the same shortcut, so this is definitely a setting you should look at).

Anyway, feedback taken: should be more intuitive how to edit things in the beginning, and maybe should show that notification less aggressively.

1 Like

Right, not negative 1. :slight_smile:

Ok, it’s looking good now. Not sure why I couldn’t get the edit dialog to appear before.

Any chance of getting this on the universal ping schedule? It will be really hard for me to transition to this no matter how good it gets if I can’t use both simultaneously for a while.

1 Like

What’s this?

Here’s the reference implementation!

UPDATE: I moved this here:

For posterity, here's the Perl version

First define some constants:

my $IA = 16807;          # constant used for RNG (see p37 of Simulation by Ross)
my $IM = 2147483647;     # constant used for RNG (2^31-1)
my $URPING = 1184083200; # ur-ping, ie, the birth of timepie/tagtime!

# $seed is a global variable that is really the state of the RNG
$seed = $initseed = 666;

$gap = 45*60; # 45 minutes between pings on average

And some helper functions:

# Return a random integer in [1,$IM-1]; changes $seed, ie, RNG state
# (This is ran0 from Numerical Recipes and has a period of ~2 billion)
sub ran0 { return $seed = $IA*$seed % $IM; }

# Return a U(0,1) random number
sub ran01 { return ran0()/$IM; }

# Return random number drawn from an exponential distribution with mean $gap
sub exprand { return -1 * $gap * log(ran01()); }

# Round to nearest integer
sub round1 { my($x) = @_; return int($x + .5 * ($x <=> 0)); }

Then define a function prevping that takes the current unixtime and returns the unixtime of the previous ping according to the universal ping schedule. Once you have that you can keep calling nextping() with the timestamp of the last ping to get the time of the next ping.

# Take previous ping time, return random next ping time (unixtime)
# NB: this has the side effect of changing the RNG state ($seed)
#     and so should only be called once per next ping to calculate,
#     after calling prevping.
sub nextping { my($prev)=@_; return max($prev+1,round1($prev+exprand())); }

# Compute the last scheduled ping time before time t
sub prevping {
  my($t) = @_;
  $seed = $initseed;
  # Starting at the beginning of time, walk forward computing next pings
  # until the next ping is >= t.
  my $nxtping = $URPING;
  my $lstping = $nxtping;
  my $lstseed = $seed;
  while($nxtping < $t) {
    $lstping = $nxtping;
    $lstseed = $seed;
    $nxtping = nextping($nxtping);
  $seed = $lstseed;
  return $lstping;

For posterity, a totally different approach for a different universal ping schedule

Alice Monday (@alice) and I came up with this together but we’ve never actually used this.

The advantage of this version is you could throw away all the fancy math and it would make sense to anyone how and why it works. The disadvantage is it’s more computationally intensive. Also it requires picking a kind of arbitrary parameter for the granularity – how far apart pings in principle can be. I’d suggest .125 seconds since that’s a safe lower bound on human reaction time. (I think the only way this matters is if you want unbiased data on how much time you spend answering TagTime pings.)

Also let’s call an eighth of a second an octant even though that’s sort of an abuse of terminology. We can get the current unixtime measured in octants by multiplying normal unixtime by 8. Or if you get unixtime in milliseconds, multiply it by 8/1000.

On to this alternate algorithm for a different universal ping schedule:

Every single unixtime (in octants) either has a ping or not. The probability of a ping is just 1/(45*60*8) — the denominator being the number of octants in 45 minutes. To make it universal you use the unixtime itself as the seed for the RNG for deciding if that octant has a ping. So, using the ran0 function above, unixtime t has a ping if:

IA * t % IM / IM < 1/(45*60*8)


16807 * t % 2147483647 < 99421

So you can start computing it at any time without worrying about history at all. Of course you don’t want to be running a loop doing a calculation 8 times per second so you walk forward, checking each unixtime (measured in octants) with the above inequality till you find the next one a ping will happen at (on average that means checking the inequality 21,600 times) and just sleep till then.

On reflection, I think it’s inferior to the mathy approach. For one thing, I don’t know if feeding very similar seeds to the RNG spoils it. Seems like it might.

PS: The current universal ping schedule artificially pushes pings forward to ensure that they’re always at least 1 second apart. So probably this version could just do seconds instead of eighths of seconds. Which maybe makes it computationally no big deal. Question remains about whether similar seeds spoils the RNG.

UPDATE: Similar seeds totally does spoil the RNG so forget the idea of using current unixtime as the seed. We could salvage this approach by starting at the dawn of (tag)time and walking forward. We’d only have to do that once when first launching the app.

1 Like

Hmm, yeah I think I could implement this for Trak. Would probably make it easier to port to other platforms too if I switch over to this.

Probably won’t be until a few days from now though, fairly busy at the moment.


hey! did you implement the universal ping schedule?

also, I’m wondering if this will be put on GitHub or anywhere? I’m very interested in using this app

1 Like

Hey – I’ve downloaded this to give it a try, nice work :slight_smile:

Is there a log file for this that can be used here: ?

1 Like

Am I the only one who find this “joke” unfunny (and in fact, extremely offensive)?

Oh no, let’s just change it. I don’t want TagTime inadvertently taking any stances on any political or religious questions!

And it turns out we can change it without changing the universal ping schedule. Just need to pick a seed and ur-ping that are part of the original schedule. Possibilities:

  1. URPING = 1184097393 (~2007), SEED = 11193462
  2. URPING = 1234180122 (~2009), SEED = 85014
  3. URPING = 1443641796 (~2015), SEED = 26506
  4. URPING = 1532992625 (~2018), SEED = 75570

I’ll pick something and change the reference implementation.

Not sure whether keeping the “universal ping schedule” is really worth it - it might be even better to make the seed dependent on time the computer is on or something like that. It probably doesn’t matter much from the usability point of view.

FWIW, this stupid (sorry, just being honest…) joke was the sole reason I stopped using TagTime (which I find a brilliant idea otherwise, and I also implemented something like this in my half-baked rescue-time Emacs-clone (still WiP, not published).

And done!

I also changed it in the Perl implementation.