# YNot Calendar:
#
# Calendar files are read line by line. Each line must be either a valid
# <program> a comment with a "#" in the first column, or an *empty* line.
# A <program> starts with either a <date> or an <opcode-list> followed by
# either a <when> value or an <icon> in parentheses followed by a <what>
# description of the event with an optional <where> after an '@' character.
#
# A full ABNF description of the calendar file is provided at the very bottom
# of this file
#
# Examples below show a variety of programs with some explanations. We'll
# practice with <opcode-lists> first. For now ignore the <icon> characters in
# parenthesis before the event description.
# US HOLIDAYS
Jan M = 1 D = & (h) New Year's Day
# "Jan" Push the value of "Jan", which is 1, onto the stack
# "M" Push the current month value onto the stack
# "=" Pop two values, if they are equal push true (0) else false (1)
# "1" Literal value is pushed as is
# "D" Push the current day value
# "=" Pop two values, check if equal, push result
# "&" Pop two values, check if both are true (0), push result
# NOTE: this is a long form for educational purposes, the following program
# is a better way to achieve the same result.
Jan m 1 d & (h) New Year's Day
# "Jan" Push 1 as above
# "m" Pop one value, subtract the M (month) value from it, push the result
# "1 d" Same method to check if it's the first
# "&" Pop two values (both test results) and check if both are true
# NOTE: Uppercase variables each have a lowercase operator. "1 d" is equivalent
# to "1 D -" which has the same boolean value as "1 D =" when true = 0.
Jan m Mon w & 3 f & (h) Martin Luther King Jr Day
# "Jan m" Is it January? Push result
# "Mon w" Is it a Monday (w = weekday)? Push result
# "&" Pop two, are both true? Push result
# "3 f" Is it the third week of the month (f is relative to first)
# "&" Are the last two tests both true?
Feb m 14 d & (h) Valentines Day
# This one should make sense by now ...
Feb m Mon w & 3 f & (h) Washington's Birthday
# Similar logic as MLK Jr day
May m Sun w & 2 f & (h) Mother's Day
# Second Sunday this time ...
May m Wed w & 1 l & (h) Memorial Day
# ...
# "1 l" Is it the last week of the month (l is relative to last)
Jun m Sun w & 3 f & (h) Father's Day
Jul m 4 d & (h) Independence Day
Sep m Mon w & 1 f & (h) Labor Day
Oct m Mon w & 2 f & (h) Columbus Day
Nov m Thu w & 4 f & (h) Thanksgiving
Dec m 31 d & (h) New Year's Eve
# COMMON CHRISTIAN HOLIDAYS
Dec m 24 d & (H) Christmas Eve
Dec m 25 d & (H) Christmas Day
25 d 0 ? D 24 < D 14 > & Dec m & (H) %d days to Christmas
# "25 d 0 ?" subtract today's day of the month from 25 and "chomp" it
# "D 24 <" today's day is less than 24? Push either true=0 or false=1
# "D 14 >" today's day is greater than 14? Push either true=0 or false=1
# "&" pop two values, are they both true? Push true=0 / false=1
# "Dec m" Is it December ...
# "&" pop two values, check if both are true, push result
# NOTE: %d in the "what" string is filled in with "chomped" value
# '?' is the chomp operator, it pops two values and stores the
# first if the second is true
E (H) Easter Sunday
# NOTE: The variable E is the calculated number of days to Easter
# When this is zero, this single-opcode program evaluates to true
47 e (H) Mardi Gras
# "47 e" subtract days-to-Easter's from 47, is it zero ...
7 e (H) Palm Sunday
46 e (H) Ash Wednesday
# As above, 7, or 46 days before Easter
E 7 / 0 ? E 0 > E 30 < & Sun w & (H) %1 week(s) to Easter
# "E 7 / 0 ?" divide the number of days to Easter by seven and "chomp" the result
# "E 0 >" days-to-Easter is greater than zero, i.e, are we *before* Easter
# "E 30 < &" but also less than 30 days before Easter
# "Sun w &" and is it also a Sunday
# ANNUAL EVENTS
1941? Sep 9 (b) Dennis Ritchie would be %d years old today
1942? Jan 1 (b) Brian Kernighan is alive and kickin' at %d years old today
1931? Oct 24 (b) Lee E McMahon (RIP) would be %d years old today
# NOTE: The '?' chomp operator has a shorthand in this form in which it is
# appended to a year (with no spaces). In this context, it subtracts the
# specified year from the current year and "chomps" the result to be used
# in the %d format specifier of the event description.
# EVENTS ON SPECIFIC DAYS
2021 Nov 26 (!) Comic-Con Special Edition begins
# NOTE: Dates must be specified as year month and day. If month names are given
# they can be abbreviated or full, uppercase or lower. If the month is
# provided in numeric form dashed or dotted dates are also valid ,e,g,
# 2021-11-26 or 2021.11.26 would be equivalent to the above date.
# TIMED EVENTS
Fri w (1700) Beer O'Clock!
# NOTE: Start time can be specified in parentheses as either HHMM or HH:MM.
# This value is used to sort events that occur on the same day. Up to
# this point in this file, all events have been all-day and have instead
# specified a single-character "icon" in the parentheses. These icons are
# displayed next to all-day events, but are of most value when your
# calendar is served on the web as it allows for different CSS formats
# (e.g., different colors) to be applied to different categories of
# all-day events such as religious or national holidays, birthdays, work
# events, etc.
# EVENTS WITH LOCATIONS
2022 Jan 13 (1430) Denstist Appointment @ MyTown Dental
# NOTE: Timed or untimed events can be given a location after an '@' symbol.
# This location data can be presented differently depending on the output
# mode. In webserver mode with the default template, this location
# becomes a link to google maps directions to the listed destination.
# ... And yes, my dentist appointments are at two-thirty.
#---------------------------------------------------------------------------------#
# START ABNF
#
# file = *lf *line
#
# line = ( event / comment ) 1*lf
#
# event = program 1*wsp description
#
# comment = "#" *( %d1-%d9 / %d11-%d126 )
# ; '#' at the start of line
#
# lf = %d10
# ; '\n'
#
# wsp = %d9 / %d32
# ; space or tab
#
# program = date / opcode-list
#
# date = year [ "?" ] 1*wsp month 1*wsp day
#
# date =/ year "-" 1*2digit "-" day
#
# date =/ year "." 1*2digit "." day
#
# year = 4digit
# ; e.g., "2021"
#
# digit = %d48-%d57
# ; 0-9
#
# month = ( 1*2digit / 1*alpa )
# ; anything recognized by strptime's %b or %m in the current locale
#
# alpha = ( %d65-%d90 / %d97-%d122 )
#
# day = 1*2digit
#
# opcode-list = 1*( opcode 1*wsp )
#
# opcode = ( number / operator / variable / name )
#
# number = [ "-" ] 1*digit
#
# operator = "+" / "-" / "*" / "/" / "%" / "=" / "<" / ">" / "&" / "|" / "^" / "!" / "?" / "("
#
# operator =/ "y" / "m" / "d" / "w" / "z" / "f" / "b" / "e"
#
# variable = "Y" / "M" / "D" / "W" / "Z" / "F" / "B" / "E"
#
# name = 1*alpha
# ; for use as an opcode, any values recognized by strptime's %a or %b placeholders are valid
# ; that's month and weekday names in the current locale, either full or abbreviated
# ; unrecognized text strings are evaluated to 0
#
# description = when 1*wsp what [ "@" where ]
#
# when = "(" *wsp time / symbol *wsp ")"
#
# time = ( 2digit ":" 2digit ) / 4digit
#
# icon = %d32-%d127
#
# what = 1*( %d32-%d63 / %d65-%d127 )
# ; any printable characters except '@'
#
# where = 1*( %d32-%d127 )
#
# END ABNF