docs: def _find_phrases( self, sentence, syntax_layer, cutPhrases, cutMaxThreshold ):
          ''' Detects NP phrases by relying on local dependency relations:
          
              1) Identifies potential heads of NP phrases;
              2) Identifies consecutive words that can form an NP phrase:
                 2.1) potential attribute + potential head;
                 2.2) quantity word or phrase + nominal;
              3) Identifies non-consecutive words (word1 __ wordN) that
                 can form a complete phrase (including the gap part);
              4) Applies post-corrections;
              
              Returns a list of tags, which contains a B-I-O style phrase 
              tag for each word in the sentence ('B'-begins phrase, 'I'-
              inside phrase, or ''-not in phrase);
          '''
          NPattribPos = [ 'Y', 'S', 'A', 'C', 'G', 'H', 'N', 'O', 'K', 'D', 'P' ]
          NPheadPos   = [ 'S', 'Y', 'H' ]
          NPlabels = [ '' for i in range(len(sentence)) ]
          #
          # 0 Faas: M2rgistame k6ik s6nad, mis v6iksid olla nimis6nafraasi peas6nad, nt:
          #        Kas [venelaste] [ambitsioon] on [siiras] ?
          #        [Raskused] algasid [aastal] 2009 , mil oli [majanduskriis] .
          #        [Põllumaad] on ka , aga [kartulikasvatamisega] on üksjagu [jamamist] .
          #
          for i in range(len(sentence)):
              pos1 = self._getPOS(sentence[i])
              if pos1 in NPheadPos:
                  NPlabels[i] = 'B'
              # Lisaks märgistame ka peasõnadena ka üksikud pronoomenid, kuigi 
              # eeldame, et need on peasõnadena vaid üksikutes fraasides;
              elif pos1 == 'P':
                  NPlabels[i] = 'B'
          #
          # I Faas: liidame yheks nimis6nafraasiks k6ik k6rvutiseisvad nimis6nafraasi
          #     sobivad s6nad, kui esimene on järgmise vahetu alluv, nt:
          #        [Venemaa otsus] alustada Süürias õhurünnakuid ...
          #        Kas [venelaste ambitsioon] on siiras ?
          #        [Järgmine hoop] tuli 2012-2013 ...
          #        [Eelmise nädala reedel] , [19. septembril] leidsid [kolleegid] ...
          #        
          for i in range(len(sentence)):
              label1  = i
              parent1 = syntax_layer[i][PARSER_OUT][0][1]
              #label1  = sentence[i][SYNTAX_LABEL]
              #parent1 = sentence[i][SYNTAX_HEAD]
              if i+1 < len(sentence):
                  label2  = i+1
                  parent2 = syntax_layer[i+1][PARSER_OUT][0][1]
                  #label2  = sentence[i+1][SYNTAX_LABEL]
                  #parent2 = sentence[i+1][SYNTAX_HEAD]
                  pos1 = self._getPOS(sentence[i])
                  pos2 = self._getPOS(sentence[i+1])
                  if int(parent1) == int(label2) and pos1 in NPattribPos and \
                     pos2 in NPheadPos:
                      if 'K' in pos1 and NPlabels[i] == '':
                          #
                          #   1) erandjuht: 
                          #    K fraasi alguses viitab peaaegu alati mingile jamale, 
                          #    seega katkestame, et vältida selliseid asju nagu:
                          #      ... , mille [kohta Eestiski] piisavalt näiteid .
                          #      ... lähedaste majandussidemete [tõttu Brasiiliaga] .
                          #      ... kultuuri allutamise [vastu rahavõimule] , vaid töötavad
                          # 
                          pass
                      elif 'D' in pos1 and not self._AdvStartingPhrase.matches(sentence[i]):
                          #
                          #   2) erandjuht: 
                          #   Lubame ainult teatud adverbe fraasi algusesse, et vältida selliseid
                          #   juhte nagu nt:
                          #      ... said sõna [ka lapsed] , aga kingitust
                          #      ... kättesaamatuks [nii Nehatu hamburgeriputka] ,
                          #      ... osta [ka hinnaga 1 kr] 
                          #      ... ette [just Los Angelese autonäitusel] ,
                          
                          #   TODO: M6nikord me ikkagi tahame, et D ka sees oleks, nt:
                          #      ... filmis " Tagasi [tulevikku] " ...
                          pass
                      else:
                          if NPlabels[i] == '':
                              NPlabels[i] = 'B'
                          NPlabels[i+1] = 'I'
          #
          # II Faas: Koondame kõrvutipaiknevad ja üksteisega alluvussuhtes olevad arvsõnad/numbrid 
          #     üheks arvudest koosnevaks "NP-fraasiks", nt:
          #       [Sada nelikümmend viis]
          #       [10 405 miljonit]
          #       [kaheksa miljardit]
          #     
          for i in range(len(sentence)):
              label1  = i
              parent1 = syntax_layer[i][PARSER_OUT][0][1]
              #label1  = sentence[i][SYNTAX_LABEL]
              #parent1 = sentence[i][SYNTAX_HEAD]
              pos1 = self._getPOS(sentence[i])
              if pos1 in ['N', 'O']  and  i+1 < len(sentence):
                  label2  = i+1
                  parent2 = syntax_layer[i+1][PARSER_OUT][0][1]
                  #label2  = sentence[i+1][SYNTAX_LABEL]
                  #parent2 = sentence[i+1][SYNTAX_HEAD]
                  pos2 = self._getPOS(sentence[i+1])
                  if pos2 in ['N', 'O'] and ( int(parent2) == int(label1) or \
                     int(parent1) == int(label2) ):
                      if NPlabels[i] == '':
                          NPlabels[i] = 'B'
                      NPlabels[i+1] = 'I'
          #
          # III Faas: Kleebime otsa NP-fraaside otsa järeltäienditena esinevad numbrilised 
          #     arvud, nt:
          #        Üritus kandis nime [Rahu Missioon 2007.]
          #        Allkirjastas [1. jaanuaril 2004.]
          #        Saabus [uus Peugeot 307] , millest [aastatel 1987-1997] ei osatud unistadagi .
          #        [Perioodil 1997-2001] oli neid rohkem , [vt tabel 1.]
          #
          for i in range(len(sentence)):
              label1  = i
              parent1 = syntax_layer[i][PARSER_OUT][0][1]
              #label1  = sentence[i][SYNTAX_LABEL]
              #parent1 = sentence[i][SYNTAX_HEAD]
              pos1 = self._getPOS(sentence[i])
              if pos1 in ['N', 'O']  and  i-1 > -1:
                  label2  = i-1
                  parent2 = syntax_layer[i-1][PARSER_OUT][0][1]
                  #label2  = sentence[i-1][SYNTAX_LABEL]
                  #parent2 = sentence[i-1][SYNTAX_HEAD]
                  if int(parent1) == int(label2) and NPlabels[i-1] != '':
                      NPlabels[i] = 'I'
          #
          # IV Faas: Kleebime arvufraaside(hulgafraaside) otsa järeltäienditena esinevad 
          #     nimisõnad, nt:
          #        Meri laius [100 kilomeetri] pikkusena .
          #        Aasta alguseks oli mahust järel [30-40 protsenti] .
          #        Jah , [kümne aasta] tagusega ei maksa siin üldse võrrelda .
          #        Mees nõudis [10 miljonit dollarit] kahjutasu [10-15 cm] kaugusele .
          #        Eelmisel nädalal võttis endalt elu veel [kaks politseiametnikku] .
          #        Kujutlesin [kaheksa miljonit aastat] vana küpressimetsa [mitukümmend aastat] nooremana .
          #
          for i in range(len(sentence)):
              label1  = i
              parent1 = syntax_layer[i][PARSER_OUT][0][1]
              #label1  = sentence[i][SYNTAX_LABEL]
              #parent1 = sentence[i][SYNTAX_HEAD]
              pos1 = self._getPOS(sentence[i])
              if pos1 in ['N', 'O']  and  i+1 < len(sentence):
                  label2  = i+1
                  parent2 = syntax_layer[i+1][PARSER_OUT][0][1]
                  #label2  = sentence[i+1][SYNTAX_LABEL]
                  #parent2 = sentence[i+1][SYNTAX_HEAD]
                  pos2    = self._getPOS(sentence[i+1])
                  if int(parent2) == int(label1) and NPlabels[i+1] != '' and pos2 != 'P':
                      if NPlabels[i]=='':
                          NPlabels[i] = 'B'
                      NPlabels[i+1] = 'I'
          # 
          # V Faas: Kui NP-fraasi l6pus on arvu/numbrifraas ( N_Y voi N_S ), siis t6stame arvufraasi
          #         lahku, isegi kui see teatud m22ral l6huks NP-fraasi, nt 
          #               [pindala 48 ha]            ==> [pindala] [48 ha]
          #               [Järvamaal 36 283 inimest] ==> [Järvamaal] [36 283 inimest]
          #               [kasahhid 3 %]             ==> [kasahhid] [3 %]
          #               [Tallinna Lihatööstuse aktsiatest 80 protsenti] ==>
          #                      [Tallinna Lihatööstuse aktsiatest] [80 protsenti]
          #
          for i in range( len(sentence) ):
              if NPlabels[i] == 'B':
                  phrase, indices = self._getPhrase( i, sentence, NPlabels )
                  posTags = [ self._getPOS(tok) for tok in phrase ]
                  if len(phrase)>2 and posTags[-1] in ['S','Y'] and posTags[-2]=='N' and \
                     posTags[0] not in ['N', 'O']:
                      #
                      # Lisakontroll: tegu ei tohiks olla aastarvuga, nt:
                      #    [Eesti Tervishoiuprojekt] [2015 Lisaks]
                      #    [Prantsusmaa loobumine EXPO] [2004 korraldamisest]
                      # 
                      yearCheck = re.match('.*\d\d\d\d.*', phrase[-2][TEXT])
                      #
                      # Lisakontroll: kui eelneb rohkem kui yks arv, siis tuleb 
                      #    poolitamispunkti nihutada, nt:
                      #       [Viinis 170] [000 USA dollari]
                      #       [Järvamaal 36] [283 inimest]
                      #
                      breakPoint = indices[-2]
                      j = -3
                      while posTags[j] == 'N':
                          breakPoint = indices[j]
                          j -= 1
                      if not yearCheck:
                          NPlabels[breakPoint] = 'B'
  
          # 
          # VI Faas: Kui NP-fraasi sobiva s6na vanem on +2 v6i rohkema s6na kaugusel s6na j2rel, 
          #          siis pole s6na veel fraasi arvatud;
          #          Arvame ta fraasi j2rgmistel juhtudel:
          #            Eelnev j2rgarv, nt:
          #                ... pühendus meenutab [teisigi] [Põhjala suurmehi] , nagu ...
          #                ... enamikus jäid [esimese] [Eesti Vabariigi aegadesse] ...
          #            Eelnev omaduss6na, nt:
          #                ... makett ühest [olulisest] [jõeäärsest tänavast] sellisena ,
          #                ... soojendades ja [suures] soojaks [köetud telgis] kuuma teed ...
          #
          for i in range(len(sentence)-1, -1, -1):
              label1  = i
              parent1 = syntax_layer[i][PARSER_OUT][0][1]
              #label1  = sentence[i][SYNTAX_LABEL]
              #parent1 = sentence[i][SYNTAX_HEAD]
              pos1 = self._getPOS(sentence[i])
              parentRelativeLoc = int(parent1) - int(label1)
              if pos1 in NPattribPos and NPlabels[i]=='' and parentRelativeLoc > 1 and \
                 i+parentRelativeLoc < len(sentence):
                  label2  = i+parentRelativeLoc
                  parent2 = syntax_layer[i+parentRelativeLoc][PARSER_OUT][0][1]
                  #label2  = sentence[i+parentRelativeLoc][SYNTAX_LABEL]
                  #parent2 = sentence[i+parentRelativeLoc][SYNTAX_HEAD]
                  if int(parent1) == int(label2) and NPlabels[i+parentRelativeLoc] != '':
                      #
                      #   Kogume kokku k6ik kahe s6na vahele j22vad token'id:
                      #  
                      interveningTokens   = []
                      interveningTokenIDs = []
                      j = i + 1
                      while ( j < i + parentRelativeLoc ):
                          interveningTokens.append( sentence[j] )
                          interveningTokenIDs.append( j )
                          j += 1
                      #
                      #   Eemaldame neist tokenid, mis juba kuuluvad fraasi:
                      #
                      if NPlabels[i+parentRelativeLoc] == 'I':
                          while ( len(interveningTokenIDs) > 0 ):
                              lastID = interveningTokenIDs.pop()
                              lastToken = interveningTokens.pop()
                              if NPlabels[lastID] == 'B':
                                  # Kui j6udsime fraasi alguseni, siis l6petame
                                  break
                      
                      #
                      #    Kontroll1: s6na ja j2rgneva s6na vahele ei tohi j22da 
                      #     punktuatsiooni ega sidendeid, kuna need j2tame alati 
                      #     fraasist v2lja;
                      #
                      punctIntervening = False
                      jaNingEgaVoi     = False
                      for interToken in interveningTokens:
                          if self._punctPos.matches( interToken ):
                              punctIntervening = True
                          if self._jaNingEgaVoi.matches( interToken ):
                              jaNingEgaVoi = True
  
                      #
                      #   Leiame s6na ja tema ylema vahelise k22ndeyhilduvuse;
                      #
                      caseAgreement = \
                          self._getCaseAgreement(sentence[i], sentence[i+parentRelativeLoc])
  
                      if pos1 == 'O' and not punctIntervening and not jaNingEgaVoi and \
                         caseAgreement != None:
                          if len(interveningTokenIDs) == 0:
                              #
                              #    VI.a.  Eelnev s6na on k22ndes yhilduv j2rgarv, nt:
                              #      ... nagu ka teised [Eesti pered] , iga ...
                              #        ... mil esimene [Tšetšeenia sõda] käis täie ...
                              #        ... ka mõnedel teistel [mineraalsetel kütetel] peale autobensiini ...
                              #        ... on pärit kolmandast [Moosese raamatust] ehk leviitide ...
                              #
                              NPlabels[i]   = 'B'
                              NPlabels[i+1] = 'I'
                          else:
                              #
                              #    VI.b.  Eelnev s6na on k22ndes yhilduv j2rgarv, ning vahele j22vad
                              #           ainult k22ndes yhilduvad s6nad, nt:
                              #        ... Teised sõjavastased [Euroopa riigid] ilmselt avaldavad ...
                              #        ... tõi ära esimesed pesuehtsad [punased värsid] . ...
                              #        ... Esimene üleriigiline [automatiseeritud haiguseregister] - vähiregister ...
                              #
                              agreements = [self._getCaseAgreement(interTok, sentence[i+parentRelativeLoc]) for interTok in interveningTokens]
                              if all(agreements):
                                  NPlabels[i] = 'B'
                                  j = i + 1
                                  while ( j <= i + parentRelativeLoc ):
                                      NPlabels[j] = 'I'
                                      j += 1
  
                      if pos1 in ['A','G'] and not punctIntervening and not jaNingEgaVoi and \
                         caseAgreement != None:
                          # 
                          #   Lisakontroll 1:
                          #      Jätame algusesse lisamata kesksõnadena esinevad sõnad, kuna 
                          #      nende puhul on tõenäoliselt tegemist millegi keerukamaga (nn
                          #      lauselühendiga):
                          #        ... Pingilt sekkunud [Chris Anstey] viskas ...
                          #        ... NBA meistriks tüürinud [Phil Jackson] ...
                          #        ... kaasaegsele maailmale mittevastav [teoreetiline lähenemine] ...
                          #
                          isVerbParticle = self._verbParticle.matches(sentence[i])
                          #
                          #  Lisakontroll 2:
                          #      Kui omaduss6na ja fraasi vahele j22b ka teisi s6nu, teeme 
                          #      kindlaks, et need s6nad poleks s6naliikidest V, D, J, mis
                          #      on probleemsed, nt:
                          #       D : ...  skreipi nii [pärilik] kui ka [nakkav haigus]  ...
                          #       V : ...  2002. aasta [keskmine] purunenud [terade saak]  ...
                          #       J : ...  oleks maakondadele [sobilik] kuni [14-rühmaline loend] Eesti  ...
                          #
                          interveningProblematicPOS = False
                          if len(interveningTokenIDs) > 0:
                              iPosTags = [ a[POSTAG] for t1 in interveningTokens for a in t1[ANALYSIS] ]
                              interveningProblematicPOS = \
                                'V' in iPosTags or 'D' in iPosTags or 'J' in iPosTags or 'Z' in iPosTags
                          if not isVerbParticle and len(interveningTokenIDs) == 0:
                              #
                              #    VI.c.  Eelnev s6na on k22ndes yhilduv ja vahetult eelnev 
                              #           omaduss6na (v.a. kesks6na), nt:
                              #           ... peeti pidu karmi [vene korra] ajal ning ...
                              #           ... äravajunud , arhailisest [Suurbritannia nurgast] ...
                              #           ... , võimaldades uutel [vapratel riikidel] kahel pool ...
                              #
                              NPlabels[i]   = 'B'
                              NPlabels[i+1] = 'I'
                          elif not isVerbParticle and len(interveningTokenIDs) > 0 and \
                              not interveningProblematicPOS:
                              #
                              #    VI.d.  Eelnev s6na on k22ndes yhilduv omaduss6na (v.a. kesks6na) 
                              #           ning vahele j22b veel v2hemalt yks sobiva POS tag'iga
                              #           s6na, nt:
                              #           ... korral on [tavaline] tugev [päevane unisus] , ...
                              #           ... mõjus silmadele [vana] mustvalge pisike [ekraan] ...
                              #           ... on enesekindel [valgete] higiste [kätega intelligent] ...
                              #
                              NPlabels[i] = 'B'
                              j = i + 1
                              while ( j <= i + parentRelativeLoc ):
                                  NPlabels[j] = 'I'
                                  j += 1
                                  
                      if pos1 in ['C'] and not punctIntervening and not jaNingEgaVoi and \
                         caseAgreement != None:
                          if i - 1 > -1  and  self._k6ige.matches( sentence[i - 1] ):
                              #
                              #    VI.e.  Eelnev s6na on k22ndes yhilduv keskv6rde omaduss6na, 
                              #           millele eelneb yliv6rde tunnus 'k6ige', nt:
                              #           ... juhib perekonda kõige noorem [täiskasvanud naine] . ...
                              #           ... Kõige suurem [akustiline erinevus] oli vokaalide ...
                              #           ... on kõige levinumad [antikolinergilised ravimid] ...
                              #
                              NPlabels[i-1] = 'B'
                              j = i
                              while ( j <= i + parentRelativeLoc ):
                                  NPlabels[j] = 'I'
                                  j += 1
                          elif re.match('^(pl\s.+|sg\s(ab|abl|ad|all|el|es|ill|in|kom|ter|tr))$', \
                               caseAgreement):
                              #
                              #    VI.f.  Eelnev s6na on k22ndes yhilduv keskv6rde omaduss6na, 
                              #           mis on kas mitmuses v6i yhildub semantilise k22ndega, nt:
                              #           ... olnud üks aktiivsemaid [NATO rahupartnereid] . ...
                              #           ... meestel lisandub halvemale [füüsilisele tervisele] veel ...
                              #           ... Varasemates [samalaadsetes uurimustes] on laste ...
                              #          (grammatilise ainsusek22nde puhul ei pruugi nii kindel
                              #           olla, et kuulub just nimis6nafraasi juurde: v6ib kuuluda
                              #           ka (olema) verbifraasi juurde)
                              #
                              NPlabels[i] = 'B'
                              j = i + 1
                              while ( j <= i + parentRelativeLoc ):
                                  NPlabels[j] = 'I'
                                  j += 1
                              
                              #ex = self.__debug_extract_NP_from_pos(sentence, NPlabels, i-1, i+parentRelativeLoc)
                              #try:
                              #    print(sentence[i][TEXT]+' | '+sentence[i+parentRelativeLoc][TEXT]+' | '+pos1+" | "+ex)
                              #except:
                              #    print(' ### Err ###')
                         
  
  
          #
          #   Viimane faas: rakendame nn j2relparandusi, proovime pahna v2lja visata ...
          #
          self._apply_post_fixes( sentence, NPlabels, cutPhrases, cutMaxThreshold )
          return NPlabels