text: from __future__ import division
  
  import six
  import humanfriendly
  import pyparsing
  from .pyhocon import ConfigFactory, HOCONConverter
  
  
  def parse_human_size(value):
      if isinstance(value, six.string_types):
          return humanfriendly.parse_size(value)
      return value
  
  
  def get_percentage(config, key, required=True, default=None):
      if required:
          value = config.get(key)
      else:
          value = config.get(key, default)
          if value is None:
              return
      try:
          if isinstance(value, six.string_types):
              value = value.strip()
              if value.endswith('%'):
                  # "50%" => 0.5
                  return float(value.strip('%')) / 100.
              # "50" => 50
  
          value = float(value)
          if value < 1:
              # 0.5 => 50% => 0.5
              return value
  
          # 50 => 0.5, 10.5 => 0.105
          return value / 100.
  
      except ValueError as e:
          raise ValueError('Config: failed parsing %s: %s' % (key, e))
  
  
  def get_human_size_default(config, key, default=None):
      raw_value = config.get(key, default)
  
      if raw_value is None:
          return default
  
      return parse_human_size(raw_value)
  
  
  def config_dict_to_text(config):
      # if already string return as is
      if isinstance(config, six.string_types):
          return config
      if not isinstance(config, dict):
          raise ValueError("Configuration only supports dictionary objects")
      try:
          # noinspection PyBroadException
          try:
              text = HOCONConverter.to_hocon(ConfigFactory.from_dict(config))
          except Exception:
              # fallback json+pyhocon
              # hack, pyhocon is not very good with dict conversion so we pass through json
              import json
              text = json.dumps(config)
              text = HOCONConverter.to_hocon(ConfigFactory.parse_string(text))
  
      except Exception:
          raise ValueError("Could not serialize configuration dictionary:\n", config)
      return text
  
  
  def text_to_config_dict(text):
      if not isinstance(text, six.string_types):
          raise ValueError("Configuration parsing only supports string")
      # noinspection PyBroadException
      try:
          return ConfigFactory.parse_string(text).as_plain_ordered_dict()
      except pyparsing.ParseBaseException as ex:
          pos = "at char {}, line:{}, col:{}".format(ex.loc, ex.lineno, ex.column)
          six.raise_from(ValueError("Could not parse configuration text ({}):\n{}".format(pos, text)), None)
      except Exception:
          six.raise_from(ValueError("Could not parse configuration text:\n{}".format(text)), None)
  