ESMF_HConfigEx.F90 Source File


Source Code

! $Id$
!
! Earth System Modeling Framework
! Copyright (c) 2002-2023, University Corporation for Atmospheric Research,
! Massachusetts Institute of Technology, Geophysical Fluid Dynamics
! Laboratory, University of Michigan, National Centers for Environmental
! Prediction, Los Alamos National Laboratory, Argonne National Laboratory,
! NASA Goddard Space Flight Center.
! Licensed under the University of Illinois-NCSA License.
!
!==============================================================================

!==============================================================================
!ESMF_EXAMPLE        String used by test script to count examples.
!==============================================================================

program ESMF_HConfigEx
#include "ESMF.h"

  use ESMF
  use ESMF_TestMod

  implicit none

  ! local variables
  integer                         :: rc, size, i, docCount
  type(ESMF_HConfig)              :: hconfig, hconfigTemp, hconfigTemp2
  type(ESMF_HConfigIter)          :: hconfigIter, hconfigIterBegin, hconfigIterEnd
  type(ESMF_Config)               :: config
  logical                         :: asOkay, valueL, isDefined
  logical                         :: isNull, isScalar, isSequence, isMap
  logical, allocatable            :: valueLSeq(:)
  character(len=:), allocatable   :: string, stringKey, tag
  character(len=:), allocatable   :: valueSSeq(:)
  integer(ESMF_KIND_I4)           :: valueI4
  integer(ESMF_KIND_I4), allocatable :: valueI4Seq(:)
  integer(ESMF_KIND_I8)           :: valueI8
  real(ESMF_KIND_R4)              :: valueR4
  real(ESMF_KIND_R8)              :: valueR8
  character(5)                    :: keyList(3)
  character(160)                  :: msgString, filename
  ! result code
  integer                     :: finalrc, result
  character(ESMF_MAXSTR)      :: testname
  character(ESMF_MAXSTR)      :: failMsg


  finalrc = ESMF_SUCCESS

!-------------------------------------------------------------------------
!-------------------------------------------------------------------------

  write(failMsg, *) "Example failure"
  write(testname, *) "Example ESMF_HConfigEx"

!-------------------------------------------------------------------------
!-------------------------------------------------------------------------

  call ESMF_Initialize(defaultlogfilename="HConfigEx.Log", &
    logkindflag=ESMF_LOGKIND_MULTI, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

!-------------------------------------------------------------------------------
!BOE
! \subsubsection{Create an empty HConfig object}
!
! By default, {\tt ESMF\_HConfigCreate()} creates an empty HConfig object.
!EOE
!BOC
  ! type(ESMF_HConfig) :: hconfig
  hconfig = ESMF_HConfigCreate(rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

!-------------------------------------------------------------------------------
!BOE
! \subsubsection{Set HConfig from string using YAML syntax}
!
! An empty HConfig object can be set directly from a string using YAML
! syntax.
!EOE
!BOC
  call ESMF_HConfigSet(hconfig, content="[1, 2, 3, abc, b, TRUE]", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

!BOE
! This sets {\tt hconfig} as a {\em sequence} of six scalar members.
!EOE

!-------------------------------------------------------------------------------
!BOE
! \subsubsection{Iterator based HConfig sequence parsing}
!
! One way to parse the elements contained in {\tt hconfig} is to use the
! iterator pattern known from laguages such as C++ or Python. HConfig
! iterators are implemented as {\tt type(ESMF\_HConfigIter)} objects that
! are initialized using one of the {\tt HConfigIter*()} methods. An iterator
! can then be used to traverse the elements in a {\em sequence} or {\em map}
! by calling the {\tt ESMF\_HConfigIterNext()} method, taking one step forward
! each time the method is called.
!
! Being a HConfig object, an iterator can be passed into any of the usual
! HConfig methods. The operation is applied to the element that the iterator is
! currently referencing. 
!
! Notice that iterators are merely references, not associated with their own
! deep allocation. This is reflected in the fact that iterators are
! {\em not} created by an assignment that has a {\tt Create()} call on the right
! hand side. As such, HConfig iterators need {\em not} be destroyed
! explicitly when done.
!
! Two special HConfig iterators are defined, referencing the beginning and
! the end of a HConfig sequence or map object.
!EOE
!BOC
  ! type(ESMF_HConfigIter) :: hconfigIterBegin, hconfigIterEnd
  hconfigIterBegin = ESMF_HConfigIterBegin(hconfig, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  hconfigIterEnd = ESMF_HConfigIterEnd(hconfig, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! In analogy to the C++ iterator pattern, {\tt hconfigIterBegin} points to the
! first element in {\tt hconfig}, while {\tt hconfigIterEnd} points one step
! beyond the last element. Using these elements together, an iterator loop
! can be written in the following intuitive way, using {\tt hconfigIter} as the
! loop variable.
!EOE
!BOC
  ! type(ESMF_HConfigIter) :: hconfigIter
  hconfigIter = hconfigIterBegin
  do while (hconfigIter /= hconfigIterEnd)

    ! Code here that uses hconfigIter
    ! to access the currently referenced
    ! element in hconfig.  .......

    call ESMF_HConfigIterNext(hconfigIter, rc=rc)
!EOC
    if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  enddo
!EOC
!BOE
! One {\em major} concern with the above iterator loop implementation is when
! Fortran {\tt cycle} statements are introduced. In orde to make the above loop
! {\tt cycle}--safe, each such {\tt cycle} statement needs to be matched with
! its own call to {\tt ESMF\_HConfigIterNext()}. This needs to be done to
! prevent endless-loop conditions, where the exit condition of the
! {\tt do while} is never reached.
!
! The {\tt cycle}--safe alternative implementation of the iterator loop
! leverages the {\tt ESMF\_HConfigIterLoop()} function instead of 
! {\tt ESMF\_HConfigIterNext()}. This approach is more akin to the
! C++
! \begin{verbatim}
!   for (element : container){
!     ...
!   }
! \end{verbatim}
! or the Python
! \begin{verbatim}
!   for element in container:
!     ...
! \end{verbatim}
! approach. It is the preferable way to write HConfig iterator loops due to its
! simplicity and inherent {\tt cycle}--safety.
!
! The {\tt ESMF\_HConfigIterLoop()} function takes three required arguments.
! The first is the loop iterator, followed by the begin and end iterators. The
! loop iterator must enter equal to the begin iterator at the start of the loop.
! Each time the {\tt ESMF\_HConfigIterLoop()} function is called, the loop
! iterator is stepped forward as appropriate, and the exit condition of having
! reached the end iterator is checked. Having both the stepping and exit logic
! in one place provided by the HConfig API simplifies the usage. In addition,
! the approach is {\tt cycle}--safe: no matter where a {\tt cycle} statement is
! inserted in the loop body, it always brings the execution back to the top of
! the while loop, which in turn calls the {\tt ESMF\_HConfigIterLoop()}
! function.
!EOE
!BOC
  ! type(ESMF_HConfigIter) :: hconfigIter
  hconfigIter = hconfigIterBegin
  do while (ESMF_HConfigIterLoop(hconfigIter, hconfigIterBegin, hconfigIterEnd, rc=rc))
!EOC
    if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
    ! Check whether the current element is a scalar.
    ! logical :: isScalar
    isScalar = ESMF_HConfigIsScalar(hconfigIter, rc=rc)
!EOC
    if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
    if (isScalar) then

      ! Any scalar can be accessed as a string.
      ! character(len=:), allocatable :: string
      string = ESMF_HConfigAsString(hconfigIter, rc=rc)
!EOC
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
      call ESMF_LogWrite("AsString: "//string, ESMF_LOGMSG_INFO, rc=rc)
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
      ! The attempt can be made to interpret the scalar as any of the other
      ! supported data types. By default, if the scalar cannot be interpreted
      ! as the requested data type, rc /= ESMF_SUCCESS is returned. To prevent
      ! such error condition, the optional, intent(out) argument "asOkay" can
      ! be provided. If asOkay == .true. is returned, the interpretation was
      ! successful. Otherwise asOkay == .false. is returned.

      ! logical :: asOkay

      ! integer(ESMF_KIND_I4) :: valueI4
      valueI4 = ESMF_HConfigAsI4(hconfigIter, asOkay=asOkay, rc=rc)
!EOC
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
      write (msgString, '("asOkay: ", l2, " valueI4: ", i10)') asOkay, valueI4
      call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
      ! integer(ESMF_KIND_I8) :: valueI8
      valueI8 = ESMF_HConfigAsI8(hconfigIter, asOkay=asOkay, rc=rc)
!EOC
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
      write (msgString, '("asOkay: ", l2, " valueI8: ", i10)') asOkay, valueI8
      call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
      ! real(ESMF_KIND_R4) :: valueR4
      valueR4 = ESMF_HConfigAsR4(hconfigIter, asOkay=asOkay, rc=rc)
!EOC
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
      write (msgString, '("asOkay: ", l2, " valueR4: ", f10.6)') asOkay, valueR4
      call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
      ! real(ESMF_KIND_R8) :: valueR8
      valueR8 = ESMF_HConfigAsR8(hconfigIter, asOkay=asOkay, rc=rc)
!EOC
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
      write (msgString, '("asOkay: ", l2, " valueR8: ", f10.6)') asOkay, valueR8
      call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
      ! logical :: valueL
      valueL = ESMF_HConfigAsLogical(hconfigIter, asOkay=asOkay, rc=rc)
!EOC
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
      write (msgString, '("asOkay: ", l2, " valueL:  ", l10)') asOkay, valueL
      call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
    else
      ! Possible recursive iteration over the current hconfigIter element.
    endif

  enddo
!EOC

!-------------------------------------------------------------------------------
!BOE
! \subsubsection{Index based random access HConfig sequence parsing}
!
! An alternative way to loop over the elements contained in {\tt hconfig},
! and parsing them, is to use an {\tt index} variable. For this approach the
! size of {\tt hconfig} is queried.
!EOE
!BOC
  ! integer :: size
  size = ESMF_HConfigGetSize(hconfig, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Then looping over the elements is done with a simple do loop. Index based
! access allows random order of access, versus the iterator approach that
! only supports begin to end iteration. This is demonstrated here by writing
! the do loop in reverse order.
!EOE
!BOC
  ! integer :: i
  do i=size, 1, -1

    ! Check whether the current element is a scalar.
    ! logical :: isScalar
    isScalar = ESMF_HConfigIsScalar(hconfig, index=i, rc=rc)
!EOC
    if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
    if (isScalar) then

      ! Any scalar can be accessed as a string.
      ! character(len=:), allocatable :: string
      string = ESMF_HConfigAsString(hconfig, index=i, rc=rc)
!EOC
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
      call ESMF_LogWrite("AsString: "//string, ESMF_LOGMSG_INFO, rc=rc)
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
      ! The attempt can be made to interpret the scalar as any of the other
      ! supported data types. By default, if the scalar cannot be interpreted
      ! as the requested data type, rc /= ESMF_SUCCESS is returned. To prevent
      ! such error condition, the optional, intent(out) argument "asOkay" can
      ! be provided. If asOkay == .true. is returned, the interpretation was
      ! successful. Otherwise asOkay == .false. is returned.
      ! logical :: asOkay

      ! integer(ESMF_KIND_I4) :: valueI4
      valueI4 = ESMF_HConfigAsI4(hconfig, index=i, asOkay=asOkay, rc=rc)
!EOC
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
      write (msgString, '("asOkay: ", l2, " valueI4: ", i10)') asOkay, valueI4
      call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
      ! integer(ESMF_KIND_I8) :: valueI8
      valueI8 = ESMF_HConfigAsI8(hconfig, index=i, asOkay=asOkay, rc=rc)
!EOC
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
      write (msgString, '("asOkay: ", l2, " valueI8: ", i10)') asOkay, valueI8
      call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
      ! real(ESMF_KIND_R4) :: valueR4
      valueR4 = ESMF_HConfigAsR4(hconfig, index=i, asOkay=asOkay, rc=rc)
!EOC
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
      write (msgString, '("asOkay: ", l2, " valueR4: ", f10.6)') asOkay, valueR4
      call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
      ! real(ESMF_KIND_R8) :: valueR8
      valueR8 = ESMF_HConfigAsR8(hconfig, index=i, asOkay=asOkay, rc=rc)
!EOC
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
      write (msgString, '("asOkay: ", l2, " valueR8: ", f10.6)') asOkay, valueR8
      call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
      ! logical :: valueL
      valueL = ESMF_HConfigAsLogical(hconfig, index=i, asOkay=asOkay, rc=rc)
!EOC
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
      write (msgString, '("asOkay: ", l2, " valueL:  ", l10)') asOkay, valueL
      call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
    else
      ! Possible recursive iteration over the current index=i element.
    endif
  enddo
!EOC
!BOE
! The above loop is safe with respect to {\tt index} potentially being specified
! with an out-of-range value. This is because {\tt ESMF\_HConfigIsScalar()}
! returns {\tt .false.} in this case. There are only four valid options of what
! {\tt type} a valid HConfig element can be. Each has an associated {\tt Is}
! method:
! \begin{itemize}
! \item Null: {\tt ESMF\_HConfigIsNull()}
! \item Scalar: {\tt ESMF\_HConfigIsScalar()}
! \item Sequence: {\tt ESMF\_HConfigIsSequence()}
! \item Map: {\tt ESMF\_HConfigIsMap()}
! \end{itemize}
! The general check to see whether an index points to a valid element is
! provided by {\tt ESMF\_HConfigIsDefined()}.
!EOE
!BOC
  ! logical :: isDefined
  isDefined = ESMF_HConfigIsDefined(hconfig, index=10, rc=rc)
!BOE
! This returns {\tt isDefined == .false.} because for {\tt hconfig} a value of
! {\tt index=10} is out of range.
!EOE

!-------------------------------------------------------------------------------
!BOE
! \subsubsection{Destroy a HConfig object}
!
! When done with {\tt hconfig}, it should be destroyed in the usual manner.
!EOE
!BOC
  call ESMF_HConfigDestroy(hconfig, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

!-------------------------------------------------------------------------------
!BOE
! \subsubsection{Create a HConfig object directly loading from YAML string}
!
! The {\tt ESMF\_HConfigCreate()} method supports loading contents from
! string using YAML syntax directly via the optional {\tt content} argument.
!EOE
!BOC
  ! type(ESMF_HConfig) :: hconfig
  hconfig = ESMF_HConfigCreate(content="{car: red, bike: 22, plane: TRUE}", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Here a map is created. In this case, all of the keys are scalars (car,
! bike, plane), as are all of the associated values (red, 22, TRUE).
!EOE

!-------------------------------------------------------------------------------
!BOE
! \subsubsection{Iterator based HConfig map parsing}
!
! The elements of the {\em map} contained in {\tt hconfig} can be iterated over
! analogous to the {\em sequence} case demonstrated earlier. Again the begin
! and end iterator variables are defined.
!EOE
!BOC
  ! type(ESMF_HConfigIter) :: hconfigIterBegin, hconfigIterEnd
  hconfigIterBegin = ESMF_HConfigIterBegin(hconfig, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  hconfigIterEnd = ESMF_HConfigIterEnd(hconfig, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Then iterate over the elements in {\tt hconfig} using an iterator loop
! variable as before.
!
! The difference of the code below, compared to the {\em sequence} case, is
! that all the {\tt As} access methods here are either of the form
! {\tt As*MapKey} or {\tt As*MapVal}. This is necessary to selectively access
! the {\em map key} or {\em map value}, respectively.
!EOE
!BOC
  ! type(ESMF_HConfigIter) :: hconfigIter
  hconfigIter = hconfigIterBegin
  do while (ESMF_HConfigIterLoop(hconfigIter, hconfigIterBegin, hconfigIterEnd, rc=rc))
!EOC
    if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
    ! Check whether the current element is a scalar both for the map key
    ! and the map value.
    ! logical :: isScalar
    isScalar = ESMF_HConfigIsScalarMapKey(hconfigIter, rc=rc)
!EOC
    if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
    isScalar = isScalar .and. ESMF_HConfigIsScalarMapVal(hconfigIter, rc=rc)
!EOC
    if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
    if (isScalar) then

      ! Any scalar can be accessed as a string. Use this for the map key.
      ! character(len=:), allocatable :: stringKey
      stringKey = ESMF_HConfigAsStringMapKey(hconfigIter, rc=rc)
!EOC
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
      ! Now access the map value. Again first access as a string, which
      ! always works.
      ! character(len=:), allocatable :: string
      string = ESMF_HConfigAsStringMapVal(hconfigIter, rc=rc)
!EOC
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
      call ESMF_LogWrite("map key="//stringKey//" map value: AsString: "// &
        string, ESMF_LOGMSG_INFO, rc=rc)
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
      ! The attempt can be made to interpret the scalar as any of the other
      ! supported data types. By default, if the scalar cannot be interpreted
      ! as the requested data type, rc /= ESMF_SUCCESS is returned. To prevent
      ! such error condition, the optional, intent(out) argument "asOkay" can
      ! be provided. If asOkay == .true. is returned, the interpretation was
      ! successful. Otherwise asOkay == .false. is returned.
      ! logical :: asOkay

      ! integer(ESMF_KIND_I4) :: valueI4
      valueI4 = ESMF_HConfigAsI4MapVal(hconfigIter, asOkay=asOkay, rc=rc)
!EOC
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
      write (msgString, &
        '("map key=", A10, " map value: asOkay: ", l2, " valueI4: ", i10)') &
        stringKey, asOkay, valueI4
      call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
      ! integer(ESMF_KIND_I8) :: valueI8
      valueI8 = ESMF_HConfigAsI8MapVal(hconfigIter, asOkay=asOkay, rc=rc)
!EOC
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
      write (msgString, &
        '("map key=", A10, " map value: asOkay: ", l2, " valueI8: ", i10)') &
        stringKey, asOkay, valueI8
      call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
      ! real(ESMF_KIND_R4) :: valueR4
      valueR4 = ESMF_HConfigAsR4MapVal(hconfigIter, asOkay=asOkay, rc=rc)
!EOC
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
      write (msgString, &
        '("map key=", A10, " map value: asOkay: ", l2, " valueR4: ", f10.6)') &
        stringKey, asOkay, valueR4
      call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
      ! real(ESMF_KIND_R8) :: valueR8
      valueR8 = ESMF_HConfigAsR8MapVal(hconfigIter, asOkay=asOkay, rc=rc)
!EOC
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
      write (msgString, &
        '("map key=", A10, " map value: asOkay: ", l2, " valueR8: ", f10.6)') &
        stringKey, asOkay, valueR8
      call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
      ! logical :: valueL
      valueL = ESMF_HConfigAsLogicalMapVal(hconfigIter, asOkay=asOkay, rc=rc)
!EOC
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
      write (msgString, &
        '("map key=", A10, " map value: asOkay: ", l2, " valueL: ", l10)') &
        stringKey, asOkay, valueL
      call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
    else
      ! Deal with case where either key or value are not scalars themselves.
    endif

  enddo
!EOC

!-------------------------------------------------------------------------------
!BOE
! \subsubsection{Key based random access HConfig map parsing}
!
! The {\em map values} stored in {\tt hconfig} can be accessed
! in random order providing the {\em map key}.
! 
! To demonstrate this, a temporary array holding keys in random order is defined.
!EOE
!BOC
  ! character(5) :: keyList(3)
  keyList = ["bike ", "plane", "car  "]
!EOC
!BOE
! Then loop over the elements of {\tt keyList} and use them as {\em map key}
! to access the {\em map values} in {\tt hconfig}.
!EOE
!BOC
  ! integer :: i
  do i=1,3

    ! Ensure that all white space padding is removed.
    ! character :: stringKey
    stringKey = trim(keyList(i))

    ! Check whether the accessed map value is a scalar.
    ! logical :: isScalar
    isScalar = ESMF_HConfigIsScalar(hconfig, keyString=stringKey, rc=rc)
!EOC
    if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
    if (isScalar) then

      ! Access as a string always works.
      ! character(len=:), allocatable :: string
      string = ESMF_HConfigAsString(hconfig, keyString=stringKey, rc=rc)
!EOC
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
      call ESMF_LogWrite("map key="//stringKey//" map value: AsString: "// &
        string, ESMF_LOGMSG_INFO, rc=rc)
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
      ! The attempt can be made to interpret the scalar as any of the other
      ! supported data types. By default, if the scalar cannot be interpreted
      ! as the requested data type, rc /= ESMF_SUCCESS is returned. To prevent
      ! such error condition, the optional, intent(out) argument "asOkay" can
      ! be provided. If asOkay == .true. is returned, the interpretation was
      ! successful. Otherwise asOkay == .false. is returned.
      ! logical :: asOkay

      ! integer(ESMF_KIND_I4) :: valueI4
      valueI4 = ESMF_HConfigAsI4(hconfig, keyString=stringKey, asOkay=asOkay, rc=rc)
!EOC
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
      write (msgString, &
        '("map key=", A10, " map value: asOkay: ", l2, " valueI4: ", i10)') &
        stringKey, asOkay, valueI4
      call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
      ! integer(ESMF_KIND_I8) :: valueI8
      valueI8 = ESMF_HConfigAsI8(hconfig, keyString=stringKey, asOkay=asOkay, rc=rc)
!EOC
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
      write (msgString, &
        '("map key=", A10, " map value: asOkay: ", l2, " valueI8: ", i10)') &
        stringKey, asOkay, valueI8
      call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
      ! real(ESMF_KIND_R4) :: valueR4
      valueR4 = ESMF_HConfigAsR4(hconfig, keyString=stringKey, asOkay=asOkay, rc=rc)
!EOC
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
      write (msgString, &
        '("map key=", A10, " map value: asOkay: ", l2, " valueR4: ", f10.6)') &
        stringKey, asOkay, valueR4
      call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
      ! real(ESMF_KIND_R8) :: valueR8
      valueR8 = ESMF_HConfigAsR8(hconfig, keyString=stringKey, asOkay=asOkay, rc=rc)
!EOC
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
      write (msgString, &
        '("map key=", A10, " map value: asOkay: ", l2, " valueR8: ", f10.6)') &
        stringKey, asOkay, valueR8
      call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
      ! logical :: valueL
      valueL = ESMF_HConfigAsLogical(hconfig, keyString=stringKey, asOkay=asOkay, rc=rc)
!EOC
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
      write (msgString, &
        '("map key=", A10, " map value: asOkay: ", l2, " valueL: ", l10)') &
        stringKey, asOkay, valueL
      call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
    else
      ! Deal with case where either key or value are not scalars themselves.
    endif

  enddo
!EOC
!BOE
! The above loop is safe with respect to {\tt stringKey} potentially
! specifying a value that is not a valid {\em map key}. This is because
! {\tt ESMF\_HConfigIsScalar()} returns {\tt .false.} in this case.
!
! The general check to see whether a {\em map key} refers to a valid element
! is provided by {\tt ESMF\_HConfigIsDefined()}.
!EOE
!BOC
  ! logical :: isDefined
  isDefined = ESMF_HConfigIsDefined(hconfig, keyString="bad-key", rc=rc)
!BOE
! This returns {\tt isDefined == .false.} because {\tt hconfig} does not
! contain {\tt "bad-key"} as one of its valid {\em map keys}.
!
! Finally destroy {\tt hconfig} when done.
!EOE
!BOC
  call ESMF_HConfigDestroy(hconfig, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

!-------------------------------------------------------------------------------
!BOE
! \subsubsection{Access HConfig from Config}
!
! The {\tt ESMF\_Config} class can be queried for a HConfig object. This allows
! the use of the HConfig API to access information contained in a Config object.
!EOE
  config = ESMF_ConfigCreate(rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  call ESMF_ConfigLoadFile(config, filename="example.yaml", rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  ! type(ESMF_Config) :: config
  ! type(ESMF_HConfig) :: hconfig
  call ESMF_ConfigGet(config, hconfig=hconfig, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! The {\tt hconfig} obtained this way is indistinguishable from an explicitly
! created HConfig instance. E.g. it can be queried for its {\em type} using the
! {\tt Is} methods:
!BOC
  ! logical :: isDefined
  isDefined = ESMF_HConfigIsDefined(hconfig, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  write (msgString, '("HConfig from Config IsDefined: ", l2)') isDefined
  call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  ! logical :: isNull
  isNull = ESMF_HConfigIsNull(hconfig, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  write (msgString, '("HConfig from Config IsNull: ", l2)') isNull
  call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  ! logical :: isSequence
  isSequence = ESMF_HConfigIsSequence(hconfig, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  write (msgString, '("HConfig from Config IsSequence: ", l2)') isSequence
  call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  ! logical :: isMap
  isMap = ESMF_HConfigIsMap(hconfig, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  write (msgString, '("HConfig from Config IsMap: ", l2)') isMap
  call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Once done with {\tt hconfig} it must {\em not} be destroyed explicitly by
! the user. The {\tt hconfig} is still owned by the {\tt config} object, and
! will be destroyed automatically when the {\tt config} object is destroyed.
! This follows the simple rule that a user only owns those objects created
! explicitly by calling a {\tt Create()} method.
!EOE
  call ESMF_ConfigDestroy(config, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

!-------------------------------------------------------------------------------
!BOE
! \subsubsection{Load HConfig from YAML file}
!
! One option to load a YAML file is to first create an empty HConfig object,
! followed by calling {\tt ESMF\_HConfigFileLoad()}.
!EOE
!BOC
  ! type(ESMF_HConfig) :: hconfig
  hconfig = ESMF_HConfigCreate(rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  call ESMF_HConfigFileLoad(hconfig, filename="example.yaml", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  ! When done destroy as usual.
  call ESMF_HConfigDestroy(hconfig, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! The alternative option is to create and load the HConfig object in a single
! call to {\tt ESMF\_HConfigCreate()} using the optional {\tt filename}
! argument to specify the YAML file.
!EOE
!BOC
  ! type(ESMF_HConfig) :: hconfig
  hconfig = ESMF_HConfigCreate(filename="example.yaml", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  ! And again destroy hconfig when done with it.
  call ESMF_HConfigDestroy(hconfig, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

!-------------------------------------------------------------------------------
!BOE
! \subsubsection{Save HConfig to YAML file}
!
! A HConfig object can be saved to a YAML file by calling the
! {\tt ESMF\_HConfigFileSave()} method. To demonstrate this, a YAML file
! containing:
! \begin{verbatim}
! # An example of YAML configuration file
!
! simple_list: [1, 2, 3, abc, b, TRUE]
! simple_map:
!   car: red
!   [bike, {p1: 10, p2: 20}]: [bmx, mountain, street]
!   plane: [TRUE, FALSE]
! \end{verbatim}
!
! is loaded to create the {\tt hconfig} object:
!EOE
!BOC
  hconfig = ESMF_HConfigCreate(filename="example.yaml", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Now the {\tt hconfig} object can be saved to file using the
! {\tt ESMF\_HConfigFileSave()} method.
!EOE
!BOC
  call ESMF_HConfigFileSave(hconfig, filename="saveMe.yml", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Notice that the resulting contents of file {\tt saveMe.yml} does {\em not}
! contain the comments of the original file. The YAML structure is saved.
! \begin{verbatim}
! simple_list: [1, 2, 3, abc, b, TRUE]
! simple_map:
!   car: red
!   [bike, {p1: 10, p2: 20}]: [bmx, mountain, street]
!   plane: [TRUE, FALSE]
! \end{verbatim}
!
! The object specified in {\tt ESMF\_HConfigFileSave()} can be a regular node
! (of any type) or a {\em sequence} iterator. In either case the file written
! represents the YAML hierarchy with the specified object as the root node.
!
! In the case of a {\em map} iterator, it is necessary to first create an
! appropriate root node utilizing the appropriate {\tt CreateAt} method. This
! allows saving either the {\em map key} or {\em map value} node at the
! current iterator. This is demonstrated below.
!
! In the current example, where {\tt hconfig} is a map with two elements, a
! map iterator can be set to the beginning using the following call.
!EOE
!BOC
  ! type(ESMF_HConfigIter) :: hconfigIter
  hconfigIter = ESMF_HConfigIterBegin(hconfig, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Here {\tt hconfigIter} cannot be saved to file directly. To write the
! {\em key} node, first create a HConfig object for it using method
! {\tt ESMF\_HConfigCreateAtMapKey()}.
!EOE
!BOC
  ! type(ESMF_HConfig) :: hconfigTemp
  hconfigTemp = ESMF_HConfigCreateAtMapKey(hconfigIter, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Then save it.
!EOE
!BOC
  call ESMF_HConfigFileSave(hconfigTemp, filename="mapKeyBegin.yaml", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! And finally destroy {\tt hconfigTemp} again.
!EOE
!BOC
  call ESMF_HConfigDestroy(hconfigTemp, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Similarly, to write the {\em value} node to file, first create a HConfig
! object for it using method {\tt ESMF\_HConfigCreateAtMapVal()}.
!EOE
!BOC
  ! type(ESMF_HConfig) :: hconfigTemp
  hconfigTemp = ESMF_HConfigCreateAtMapVal(hconfigIter, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Then save it.
!EOE
!BOC
  call ESMF_HConfigFileSave(hconfigTemp, filename="mapValBegin.yaml", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! And destroy it.
!EOE
!BOC
  call ESMF_HConfigDestroy(hconfigTemp, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Since {\tt hconfig} is a {\em map} node, it is also possible to directly
! create a {\em value} node by calling {\tt ESMF\_HConfigCreateAt()}
! on it, using the desired {\em key}.
!EOE
!BOC
  ! type(ESMF_HConfig) :: hconfigTemp
  hconfigTemp = ESMF_HConfigCreateAt(hconfig, keyString="simple_map", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Now {\tt hconfigTemp} points to the {\em value} node, that is
! associated with the "simple\_map" key, which is in turn a map:
! \begin{verbatim}
! car: red
! [bike, {p1: 10, p2: 20}]: [bmx, mountain, street]
! plane: [TRUE, FALSE]
! \end{verbatim}
! It can be saved to file as usual.
!EOE
!BOC
  call ESMF_HConfigFileSave(hconfigTemp, filename="mapValAtKey.yaml", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Any of the {\em value} nodes of {\tt hconfigTemp} can be accessed through
! recursive usage of the {\tt ESMF\_HConfigCreateAt()} method.
! For example, the following call accesses the {\em value} node that is
! associated with {\tt keyString="[bike, {p1: 10, p2: 20}]"}. Here the
! {\tt keyString} is interpreted as YAML syntax, for which an internal HConfig
! representation is created, and finally the map held by {\tt hconfigTemp} is
! searched for a matching key.
!EOE
!BOC
  ! type(ESMF_HConfig) :: hconfigTemp2
  hconfigTemp2 = ESMF_HConfigCreateAt(hconfigTemp, &
    keyString="[bike, {p1: 10, p2: 20}]", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Now {\tt hconfigTemp2} points to the {\em sequence node} with contents
! {\tt [bmx, mountain, street]}. It, too, can be saved to file.
!EOE
!BOC
  call ESMF_HConfigFileSave(hconfigTemp2, filename="mapValRecursive.yaml", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Finally {\tt hconfigTemp2}, {\tt hconfigTemp} and {\tt hconfig} should be destroyed.
!EOE
!BOC
  call ESMF_HConfigDestroy(hconfigTemp2, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  call ESMF_HConfigDestroy(hconfigTemp, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  call ESMF_HConfigDestroy(hconfig, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)


!-------------------------------------------------------------------------------
!BOE
! \subsubsection{Tags and Schemas}
!
! The HConfig class implements tags to identify a node's data type according to
! the YAML standard. The combination of a set of defined tags and a mechanism
! to resolve non-specific tags is called a schema under YAML. The HConfig class
! implements the YAML Core schema, which is an extension of the JSON schema.
!
! This example starts with an empty HConfig object.
!EOE
!BOC
  ! type(ESMF_HConfig) :: hconfig
  hconfig = ESMF_HConfigCreate(rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Method {\tt ESMF\_HConfigGetTag()} is used to query the tag.
!EOE
!BOC
  ! character(len=:), allocatable :: tag
  tag = ESMF_HConfigGetTag(hconfig, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  write (msgString, '("Empty HConfig tag:       ", A30)') tag
  call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! \paragraph{Null}
! The {\tt hconfig} is an empty object, in other words it is associated with
! NULL. The Core schema tag for this situation is
! {\tt{\bf tag:yaml.org,2002:null}}.
!
! Next, file {\tt exampleWithTags.yaml} is loaded.
!BOC
  call ESMF_HConfigFileLoad(hconfig, filename="exampleWithTags.yaml", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! The file contains the following YAML:
! \begin{verbatim}
! value_one:    {word1: this, word2: is, word3: a, word4: map}
! value_two:    [this, is, a, list]
! value_three:            123
! value_four:   !!float   123
! value_five:             2.5
! value_six:    !!str     2.5
! value_seven:            False
! value_eight:  !!str     true
! value_nine:             0x234
! value_ten:              Null
! value_eleven:
! value_twelve:  !myStuff xyz
! \end{verbatim}
!
! The value associated with {\em map key} "value\_ten" is explicitly set to
! {\tt Null}. The associated tag for this node can be obtained
! directly by supplying the {\tt keyString} argument.
!EOE
!BOC
  tag = ESMF_HConfigGetTag(hconfig, keyString="value_ten", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  write (msgString, '("value_ten HConfig tag:  ", A30)') tag
  call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! The resolved Core schema tag is again {\tt{\bf tag:yaml.org,2002:null}}. There
! are four special values that resolve to this tag: {\tt null}, {\tt Null},
! {\tt NULL}, and {\tt $\sim$}. In addition to those special values, an {\em empty}
! value, as demonstrated by {\em key} "value\_eleven", also automatically
! resolves to {\tt{\bf tag:yaml.org,2002:null}}.
!EOE
!BOC
  tag = ESMF_HConfigGetTag(hconfig, keyString="value_eleven", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  write (msgString, '("value_eleven HConfig tag:  ", A30)') tag
  call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! \paragraph{Map}
! On the top level, after loading the YAML file, {\tt hconfig} is a map. 
! Querying again for the tag of {\tt hconfig},
!EOE
!BOC
  tag = ESMF_HConfigGetTag(hconfig, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  write (msgString, '("Top level HConfig tag: ", A30)') tag
  call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! results in the Core schema tag of {\tt{\bf tag:yaml.org,2002:map}}.
!
! \paragraph{Sequence}
! The value associated with {\em map key} "value\_two" in the current
! {\tt hconfig} object is a sequence. The tag for this node can be obtained
! directly by supplying the {\tt keyString} argument.
!EOE
!BOC
  tag = ESMF_HConfigGetTag(hconfig, keyString="value_two", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  write (msgString, '("value_two HConfig tag:  ", A30)') tag
  call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! The resolved Core schema tag for a sequence is {\tt{\bf tag:yaml.org,2002:seq}}.
!
! \paragraph{String}
! All of the {\em keys} of the currently loaded {\tt hconfig} object are
! strings. To obtain the tag that is associated with the first key node,
! an iterator is used to access the map nodes individually.
!EOE
!BOC
  ! type(ESMF_HConfigIter) :: hconfigIter
  hconfigIter = ESMF_HConfigIterBegin(hconfig, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Now the {\tt ESMF\_HConfigGetTagMapKey()} method can be used to obtain
! the tag for the first key node.
!EOE
!BOC
  tag = ESMF_HConfigGetTagMapKey(hconfigIter, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  write (msgString, '("first key HConfig tag:  ", A30)') tag
  call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Here the Core schema tag resolves to {\tt{\bf tag:yaml.org,2002:str}}.
!
! \paragraph{Integer}
! The value associated with {\em map key} "value\_three" in the current
! {\tt hconfig} object is an integer number. The tag for this node can be
! obtained as before by directly supplying the {\tt keyString} argument.
!EOE
!BOC
  tag = ESMF_HConfigGetTag(hconfig, keyString="value_three", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  write (msgString, '("value_three HConfig tag:  ", A30)') tag
  call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! The Core schema tag resolves to {\tt{\bf tag:yaml.org,2002:int}}.
!
! The value associated with {\em map key} "value\_nine" in the current
! {\tt hconfig} object is an integer number in hex. The tag for this node can be
! obtained as before by directly supplying the {\tt keyString} argument.
!EOE
!BOC
  tag = ESMF_HConfigGetTag(hconfig, keyString="value_nine", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  write (msgString, '("value_nine HConfig tag:  ", A30)') tag
  call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! The Core schema tag resolves to {\tt{\bf tag:yaml.org,2002:int}}.
!
! \paragraph{Floating Point}
! The value associated with {\em map key} "value\_five" in the current
! {\tt hconfig} object is a floating point number. The tag for this node can be
! obtained as before by directly supplying the {\tt keyString} argument.
!EOE
!BOC
  tag = ESMF_HConfigGetTag(hconfig, keyString="value_five", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  write (msgString, '("value_five HConfig tag:    ", A30)') tag
  call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! The Core schema tag resolves to {\tt{\bf tag:yaml.org,2002:float}}.
!
! \paragraph{Boolean}
! The value associated with {\em map key} "value\_seven" in the current
! {\tt hconfig} object is a boolean. The tag for this node can be
! obtained as before by directly supplying the {\tt keyString} argument.
!EOE
!BOC
  tag = ESMF_HConfigGetTag(hconfig, keyString="value_seven", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  write (msgString, '("value_seven HConfig tag:    ", A30)') tag
  call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! The Core schema tag resolves to {\tt{\bf tag:yaml.org,2002:bool}}. The
! supported boolean values are {\tt true}, {\tt True}, {\tt TRUE},
! {\tt false}, {\tt False}, and {\tt FALSE}.
!
! \paragraph{Explicit standard tags}
! Standard short-hand tags can be specified to change the default resolution.
! This is demonstrated for {\em map keys} "value\_four", "value\_six", and
! "value\_eight".
!EOE
!BOC
  tag = ESMF_HConfigGetTag(hconfig, keyString="value_four", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  write (msgString, '("value_four HConfig tag:    ", A30)') tag
  call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  tag = ESMF_HConfigGetTag(hconfig, keyString="value_six", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  write (msgString, '("value_six HConfig tag:    ", A30)') tag
  call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  tag = ESMF_HConfigGetTag(hconfig, keyString="value_eight", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  write (msgString, '("value_eight HConfig tag:    ", A30)') tag
  call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! The default resolution of these three keys would be
! {\tt tag:yaml.org,2002:int}, {\tt tag:yaml.org,2002:float}, and
! {\tt tag:yaml.org,2002:bool}, respectively. However, with the explict tags
! in place, they are resolved to {\tt tag:yaml.org,2002:float},
! {\tt tag:yaml.org,2002:str}, {\tt tag:yaml.org,2002:str}, instead.
!
! \paragraph{Explicit custom tags}
! The HConfig class supports application-specific local tags as per the YAML
! standard. These are tags that are not known by the Core schema. If such a
! tag is encountered on a node, it is preserved and no further automatic
! tag resolution is performed.
!
! The value associated with {\em map key} "value\_twelve" in the current
! {\tt hconfig} object has a custom tag. The tag for this node can be
! obtained as before by directly supplying the {\tt keyString} argument.
!EOE
!BOC
  tag = ESMF_HConfigGetTag(hconfig, keyString="value_twelve", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  write (msgString, '("value_twelve HConfig tag:    ", A30)') tag
  call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! The returned tag is {\tt{\bf !myStuff}}.
!
! Finally clean up {\tt hconfig}.
!EOE
!BOC
  ! Destroy hconfig when done with it.
  call ESMF_HConfigDestroy(hconfig, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

!-------------------------------------------------------------------------------
!BOE
! \subsubsection{Adding, Setting, and Removing elements from HConfig object}
!
! After creating a HConfig object without specifying {\tt content} or
! {\tt filename}, it is empty.
!EOE
!BOC
  ! type(ESMF_HConfig) :: hconfig
  hconfig = ESMF_HConfigCreate(rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

  call ESMF_HConfigFileSave(hconfig, filename="build_and_edit_00.yaml", rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Now the {\tt ESMF\_HConfigAdd()} method can be used to add new elements to
! an existing HConfig object. The {\tt Add()} interfaces are heavily overloaded,
! each specific entry point featuring a number of optional arguments. The two
! fundamentally different ways of using {\tt Add()} are: (1) adding an element
! at the end of a {\em sequence} or (2) adding an element to a {\em map}.
! Here, where {\tt hconfig} is empty, either option is possible. The way the
! first element is added determines whether {\tt hconfig} is a sequence or
! a map.
!
! The following call adds an element to {\tt hconfig} without specifying the
! {\tt addKey} or {\tt addKeyString} argument. This indicates that a sequence
! element is added to the end, and as a consequence rendering {\tt hconfig}
! a {\em sequence}.
!EOE
!BOC
  call ESMF_HConfigAdd(hconfig, "first added item", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

  call ESMF_HConfigFileSave(hconfig, filename="build_and_edit_01.yaml", rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Additional elements can be added at the end of {\tt hconfig}.
!EOE
!BOC
  call ESMF_HConfigAdd(hconfig, 12.57_ESMF_KIND_R8, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

  call ESMF_HConfigFileSave(hconfig, filename="build_and_edit_02.yaml", rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! At this point, the content of {\tt hconfig} is a sequence with two elements.
! \begin{verbatim}
! - first added item
! - 12.5700000000
! \end{verbatim}
!
! It is also possible to add an entire HConfig structure as an item to the
! existing sequence. One way to do this is to use standar YAML syntax when
! adding the element. Here a {\em map} is added to the end of {\tt hconfig}.
!EOE
!BOC
  call ESMF_HConfigAdd(hconfig, "{k1: 7, k2: 25}", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

  call ESMF_HConfigFileSave(hconfig, filename="build_and_edit_03.yaml", rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! This results in the following content, where the third element of the sequence
! is the map that was just added.
! \begin{verbatim}
! - first added item
! - 12.5700000000
! - {k1: 7, k2: 25}
! \end{verbatim}
!
! A HConfig structure can even be loaded from file and added to the end of 
! {\tt hconfig}. This requires a temporary HConfig object.
!EOE
!BOC
  ! type(ESMF_HConfig) :: hconfigTemp
  hconfigTemp = ESMF_HConfigCreate(filename="example.yaml", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  call ESMF_HConfigAdd(hconfig, hconfigTemp, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  call ESMF_HConfigDestroy(hconfigTemp, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

  call ESMF_HConfigFileSave(hconfig, filename="build_and_edit_04.yaml", rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! The result is the following content for {\tt hconfig}.
! \begin{verbatim}
! - first added item
! - 12.5700000000
! - {k1: 7, k2: 25}
! - simple_list: [1, 2, 3, abc, b, TRUE]
!   simple_map:
!     car: red
!     [bike, {p1: 10, p2: 20}]: [bmx, mountain, street]
!     plane: [TRUE, FALSE]
! \end{verbatim}
!
! Using the {\tt CreateAt()} method, it is easy to gain access to any specific
! element in {\tt hconfig}. Since {\tt hconfig} is a {\em sequence}, the proper
! access is by {\em index}.
!EOE
!BOC
  ! type(ESMF_HConfig) :: hconfigTemp
  hconfigTemp = ESMF_HConfigCreateAt(hconfig, index=3, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

  call ESMF_HConfigFileSave(hconfigTemp, filename="build_and_edit_05.yaml", rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! This creates a temporary HConfig object that {\em references} the 3rd element
! of the sequence stored by {\tt hconfig}. If {\tt hconfigTemp} were to be
! saved to file, it would have the following content.
! \begin{verbatim}
! {k1: 7, k2: 25}
! \end{verbatim}
!
! Using the {\tt Set()} methods, contents in {\tt hconfigTemp}, and thus in
! the 3rd element of {\tt hconfig} can be modified. The content of
! {\tt hconfigTemp} is a {\em map}, and the proper access is by {\em map key}.
! Here key "k2" is being modified.
!EOE
!BOC
  call ESMF_HConfigSet(hconfigTemp, 12.5, keyString="k2", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! The {\tt hconfigTemp} is a reference to a {\em map}, and new elements can be
! added using the {\tt addKeyString} argument.
!EOE
!BOC
  call ESMF_HConfigAdd(hconfigTemp, .true., addKeyString="k3", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  call ESMF_HConfigDestroy(hconfigTemp, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  call ESMF_HConfigFileSave(hconfig, filename="build_and_edit_06.yaml", rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! After these operations, the content of {\tt hconfig} has changed to
! \begin{verbatim}
! - first added item
! - 12.5700000000
! - {k1: 7, k2: 12.5000000000, k3: True}
! - simple_list: [1, 2, 3, abc, b, TRUE]
!   simple_map:
!     car: red
!     [bike, {p1: 10, p2: 20}]: [bmx, mountain, street]
!     plane: [TRUE, FALSE]
! \end{verbatim}
! Notice that while {\tt hconfigTemp} should be destroyed explicitly, as in the
! example above, doing so does {\em not} affect the referenced node inside the
! {\tt hconfig} object. In other words, {\tt hconfigTemp} was a reference, and
! {\em not} a deep copy of the node! There is some allocated memory associated
! with the {\tt hconfigTemp} reference that gets cleaned up with the
! {\tt Destroy()} call, but it does not affect the reference itself.
!
! The {\tt Set()} method can also be used to edit the element referenced
! itself. Here the 4th element in the {\tt hconfig} sequence is set to be a
! simple scalar string value using this approach.
!EOE
!BOC
  ! type(ESMF_HConfig) :: hconfigTemp
  hconfigTemp = ESMF_HConfigCreateAt(hconfig, index=4, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  call ESMF_HConfigSet(hconfigTemp, "Simple scalar string value", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  call ESMF_HConfigDestroy(hconfigTemp, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

  call ESMF_HConfigFileSave(hconfig, filename="build_and_edit_07.yaml", rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! The content of {\tt hconfig} has been updated as below.
! \begin{verbatim}
! - first added item
! - 12.5700000000
! - {k1: 7, k2: 12.5000000000, k3: True}
! - Simple scalar string value
! \end{verbatim}
!
! There is a simpler alternative for {\em direct} element editing in an
! HConfig object via the {\tt Set()} method. Using the {\tt index} or
! {\tt keyString} argument, a sequence or map element, respectively, can
! be edited directly. For instance,
!EOE
!BOC
  call ESMF_HConfigSet(hconfig, "[a, b, c]", index=4, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

  call ESMF_HConfigFileSave(hconfig, filename="build_and_edit_08.yaml", rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! sets the 4th element of {\tt hconfig} directly, without the need of a
! temporary HConfig variable. This updates the content to:
! \begin{verbatim}
! - first added item
! - 12.5700000000
! - {k1: 7, k2: 12.5000000000, k3: True}
! - [a, b, c]
! \end{verbatim}
!
! Elements can be deleted from a HConfig object holding a sequence or map
! using the {\tt Remove()} method, specifying the {\em index} or
! {\em map key}, respectively. Here the 2nd element of the sequence held by
! {\tt hconfig} is removed.
!EOE
!BOC
  call ESMF_HConfigRemove(hconfig, index=2, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

  call ESMF_HConfigFileSave(hconfig, filename="build_and_edit_09.yaml", rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! The result is a sequence with only three remaining elements.
! \begin{verbatim}
! - first added item
! - {k1: 7, k2: 12.5000000000, k3: True}
! - [a, b, c]
! \end{verbatim}
!
! To demonstrate removal of an element from a {\em map}, the second
! {\tt hconfig} element is referenced by a temporary HConfig object. The element
! with key "k2" is then removed using the respective {\tt Remove()} method.
!EOE
!BOC
  ! type(ESMF_HConfig) :: hconfigTemp
  hconfigTemp = ESMF_HConfigCreateAt(hconfig, index=2, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  call ESMF_HConfigRemove(hconfigTemp, keyString="k2", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  call ESMF_HConfigDestroy(hconfigTemp, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

  call ESMF_HConfigFileSave(hconfig, filename="build_and_edit_10.yaml", rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! The resulting {\tt hconfig} content is as expected.
! \begin{verbatim}
! - first added item
! - {k1: 7, k3: True}
! - [a, b, c]
! \end{verbatim}
!
! Finally the entire contents of {\tt hconfig} can be deleted by setting the
! node itself to one of the special NULL values.
!EOE
!BOC
  call ESMF_HConfigSet(hconfig, "NULL", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

  call ESMF_HConfigFileSave(hconfig, filename="build_and_edit_11.yaml", rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! If saved to file, the contents of {\tt hconfig} shows up as a simple tilde
! character, indicating its NULL value.
! \begin{verbatim}
! ~
! \end{verbatim}
!
! At this point {\tt hconfig} is neither a {\em sequence} nor a {\em map}. It is
! NULL. Adding a map element, i.e. an element with a {\em key}, turns
! {\tt hconfig} into a map.
!EOE
!BOC
  call ESMF_HConfigAdd(hconfig, "first added item", addKeyString="item1", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

  call ESMF_HConfigFileSave(hconfig, filename="build_and_edit_12.yaml", rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! The contents of {\tt hconfig} now is a map with a single entry:
! character, indicating its NULL value.
! \begin{verbatim}
! item1: first added item
! \end{verbatim}
!
! As in other contexts before, the content as well as the specified
! {\tt addKeyString} can be of any legal YAML syntax. This is demonstrated
! in the following {\tt Add()} calls.
!EOE
!BOC
  ! Add YAML sequence content with simple scalar key.
  call ESMF_HConfigAdd(hconfig, "[2, added, item]", addKeyString="item2", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  ! Add simple scalar content with a YAML map as key.
  call ESMF_HConfigAdd(hconfig, "third added item", addKeyString="{item: 3}", &
    rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  ! Add complex YAML content with YAML sequence as key.
  call ESMF_HConfigAdd(hconfig, "{4th: item, 5th: [true, false]}", &
    addKeyString="[1, 2, 3, 4]", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

  call ESMF_HConfigFileSave(hconfig, filename="build_and_edit_13.yaml", rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Resulting in the final contents of {\tt hconfig}:
! \begin{verbatim}
! item1: first added item
! item2: [2, added, item]
! {item: 3}: third added item
! [1, 2, 3, 4]: {4th: item, 5th: [true, false]}
! \end{verbatim}
! Finally clean up {\tt hconfig}.
!EOE
!BOC
  ! Destroy hconfig when done with it.
  call ESMF_HConfigDestroy(hconfig, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

!-------------------------------------------------------------------------------
!BOE
! \subsubsection{Working with multiple YAML documents}
!
! The YAML standard supports multiple documents in a single file by separating
! each document with a line containing three dashes (-{}-{}-). Optionally the
! end of each document may be indicated by three periods (...). For example,
! the following YAML file contains three documents (notice the optional usage
! of the document end marker):
! \begin{verbatim}
! ---
! - This
! - is
! - the
! - first document.
! ...
! ---
! - And
! - a second document.
! ---
! - And
! - finally a
! - third document.
! \end{verbatim}
! All of the documents contained in a YAML file can be loaded into a single
! HConfig object all at once.
!EOE
!BOC
  ! type(ESMF_HConfig) :: hconfig
  hconfig = ESMF_HConfigCreate(filename="multiDoc.yaml", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! The number of documents held by {\tt hconfig} can be queried.
!EOE
!BOC
  ! integer :: docCount
  docCount = ESMF_HConfigGetDocCount(hconfig, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  write (msgString, '("docCount: ", i8)') docCount
  call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! When saving {\tt hconfig}, a multi-document YAML file will be written.
!EOE
!BOC
  call ESMF_HConfigFileSave(hconfig, filename="multi_00.yaml", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! The {\tt ESMF\_HConfigFileSave()} method implements strict usage of both
! document markers when saving a multi-document HConfig object.
! \begin{verbatim}
! ---
! - This
! - is
! - the
! - first document.
! ...
! ---
! - And
! - a second document.
! ...
! ---
! - And
! - finally a
! - third document.
! ...
! \end{verbatim}
!
! The optional {\tt doc} argument can be specified when saving the
! multi-document {\tt hconfig} to file. Only the specified document, by index,
! is written to file.
!EOE
!BOC
  call ESMF_HConfigFileSave(hconfig, filename="multi_01.yaml", doc=2, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! This operation results in a single document file:
! \begin{verbatim}
! - And
! - a second document.
! \end{verbatim}
! The {\tt ESMF\_HConfigFileLoad()} method also accepts the optional {\tt doc}
! argument. When specified, the result is a single-document {\tt hconfig}
! object, holding the content of the indicated document within the loaded file.
!EOE
!BOC
  call ESMF_HConfigFileLoad(hconfig, filename="multiDoc.yaml", doc=3, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Saving {\tt hconfig} to file shows the expected situation.
!EOE
!BOC
  call ESMF_HConfigFileSave(hconfig, filename="multi_02.yaml", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Resulting in:
! \begin{verbatim}
! - And
! - finally a
! - third document.
! \end{verbatim}
!
! Most HConfig methods provide the optional {\tt doc} argument. If present,
! the method applies to the specified document. The default for when the
! {\tt doc} argument is not present, for most methods is to use the first
! document in the object. The exceptions to this rule are the
! {\tt ESMF\_HConfigFileSave()} and {\tt ESMF\_HConfigFileLoad()} methods.
! Here the default is to apply the operation to {\em all} documents.
!
! When done, clean up {\tt hconfig} as usual.
!EOE
!BOC
  ! Destroy hconfig when done with it.
  call ESMF_HConfigDestroy(hconfig, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

!-------------------------------------------------------------------------------
!BOE
! \subsubsection{Sequence shortcuts for: Create, As, Add, and Set}
!
! The HConfig class offers shortcut methods for the sake of convenience when
! working with sequences where all elements are of the same typekind. In these
! cases a sequence can be represented as a one-dimensional Fortran array. The
! interfaces are overloaded for one-dimensional string, logical, I4, I8, R4,
! and R8 typekinds.
!
! Using a Fortran array constructor for the actual argument, a sequence of I4
! data is created.
!EOE
!BOC
  ! type(ESMF_HConfig) :: hconfig
  hconfig = ESMF_HConfigCreate([1,2,3], rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  call ESMF_HConfigFileSave(hconfig, filename="shortcut_00.yaml", rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! The content of {\tt hconfig} can be accessed in the usual manner, via
! iterators or indexed access. Alternatively, the sequence of I4 elements
! can be retrieved in a single call using a one-dimensional allocatable
! Fortran array of the appropriate typekind.
!EOE
!BOC
  ! integer(ESMF_KIND_I4), allocatable :: valueI4Seq(:)
  valueI4Seq = ESMF_HConfigAsI4Seq(hconfig, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  write (msgString, '("valueI4Seq: ", 3i8)') valueI4Seq
  call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! The optional, intent(out) argument {\tt asOkay} is available as in the scalar
! access methods. If specified, errors triggered by unsupported typekind
! conversion exceptions are suppressed, and instead {\tt asOkay == .false.} is
! returned by the call.
!
! Here an attempt is made to access the content of {\tt hconfig} as a sequence
! of logicals. This is not supported, and will be flagged in the return value
! of {\tt asOkay}.
!EOE
!BOC
  ! logical, allocatable :: valueLSeq(:)
  valueLSeq = ESMF_HConfigAsLogicalSeq(hconfig, asOkay=asOkay, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  write (msgString, '("asOkay for Logical: ", l2)') asOkay
  call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Finally the content of {\tt hconfig} is accessed as a sequence of strings.
! This is always supported since every typekind can be represented in string
! form.
!EOE
!BOC
  ! character(len=:), allocatable :: valueSSeq(:)
  valueSSeq = ESMF_HConfigAsStringSeq(hconfig, stringLen=10, asOkay=asOkay, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  write (msgString, '("asOkay for String: ", l2)') asOkay
  call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  write (msgString, '("valueSSeq: ", 3A10)') valueSSeq
  call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Next {\tt hconfig} is cleaned up before re-creating it as an empty HConfig
! object.
!EOE
!BOC
  ! Clean up hconfig.
  call ESMF_HConfigDestroy(hconfig, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  ! type(ESMF_HConfig) :: hconfig
  hconfig = ESMF_HConfigCreate(rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Sequences can be added to {\tt hconfig} conveniently using the overloaded
! {\tt Add()} interfaces that accept one-dimensional Fortran arrays. Here a
! sequence of strings is added as the value of a map entry with key string "k1".
!EOE
!BOC
  call ESMF_HConfigAdd(hconfig, ["aaa","bbb","ccc"], addKeyString="k1", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  call ESMF_HConfigFileSave(hconfig, filename="shortcut_01.yaml", rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! Next a sequence of R4 values is added to the map held by {\tt hconfig},
! under key string "k2".
!EOE
!BOC
  call ESMF_HConfigAdd(hconfig, [1.0,1.25,1.5], addKeyString="k2", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  call ESMF_HConfigFileSave(hconfig, filename="shortcut_02.yaml", rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! At this point {\tt hconfig} contains the following information:
! \begin{verbatim}
! k1:
!   - aaa
!   - bbb
!   - ccc
! k2:
!   - 1
!   - 1.25
!   - 1.5
! \end{verbatim}
!
! The {\tt Set()} interfaces are also overloaded to accept one-dimensional
! Fortran arrays as input. This makes it easy to set any node to a sequence
! that is available as Fortran array. Here the value associated with key "k1"
! is changed to a list of two logicals.
!EOE
!BOC
  call ESMF_HConfigSet(hconfig, [.true.,.false.], keyString="k1", rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  call ESMF_HConfigFileSave(hconfig, filename="shortcut_03.yaml", rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! This changes the content of {\tt hconfig} as expected.
! \begin{verbatim}
! k1:
!   - True
!   - False
! k2:
!   - 1
!   - 1.25
!   - 1.5
! \end{verbatim}
!
! Finally clean up {\tt hconfig} as usual.
!EOE
!BOC
  ! Destroy hconfig when done with it.
  call ESMF_HConfigDestroy(hconfig, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

!-------------------------------------------------------------------------------
!-------------------------------------------------------------------------------
  ! IMPORTANT: ESMF_STest() prints the PASS string and the # of processors in the log
  ! file that the scripts grep for.
  call ESMF_STest((finalrc.eq.ESMF_SUCCESS), testname, failMsg, result, ESMF_SRCLINE)

  call ESMF_Finalize(rc=rc)
  if (rc/=ESMF_SUCCESS) finalrc = ESMF_FAILURE
  if (finalrc==ESMF_SUCCESS) then
    print *, "PASS: ESMF_HConfigEx.F90"
  else
    print *, "FAIL: ESMF_HConfigEx.F90"
  endif

end program