« first day (532 days earlier)      last day (917 days later) » 

12:36 AM
Okay, so we have a simple working Tetris program (pending a test on the real computer). What should we do now?
 
Golf the program down? Use less RAM?
 
I guess we need to decide, if this program (after golfing) will be what we post. And if we want to finish up some other things (compiler, LLVM, etc.) before posting.
There might be some stuff I can do to cut down on RAM usage.
Not much though
 
1:26 AM
@StepHen hello!
 
hey :)
how expensive will it be to render the GoL behind Tetris, if you are even going to?
 
we don't know yet
 
@StepHen pretty expensive
 
@PhiNotPi good answer
 
But if I'm correct (almost certainly not) we can cut it down by a few orders of magnitude
 
1:31 AM
@KZhang were you able to expand RAM? Also how does RAM compare to ROM in density?
Eyeballing it gives each RAM slot 2x the width of one ROM slot.
 
I'm kinda redesinging the RAM a slight bit. Each RAM bit is 22x22 metapixels, and each ROM bit is 11x11 metapixels
 
oh hey look
Jun 9 '16 at 2:54, by El'endia Starman
I think we'll have a full solution within the month.
 
lol yeah somebody pointed that out earlier
 
-_- Suffice to say that this turned out to be a lot harder than anticipated.
 
@PhiNotPi lol it was me
 
1:37 AM
@El'endiaStarman I would say that it just requires having a lot of people in one chat room at one time.
Having a project so deep down a rabbit hole has the side effect of making all the team members practically irreplaceable.
 
1:50 AM
Golfing assembly basically requires anti-golfing the Cogol source.
 
@PhiNotPi is the assembly "one to one" with GoL?
 
@StepHen yes, each line of assembly is a column of ROM in the computer
 
did you golf the computer? :P
 
Nope, not really.
TIL I have type warnings in Cogol. I forgot adding those.
 
2:09 AM
@KZhang I was actually able to reduce RAM usage by almost half.
The assembly code has been updated on github.
 
Nice!
 
2:32 AM
current best version has 446 instructions, and uses 81 RAM slots
 
 
5 hours later…
8:02 AM
@PhiNotPi I think at this point, the hard work has mostly been done.
I think we'll have a full solution within the month.
6
 
Anonymous
@wizzwizz4 Starring this for when it is inevitably incorrect :P
 
That's assuming the LLVM backend is published soon so that others can work on it.
We have a working computer, which is the hard part.
All we need now is some assembly programmers or a LLVM backend and some C programmers.
 
Anonymous
I can definitely write Tetris in C if quartara manages to get the LLVM backend working
 
Meanwhile, I would try to help with optimisation of the LLVM backend so that the RAM doesn't have to be expanded again.
 
Anonymous
In fact, we could probably take one of the many Tetris implementations already in C and just use that (with minor changes to accompany the fact that we won't have ncurses)
 
8:12 AM
@Mego And once that works, optimise it in LLVM except for glaring algorithm issues.
 
Anonymous
Even better: write Tetris in Cython so that another couple of languages can be tossed on the stack of languages we've used :P
 
@Mego Write it in BASIC.
BASIC -> BF -> lots of esolangs -> CPython -> C
 
Anonymous
@wizzwizz4 What esolangs support BF -> ? -> Python?
 
Anonymous
I meant compilation/transpilation, not interpreting
 
Anonymous
Trying to layer a few interpreters on top of our creation will cause the whole thing to topple :P
 
@Mego Well, there's transpilation from BASIC -> BF -> movfuscator -> assembly
You could then use a transpiler to get it into a simulator, which you then compile via LLVM into QFTASM.
 
Anonymous
@wizzwizz4 movfuscator doesn't work
 
@Mego Really?
It compiles to a different architecture, but that's not a very big problem.
 
Anonymous
8:50 AM
I've tried movfuscator on many different programs, and it always fails
 
9:35 AM
@Mego O_o really?
@Mego just use dennis style bf transpilation
 
10:04 AM
@Mego Are you sure you're using the right CPU?
 
Anonymous
10:43 AM
@wizzwizz4 That's not even the problem. The movfuscator program itself fails.
 
@Mego Did you have the required prerequisites?
 
Anonymous
11:04 AM
@wizzwizz4 This really isn't the right place to be trying to debug it. And yes, I did.
 
@Mego Ok.
 
 
2 hours later…
12:56 PM
@wizzwizz4 So are people wanting to finish LLVM and write Tetris in C, vs. writing Tetris as I've done so far?
 
@PhiNotPi Yes.
 
@PhiNotPi if you've already done it, just post it and let them do what they want :P
 
If you've made a working one, that's great.
We would probably use that instead.
The most important thing is to get a full solution within the month.
 
@wizzwizz4 I mean, a working Tetris game is linked on the starboard.
 
@PhiNotPi post it before someone else does then :P
 
12:58 PM
@PhiNotPi I thought that was the semi-working one.
The one without interactivity.
 
This one is interactive, has preview pieces, line clears, and scoring.
 
@PhiNotPi what exactly are you waiting for? more golfing?
 
@StepHen For the team to decide if this is the thing we want to post.
 
1:12 PM
@Mego @muddyfish @El'endiaStarman @everyoneelse So, this project currently has a few loose ends: an unfinished compiler (well, two of them if you count Cogol), and an unfinished LLVM port, and maybe some other things. Given that we have a basic functional Tetris game (pending a run on the real computer), what do we want to finish up before we post our solution?
Do people want to re-write Tetris in a different language?
Are there any other changes we should make to the computer before it is "finalized"? (@KZhang is currently redoing some parts of RAM)
And then, when we decide to post our solution, we need to decide what content (out of all the hardware/software stuff we've done over the past 1.5 years) will be included in our answer(s).
 
Anonymous
1:32 PM
@PhiNotPi The only really big thing I think we're missing is a VarLife -> GoL compiler. I'd be happy to work on that. With that, we can have an actual GoL solution (though it would have to be zoomed out to the VarLife level to make sense). Other than that, finishing the blog with the current status of the project would be a good idea, as then we could post a summary of the pieces as an answer to comply with the post limit, and point to the blog as a source of more information.
 
@Mego If you could work on that it would be appreciated.
 
Anonymous
@PhiNotPi I would be glad to do so. With that final piece, this project will be a success. However, I think it's still a good idea to continue to work on the LLVM backend, so that we can make even more insane creations in GoL more easily, with a timeline of less than a year and a half :P
 
@Mego I would recommend you directly create a gz stream compatible with Golly.
Otherwise you'll end up with a "your 250TB drive is full, 0% complete" message.
 
250 TB? what for?
 
Anonymous
1:58 PM
@wizzwizz4 That's the intention. I primarily just need to grok how the OTCA metapixel works.
 
@Mego There's a very small difference between metapixels of different rules (just a couple of 2x2 blocks), and then you need the dead/alive versions of each.
 
Anonymous
2:25 PM
Ah I see, you place Eater-1s in registers to set the rules
 
threw together a quick blog post mainly to say that the blog isn't dead: blog.phinotpi.com/2017/08/03/a-return-from-the-brink
 
Anonymous
I'm a bit glad that the circuit simulator ended up being unnecessary. It would've been a pain to get it working.
 
yeah
 
Anonymous
2:41 PM
So here's the thing... Apparently, since Golly 1.1, a Python script called metafier.py has shipped that converts patterns to OTCA grids
 
The issue with metafier is that it can't handle the mixing of rules
 
Anonymous
Yep, but it shouldn't be too hard to hack to handle that
 
Anonymous
2:54 PM
@KZhang In your computer file for Golly, which rules do each of the states encode?
 
Anonymous
Obviously 0 is B/S, and I recognize 2 and 4 as being B1/S and B2/S from earlier work, but the rest I have no clue about, being unable to decipher the rule file
 
@Mego You can see the rule specs in VarLife (see room description). Black is B/S, blue is B1/S, green is B2/S, and red is B12/S1.
 
Anonymous
Ohh the other states are the alive versions
 
How can random numbers be generated?
 
Implementing an RNG?
 
3:07 PM
yeah
 
@muddyfish I have a PRNG in my Tetris version
Also it uses player input (moves) to help scramble the numbers.
 
I'm assuming we'd be looking at the state of the button inputs each frame and seeding the RNG with it?
@PhiNotPi You have the COGOL source?
 
I could make it were a player supplies a seed at the start of the game. Right now the first two pieces are always the same (since no player moves are made yet).
yes
 
I'll take a look
 
do prng {
    shifted = rand << 1;
    rand ^= shifted;
    shifted = rand >>> 5;
    rand ^= shifted;
    shifted = rand << 2;
    rand ^= shifted;
    randval = rand & 7;
} while (randval < 1);
 
3:10 PM
@PhiNotPi How do you input moves?
 
And the pieces are injected at the same position at the top?
 
Here, "rand" holds the random seed, "shifted" is just a temp variable, and "randval" is which tetris piece to pick.
 
I guess I'll have to look up what shapes the pieces are at some point :D
 
@El'endiaStarman Input is by manually changing a bit in RAM address 1. A value of 0 = no move, 1 = counterclockwise, 2 = left, 4 = down (soft drop), 8 = right, 16 = clockwise.
Address 1 is automatically set to zero again after each move.
 
@mego blue/cyan: B1/S; green/yellow: B2/S; red/orange: B12/S1
 
3:15 PM
Oh man, I can't believe I'm playing Tetris.
 
@muddyfish yes
 
It's kind of amazing we're thinking about actually programming Tetris now
 
Rotation is slightly fudged from what real tetris is like, here all pieces rotate around one of their four blocks, in normal tetris certain pieces rotate in off-center ways.
But fixing that would actually take quite a bit of new code.
 
@Mego
    B/S B1/S B2/S B12/S1
Off  0    2    4    6
On   1    3    5    7
 
Xorshift random number generators are a class of pseudorandom number generators that were discovered by George Marsaglia. Specifically, they are a subset of linear-feedback shift registers (LFSRs) which allow a particularly efficient implementation without using excessively sparse polynomials. They generate the next number in their sequence by repeatedly taking the exclusive or of a number with a bit-shifted version of itself. This makes them extremely fast on modern computer architectures. Like all LFSRs, the parameters have to be chosen very carefully in order to achieve a long period. Xorshift...
^ the PRNG algorithm I use
 
Anonymous
3:25 PM
@KZhang Thanks, I think I have a modified metafier.py working - just need to test it
 
@PhiNotPi: Man, that was tough. Where can I see my score?
 
the top line is a binary display of your score
 
@El'endiaStarman ram address 3
(3-32 is the display)
Here's how scores are calculated (basically the next-simplest thing after 1 point per line): the number of points is determined by the number of lines you clear with a single piece. 0 -> 0, 1 -> 1, 2 -> 2, 3 -> 4, 4 -> 8
 
Ah, score of 4 for me.
Also, I just noticed that the display is mirrored with respect to the actual RAM. Not sure why though.
 
Gives people bonus for multi-line clears.
@El'endiaStarman For me at least it sometimes has been. Recently it hasn't been mirrored.
 
3:30 PM
The actual RAM/computer can be rotated if necessary
 
I don't have the computer in front of me, but which direction of RAM is higher addresses, and which side of RAM has the higher/lower bits within a number?
 
Anonymous
A test of the modified metafier script on a wire worked well. Now to run it on the entire computer...
 
@Mego Maybe start with just the prime finder?
 
Anonymous
@KZhang I'm running it on the uninitialized computer
 
I would think that doing it on the prime finder would be easier to test for bugs
 
Anonymous
3:34 PM
If that goes well, then I'll run it on the prime finder
 
Anonymous
@KZhang Right now I just want to make sure it can convert large structures accurately, before I try running any programs
 
@PhiNotPi The RAM's higher addresses are towards the right, and the lower bits of RAM are towards the top. This can be changed just by rotating/flipping the whole computer.
 
Anonymous
Oh crap I'm going to run out of RAM before it finishes converting this
 
Anonymous
Yeah nowhere even close to enough RAM
 
@Mego how much we talking?
 
3:41 PM
@PhiNotPi I've seen a glitch twice where rotating the I piece makes it diagonal.
Also, I think the RAM display is mirrored or not depending on whether you initialized the display before or after running the program, oddly enough.
 
@El'endiaStarman uhh... I haven't seen that. Can you describe what you're doing?
 
Anonymous
@PhiNotPi I was about 10 lines in, and it was using 3 gigs
 
@PhiNotPi I dunno exactly how to trigger it. I just tried to rotate it with 1, and maybe I input it at a bad time?
 
if you guys could manage to host a website to play GoL tetris on you could get rich off the ad money, especially if this goes viral
 
I have two problems with that: 1) an actual implementation of Tetris in GoL would take ages to run, and 2) I hate ads.
 
3:44 PM
I like money though....
 
@El'endiaStarman I'd click on them
 
Anonymous
Better idea: make it like an arcade - you have to pay a quarter per play
 
@Mego but then you have to get credit card info or whatnot
 
@El'endiaStarman does a diagonal I fall and lock in place?
 
Anonymous
Yet another layer of abstraction
 
3:45 PM
@PhiNotPi Yep.
 
@Mego if you no one can actually play it, you don't have to actually make it
 
user image
3
I haven't seen it happen with other pieces yet.
 
Anonymous
I'm a bit concerned about the sheer size of the resulting GoL pattern
 
Anonymous
A gzip-compressed RLE will still be huge
 
@El'endiaStarman and other pieces can fall on that piece and lock in place as well?
 
3:50 PM
Lemme see.
 
If you find another diagonal I piece falling, please pause the game so I can debug the RAM.
 
Yep, they can lock in place on the diagonal I piece.
 
Soo.... I could see a way that a move is not registered because you managed to enter it between when if tests for a move and when it resets the move.
But I don't see a way something could get diagonal.
 
Five I pieces later and I didn't reproduce the bug. Will try again. (Though I should be working...)
 
I think I found it... you somehow managed to snipe a move within the move-checking code.
 
4:01 PM
@PhiNotPi There are some golfier / faster PRNGs here.
(SEED+1)*75 mod 65537 - 1 was good enough for the ZX Spectrum.
 
@wizzwizz4 I don't think that will beat the 6-instruction generator I have now.
 
@PhiNotPi Those were instructions?
I thought they were lines of COGOL. :-/
 
@wizzwizz4 But in this case each line is only 1 QFTASM instruction (and It's cogol not cobol)
 
@PhiNotPi Ah.
 
@El'endiaStarman fixed the rotation bug with changes pushed to github
Input method remains the same, but use 3-33 as the display lines now (line 33 shows your input as it is being applied)
 
4:12 PM
@PhiNotPi Nice!
 
Anonymous
So while I'm racking my brain for a workaround to the memory issue, I decided to compute how many cells will be present in the compiled GoL pattern - 6330714685440. With each cell taking 1 bit (uncompressed), that's just under 737 GiB.
 
The macrocell file format is actually really good for metapixels
 
@Mego Time to rent a supercomputer.
 
Anonymous
I still have to figure out a way to generate the compiled pattern memory-efficiently
 
Anonymous
@El'endiaStarman Hah I wish
 
Anonymous
4:20 PM
I'm afraid what I might have to do is handroll the RLE compression and save the pattern to disk every line of metapixels
 
Nah, if we do try to do direct file writing, we should try writing in the macrocell file format
 
Anonymous
So the macrocell format is based on Golly's internal compressed representation, yes?
 
It's... interesting. Golly help on the MC format
 
Anonymous
10 lines of metapixels (out of 1324) took up 3.5 GB of ram. Assuming the memory usage is linear, the whole pattern will take around 450 GB.
 
Anonymous
The only way this will be possible is by dumping each line of metapixels as it finishes (or maybe every X lines)
 
4:33 PM
@Mego Sounds like you need the Revolutionary™ Page™ To Disk©â„˘ technology new in Linux® 0.12
 
Anonymous
@quartata Virtual Memory is gross and also my pagefile isn't nearly large enough
 
FWIW I think it's sufficient to know it would work in pure GOL even if it's too big to be run. If people actually want to play it they'll be using VarLife either way
Also if the memory consumption is coming fom the actual grid you need the power of std::vector<bool>
 
Anonymous
4:49 PM
Ran into another problem: QuickLife (the algo normally used in metafier) doesn't support MC format. I changed to HashLife, but I think I might have made a mistake because it's super slow.
 
Anonymous
Let's hope gzipped-RLE won't blow up my hard drive too much
 
Anonymous
Wow, that's coming out a lot smaller than expected - under 3 MB per 5 lines
 
Anonymous
5:04 PM
This should only take a few hours
 
Anonymous
Then I get to concatenate all the RLE stuff
 
Anonymous
hooray
 
Anonymous
And then I get to run it again for each program
 
Anonymous
more hooray
 
Anonymous
Though if this works, I'll upload the script and let someone else's computer grind out the rest
2
 
5:09 PM
@Mego If at first it takes too long: delegate, delegate, delegate.
 
Anonymous
Honestly we're probably ready to post at this point, assuming this script has no issues
 
@Mego You're talking about yourselves in plural?
 
brb putting a 50 rep bounty on it so that people can't put 500s for a week :P
 
Oh, you mean post the answer.
@StepHen Not yet.
 
Anonymous
@wizzwizz4 Yeah the answer
 
Anonymous
5:12 PM
I'll upload the pattern files when I get them all done
 
I thought you meant the script.
And the gzipped files could probably be compressed more.
 
Anonymous
@StepHen Bounties won't do any good, because the answer is going to be CW
 
Anonymous
@wizzwizz4 It should come out to under a GB for all of the gzipped files, so I'm not worried
 
@Mego that's not what I heard last time - @PhiNotPi said you're doing multiple answers
 
Anonymous
@StepHen Oh, I missed that bit
 
5:13 PM
there's no good reason to CW it, it'll be a waste of a ton of rep
 
Anonymous
I guess each participant is going to write up their own answer, explaining their role?
 
if you don't CW you'll set the record for most bounties awarded to one challenge
@Mego I assume so, but I'm uninformed
 
Anonymous
Then it would suck if some answers got more bounties than others
 
@Mego you'll all get so many upvotes it won't really matter
and even if it's uneven it's better than CW
 
Anonymous
Rep cap for years :D
 
5:15 PM
@Mego more like get 200 upvotes in two days and cry
and then it goes viral in a week and it happens again
 
Anonymous
@StepHen Same thing
 
Anonymous
Still, that will get me gold badges I don't have :P
 
Anonymous
I'll go ahead and upload the modified metafier script
 
@muddyfish btw, the modulo thing, it only seems to bork inside an operator function. Inside sub main, it works fine and inside a custom function, like sub modulo, it also works fine
 
Anonymous
5:24 PM
Have fun waiting several hours for Tetris to compile
 
Anonymous
Actually we could run metafier on just the ROMs and then load those into the metafied computer
 
so the metafier, if I understood it correctly, converts OTCA metapixels into B2/S23 GoL pixels?
 
Anonymous
@Cowsquack It converts Varlife pixels into OTCA metapixels
 
Anonymous
It essentially "compiles" Varlife patterns into B2/S23 patterns
 
I have access to some computers with stupid amounts of RAM (I think 3TB RAM is the largest) but I think that might count as abuse of work systems :P
 
5:31 PM
My computer has an SSD which would help with the RLE output stuff
 
Anonymous
If it wasn't for the fact that it is running in Golly, probably
 
Anonymous
But Golly is weird with how it runs Python scripts, so all bets are off
 
Yeah that's the problem
 
Anonymous
It would be much simpler with a standalone GoL simulation library in Python, but Golly is what we've been using
 
so wait what "language" is the final Tetris program going to be in? Or are you using your computer for several different Tetris implementations
 
5:36 PM
We'll probably have a couple
 
@muddyfish If you ask whether you can compile a program that is a world-first, in exchange for your company having access to the source code, they might say yes.
 
But it sounds like the initial one will be just in assembly which makes sense
 
Anonymous
We should write a C compiler in QFTASM :P
 
@Mego isn't that the point of COGOL and what Phi is doing?
 
COGOL isn't C
 
Anonymous
5:38 PM
It has one letter in common, and very little more
 
@quartata oh, I was misinformed then :)
 
@Mego That would be incredibly hard. Anything written using this LLVM backend will need to be freestanding
 
Anonymous
Maybe a 32-bit ARMv7 emulator would be a better goal :P
 
That would be easier probably.
It's not really architecture that's the problem, it's just that we don't really have a format for easy linking
 
Anonymous
Then we can cross-compile all the things
 
Anonymous
5:40 PM
Then we can run Golly within GoL and complete the circle
 
Next project: Linux in GOL
 
Actually I thought this might be a good one: en.wikipedia.org/wiki/List_of_Game_%26_Watch_games#Ball
 
Anonymous
Nah, Pong
 
Oh duh
That's easier than Tetris actually
except for controls
 
Anonymous
A very simple AI and two buttons would do the trick
 
5:43 PM
And then.....Spacewar!?
 
We could make it two player
Like, hot seat
Lame but easier
@El'endiaStarman oh no
oh I can see it now
"GoL SpaceWar KOTH"
 
"Leaderboard to be updated in 3018."
 
Back on topic I've kind of realized a problem here
I have these registers that are really just dedicated addresses
But the problem is that when it's the destination register it needs to be 16 but when it's the source it needs to be A16
 
@quartata I think I can see where this is going.
 
so I need a more sophisticated DAG pattern for load/store
Maybe two kinds of "moves": moving a constant and everything else
let me see what the LLVM IR writes those as
 
5:49 PM
@quartata Cogol is to C what our processor is to an Intel i9.
 
@quartata Could you share what you have so far?
 
Anonymous
Writing file 19 out of 265 :/
 
@quartata By easy linking do you mean relative jumps? (position-independent code)
 
@PhiNotPi Definitely part of the problem
The other problem is that we would need to make a much more sophisticated CreateROM.py which we don't have time for
@wizzwizz4 I'd prefer to wait until it works, now that I know we're probably not using it for Tetris anyways
don't really need to rush it
 
For some discussion of how to build Golly macrocell files efficiently without running out of memory,
 
5:57 PM
@Mego We'd have to sort out how we want to structure it, so that each user can write more-or-less about what they've contributed but to make it so that the overall set of answers has a coherent structure that the audience can follow.
 
@quartata Ok. Just do the bare minimum - I want to help with the optimisation! :-)
 
It needs at least 2 particular optimization passes to be useful (jump threading and branch delay slot elimination)
 
The way metafier.py builds patterns in memory is fine for small fields, but it can be done a different way that will be much less RAM-intensive.
 
@quartata It's possible to do 2-instruction conditional relative jumps.
 
Well yeah by messing with the PC
 
J F
5:59 PM
@wizzwizz4 Just don’t tell them that everyone gets access to the source code.
 
It's still kind of nasty because I have to keep track of all the offsets myself
 
@JF Naturally.
 
@DaveGreene So, you're saying that we could try completely ditch golly's pasting, and instead modify the macrocell file directly?
 
I think that would be a good thing in general
Like, right now I can't get LLVM to assemble the output directly because you have to go through Golly
 
Anonymous
I'm very interested in an approach that directly deals with macrocell files and eliminates the need for Golly
 
6:22 PM
I'm in the middle of coding a direct macrocell writer script for Adam Goucher's Hashlife-friendly "megacells", but those use gliders as signals so the metacells are tilted at 45 degrees to the Life universe.
OTCA metacells should be relatively easy to write a direct macrocell file writer script for, with the option to include ON and OFF macrocells programmed for the various different rules -- it just takes a little getting used to the format.
-- Sorry, "ON and OFF metacells", not macrocells...
 
 
2 hours later…
8:05 PM
@quartata This might be relevant - the answers might contain useful info.
 
8:26 PM
?
We have 16-bit words
 
@quartata I expected more stuff to be in the answer.
 
I'm done redesigning the RAM, time to expand it
 
8:47 PM
How much?
 
I'm gonna make it big enough for Phi's current tetris program. I haven't checked how much RAM that needs yet.
 
I'm currently dedicating 16 words of scratch memory ("registers") so I kind of was curious how much that will take out of what we have
Well, 15 + the program counter I guess
 
The general idea is to minimize ROM/RAM usage, but it can be expanded to however much you need
 
We should in general compile with -Os methinks
 
@quartata We'll have to make the optimisations ourselves.
At least some of them anyway.
 
8:52 PM
Only a few have to be done at machine code generation
3 hours ago, by quartata
It needs at least 2 particular optimization passes to be useful (jump threading and branch delay slot elimination)
I guess elimination was a bad word
Hoisting is better
pretty much what it is
 
9:30 PM
@KZhang you could pick some powers of two for RAM and ROM size.
 
 
2 hours later…
11:05 PM
Kinda sucks that I can't keep LLVM and Cogol compatible -- Cogol subroutines will probably clobber my stuff
 
11:34 PM
@quartata What exactly do you mean by "compatible"?
 
Being able to call Cogol-emitted assembly from LLVM-emitted assembly
 
That would be interesting, although I didn't anticipate that even being a possibility.
 

« first day (532 days earlier)      last day (917 days later) »