docs: @OverrideOnDemand
    protected void addGlobalAndPerRequestCSSAndJS (@Nonnull final IRequestWebScopeWithoutResponse aRequestScope,
                                                   @Nonnull final HCHtml aHtml)
    {
      final boolean bRegular = HCSettings.isUseRegularResources ();
      final HCHead aHead = aHtml.head ();
  
      // Add configured and per-request CSS
      final ICommonsOrderedSet <ICSSPathProvider> aCSSs = PhotonCSS.getAllRegisteredCSSIncludesForGlobal ();
      PhotonCSS.getAllRegisteredCSSIncludesForThisRequest (aCSSs);
  
      // Add each CSS separately
      for (final ICSSPathProvider aCSS : aCSSs)
        aHead.addCSS (PhotonHTMLHelper.getCSSNode (aRequestScope, aCSS, bRegular));
  
      // Add all configured and per-request JS
      final ICommonsOrderedSet <IJSPathProvider> aJSs = PhotonJS.getAllRegisteredJSIncludesForGlobal ();
      PhotonJS.getAllRegisteredJSIncludesForThisRequest (aJSs);
  
      // Add each JS separately
      for (final IJSPathProvider aJS : aJSs)
        aHead.addJS (PhotonHTMLHelper.getJSNode (aRequestScope, aJS, bRegular));
    }
  
    /**
     * Overridable method to fill head and body.
     *
     * @param aRequestScope
     *        Current request scope
     * @param aHtml
     *        Created (empty) HTML node
     * @param aDisplayLocale
     *        The display locale of the current request
     */
    protected abstract void fillHeadAndBody (@Nonnull IRequestWebScopeWithoutResponse aRequestScope,
                                             @Nonnull HCHtml aHtml,
                                             @Nonnull Locale aDisplayLocale);
  
    @Nonnull
    public final HCHtml createHTML (@Nonnull final IRequestWebScopeWithoutResponse aRequestScope) throws ForcedRedirectException
    {
      final Locale aDisplayLocale = RequestSettings.getDisplayLocale (aRequestScope);
      final IHCConversionSettingsToNode aConversionSettings = HCSettings.getConversionSettings ();
  
      // Create the surrounding HTML element
      final HCHtml aHtml = createHCHtml (aDisplayLocale);
  
      // Main content filling
      fillHeadAndBody (aRequestScope, aHtml, aDisplayLocale);
  
      // customize, finalize and extract resources
      // This must be done before the CSS and JS are included because per-request
      // resource registration happens inside
      HCRenderer.prepareForConversion (aHtml, aHtml.body (), aConversionSettings);
  
      // Add global and per-request CSS and JS
      addGlobalAndPerRequestCSSAndJS (aRequestScope, aHtml);
  
      // Extract and merge all inline out-of-band nodes
      if (aConversionSettings.isExtractOutOfBandNodes ())
      {
        final ICommonsList <IHCNode> aOOBNodes = aHtml.getAllOutOfBandNodesWithMergedInlineNodes ();
        aHtml.addAllOutOfBandNodesToHead (aOOBNodes);
      }
  
      // Merge all external CSS and JS nodes
      PhotonHTMLHelper.mergeExternalCSSAndJSNodes (aRequestScope,
                                                   aHtml.head (),
                                                   PhotonAppSettings.isMergeCSSResources (),
                                                   PhotonAppSettings.isMergeJSResources (),
                                                   PhotonAppManager.getWebSiteResourceBundleMgr ());
  
      // Move scripts to body? If so, after aggregation!
      if (HCSettings.isScriptsInBody ())
        aHtml.moveScriptElementsToBody ();
  
      // This is only required so that the additional CSS/JS nodes on the head get
      // the correct EHCNodeState
      if (false)
        HCRenderer.prepareForConversion (aHtml.head (), aHtml.body (), aConversionSettings);
  
      return aHtml;
    }
  
    @Override
    public String toString ()
    {
      return new ToStringGenerator (this).getToString ();
    }
  }