@Override
  public String getInfoLine() {

    String date = LONG_DATE_FORMAT.format(post.getStartTime());

    if (date.startsWith(SHORT_DATE_FORMAT.format(post.getEndTime()))) {

      // Same day event
      date =
          StringUtils.toSentenceCase(date)
              + "-"
              + TimeUtils.TIME_FORMATTER.format(post.getEndTime());

    } else {

      date =
          StringUtils.toSentenceCase(date)
              + " - "
              + StringUtils.toSentenceCase(LONG_DATE_FORMAT.format(post.getEndTime()));
    }

    if (!StringUtils.isEmpty(post.getLocation())) {

      date = date + " · " + post.getLocation();
    }

    return date;
  }
  @Override
  public InputStream getData() throws Exception {

    if (post.getDescription() != null) {

      return StringUtils.getInputStream(post.getDescription());

    } else {

      return StringUtils.getInputStream("");
    }
  }
  public static String validateNotEmptyParameter(
      String fieldName, HttpServletRequest req, Collection<ValidationError> errors) {

    String parameter = req.getParameter(fieldName);

    if (StringUtils.isEmpty(parameter)) {
      errors.add(new ValidationError(fieldName, ValidationErrorType.RequiredField));
      return null;
    } else {
      return parameter;
    }
  }
  public static <T> T validateParameter(
      String fieldName,
      String displayName,
      HttpServletRequest req,
      boolean required,
      Integer minLength,
      Integer maxLength,
      BeanStringPopulator<T> typePopulator,
      Collection<ValidationError> errors) {

    String value = req.getParameter(fieldName);

    if (StringUtils.isEmpty(value)) {

      if (required) {

        errors.add(new ValidationError(fieldName, displayName, ValidationErrorType.RequiredField));
      }

      return null;
    }

    value = value.trim();

    if (maxLength != null && value.length() > maxLength) {

      errors.add(new TooLongContentValidationError(fieldName, value.length(), maxLength));
      return null;

    } else if (minLength != null && value.length() < minLength) {

      errors.add(new ValidationError(fieldName, displayName, ValidationErrorType.TooShort));
      return null;
    }

    if (!typePopulator.validateFormat(value)) {

      errors.add(new ValidationError(fieldName, displayName, ValidationErrorType.InvalidFormat));
      return null;
    }

    return typePopulator.getValue(value);
  }
  @Override
  public SimpleForegroundModuleResponse processRequest(
      HttpServletRequest req, HttpServletResponse res, User user, URIParser uriParser)
      throws AccessDeniedException, URINotFoundException {

    // TODO add support to separate numeric foreground module aliases from moduleID's (fv prefix?)
    // TODO add support to separate background module hashcodes from moduleID's (bv prefix?)

    Integer sectionID;

    if (uriParser.size() >= 3 && uriParser.get(1).equals("global")) {

      if (!enableGlobalContentLinks) {

        throw new AccessDeniedException("Global content links are disabled");
      }

      Properties globalContentLinks = this.globalContentLinks;

      if (globalContentLinks == null) {

        throw new URINotFoundException(uriParser);
      }

      if (!globalContentLinks.isEmpty()) {

        String filePath = getFilePath(uriParser, 1);

        for (Entry<Object, Object> linkEntry : globalContentLinks.entrySet()) {

          if (filePath.startsWith(linkEntry.getKey().toString())) {

            URL linkedURL = this.getClass().getResource(linkEntry.getValue() + filePath);

            if (linkedURL != null) {

              try {
                InputStream fileStream = linkedURL.openStream();

                if (fileStream != null) {

                  this.sendFile(
                      req,
                      res,
                      uriParser,
                      linkedURL,
                      fileStream,
                      user,
                      linkEntry.getValue().toString(),
                      filePath,
                      null,
                      null);

                  return null;
                }
              } catch (IOException e) {
                log.error(
                    "Unable to load file from url "
                        + linkedURL
                        + " belonging to global content links",
                    e);
              }
            }
          }
        }
      }

    } else if (uriParser.size() >= 5
        && (uriParser.get(1).equals("f") || uriParser.get(1).equals("b"))
        && !uriParser.getFormattedURI().contains("..")
        && (sectionID = NumberUtils.toInt(uriParser.get(2))) != null) {

      // Get the requested section
      SectionInterface sectionInterface = systemInterface.getSectionInterface(sectionID);

      if (sectionInterface == null) {

        // The requested section is not started or does not exist
        throw new AccessDeniedException(
            "The requested section ID was not found in cache (URI: "
                + uriParser.getFormattedURI()
                + ")");

      } else if (!AccessUtils.checkAccess(user, sectionInterface.getSectionDescriptor())) {

        // The user does not have access to the requested section
        throw new AccessDeniedException(
            "User does not have access to section "
                + sectionInterface.getSectionDescriptor()
                + " (URI: "
                + uriParser.getFormattedURI()
                + ")");
      }

      // Check that the user has access to all parent section
      SectionInterface parentSection = sectionInterface.getParentSectionInterface();

      while (parentSection != null) {

        if (!AccessUtils.checkAccess(user, parentSection.getSectionDescriptor())) {

          // User does not have access to a parent section
          throw new AccessDeniedException(
              "User does not have access to section "
                  + sectionInterface.getSectionDescriptor()
                  + " (URI: "
                  + uriParser.getFormattedURI()
                  + ")");
        }

        parentSection = parentSection.getParentSectionInterface();
      }

      boolean foreground = uriParser.get(1).equals("f");

      String moduletype;

      if (foreground) {

        moduletype = "foreground module";

      } else {

        moduletype = "background module";
      }

      Integer moduleID = NumberUtils.toInt(uriParser.get(3));

      // Get the requested module
      Entry<? extends VisibleModuleDescriptor, ? extends Module<?>> moduleEntry = null;

      if (moduleID != null) {

        if (foreground) {

          moduleEntry = sectionInterface.getForegroundModuleCache().getEntry(moduleID);

        } else {

          moduleEntry = sectionInterface.getBackgroundModuleCache().getEntry(moduleID);
        }
      }

      if (moduleEntry == null) {

        if (foreground) {

          String alias = uriParser.get(3);

          moduleEntry = sectionInterface.getForegroundModuleCache().getEntry(alias);

        } else if (moduleID != null) {

          moduleEntry = sectionInterface.getBackgroundModuleCache().getEntryByHashCode(moduleID);
        }
      }

      if (moduleEntry != null) {

        VisibleModuleDescriptor moduleDescriptor = moduleEntry.getKey();

        // Check if the user has access to this module
        if (AccessUtils.checkAccess(user, moduleDescriptor)) {

          // Check that the module has a static content directory set
          if (!StringUtils.isEmpty(moduleDescriptor.getStaticContentPackage())) {

            // Check that the requested file exists in the specified classpath directory

            String filePath = getFilePath(uriParser, 3);

            URL url =
                moduleEntry
                    .getValue()
                    .getClass()
                    .getResource(moduleDescriptor.getStaticContentPackage() + filePath);

            InputStream fileStream = null;

            if (url != null) {

              try {
                fileStream = url.openStream();
              } catch (IOException e) {
              }
            }

            if (fileStream != null) {

              log.debug(
                  "Sending file "
                      + moduleDescriptor.getStaticContentPackage()
                      + filePath
                      + " from "
                      + moduletype
                      + " "
                      + moduleDescriptor
                      + " reqested using URI "
                      + uriParser.getFormattedURI()
                      + " to user "
                      + user);

              this.sendFile(
                  req,
                  res,
                  uriParser,
                  url,
                  fileStream,
                  user,
                  moduleDescriptor.getStaticContentPackage(),
                  filePath,
                  moduleDescriptor,
                  moduletype);

              return null;

            } else if ((fileStream =
                    moduleEntry
                        .getValue()
                        .getClass()
                        .getResourceAsStream(
                            moduleDescriptor.getStaticContentPackage()
                                + "/StaticContentLinks.properties"))
                != null) {

              Properties links = new Properties();

              try {
                links.load(fileStream);

              } catch (IOException e) {
                log.error(
                    "Unable to load static content links belonging to "
                        + moduletype
                        + " "
                        + moduleDescriptor,
                    e);
              } finally {
                StreamUtils.closeStream(fileStream);
              }

              if (!links.isEmpty()) {

                for (Entry<Object, Object> linkEntry : links.entrySet()) {

                  if (filePath.startsWith(linkEntry.getKey().toString())) {

                    URL linkedURL =
                        moduleEntry
                            .getValue()
                            .getClass()
                            .getResource(linkEntry.getValue() + filePath);

                    if (linkedURL != null) {

                      try {
                        fileStream = linkedURL.openStream();

                        if (fileStream != null) {

                          this.sendFile(
                              req,
                              res,
                              uriParser,
                              linkedURL,
                              fileStream,
                              user,
                              linkEntry.getValue().toString(),
                              filePath,
                              moduleDescriptor,
                              moduletype);

                          return null;
                        }

                      } catch (IOException e) {
                        log.error(
                            "Unable to load file from url "
                                + linkedURL
                                + " belonging to "
                                + moduletype
                                + " "
                                + moduleDescriptor,
                            e);
                      }
                    }
                  }
                }
              }

            } else {
              log.info(
                  "File "
                      + uriParser.getFormattedURI()
                      + " requested from "
                      + moduletype
                      + " "
                      + moduleDescriptor
                      + " by user "
                      + user
                      + " not found");
            }

          } else {
            log.info(
                "User "
                    + user
                    + " requested static content from "
                    + moduletype
                    + " "
                    + moduleDescriptor
                    + " which has no static content package set, using URI "
                    + uriParser.getFormattedURI());
          }
        } else {
          throw new AccessDeniedException(
              "User does not have access to "
                  + moduletype
                  + " "
                  + moduleEntry.getKey()
                  + " (URI: "
                  + uriParser.getFormattedURI()
                  + ")");
        }
      } else {
        log.info(
            "Invalid sectionID or moduleID in URI "
                + uriParser.getFormattedURI()
                + " requested by user "
                + user);
      }
    } else {
      log.info("Invalid URI " + uriParser.getFormattedURI() + " requested by user " + user);
    }

    throw new URINotFoundException(uriParser);
  }