mirror of
https://salsa.debian.org/dskoll/remind.git
synced 2026-04-16 06:18:47 +02:00
Add $DedupeReminders global variable.
This commit is contained in:
@@ -2520,6 +2520,26 @@ This variable can be set only to "/" or "-". It holds the character
|
|||||||
used to separate portions of a date when \fBRemind\fR prints a DATE or
|
used to separate portions of a date when \fBRemind\fR prints a DATE or
|
||||||
DATETIME value.
|
DATETIME value.
|
||||||
.TP
|
.TP
|
||||||
|
.B $DedupeReminders
|
||||||
|
If this variable is set to 1, then Remind will suppress duplicate
|
||||||
|
reminders. A given reminder is considered to be a duplicate of a
|
||||||
|
previous one if it has the \fIexact\fR same trigger date, trigger
|
||||||
|
time, and body. By default, this variable is set to 0 and Remind does
|
||||||
|
not suppress duplicate reminders.
|
||||||
|
.RS
|
||||||
|
.PP
|
||||||
|
As an example, consider the following reminder file:
|
||||||
|
.nf
|
||||||
|
SET $DedupeReminders 1
|
||||||
|
REM Wednesday MSG Phooey
|
||||||
|
REM 20 MSG Phooey
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
On Wednesday, 20 November 2024, only \fIone\fR "Phooey" will be issued.
|
||||||
|
In December of 2024, "Phooey" will be issued every Wednesday as well
|
||||||
|
as on Friday, 20 December 2024
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
.B $DefaultColor
|
.B $DefaultColor
|
||||||
This variable can be set to a string that has the form of three
|
This variable can be set to a string that has the form of three
|
||||||
space-separated numbers. Each number must be an integer from 0 to
|
space-separated numbers. Each number must be an integer from 0 to
|
||||||
|
|||||||
@@ -26,9 +26,10 @@ MANS= $(srcdir)/../man/rem2ps.1 $(srcdir)/../man/remind.1 \
|
|||||||
.SUFFIXES:
|
.SUFFIXES:
|
||||||
.SUFFIXES: .c .o
|
.SUFFIXES: .c .o
|
||||||
|
|
||||||
REMINDSRCS= calendar.c dynbuf.c dorem.c dosubst.c expr.c files.c funcs.c \
|
REMINDSRCS= calendar.c dedupe.c dynbuf.c dorem.c dosubst.c expr.c \
|
||||||
globals.c hbcal.c init.c main.c md5.c moon.c omit.c queue.c \
|
files.c funcs.c globals.c hbcal.c init.c main.c md5.c \
|
||||||
sort.c token.c trigger.c userfns.c utils.c var.c
|
moon.c omit.c queue.c sort.c token.c trigger.c \
|
||||||
|
userfns.c utils.c var.c
|
||||||
|
|
||||||
REMINDHDRS=config.h custom.h dynbuf.h err.h globals.h lang.h \
|
REMINDHDRS=config.h custom.h dynbuf.h err.h globals.h lang.h \
|
||||||
md5.h protos.h rem2ps.h types.h version.h
|
md5.h protos.h rem2ps.h types.h version.h
|
||||||
|
|||||||
@@ -2054,8 +2054,6 @@ static int DoCalRem(ParsePtr p, int col)
|
|||||||
if ((dse == DSEToday) ||
|
if ((dse == DSEToday) ||
|
||||||
(DoSimpleCalDelta &&
|
(DoSimpleCalDelta &&
|
||||||
ShouldTriggerReminder(&trig, &tim, dse, &err))) {
|
ShouldTriggerReminder(&trig, &tim, dse, &err))) {
|
||||||
NumTriggered++;
|
|
||||||
|
|
||||||
/* The parse_ptr should not be nested, but just in case... */
|
/* The parse_ptr should not be nested, but just in case... */
|
||||||
if (!p->isnested) {
|
if (!p->isnested) {
|
||||||
if (DBufPuts(&raw_buf, p->pos) != OK) {
|
if (DBufPuts(&raw_buf, p->pos) != OK) {
|
||||||
@@ -2152,9 +2150,20 @@ static int DoCalRem(ParsePtr p, int col)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
s = DBufValue(&obuf);
|
s = DBufValue(&obuf);
|
||||||
|
if (DedupeReminders) {
|
||||||
|
if (ShouldDedupe(dse, tim.ttime, DBufValue(&obuf))) {
|
||||||
|
DBufFree(&obuf);
|
||||||
|
DBufFree(&raw_buf);
|
||||||
|
DBufFree(&pre_buf);
|
||||||
|
FreeTrig(&trig);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!DoSimpleCalendar) while (isempty(*s)) s++;
|
if (!DoSimpleCalendar) while (isempty(*s)) s++;
|
||||||
DBufPuts(&pre_buf, s);
|
DBufPuts(&pre_buf, s);
|
||||||
s = DBufValue(&pre_buf);
|
s = DBufValue(&pre_buf);
|
||||||
|
NumTriggered++;
|
||||||
e = NEW(CalEntry);
|
e = NEW(CalEntry);
|
||||||
if (!e) {
|
if (!e) {
|
||||||
DBufFree(&obuf);
|
DBufFree(&obuf);
|
||||||
|
|||||||
175
src/dedupe.c
Normal file
175
src/dedupe.c
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
/***************************************************************/
|
||||||
|
/* */
|
||||||
|
/* DEDUPE.C */
|
||||||
|
/* */
|
||||||
|
/* Code to suppress duplicate reminders */
|
||||||
|
/* */
|
||||||
|
/* This file is part of REMIND. */
|
||||||
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
|
/* */
|
||||||
|
/***************************************************************/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "globals.h"
|
||||||
|
#include "protos.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define DEDUPE_HASH_SLOTS 64
|
||||||
|
typedef struct dedupe_entry {
|
||||||
|
struct dedupe_entry *next;
|
||||||
|
int trigger_date;
|
||||||
|
int trigger_time;
|
||||||
|
char const *body;
|
||||||
|
} DedupeEntry;
|
||||||
|
|
||||||
|
static DedupeEntry *DedupeTable[DEDUPE_HASH_SLOTS];
|
||||||
|
|
||||||
|
/***************************************************************/
|
||||||
|
/* */
|
||||||
|
/* FreeDedupeEntry */
|
||||||
|
/* */
|
||||||
|
/* Free a DedupeEntry object */
|
||||||
|
/* */
|
||||||
|
/***************************************************************/
|
||||||
|
static void
|
||||||
|
FreeDedupeEntry(DedupeEntry *e)
|
||||||
|
{
|
||||||
|
if (e->body) {
|
||||||
|
free((char *) e->body);
|
||||||
|
}
|
||||||
|
free(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************/
|
||||||
|
/* */
|
||||||
|
/* GetDedupeBucket */
|
||||||
|
/* */
|
||||||
|
/* Get the bucket for a given date and body */
|
||||||
|
/* */
|
||||||
|
/***************************************************************/
|
||||||
|
static unsigned int
|
||||||
|
GetDedupeBucket(int trigger_date, int trigger_time, char const *body)
|
||||||
|
{
|
||||||
|
unsigned int bucket = trigger_date;
|
||||||
|
if (trigger_time != NO_TIME) {
|
||||||
|
bucket += trigger_time;
|
||||||
|
}
|
||||||
|
bucket += HashVal(body);
|
||||||
|
return bucket % DEDUPE_HASH_SLOTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************/
|
||||||
|
/* */
|
||||||
|
/* FindDedupeEntry */
|
||||||
|
/* */
|
||||||
|
/* Check if we have a dedupe entry for a given date and body */
|
||||||
|
/* */
|
||||||
|
/***************************************************************/
|
||||||
|
static DedupeEntry *
|
||||||
|
FindDedupeEntry(int trigger_date, int trigger_time, char const *body)
|
||||||
|
{
|
||||||
|
DedupeEntry *e;
|
||||||
|
|
||||||
|
unsigned int bucket = GetDedupeBucket(trigger_date, trigger_time, body);
|
||||||
|
|
||||||
|
e = DedupeTable[bucket];
|
||||||
|
while(e) {
|
||||||
|
if (e->trigger_date == trigger_date &&
|
||||||
|
e->trigger_time == trigger_time &&
|
||||||
|
!strcmp(body, e->body)) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
e = e->next;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************/
|
||||||
|
/* */
|
||||||
|
/* InsertDedupeEntry */
|
||||||
|
/* */
|
||||||
|
/* Insert a dedupe entry for given date and body. */
|
||||||
|
/* */
|
||||||
|
/***************************************************************/
|
||||||
|
static void
|
||||||
|
InsertDedupeEntry(int trigger_date, int trigger_time, char const *body)
|
||||||
|
{
|
||||||
|
DedupeEntry *e;
|
||||||
|
|
||||||
|
unsigned int bucket = GetDedupeBucket(trigger_date, trigger_time, body);
|
||||||
|
|
||||||
|
e = malloc(sizeof(DedupeEntry));
|
||||||
|
if (!e) {
|
||||||
|
return; /* No error checking... what can we do? */
|
||||||
|
}
|
||||||
|
e->trigger_date = trigger_date;
|
||||||
|
e->trigger_time = trigger_time;
|
||||||
|
e->body = strdup(body);
|
||||||
|
if (!e->body) {
|
||||||
|
free(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e->next = DedupeTable[bucket];
|
||||||
|
DedupeTable[bucket] = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************/
|
||||||
|
/* */
|
||||||
|
/* ShouldDedupe */
|
||||||
|
/* */
|
||||||
|
/* Returns 1 if we've already issued this exact reminder; 0 */
|
||||||
|
/* otherwise. If it returns 0, remembers that we have seen */
|
||||||
|
/* the reminder */
|
||||||
|
/* */
|
||||||
|
/***************************************************************/
|
||||||
|
int
|
||||||
|
ShouldDedupe(int trigger_date, int trigger_time, char const *body)
|
||||||
|
{
|
||||||
|
DedupeEntry *e = FindDedupeEntry(trigger_date, trigger_time, body);
|
||||||
|
|
||||||
|
if (e) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
InsertDedupeEntry(trigger_date, trigger_time, body);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************/
|
||||||
|
/* */
|
||||||
|
/* ClearDedupeTable */
|
||||||
|
/* */
|
||||||
|
/* Free all the storage used by the dedupe table */
|
||||||
|
/* */
|
||||||
|
/***************************************************************/
|
||||||
|
void
|
||||||
|
ClearDedupeTable(void)
|
||||||
|
{
|
||||||
|
DedupeEntry *e, *next;
|
||||||
|
for (int i=0; i<DEDUPE_HASH_SLOTS; i++) {
|
||||||
|
e = DedupeTable[i];
|
||||||
|
while (e) {
|
||||||
|
next = e->next;
|
||||||
|
FreeDedupeEntry(e);
|
||||||
|
e = next;
|
||||||
|
}
|
||||||
|
DedupeTable[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/***************************************************************/
|
||||||
|
/* */
|
||||||
|
/* InitDedupeTable */
|
||||||
|
/* */
|
||||||
|
/* Initialize the dedupe table at program startup */
|
||||||
|
/* */
|
||||||
|
/***************************************************************/
|
||||||
|
void
|
||||||
|
InitDedupeTable(void)
|
||||||
|
{
|
||||||
|
for (int i=0; i<DEDUPE_HASH_SLOTS; i++) {
|
||||||
|
DedupeTable[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1315,6 +1315,14 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queue
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If this is a dupe and we are de-duping, do nothing */
|
||||||
|
if (DedupeReminders) {
|
||||||
|
if (ShouldDedupe(dse, tim->ttime, DBufValue(&buf))) {
|
||||||
|
DBufFree(&buf);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If we are sorting, just queue it up in the sort buffer */
|
/* If we are sorting, just queue it up in the sort buffer */
|
||||||
if (SortByDate) {
|
if (SortByDate) {
|
||||||
if (InsertIntoSortBuffer(dse, tim->ttime, DBufValue(&buf),
|
if (InsertIntoSortBuffer(dse, tim->ttime, DBufValue(&buf),
|
||||||
|
|||||||
@@ -139,6 +139,7 @@ EXTERN INIT( int UseVTColors, 0);
|
|||||||
EXTERN INIT( int Use256Colors, 0);
|
EXTERN INIT( int Use256Colors, 0);
|
||||||
EXTERN INIT( int UseTrueColors, 0);
|
EXTERN INIT( int UseTrueColors, 0);
|
||||||
EXTERN INIT( int TerminalBackground, TERMINAL_BACKGROUND_UNKNOWN);
|
EXTERN INIT( int TerminalBackground, TERMINAL_BACKGROUND_UNKNOWN);
|
||||||
|
EXTERN INIT( int DedupeReminders, 0);
|
||||||
|
|
||||||
/* Latitude and longitude */
|
/* Latitude and longitude */
|
||||||
EXTERN INIT( int LatDeg, 0);
|
EXTERN INIT( int LatDeg, 0);
|
||||||
|
|||||||
@@ -192,6 +192,8 @@ void InitRemind(int argc, char const *argv[])
|
|||||||
|
|
||||||
PurgeFP = NULL;
|
PurgeFP = NULL;
|
||||||
|
|
||||||
|
InitDedupeTable();
|
||||||
|
|
||||||
/* Make sure remind is not installed set-uid or set-gid */
|
/* Make sure remind is not installed set-uid or set-gid */
|
||||||
if (getgid() != getegid() ||
|
if (getgid() != getegid() ||
|
||||||
getuid() != geteuid()) {
|
getuid() != geteuid()) {
|
||||||
|
|||||||
@@ -226,6 +226,7 @@ PerIterationInit(void)
|
|||||||
DefaultColorB = -1;
|
DefaultColorB = -1;
|
||||||
NumTriggered = 0;
|
NumTriggered = 0;
|
||||||
ClearLastTriggers();
|
ClearLastTriggers();
|
||||||
|
ClearDedupeTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|||||||
@@ -249,3 +249,8 @@ void print_builtinfunc_tokens(void);
|
|||||||
void print_remind_tokens(void);
|
void print_remind_tokens(void);
|
||||||
void get_var_hash_stats(int *total, int *maxlen, double *avglen);
|
void get_var_hash_stats(int *total, int *maxlen, double *avglen);
|
||||||
void get_userfunc_hash_stats(int *total, int *maxlen, double *avglen);
|
void get_userfunc_hash_stats(int *total, int *maxlen, double *avglen);
|
||||||
|
|
||||||
|
/* Dedupe code */
|
||||||
|
int ShouldDedupe(int trigger_date, int trigger_time, char const *body);
|
||||||
|
void ClearDedupeTable(void);
|
||||||
|
void InitDedupeTable(void);
|
||||||
|
|||||||
@@ -864,6 +864,7 @@ static SysVar SysVarArr[] = {
|
|||||||
{"DateSep", 1, SPECIAL_TYPE, date_sep_func, 0, 0 },
|
{"DateSep", 1, SPECIAL_TYPE, date_sep_func, 0, 0 },
|
||||||
{"DateTimeSep", 1, SPECIAL_TYPE, datetime_sep_func, 0, 0 },
|
{"DateTimeSep", 1, SPECIAL_TYPE, datetime_sep_func, 0, 0 },
|
||||||
{"December", 1, STR_TYPE, &DynamicMonthName[11],0, 0 },
|
{"December", 1, STR_TYPE, &DynamicMonthName[11],0, 0 },
|
||||||
|
{"DedupeReminders",1, INT_TYPE, &DedupeReminders, 0, 1 },
|
||||||
{"DefaultColor", 1, SPECIAL_TYPE, default_color_func, 0, 0 },
|
{"DefaultColor", 1, SPECIAL_TYPE, default_color_func, 0, 0 },
|
||||||
{"DefaultPrio", 1, INT_TYPE, &DefaultPrio, 0, 9999 },
|
{"DefaultPrio", 1, INT_TYPE, &DefaultPrio, 0, 9999 },
|
||||||
{"DefaultTDelta", 1, INT_TYPE, &DefaultTDelta, 0, 1440 },
|
{"DefaultTDelta", 1, INT_TYPE, &DefaultTDelta, 0, 1440 },
|
||||||
|
|||||||
25
tests/dedupe.rem
Normal file
25
tests/dedupe.rem
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
SET $DedupeReminders 1
|
||||||
|
SET $SuppressLRM 1
|
||||||
|
REM Wednesday MSG foo
|
||||||
|
FLUSH
|
||||||
|
REM 8 MSG foo
|
||||||
|
FLUSH
|
||||||
|
REM Wednesday MSG Bar
|
||||||
|
FLUSH
|
||||||
|
REM Wednesday MSG Bar
|
||||||
|
FLUSH
|
||||||
|
REM Wednesday AT 23:59 +1440 MSG with_time
|
||||||
|
FLUSH
|
||||||
|
REM AT 23:59 +1440 MSG with_time
|
||||||
|
FLUSH
|
||||||
|
REM AT 23:58 +1440 MSG with_time
|
||||||
|
FLUSH
|
||||||
|
|
||||||
|
REM 8 RUN echo %"foo%"
|
||||||
|
FLUSH
|
||||||
|
REM 8 RUN echo %"foo%"
|
||||||
|
FLUSH
|
||||||
|
REM Wed RUN echo %"foo%"
|
||||||
|
FLUSH
|
||||||
|
REM Wed RUN echo %"bar%"
|
||||||
|
FLUSH
|
||||||
@@ -586,6 +586,10 @@ rm -f ../tests/once.timestamp
|
|||||||
# Newlines in calendar output
|
# Newlines in calendar output
|
||||||
(echo 'REM 16 MSG foo%_bar%_baz wookie quux apple %_ %_ %_ blech'; echo "REM 16 MSG ANOTHER") | ../src/remind -c -w80 - 1 sep 1990 >> ../tests/test.out 2>&1
|
(echo 'REM 16 MSG foo%_bar%_baz wookie quux apple %_ %_ %_ blech'; echo "REM 16 MSG ANOTHER") | ../src/remind -c -w80 - 1 sep 1990 >> ../tests/test.out 2>&1
|
||||||
|
|
||||||
|
# Dedupe feature
|
||||||
|
../src/remind -c ../tests/dedupe.rem 1 November 2023 >> ../tests/test.out 2>&1
|
||||||
|
../src/remind -q ../tests/dedupe.rem 8 November 2023 >> ../tests/test.out 2>&1
|
||||||
|
|
||||||
# Remove references to SysInclude, which is build-specific
|
# Remove references to SysInclude, which is build-specific
|
||||||
grep -F -v '$SysInclude' < ../tests/test.out > ../tests/test.out.1 && mv -f ../tests/test.out.1 ../tests/test.out
|
grep -F -v '$SysInclude' < ../tests/test.out > ../tests/test.out.1 && mv -f ../tests/test.out.1 ../tests/test.out
|
||||||
|
|
||||||
|
|||||||
@@ -2729,6 +2729,7 @@ Variable Value
|
|||||||
$DateSep "-"
|
$DateSep "-"
|
||||||
$DateTimeSep "@"
|
$DateTimeSep "@"
|
||||||
$December "December"
|
$December "December"
|
||||||
|
$DedupeReminders 0 [0, 1]
|
||||||
$DefaultColor "-1 -1 -1"
|
$DefaultColor "-1 -1 -1"
|
||||||
$DefaultPrio 5000 [0, 9999]
|
$DefaultPrio 5000 [0, 9999]
|
||||||
$DefaultTDelta 0 [0, 1440]
|
$DefaultTDelta 0 [0, 1440]
|
||||||
@@ -13377,7 +13378,93 @@ No reminders.
|
|||||||
| | | | | | | |
|
| | | | | | | |
|
||||||
| | | | | | | |
|
| | | | | | | |
|
||||||
+----------+----------+----------+----------+----------+----------+----------+
|
+----------+----------+----------+----------+----------+----------+----------+
|
||||||
|
+----------------------------------------------------------------------------+
|
||||||
|
| November 2023 |
|
||||||
|
+----------+----------+----------+----------+----------+----------+----------+
|
||||||
|
| Sunday | Monday | Tuesday |Wednesday | Thursday | Friday | Saturday |
|
||||||
|
+----------+----------+----------+----------+----------+----------+----------+
|
||||||
|
| | | |1 |2 |3 |4 |
|
||||||
|
| | | | | | | |
|
||||||
|
| | | |11:58pm |11:58pm |11:58pm |11:58pm |
|
||||||
|
| | | |with_time |with_time |with_time |with_time |
|
||||||
|
| | | | | | | |
|
||||||
|
| | | |11:59pm |11:59pm |11:59pm |11:59pm |
|
||||||
|
| | | |with_time |with_time |with_time |with_time |
|
||||||
|
| | | | | | | |
|
||||||
|
| | | |foo | | | |
|
||||||
|
| | | | | | | |
|
||||||
|
| | | |Bar | | | |
|
||||||
|
| | | | | | | |
|
||||||
|
| | | |bar | | | |
|
||||||
|
+----------+----------+----------+----------+----------+----------+----------+
|
||||||
|
|5 |6 |7 |8 |9 |10 |11 |
|
||||||
|
| | | | | | | |
|
||||||
|
|11:58pm |11:58pm |11:58pm |11:58pm |11:58pm |11:58pm |11:58pm |
|
||||||
|
|with_time |with_time |with_time |with_time |with_time |with_time |with_time |
|
||||||
|
| | | | | | | |
|
||||||
|
|11:59pm |11:59pm |11:59pm |11:59pm |11:59pm |11:59pm |11:59pm |
|
||||||
|
|with_time |with_time |with_time |with_time |with_time |with_time |with_time |
|
||||||
|
| | | | | | | |
|
||||||
|
| | | |foo | | | |
|
||||||
|
| | | | | | | |
|
||||||
|
| | | |Bar | | | |
|
||||||
|
| | | | | | | |
|
||||||
|
| | | |bar | | | |
|
||||||
|
+----------+----------+----------+----------+----------+----------+----------+
|
||||||
|
|12 |13 |14 |15 |16 |17 |18 |
|
||||||
|
| | | | | | | |
|
||||||
|
|11:58pm |11:58pm |11:58pm |11:58pm |11:58pm |11:58pm |11:58pm |
|
||||||
|
|with_time |with_time |with_time |with_time |with_time |with_time |with_time |
|
||||||
|
| | | | | | | |
|
||||||
|
|11:59pm |11:59pm |11:59pm |11:59pm |11:59pm |11:59pm |11:59pm |
|
||||||
|
|with_time |with_time |with_time |with_time |with_time |with_time |with_time |
|
||||||
|
| | | | | | | |
|
||||||
|
| | | |foo | | | |
|
||||||
|
| | | | | | | |
|
||||||
|
| | | |Bar | | | |
|
||||||
|
| | | | | | | |
|
||||||
|
| | | |bar | | | |
|
||||||
|
+----------+----------+----------+----------+----------+----------+----------+
|
||||||
|
|19 |20 |21 |22 |23 |24 |25 |
|
||||||
|
| | | | | | | |
|
||||||
|
|11:58pm |11:58pm |11:58pm |11:58pm |11:58pm |11:58pm |11:58pm |
|
||||||
|
|with_time |with_time |with_time |with_time |with_time |with_time |with_time |
|
||||||
|
| | | | | | | |
|
||||||
|
|11:59pm |11:59pm |11:59pm |11:59pm |11:59pm |11:59pm |11:59pm |
|
||||||
|
|with_time |with_time |with_time |with_time |with_time |with_time |with_time |
|
||||||
|
| | | | | | | |
|
||||||
|
| | | |foo | | | |
|
||||||
|
| | | | | | | |
|
||||||
|
| | | |Bar | | | |
|
||||||
|
| | | | | | | |
|
||||||
|
| | | |bar | | | |
|
||||||
|
+----------+----------+----------+----------+----------+----------+----------+
|
||||||
|
|26 |27 |28 |29 |30 | | |
|
||||||
|
| | | | | | | |
|
||||||
|
|11:58pm |11:58pm |11:58pm |11:58pm |11:58pm | | |
|
||||||
|
|with_time |with_time |with_time |with_time |with_time | | |
|
||||||
|
| | | | | | | |
|
||||||
|
|11:59pm |11:59pm |11:59pm |11:59pm |11:59pm | | |
|
||||||
|
|with_time |with_time |with_time |with_time |with_time | | |
|
||||||
|
| | | | | | | |
|
||||||
|
| | | |foo | | | |
|
||||||
|
| | | | | | | |
|
||||||
|
| | | |Bar | | | |
|
||||||
|
| | | | | | | |
|
||||||
|
| | | |bar | | | |
|
||||||
|
+----------+----------+----------+----------+----------+----------+----------+
|
||||||
|
Reminders for Wednesday, 8th November, 2023:
|
||||||
|
|
||||||
|
foo
|
||||||
|
|
||||||
|
Bar
|
||||||
|
|
||||||
|
with_time
|
||||||
|
|
||||||
|
with_time
|
||||||
|
|
||||||
|
foo
|
||||||
|
bar
|
||||||
# Remind Tokens
|
# Remind Tokens
|
||||||
|
|
||||||
addomit
|
addomit
|
||||||
@@ -13623,6 +13710,7 @@ $Daemon
|
|||||||
$DateSep
|
$DateSep
|
||||||
$DateTimeSep
|
$DateTimeSep
|
||||||
$December
|
$December
|
||||||
|
$DedupeReminders
|
||||||
$DefaultColor
|
$DefaultColor
|
||||||
$DefaultPrio
|
$DefaultPrio
|
||||||
$DefaultTDelta
|
$DefaultTDelta
|
||||||
|
|||||||
Reference in New Issue
Block a user