docs: def _parse_tsplib(f):
      """Parses a TSPLIB file descriptor and returns a dict containing the problem definition"""
      line = ''
  
      specs = {}
  
      used_specs = ['NAME', 'COMMENT', 'DIMENSION', 'CAPACITY', 'TYPE', 'EDGE_WEIGHT_TYPE']
      used_data = ['DEMAND_SECTION', 'DEPOT_SECTION']
  
      # Parse specs part
      for line in f:
          line = strip(line)
  
          # Arbitrary sort, so we test everything out
          s = None
          for s in used_specs:
              if line.startswith(s):
                  specs[s] = line.split('{} :'.format(s))[-1].strip() # get value data part
                  break
  
          if s == 'EDGE_WEIGHT_TYPE' and s in specs and specs[s] == 'EXPLICIT':
              used_specs.append('EDGE_WEIGHT_FORMAT')
  
          # All specs read
          if len(specs) == len(used_specs):
              break
  
      if len(specs) != len(used_specs):
          missing_specs = set(used_specs).symmetric_difference(set(specs))
          raise ParseException('Error parsing TSPLIB data: specs {} missing'.format(missing_specs))
  
      print(specs)
  
      if specs['EDGE_WEIGHT_TYPE'] == 'EUC_2D':
          used_data.append('NODE_COORD_SECTION')
      elif specs['EDGE_WEIGHT_FORMAT'] == 'FULL_MATRIX':
          used_data.append('EDGE_WEIGHT_SECTION')
      else:
          raise ParseException('EDGE_WEIGHT_TYPE or EDGE_WEIGHT_FORMAT not supported')
  
      _post_process_specs(specs)
  
      # Parse data part
      for line in f:
          line = strip(line)
  
          for d in used_data:
              if line.startswith(d):
                  if d == 'DEPOT_SECTION':
                      specs[d] = _parse_depot_section(f)
                  elif d in ['NODE_COORD_SECTION', 'DEMAND_SECTION']:
                      specs[d] = _parse_nodes_section(f, d, specs['DIMENSION'])
                  elif d == 'EDGE_WEIGHT_SECTION':
                      specs[d] = _parse_edge_weight(f, specs['DIMENSION'])
  
          if len(specs) == len(used_specs) + len(used_data):
              break
  
      if len(specs) != len(used_specs) + len(used_data):
          missing_specs = set(specs).symmetric_difference(set(used_specs).union(set(used_data)))
          raise ParseException('Error parsing TSPLIB data: specs {} missing'.format(missing_specs))
  
      _post_process_data(specs)
  
      return specs