text: from __future__ import unicode_literals
  import io, datetime, sys
  
  if sys.version_info[0] == 3:
      long = int
      unicode = str
  
  
  def dumps(obj, sort_keys=False):
      fout = io.StringIO()
      dump(obj, fout, sort_keys=sort_keys)
      return fout.getvalue()
  
  
  _escapes = {'\n': 'n', '\r': 'r', '\\': '\\', '\t': 't', '\b': 'b', '\f': 'f', '"': '"'}
  
  
  def _escape_string(s):
      res = []
      start = 0
  
      def flush():
          if start != i:
              res.append(s[start:i])
          return i + 1
  
      i = 0
      while i < len(s):
          c = s[i]
          if c in '"\\\n\r\t\b\f':
              start = flush()
              res.append('\\' + _escapes[c])
          elif ord(c) < 0x20:
              start = flush()
              res.append('\\u%04x' % ord(c))
          i += 1
  
      flush()
      return '"' + ''.join(res) + '"'
  
  
  def _escape_id(s):
      if any(not c.isalnum() and c not in '-_' for c in s):
          return _escape_string(s)
      return s
  
  
  def _format_list(v):
      return '[{0}]'.format(', '.join(_format_value(obj) for obj in v))
  
  # Formula from:
  #   https://docs.python.org/2/library/datetime.html#datetime.timedelta.total_seconds
  # Once support for py26 is dropped, this can be replaced by td.total_seconds()
  def _total_seconds(td):
      return ((td.microseconds
               + (td.seconds + td.days * 24 * 3600) * 10**6) / 10.0**6)
  
  def _format_value(v):
      if isinstance(v, bool):
          return 'true' if v else 'false'
      if isinstance(v, int) or isinstance(v, long):
          return unicode(v)
      if isinstance(v, float):
          return repr(v)
      elif isinstance(v, unicode) or isinstance(v, bytes):
          return _escape_string(v)
      elif isinstance(v, datetime.datetime):
          offs = v.utcoffset()
          offs = _total_seconds(offs) // 60 if offs is not None else 0
  
          if offs == 0:
              suffix = 'Z'
          else:
              if offs > 0:
                  suffix = '+'
              else:
                  suffix = '-'
                  offs = -offs
              suffix = '{0}{1:.02}{2:.02}'.format(suffix, offs // 60, offs % 60)
  
          if v.microsecond:
              return v.strftime('%Y-%m-%dT%H:%M:%S.%f') + suffix
          else:
              return v.strftime('%Y-%m-%dT%H:%M:%S') + suffix
      elif isinstance(v, list):
          return _format_list(v)
      else:
          raise RuntimeError(v)
  
  
  def dump(obj, fout, sort_keys=False):
      tables = [((), obj, False)]
  
      while tables:
          name, table, is_array = tables.pop()
          if name:
              section_name = '.'.join(_escape_id(c) for c in name)
              if is_array:
                  fout.write('[[{0}]]\n'.format(section_name))
              else:
                  fout.write('[{0}]\n'.format(section_name))
  
          table_keys = sorted(table.keys()) if sort_keys else table.keys()
          new_tables = []
          for k in table_keys:
              v = table[k]
              if isinstance(v, dict):
                  new_tables.append((name + (k,), v, False))
              elif isinstance(v, list) and v and all(isinstance(o, dict) for o in v):
                  new_tables.extend((name + (k,), d, True) for d in v)
              elif v is None:
                  # based on mojombo's comment: https://github.com/toml-lang/toml/issues/146#issuecomment-25019344
                  fout.write(
                      '#{} = null  # To use: uncomment and replace null with value\n'.format(_escape_id(k)))
              else:
                  fout.write('{0} = {1}\n'.format(_escape_id(k), _format_value(v)))
  
          tables.extend(reversed(new_tables))
  
          if tables:
              fout.write('\n')
  