docs: public final ObservableMap<Object, Object> getProperties() {
          if (properties == null) {
              properties = FXCollections.observableMap(new HashMap<>());
  
              MapChangeListener<? super Object, ? super Object> changeListener = change -> {
                  if (change.getKey().equals("com.calendarfx.recurrence.source")) { //$NON-NLS-1$
                      if (change.getValueAdded() != null) {
                          @SuppressWarnings("unchecked")
                          Entry<T> source = (Entry<T>) change.getValueAdded();
  
                          // lookup of property first to instantiate
                          recurrenceSourceProperty();
                          recurrenceSource.set(source);
                      }
                  } else if (change.getKey().equals("com.calendarfx.recurrence.id")) { //$NON-NLS-1$
                      if (change.getValueAdded() != null) {
                          setRecurrenceId((String) change.getValueAdded());
                      }
                  }
              };
  
              properties.addListener(changeListener);
          }
  
          return properties;
      }