docs: def check_flags(self, ds):
          '''
          Check the flag_values, flag_masks and flag_meanings attributes for
          variables to ensure they are CF compliant.
  
          CF §3.5 The attributes flag_values, flag_masks and flag_meanings are
          intended to make variables that contain flag values self describing.
          Status codes and Boolean (binary) condition flags may be expressed with
          different combinations of flag_values and flag_masks attribute
          definitions.
  
          The flag_values and flag_meanings attributes describe a status flag
          consisting of mutually exclusive coded values.
  
          The flag_meanings attribute is a string whose value is a blank
          separated list of descriptive words or phrases, one for each flag
          value. Each word or phrase should consist of characters from the
          alphanumeric set and the following five: '_', '-', '.', '+', '@'.
  
          The flag_masks and flag_meanings attributes describe a number of
          independent Boolean conditions using bit field notation by setting
          unique bits in each flag_masks value.
  
          The flag_masks, flag_values and flag_meanings attributes, used
          together, describe a blend of independent Boolean conditions and
          enumerated status codes. A flagged condition is identified by a bitwise
          AND of the variable value and each flag_masks value; a result that
          matches the flag_values value indicates a true condition.
  
          :param netCDF4.Dataset ds: An open netCDF dataset
          :rtype: list
          :return: List of results
          '''
          ret_val = []
  
          for name in cfutil.get_flag_variables(ds):
              variable = ds.variables[name]
              flag_values = getattr(variable, "flag_values", None)
              flag_masks = getattr(variable, "flag_masks", None)
  
              valid_flags_var = TestCtx(BaseCheck.HIGH, self.section_titles['3.5'])
              # Check that the variable defines mask or values
              valid_flags_var.assert_true(flag_values is not None or flag_masks is not None,
                                          "{} does not define either flag_masks or flag_values".format(name))
              ret_val.append(valid_flags_var.to_result())
  
              valid_meanings = self._check_flag_meanings(ds, name)
              ret_val.append(valid_meanings)
  
              # check flag_values
              if flag_values is not None:
                  valid_values = self._check_flag_values(ds, name)
                  ret_val.append(valid_values)
  
              # check flag_masks
              if flag_masks is not None:
                  valid_masks = self._check_flag_masks(ds, name)
                  ret_val.append(valid_masks)
  
              if flag_values is not None and flag_masks is not None:
                  allv = list(map(lambda a, b: a & b == a, list(zip(flag_values, flag_masks))))
  
                  allvr = Result(BaseCheck.MEDIUM, all(allv), self.section_titles['3.5'])
                  if not allvr.value:
                      allvr.msgs = ["flag masks and flag values for '{}' combined don't equal flag value".format(name)]
  
                  ret_val.append(allvr)
  
          return ret_val