docs: def parse_indicators(parts, ethnicity):
    """
      Parses terms that may or may not be "indicators" of trafficking. Some terms are used for
      non-trafficking related purposes (e.g. matching or identification problems). Also good to 
      note is that this list has been growing slowly for about 2 years and some indicators have
      been removed/combined. Thus, you may notice that some numeric values are non-existent.
  
      TODO: Move logic from hard-coded into JSON config file(s).
      
        parts -> The backpage ad's posting_body, separated into substrings
        ethnicity -> The ethnicity list that we parsed for the ad
    """
  
    ret_val=[]
    for part in parts:
      part=part.lower()
      part = part.replace('virginia', '').replace('fresh pot', '')
      part = re.sub(r'virgin ?island', '', part)
      part = re.sub(r'no teen', '', part)
  
      if re.compile(r'new ?to ?the ?(usa?|country)').search(part):
        ret_val.append(1)
      if "natasha" in part or "svetlana" in part:
        ret_val.append(2)
      if 'young' in part:
        ret_val.append(3)
      if re.compile(r'just *(hit|turned) *18').search(part):
        ret_val.append(5)
      if re.compile(r'fresh *meat').search(part):
        ret_val.append(6)
      if 'virgin' in part:
        ret_val.append(7)
      if 'foreign' in part:
        ret_val.append(8)
      if re.compile(r'(just|fresh)( *off *)?( *the *)boat').search(part):
        ret_val.append(9)
      if re.compile(r'fresh from over ?sea').search(part):
        ret_val.append(9)
      if re.compile(r'easy *sex').search(part):
        ret_val.append(10)
      if re.compile(r'come *chat *with *me').search(part):
        ret_val.append(11)
      if re.compile(r'\b(massage|nuru)\b').search(part):
        ret_val.append(12)
      if re.compile(r'escort *agency').search(part):
        ret_val.append(13)
      if re.compile(r'((https?)|www)\.\w{5,30}?.com').search(part):
        ret_val.append(14)
      if (re.compile(r'world( )*series').search(part) or re.compile(r'grand( )*slam').search(part) or
         re.compile(r'base( )?ball').search(part) or re.compile(r'double( )?play').search(part) or
         'cws' in part or re.compile(r'home( )?run').search(part) or re.compile(r'batter( )?up').search(part) or
         re.compile(r'triple( )?play').search(part) or re.compile(r'strike( )?out').search(part) or
         'sports' in part):
        ret_val.append(15)
      if (re.compile(r'new ?girls').search(part) or re.compile(r'new ?arrivals').search(part) or
         re.compile(r'just ?in ?from ? \w{3,15}\W').search(part) or re.compile(r'new \w{3,9} staff').search(part)):
        ret_val.append(17)
      if re.compile(r'brand *new').search(part):
        ret_val.append(18)
      if re.compile(r'coll(e|a)ge').search(part) and 15 not in ret_val:
        ret_val.append(19)
      if 'teen' in part:
        ret_val.append(20)
      if re.compile(r'high ?school').search(part):
        ret_val.append(21)
      if re.compile(r'daddy\'?s? ?little ?girl').search(part):
        ret_val.append(22)
      if 'fresh' in part:
        ret_val.append(23)
      phrases = [(r'100%' + re.escape(eth)) for eth in ethnicity]
      if any(re.compile(phrase).search(part) for phrase in phrases):
        ret_val.append(24)
      if re.compile(r'speaks? \d\d? language').search(part):
        ret_val.append(25)
      if re.compile(r'new to the (country|us)').search(part):
        ret_val.append(26)
      if re.compile(r'massage ?parlou?r').search(part):
        ret_val.append(27)
      if re.compile(r'come see us at ').search(part):
        ret_val.append(28)
      if (re.compile(r'420 ?friendly').search(part) or re.compile(r'party ?friendly').search(part) or 
          re.compile(r'420 ?sp').search(part) or ' 420 ' in part):
        ret_val.append(30)
      if 'under 35' in part:
        ret_val.append(31)
      if re.compile(r'\b(avail(able)?|open) *24(/|\\|-)7\b').search(part):
        ret_val.append(33)
      if re.compile(r'no ?(indian)').search(part) or re.compile(r'indians? not ((allow)|(welcome))'):
        ret_val.append(36)
      if re.compile(r'no ?(hispanic|mexican)').search(part) or re.compile(r'(hispanic|mexican)s? not ((allow)|(welcome))'):
        ret_val.append(37)
      if 'incall' in part:
        ret_val.append(38)
      if 'outcall' in part:
        ret_val.append(39)
  
      parts = part.split('from ')
      parts.pop(0)
      for p in parts:
        p = re.sub(r' +', ' ', p)
        if p.split(' ')[0].lower() in countries:
          ret_val.append(27)
          break
      eastern_euro_countries = ['estonia', 'latvia', 'lithuania', 'armenia', 'russia', 'kazakhstan', 'ukrain', 'belarus',
                                'moldova', 'czech', 'austria', 'croatia', 'hungary', 'poland', 'slovakia', 'slovenia',
                                'albania', 'bosnia', 'bulgaria', 'greece', 'macedonia', 'romania']
      if any(c in part for c in eastern_euro_countries):
        ret_val.append(28)
    ret_val = list(set(ret_val))
    return ret_val