[Hejes-devel] [803] moved old egybekulon.py to branches/archaic

hejes-devel at nytud.hu hejes-devel at nytud.hu
Mon Jun 3 15:47:25 CEST 2013


Revision: 803
Author:   mihaltz
Date:     2013-06-03 15:47:25 +0200 (Mon, 03 Jun 2013)
Log Message:
-----------
moved old egybekulon.py to branches/archaic

Added Paths:
-----------
    branches/archaic/web2py/applications/helyesiras_webdev.old/modules/egybekulon.py

Removed Paths:
-------------
    trunk/web2py/applications/helyesiras_webdev/modules/egybekulon.py

Copied: branches/archaic/web2py/applications/helyesiras_webdev.old/modules/egybekulon.py (from rev 801, trunk/web2py/applications/helyesiras_webdev/modules/egybekulon.py)
===================================================================
--- branches/archaic/web2py/applications/helyesiras_webdev.old/modules/egybekulon.py	                        (rev 0)
+++ branches/archaic/web2py/applications/helyesiras_webdev.old/modules/egybekulon.py	2013-06-03 13:47:25 UTC (rev 803)
@@ -0,0 +1,2670 @@
+#!/usr/bin/env python
+# coding: utf8
+
+"""
+Module for the egybeírás-különírás functionalities
+
+ at author: MM, LZS, ...
+"""
+
+from __future__ import print_function
+import re
+import sys
+import morfologia
+import Wordform
+
+
+# If this module is run or used outside of a web2py framework instance (i.e. from the command line),
+# we have to connect to the database manually (it would be taken care of in models/db.py)
+# TODO: more standard test to see if we're in web2py and db.py was loaded?
+try:
+  mydb
+except NameError:
+  sys.path.append('/opt/web2py')
+  from gluon import *
+  mydb = DAL('mysql://dbdicter:dbdicter123@localhost/dbdict', migrate_enabled=False)
+  #TODO: create a load_my_database() function in db.py and call that instead (so future modifications will not affect us)
+
+
+class WordInfo:
+  """Class for encapsulating morphologia.MorphInfo and Wordform.LexicalEntry instances for a specific wordform.
+     @author: MM
+  """
+  
+  def __init__(self, wordform):
+    """Initialize for wordform (UTF-8 string).
+    """  
+    self.wordform = wordform
+    self.morphInfo = None
+    self.morphInfo = morfologia.MorphInfo(wordform, use_humor=True, use_humor_6_3=True, use_xerox=False, use_ocamorph=False)
+    self.lexicalEntry = None
+    myid = None
+    for id, word in Wordform.forToken(mydb, wordform):
+      if word == unicode(wordform, "utf-8"):
+        myid = id
+        break
+    if myid != None:
+      self.lexicalEntry = Wordform.loadLexicalEntry(mydb, myid)
+    self.parseHumorCache = None # for caching output of MorphInfo.parseHumorData()	
+    
+  def morph(self):
+    """Returns the associated MorphInfo object, or None if there was an error initializing it"""  
+    return self.morphInfo
+    
+  def lex(self):
+    """Returns the associated LexicalEntry object, or None if wordform is unknown or if there was an error initializing the object"""
+    return self.lexicalEntry
+
+  def getParseHumorData(self):
+    """Wrapper for accessing self.morph().parseHumorData() via a cache to avoid overhead with multiple calls.
+       Returns (the cached or computed) value of self.morph().parseHumorData().
+    """
+    if self.parseHumorCache == None:
+      self.parseHumorCache = self.morphInfo.parseHumorData()
+    return self.parseHumorCache  
+    
+  def hasLexProp(self, prop):
+    """Returns True iff the value for the lexical property name is not None in wordform's LexicalPropery instance
+       @see Wordform.LexicalProperty for property names and their meanings
+    """
+    if self.lexicalEntry != None and prop in vars(self.lexicalEntry) and vars(self.lexicalEntry)[prop] != None:
+      return True
+    return False
+    
+  def hasPoSCase(self, pos, case=None):
+    """Returns True iff wordform has a Humor analysis whose PoS is pos and whose case is case.
+       If case=None it is not checked. pos and case are Humor codes.
+       Note: consider using matchPoSSequence() instead, it gives more control
+       TODO: use humor2005_stemmer + python API in morfologia instead...
+    """
+    if self.morphInfo == None or 'humor' not in self.morphInfo.getGoodIds():
+      return False
+    if pos not in morfologia.POSNORM:
+      return False
+    hpos = '[' + pos + ']'
+    hcase = '[' + case + ']' if case != None else None
+    for anal in self.morphInfo.getRawData()['humor']:
+      if not anal:
+        continue
+      if case == None and hpos in anal:
+        return True
+      elif case != None and hpos in anal and anal.endswith(hcase):
+        return True
+    return False
+    
+  def hasFinalPoS(self, pos):
+    """Returns True iff wordform has a Humor analysis whose final PoS (after derivations) is pos (a Humor PoS code).
+    """
+    if self.morphInfo == None or 'humor' not in self.morphInfo.getGoodIds():
+      return False
+    if pos not in morfologia.POSNORM:
+      return False
+    for anal in self.morphInfo.getMorphs():
+      if anal[0] == morfologia.POSNORM[pos]:
+        return True
+    return False
+    
+  def matchPoSSequence(self, expr):
+    """Returns True iff wordform has a Humor analysis whose morphs' PoS's concatenated by ',' is matched by regular expression expr.
+       Example:
+       >>WordInfo('ezrediket').matchPoSSequence('SZN,_SORSZ,.*')
+       True
+    """
+    if self.morphInfo == None or 'humor' not in self.morphInfo.getGoodIds():
+      return False
+    x = self.getParseHumorData()
+    if x == []:
+      return False
+    for anal in x:
+      if re.match(expr, ','.join([x[2] for x in anal])):
+        return True
+    return False
+    
+  def getNCompParts(self):
+    """Return number of compound parts of wordform, based on humor analyses.
+       Note: adds up n. of comp. parts for each morpheme and returns maximum over all analyses.
+       Note2: calculated value may not be exact (e.g. igekotos are always worth 1, tobbtagu szamnevs are always worth 2 comp. parts),
+       use it rather to test whether wordform is a compound or not (returns >1 or ==1).
+       Returns None if no humor data was available.
+    """
+    if self.morphInfo == None:
+      return None
+    x = self.getParseHumorData()
+    if x == []:
+      return None
+    max = 0
+    for anal in x:
+      sum = 0
+      for morph in anal:
+        if morph[3] == -1: # egytagu szamnev
+          sum += 1
+        elif morph[3] == -3 or morph[2] == 'IK': # igekoto
+          if int(morph[4]) > 1: # more than 1 syllable
+            sum += 1
+        elif morph[3] == -2: # tobbtagu szamnev
+          sum += 2
+        else:
+          sum += morph[3]
+      if sum > max:
+        max = sum
+    return max
+
+
+  def getNSyllables(self):
+    """Returns number of syllables of wordform, based on humor analyses.
+       Note: inflexions make no difference (but formating elements do!).
+       Note: getNSyllables() returns -99 if a morph's number of syllabes isn't available.
+       @author: LZS
+    """
+    if self.morphInfo == None:
+      return None
+    x = self.getParseHumorData()
+    if x == []:
+      return None
+    for anal in x:
+      syll = 0
+      for morph in anal:
+        if morph[4] == -99:
+          syll = -99
+        else:
+          syll += int(morph[4])
+    return syll
+  
+  
+
+  def getVerbLex(self):
+    """ A helper method which returns the lexical form of a verb (E/3 in Hungarian), based on humor analyses.
+        @author: LZS
+    """
+    lex = ''
+    ige = ''
+    tmp = ''
+    ik = ''
+    isMuv = False
+    if self.getParseHumorData() == []:
+      return None
+    for ls in self.getParseHumorData():
+      muv = False
+      if self.matchPoSSequence('IGE,_MUV,_OKEP,NOM'):
+        muv = True 
+      for l in ls:
+        if muv == True:
+          _muv = [s for s in l if type(s).__name__ == 'str' and '_MUV' in s]
+          if _muv == ['_MUV']:
+            isMuv = True
+            if tmp == '':
+              tmp = l[0]
+    for ls in self.getParseHumorData():
+      for l in ls:
+        matching0 = [s for s in l if type(s).__name__ == 'str' and 'IK' in s]
+        if matching0 == ['IK']:
+          if ik == '':
+            ik = l[0]
+        matching1 = [s for s in l if type(s).__name__ == 'str' and 'IGE' in s]
+        if matching1 == ['IGE']:
+          if ige == '':
+            if l[0][-2:] == 'ik' and isMuv == True:
+              ige = l[1]
+            elif isMuv == True:
+              ige = l[0]
+            else:
+              ige = l[0]
+    lex = ik + ige + tmp if muv == True else ik + ige
+    return lex
+
+
+  def getNominalStem(self):
+    """ A helper method which returns the stem of a noun, based on humor analyses.
+        @author: LZS
+    """
+    stem = ''
+    if self.getParseHumorData() == []:
+      return None
+    for ls in self.getParseHumorData():
+      for l in ls:
+        fn = [s for s in l if type(s).__name__ == 'str' and 'FN' in s]
+        if fn != []:
+          tmp = l[0]
+          stem = ''.join([c for c in tmp if c not in '*'])
+          return stem
+      
+            
+  def getVerbalStem(self):
+    """ A helper method which returns the stem of a verb, based on humor analyses.
+        @author: LZS
+    """
+    stem = ''
+    ige = ''
+    ik = ''
+    tmp = ''
+    if self.getParseHumorData() == []:
+      return None
+    for ls in self.getParseHumorData():
+      muv = False
+      if self.matchPoSSequence('IGE,_MUV,_OKEP,NOM'):
+        muv = True
+      for l in ls:
+        if muv == True:
+          _muv = [s for s in l if type(s).__name__ == 'str' and '_MUV' in s]
+          if _muv == ['_MUV']:
+            if tmp == '':
+              tmp = l[0]
+        matching0 = [s for s in l if type(s).__name__ == 'str' and 'IK' in s]
+        if matching0 == ['IK']:
+          if ik == '':
+            ik = l[0]
+        matching1 = [s for s in l if type(s).__name__ == 'str' and 'IGE' in s]
+        if matching1 == ['IGE']:
+          if ige == '':
+            ige = l[1] if l[1] != '' else l[0]
+    stem = ik + ige + tmp if muv == True else ik + ige
+    return stem  
+        
+
+  def getVocals(self):
+    voc = []
+    unicodeString = self.wordform.decode('utf-8')
+    for i in range(len(unicodeString)):
+      if Wordform.Phonology.CV(unicodeString[i]) == 'V':
+        voc.append(unicodeString[i])
+    return voc
+
+
+      
+  def getHarmony(self):
+    vocalList = []
+    velar = False
+    velarWordHarmony = False
+    voc = self.getVocals()
+    exc = re.compile(u'[eéií]')
+    mely = re.compile(u'[aáoóuú]')
+    magas = re.compile(u'[eéiíöőüű]')
+    for v in voc:
+      if re.match(mely, v):
+        velar = True
+        tmp = (v, velar)
+        vocalList.append(tmp)
+      elif re.match(magas, v):
+        velar = False
+        tmp = (v, velar)
+        vocalList.append(tmp)
+    for v in vocalList:
+      if v[1] == True:
+        velarWordHarmony = True
+    return velarWordHarmony
+          
+      
+  def toStr(self):
+    """Return string representation of (basic information stored in) object."""
+    s = {}
+    s['wordform'] = self.wordform
+    s['morph'] = self.morph().getRawData() if self.morph() else str(None)
+    if not self.lex():
+      s['lex'] = str(None)
+    else:
+      slex = {}
+      for k, v in vars(self.lex()).items():
+        if v:
+          slex[k] = v
+      s['lex'] = slex
+    return str(s)
+
+# # # end class WordInfo # # #
+
+
+class SpellingRuleBase:
+  """Base Class for AKH egybeírás-különírás spelling rule implementation classes.
+     The derived classes provide a verdict (spelling solutions: egybe, külön, kötőjellel) for an input (arrays of WordInfo instances),
+     permitting dialogs consisting of turns consisting of interim questions (by class) and answers (by user). 
+     @author: MM     
+  """
+  
+
+  @staticmethod
+  def match(inp):
+    """Use this static method to test whether the rule represented by this class is applicable to a specific input.
+       Parameter inp is an array of WordInfo instances, corresponding to input tokens (completely segmented?).
+       Returns True iff the requirements for the application of this spelling rule are matched by inp.
+    """
+    pass
+
+  def __init__(self, inp):
+    """Constructor. Initializes self.inp (copy of input) and self.state (status of dialog between class and user).
+       self.state values:
+         0: object was initialized but dialog has not yet started
+         1,2,3,...: 1st, 2nd, 3rd etc. turn of conversation
+         999: object provided verdict, dialog ended
+    """
+    self.inp = inp
+    self.state = 0
+    
+  def getId(self):
+    """Return a string which is the unique id of this rule."""
+    pass
+
+  def getName(self):
+    """Return a string giving the human-understandable name of the rule."""
+    pass
+    
+  def communicate(self, message=None):
+    """Parameter answer: array holding the answer(s) by the user to the question asked by the class in the previous turn. If message==[] a new dialog is started.
+       Returns either tuple ('!', <verdict>) or tuple ('?', <question>) or tuple (None, 'error_message').
+       <verdict> is an array of solutions: [([separators], 'comment', [AKH-ids]), ...]
+         where [separators] contains N-1 instances (iff len(self.inp)==N) of either '' or ' ' or '-' (kiskotojel) or '--' (nagykotojel).
+         [AKH-ids] contains (string) ids of AKH paragraphs that played a role in this solution, 'comment' is an optional textual explanation for this solution.
+       <question> is a structure that represents an interim question asked by class with possible answers and their ids:
+         ('question prompt', [(answer_id, 'answer text'), ...]). 
+         One of answer_id's (strings) should be provided in parameter message when calling communicate() in the next turn.
+    """
+    pass
+    
+# # # end class SpellingRuleBase # # #
+
+class RuleSzinneviAlaptag(SpellingRuleBase):
+  """
+     Név: színnévi alaptag (M_EK_SZIN) (AkH. 110)
+
+     Feladat: minőségjelzős színnevek egybe v. külön
+
+     Erőforrás: MA, lista színárnyalatot kifejező melléknevekről (LIST1), lista színnevekről (LIST2)
+
+     Azonosító jegyek: 1:{HA}?+2:{MN.NOM & in(LIST1)}+3:{MN.NOM & in(LIST2)};
+
+     Működés:
+
+     if (2==egyszeru & 3==egyszeru) {
+      if (exists(1)) { 
+       kulon(1,2,3); %rendkívül sötét zöld
+       } else {
+        egybe(2,3); %sötétzöld
+       }
+     } else { % 2==osszetett | 3==osszetett => xerox kod = ^CB
+       kulon(1?,2,3) %nagyon? világos narancssárga
+     }
+     Megjegyzés:  -
+  
+     TODO: if alaptag is összetett but was split: e.g. rózsa szín, narancs sárga
+     
+     @author: MM     
+  """
+
+  @staticmethod
+  def match(inp):
+    if len(inp) not in [2, 3]:
+      return False
+    alaptag = 1 if len(inp) == 2 else 2 # index of the alaptag in inp
+    if not inp[alaptag].hasLexProp('Color1'): # színnév
+      return False
+    if not inp[alaptag - 1].hasLexProp('Color3'): # színárnyalat
+      return False
+    #if not inp[alaptag].hasPoSCase('MN', 'NOM'):
+    if not inp[alaptag].matchPoSSequence('.*MN,NOM'):
+      return False
+    #if not inp[alaptag-1].hasPoSCase('MN', 'NOM'):
+    if not inp[alaptag - 1].matchPoSSequence('.*MN,NOM'):    
+      return False
+    if alaptag == 2 and not inp[alaptag - 2].hasPoSCase('HA'):
+      return False
+    return True
+   
+  def getId(self):
+    return "M_EK_SZIN"
+   
+  def getName(self):
+    return "Színnévi alaptag (M_EK_SZIN) (AkH. 110)"
+    
+  def communicate(self, message=None):
+    sols = []
+    alaptag = 1 if len(self.inp) == 2 else 2 # index of the alaptag in inp
+    if self.inp[alaptag].getNCompParts() == 1 and self.inp[alaptag - 1].getNCompParts() == 1: # 2==egyszeru & 3==egyszeru
+      if alaptag == 2: # len(inp)==3
+        sols.append(([' ', ' '], 'A szókapcsolat határozót is tartalmaz, ezért külön írjuk a jelzőt és a színnévi alaptagot', ['110'])) # kulon(1,2,3)
+      else: # len(inp)==2
+        sols.append(([''], 'A színárnyalatot kifejező melléknévi jelzőt egybeírjuk a színt jelölő melléknévvel, ha mindkettő egyszerű szó.', ['110.'])) # egybe(2,3)
+    elif self.inp[alaptag].getNCompParts() > 1 or self.inp[alaptag - 1].getNCompParts() > 1: # 2==osszetett | 3==osszetett
+      sols.append(([' ', ' '] if alaptag == 2 else [' '], 'A színnévi alaptag vagy minőségjelzője összetett, ezért külön írjuk őket', ['110.'])) # kulon(1,2,3) or kulon(2,3)
+    else:
+      self.state = 999
+      return (None, 'A színnév vagy a minőségjelző összetételi tagjainak számát nem lehetett meghatározni')
+    self.state = 999
+    return ('!', sols)
+
+# # # end class RuleSzinneviAlaptag # # #
+
+
+class RuleAnyagneviMozgoszabaly(SpellingRuleBase):
+  """
+     Név: anyagnévi mozgószabály (M_EK_ANYAGNEV) (AkH. 115., OH. 134.)
+
+     Feladat: anyagnevet tartalmazó szerkezetek egybe v. külön, anyagnévi mozgószabály
+
+     Erőforrás: MA, lista anyagnevekről (LIST)
+
+     Azonosító jegyek: 1:in LIST + 2:{FN,NOM} or 1:in LIST + 2:{.*(FN(,_IKEP)?|MN),NOM')} + 3:{FN,NOM} or      1:.*(FN(,_IKEP)?|MN),NOM + 2:in LIST + 3:{FN,NOM}
+
+     Működés:
+     
+    if (not exists(3) { % 2 tagú bemenet) {
+      if (1 == osszetett && 2 == osszetett) {
+        if (1 in(LIST1) && 1 in(LIST2)) { % az előtag egyszerre szín- és anyagnév, pl. arany
+          kerdezd: "Az előtag anyagnév vagy színnév?"
+          if (anyagnev) {
+           egybe(1,2)
+          }
+          else if (színnév) {
+           kulon(1,2)
+          }
+       }
+      else {
+        egybe(1,2)
+       }
+    }
+    if (1 == osszetett || 2 == osszetett) {
+      kulon(1,2)
+    }
+
+ }
+
+
+     else {  % 3 tagú bemenet
+       if (1 == .*(FN(,_IKEP)?|MN|(IGE,_MIB)),NOM && not in LIST1) {
+         if (1 in LIST3) { % -i képzős földrajzi név, carrarai márvány szobor
+           kulon(1,2,3)
+        } 
+         else {    % tisztaselyem ruha vs. tiszta selyemruha
+           kerdezd: "A jelző az anyag nevére vagy az alaptagra vonatkozik?" 
+           if (anyag nevere) {
+             kulon(egybe(1,2), 3)
+           }
+           else if (alaptagra) {
+             kulon(1, egybe(2,3))
+           }
+         }
+      else if (1 in(LIST1) && 2 == .*(FN(,_IKEP)?|MN|(IGE,_MIB)),NOM { % bőr átmeneti kabát
+        kulon(1,2,3)
+       }
+    }
+}
+  
+  
+    @author: LZS
+  """
+    
+  @staticmethod
+  def match(inp):
+    if len(inp) not in [2, 3]:
+      return False
+    alaptag = 1 if len(inp) == 2 else 2 # index of the alaptag in inp
+#    if alaptag == 1 and not (inp[alaptag - 1].hasLexProp('Material1') or inp[alaptag - 1].hasLexProp('Material2')) and not inp[alaptag].matchPoSSequence('.*FN,NOM'): # anyagnév
+#      return False
+    if alaptag == 1 and not (inp[alaptag - 1].hasLexProp('Material1') or inp[alaptag - 1].hasLexProp('Material2')) and not inp[alaptag].hasPoSCase('.*FN,NOM'): # anyagnév
+      return False
+    if alaptag == 1 and (inp[alaptag - 1].hasLexProp('Material1') or inp[alaptag - 1].hasLexProp('Material2')) and WordInfo(inp[alaptag - 1].wordform + inp[alaptag].wordform).hasLexProp('Jelentessurito'):
+      return False
+    if alaptag == 2 and not (((inp[alaptag - 2].hasLexProp('Material1') or inp[alaptag - 2].hasLexProp('Material2')) and inp[alaptag - 1].matchPoSSequence('.*(FN(,_IKEP|,_UKEP)?|MN),NOM') and inp[alaptag].matchPoSSequence('.*FN,NOM')) or (inp[alaptag - 2].matchPoSSequence('.*(FN(,_IKEP)?|MN),NOM') and (inp[alaptag - 1].hasLexProp('Material1') or inp[alaptag - 1].hasLexProp('Material2')) and inp[alaptag].matchPoSSequence('.*FN,NOM'))):
+      return False
+    return True
+   
+  def getId(self):
+    return "M_EK_ANYAGNEV"
+   
+  def getName(self):
+    return "Anyagnévi mozgószabály (M_EK_ANYAGNEV) (AkH. 115., OH. 117.)"
+    
+  def communicate(self, message=[]):
+    sols = []
+    alaptag = 1 if len(self.inp) == 2 else 2 # index of the alaptag in inp
+    FirstLetter0 = Wordform.Phonology.CV(self.inp[alaptag - 1].wordform[0]) # anyagnév/színnév
+    FirstLetter1 = Wordform.Phonology.CV(self.inp[alaptag].wordform[0]) # utótag (alaptag)
+    det1 = 'A' if FirstLetter0 == 'C' else 'Az'
+    det2 = 'A' if FirstLetter1 == 'C' else 'Az'
+    if len(self.inp) == 2:
+      if self.inp[alaptag].getNCompParts() == 1 and self.inp[alaptag - 1].getNCompParts() == 1: # 2==egyszeru & 3==egyszeru: bőröv, selyeming
+        if ((self.inp[alaptag - 1].hasLexProp('Material1') or self.inp[alaptag - 1].hasLexProp('Material2')) and (self.inp[alaptag - 1].hasLexProp('Color1') or self.inp[alaptag - 1].hasLexProp('Color2') or self.inp[alaptag - 1].hasLexProp('Color3'))):
+          if self.state == 0:
+            self.state = 1
+            return('?', (det1 + ' "' + self.inp[alaptag - 1].wordform + '" anyagnév vagy színnév?',
+                         [('1', det2 + ' ' + self.inp[alaptag].wordform + ' ebből az anyagból készült.'),
+                          ('2', det2 + ' ' + self.inp[alaptag].wordform + ' ilyen színű.'),
+                          ('3', 'A kérdés nem értelmezhető. Nem anyagnévi jelzős szerkezetről van szó.')]))
+          elif self.state == 1:
+            if message == '1':
+              sols.append(([''], 'Az anyagnévi jelzőt, ha egyszerű szó, egybeírjuk a nem összetett főnevekkel.', ['115.'])) # egybe(2,3)
+              self.state = 999
+              return ('!', sols)
+            elif message == '2':
+              sols.append(([' '], 'Ha a jelző a jelzett szó színére, nem pedig az anyagára vonatkozik, a kifejezést különírjuk, minőségjelzős szerkezetről lévén szó.', ['107. a)']))
+              self.state = 999
+              return ('!', sols)
+            elif message == '3':
+              return (None, 'Nem anyagnévi jelzős szerkezetről van szó.')          
+          else:
+            return (None, 'Hiba!')
+        elif self.inp[alaptag - 1].hasLexProp('Material1') or self.inp[alaptag - 1].hasLexProp('Material2'):
+          #print('anyagnevi elotag')
+          sols.append(([''], 'Az anyagnévi jelzőt, ha egyszerű szó, egybeírjuk a nem összetett főnevekkel.', ['115.']))
+          self.state = 999
+          return ('!', sols)
+      elif self.inp[alaptag].getNCompParts() > 1 or self.inp[alaptag - 1].getNCompParts() > 1: # 2==osszetett | 3==osszetett
+        sols.append(([' '], 'Ha az anyagnévi jelzős kapcsolatnak valamelyik vagy mindkét tagja összetett szó, az anyagnevet különírjuk jelzett szavától.', ['115.']))
+    elif len(self.inp) > 2:
+      FirstLetter0 = Wordform.Phonology.CV(self.inp[alaptag - 2].wordform[0]) # jelző
+      det0 = 'A' if FirstLetter0 == 'C' else 'Az'
+      FirstLetter1 = Wordform.Phonology.CV(self.inp[alaptag - 1].wordform[0]) # anyagnév
+      det1 = 'A' if FirstLetter1 == 'C' else 'Az'
+      FirstLetter2 = Wordform.Phonology.CV(self.inp[alaptag].wordform[0]) # alaptag
+      det2 = 'A' if FirstLetter2 == 'C' else 'Az'
+      sub0 = 'ra' if self.inp[alaptag].getHarmony() == True else 're'
+      sub1 = 'ra' if self.inp[alaptag - 1].getHarmony() == True else 're'
+      if self.inp[alaptag - 2].matchPoSSequence('.*(FN(,_IKEP)?|MN|(IGE,_MIB)),NOM') and not (self.inp[alaptag - 2].hasLexProp('Material1') or self.inp[alaptag - 2].hasLexProp('Material2')):
+        if self.inp[alaptag - 2].hasLexProp('ProperGeo'):
+          if self.state == 0:
+            self.state = 1
+            return('?', (det0 + ' "' + self.inp[alaptag - 2].wordform + '" jelző mire vonatkozik?',
+                         [('1', det2 + ' ' + self.inp[alaptag].wordform + sub0 + '. ' + det2 + ' ' + self.inp[alaptag].wordform + ' ' + self.inp[alaptag - 2].wordform + '.'),
+                          ('2', det1 + ' ' + self.inp[alaptag - 1].wordform + sub1 + '. ' + det1 + ' ' + self.inp[alaptag - 1].wordform + ' ' + self.inp[alaptag - 2].wordform + '.'),
+                          ('3', 'A kérdés nem értelmezhető. Nem anyagnévi jelzős szerkezetről van szó.')]))    
+            
+          elif self.state == 1:
+            if message == '1':
+              sols.append(([' ', ' '], '...', ['']))  
+              self.state = 999
+              return ('!', sols)
+            elif message == '2':   
+              sols.append(([' ', ' '], 'Ha az anyagnévi jelzős szerkezetben az anyagnév jelzője melléknévképzővel ellátott földrajzi név, minden tagot külön szóba írunk.', [''], ['134.'])) # OH. 134.
+              self.state = 999
+              return ('!', sols)
+            elif message == '3':
+              return (None, 'Nem az anyagnévi jelzős szerkezetről van szó.')
+        elif self.state == 0:
+          self.state = 1
+          return('?', (det0 + ' "' + self.inp[alaptag - 2].wordform + '" az anyag nevére vagy az alaptagra vonatkozik?',
+                       [('1', 'Az anyag nevére. ' + det1 + ' ' + self.inp[alaptag - 1].wordform + ' ' + self.inp[alaptag - 2].wordform + '.'),
+                        ('2', 'Az alaptagra. ' + det2 + ' ' + self.inp[alaptag].wordform + ' ' + self.inp[alaptag - 2].wordform + '.')]))
+        elif self.state == 1:
+          if message == '1':
+            sols.append((['', ' '], 'Ha az anyagnévi jelző szerepét különírt szószerkezet tölti be, az eredetileg különírt szerkezetet egybeírjuk, az alkalmi összetétellé váltó jelző és a jelzett szó azonban különírandó.', [''], ['134.'])) # OH. 134.
+            self.state = 999
+            return ('!', sols)
+          elif message == '2':
+            sols.append(([' ', ''], 'Ha a jelző a szerkezet alaptagjára vonatkozik, az anyagnévi jelzőt egybeírjuk az alaptaggal, az alkalmi jelzőt pedig különírjuk az anyagnevet tartalmzó összetételtől.', ['?']))
+            self.state = 999
+            return ('!', sols)
+          else:
+           return ('Hiba!')
+      elif (self.inp[alaptag - 2].hasLexProp('Material1') or self.inp[alaptag - 2].hasLexProp('Material2')) and self.inp[alaptag - 1].matchPoSSequence('.*(FN(,_IKEP|,_UKEP)|MN|(IGE,_MIB)),NOM'):
+        sols.append(([' ', ' '], 'Ha az anyagnévi jelző egy különírt szószerkezetre vonatkozik, a jelzőt is különírjuk.', ['']))
+    else:
+      self.state = 999
+      return (None, 'Az összetételi tagok számát nem lehetett meghatározni.')
+    self.state = 999
+    return ('!', sols)
+
+# # # end class RuleAnyagneviMozgoszabaly # # #
+
+
+class RuleSorszamneviJelzosSzerk(SpellingRuleBase):
+  """
+     Név: sorszámnévi jelzős szerkezetek (kód: M_EK_SORSZAMNEV) (AkH. 120.)
+
+     Feladat: sorszámnévi/törtszámnévi jelzős szerkezetek egybe vagy külön
+
+     Erőforrás: morfológiai elemzők (MA)
+
+     Azonosító jegyek: 1:{SZN+_SORSZ, SZN+_TORT} + 2:{FN, MN(FN+_IKEP, FN+_SKEP, FN+_UKEP), SZN}
+
+     Működés:
+
+     if (1: SZN+_SORSZ) { % ezredik év
+       kulon(1,2)
+     }
+     else { % ötödévben
+       egybe(1,2)
+     }
+     
+     @author: MM    
+  """
+
+  @staticmethod
+  def match(inp):
+    if len(inp) != 2:
+      return False
+    if not (inp[0].matchPoSSequence('SZN,_SORSZ,NOM') or inp[0].matchPoSSequence('SZN,_TORT,NOM')): # 1:{SZN+_SORSZ, SZN+_TORT}
+      return False
+    if not (inp[1].hasFinalPoS('FN') or inp[1].hasFinalPoS('SZN') or inp[1].matchPoSSequence('FN,_IKEP,.+') or inp[1].matchPoSSequence('FN,_SKEP,.+') or inp[1].matchPoSSequence('FN,_UKEP,.+') or inp[1].matchPoSSequence('FN\|NM,.*')): # 2:{FN, MN(FN+_IKEP, FN+_SKEP, FN+_UKEP), SZN}
+      return False
+    return True
+   
+  def getId(self):
+    return "M_EK_SORSZAMNEV"
+   
+  def getName(self):
+    return "Sorszámnévi jelzős szerkezetek (kód: M_EK_SORSZAMNEV) (AKH 120)"
+    
+  def communicate(self, message=None):
+    sols = []
+    if self.inp[0].matchPoSSequence('SZN,_SORSZ,NOM'): # if (1: SZN+_SORSZ) { % ezredik év
+      sols.append(([' '], 'A -dik képzős sorszámnévi jelzőt nem írjuk egybe sem a jelzett főnévvel, sem a (rendszerint -i, -s, -ú, -ű képzős) melléknévvel', ['120.'])) # kulon(1,2)
+    else: # else { % ötödévben
+      sols.append(([''], 'A -d képzős sorszámnévi jelzőt egybeírjuk mind a főnevekkel, mind a melléknevekkel, mind a számnevekkel', ['120'])) # egybe(1,2)
+    self.state = 999
+    return ('!', sols)
+
+# # # end class RuleSorszamneviJelzosSzerk # # #
+
+class RuleJelzoiElotag(SpellingRuleBase):
+  """Név: jelzői előtag (kód: M_EK_ELOTAG) (AkH. 111.)
+
+     Feladat: önállóan nem használt jelzői előtagos összetételek kezelése 
+
+     Erőforrás: morfológiai elemzők (MA), önállóan nem használt jelzői előtagok listája (LIST)
+     
+     Azonosító jegyek: 1: in(LIST), 2: (bármi)
+
+     Működés:
+     
+     if (1 in(LIST) {
+       egybe(1,2)
+     }
+  
+     @author: LZS
+     
+  """
+    
+  @staticmethod
+  def match(inp):
+    if len(inp) != 2:
+      return False
+    if not (inp[0].hasLexProp('CompoundPrefix2') and inp[1].matchPoSSequence('FN,NOM')):
+      return False
+    return True
+
+  def getId(self):
+    return "M_EK_ELOTAG"
+   
+  def getName(self):
+    return "Önállóan nem használt jelzői előtagos összetételek kezelése (kód: M_EK_ELOTAG) (AkH. 111)."
+    
+  def communicate(self, message=None):
+    sols = []
+    sols.append(([''], 'Az olyan összetételeket, amelyekben a főnév minőségjelzője összetételi alakjában vagy jelentésében önálló szóként nem használatos, mindig egybe kell írni.',
+                 [''], ['111.'])) # OH. 111.
+    self.state = 999
+    return ('!', sols)
+
+# TODO: össz-szövetségi
+    
+
+# # # end class RuleJelzoiElotag # # #
+
+class RuleJeloletlenAlanyos(SpellingRuleBase):
+  """
+    Név: alanyos alárendelés (kód: M_EK_ALANY) (AkH. 106.)
+
+    Feladat: alanyos alárendelések egybe vagy külön
+
+    Erőforrás: morfológiai elemzők (MA); kivétellista az egybeírandókról (LIST)
+
+    Azonosító jegyek: 1:{MN.NOM}?+2:{FN.NOM,FN.PSe3}+3:{IGE.TMe3,MIB.NOM,MIF.NOM,HIN}
+
+    Működés:
+
+    if (2+3 in LIST) { 
+     if (exists(1)) { 
+      kulon(1,2,3); %magyar ember lakta
+     } else {
+      egybe(2,3); %emberlakta
+     }
+    } else {
+     kulon(1?,2,3) %magyar? traktor szántotta
+    }
+
+    @author: LZS
+  """
+  
+  @staticmethod
+  def match(inp):
+    if len(inp) not in [2,3]:
+      return False
+    alaptag = 1 if len(inp) == 2 else 2 # index of the alaptag in inp
+    if len(inp) == 3:
+      if not inp[alaptag - 2].matchPoSSequence('(MN|(FN,_IKEP)|(IGE,_(MIB|_OKEP)))') and not inp[alaptag - 1].matchPoSSequence('FN(,PSe3)?,NOM') and not inp[alaptag].matchPoSSequence('((IGE(,_OKEP|_MIB|_HIN))|(IGE,TMe3))'):
+        return False
+    if len(inp) == 2:
+      if not (WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('Alanyos') or (inp[alaptag - 1].matchPoSSequence('FN,(PSe3,)?NOM') and inp[alaptag].matchPoSSequence('IGE,TMe3'))):
+        return False
+    return True
+  
+  def getId(self):
+    return "M_EK_JELOLETLEN_ALANYOS"
+  
+  def getName(self): 
+    return "Jelöletlen alanyos alárendelő összetételek (kód: M_EK_JELOLETLEN_ALANYOS) (AkH. 106.)"
+
+  def communicate(self, message=None):
+    sols = []
+    if len(self.inp) == 3:
+      if self.inp[0].matchPoSSequence('(MN|(FN,_IKEP)|(IGE,_(MIB|_OKEP)))') and self.inp[1].matchPoSSequence('FN(,PSe3)?,NOM') and self.inp[2].matchPoSSequence('((IGE(,_OKEP|_MIB|_HIN))|(IGE,TMe3))'):
+        sols.append(([' ', ' '], 'Ha az alanyi bővítménynek jelzője van, minden tagot külön szóba írunk.', ['']))
+    else:
+      if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('Alanyos'):
+        sols.append(([''], 'Az alanyos alárendelő összetételek egybeírandók (jelentésváltozás, vagy csupán a hagyomány miatt).', ['106. b, c)']))
+      else:
+        sols.append(([' '], 'Az alanyos kapcsolatok tagjait különírjuk egymástól.', ['106. a)']))
+    self.state = 999
+    return ('!', sols)
+
+# # # end class RuleJeloletlenAlanyos # # #
+                
+
+class RuleJeloletlenTargyas(SpellingRuleBase):
+  """
+     Név: jelöletlen tárgyas összetételek (kód: M_EK_JELOLETLEN_TARGYAS) (AkH. 123., OH. 104.)
+     
+     Feladat: jelöletlen tárgyas összetételek helyesírása
+     
+     Erőforrás: morfológiai elemzők (MA)
+     
+     Azonosító jegyek: 1:{(FN(PSe3)?, MN, NU} + 2:{MIB, MIN, HI}
+     
+     Működés: 
+     
+     if(1 + 2) { % tárgyas alárendelés
+        egybe(1,2) % jelöletlen tárgyas alárendelő összetétel mindig egybe
+        }
+        
+    Ezután meg kell vizsgálni, esetleg a 6:3-as szabály miatt nem kell-e kötőjel.
+     
+     @author: LZS    
+  """
+  @staticmethod
+  def match(inp):
+    if len(inp) != 2:
+      return False
+    if inp[0].matchPoSSequence('HA') and inp[0].matchPoSSequence('FN,NOM'):
+      return False # pl. otthon + maradó nem tárgyas
+    if not(inp[0].matchPoSSequence('((FN\|NM)|FN|NM)(,(PS)?e3)?,NOM')):
+      return False
+    if not (inp[1].matchPoSSequence('(IK,)?IGE,(_MIB|_OKEP|_HIN)')):
+      return False
+    if WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('Alanyos'):
+      return False
+    if WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('AllSzokapcs'):
+      return False
+    return True
+  
+  def getId(self):
+    return "M_EK_JELOLETLEN_TARGYAS"
+  
+  def getName(self): 
+    return "Jelöletlen tárgyas összetételek (kód: M_EK_JELOLETLEN_TARGYAS) (AkH. 123., OH. 204.)"
+
+  def communicate(self, message=None):
+    sols = []
+    sols.append(([''], 'A jelöletlen tárgyas összetételt mindig egybeírjuk (esetleg kötőjellel, amennyiben érvényesül a szótagszámlálási szabály).', ['123.'])) # egybe(1,2)
+    self.state = 999
+    return ('!', sols)
+
+# # # end class RuleJeloletlenTargyas # # #    
+
+
+class RuleJeloletlenHatarozos(SpellingRuleBase):
+  """
+     Név: jelöletlen határozós összetételek (kód: M_EK_JELOLETLEN_TARGYAS) (AkH. 123., OH. 104.)
+     
+     Feladat: jelöletlen határozós összetételek helyesírása
+     
+     Erőforrás: morfológiai elemzők (MA)
+     
+     Azonosító jegyek: 1:{FN, MN, HA, INF, HI} + 2:{FN, MN, HA, MIF, MIB, HI} + (3:{FN, MN})?
+     
+     Működés: 
+     
+     if(1 + 2) { % határozós alárendelés
+        egybe(1,2) % jelöletlen határozós alárendelő összetétel mindig egybe
+        }
+        
+    Ezután meg kell vizsgálni, esetleg a 6:3-as szabály miatt nem kell-e kötőjel.
+     
+     @author: LZS
+  """
+  @staticmethod  
+  def match(inp):
+    if len(inp) != 2:
+      return False
+    match1 = inp[0].matchPoSSequence('FN,NOM') and inp[1].hasLexProp('HatarozosMelleknev')
+    #match2 = inp[0].matchPoSSequence('((FN(,PSe3)?|MN),NOM|HA|NU|IK|((IK,)?IGE(,_MUV)?,(_HIN|INF)))') and inp[1].matchPoSSequence('MN,NOM|HA|((IK,)?IGE,((_MIB|_IF|Me3)|_HIN(,.*))?)?')
+    match2 = inp[0].matchPoSSequence('((FN(,PSe3)?|MN),NOM|HA|NU|IK|((IK,)?IGE(,_MUV)?,(_HIN|INF)))') and inp[1].matchPoSSequence('MN,NOM|HA|(IK)?IGE,(_MIB|_IF|HIN)?')
+    match3 = WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('HatarozosJeloletlenKivetel')
+    match4 = WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('HatarozoiIgeneviElotag')
+    
+#    print(match1)
+#    print(match2)
+#    print(match3)
+#    print(match4)
+#    
+    if inp[0].matchPoSSequence('FN,NOM') and inp[1].matchPoSSequence('IGE,_OKEP,NOM') and inp[1].matchPoSSequence('FN,NOM') and not match3: # -ó/-ő igeképzős utótagúak általában tárgyasak, nem határozósak
+      return False
+  
+    if not (match1 or match2 or match3 or match4):
+      return False
+  
+#    if not (WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('AllSzokapcs')):
+#      return False
+#    if not (inp[0].matchPoSSequence('FN,NOM') and inp[1].hasLexProp('HatarozosMelleknev')):
+#      return False
+#    if not (inp[0].matchPoSSequence('((FN(,PSe3)?|MN),NOM|HA|NU|((IK,)?IGE(,_MUV)?,(_HIN|INF)))')):
+#      return False
+#    if not (inp[1].matchPoSSequence('MN,NOM|HA|((IK,)?IGE,((_OKEP|_MIB|_IF|Me3)|_HIN(,.*))?)?')):
+#      return False   
+
+#      if ((inp[0].hasLexProp('Folk') or inp[0].hasLexProp('Major')) and (inp[1].hasLexProp('Folk') or inp[1].hasLexProp('Major'))): # nép, nyelv, szaknév
+#        return False 
+#    if (inp[0].hasLexProp('AgeGroup') or inp[0].hasLexProp('Emphasis') or inp[0].hasLexProp('Folk') or inp[0].hasLexProp('Major') or inp[0].hasLexProp('Material')): # kort jelolő főnév, nyomatékosító főnév
+#      return False
+
+
+    if WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('Alanyos'):
+      return False
+    return True
+    
+    
+  def getId(self):
+    return "M_EK_JELOLETLEN_HATAROZOS"
+  
+  def getName(self): 
+    return "Jelöletlen határozós összetételek (kód: M_EK_JELOLETLEN_HATAROZOS) (AkH. 125., OH. 105--107.)"    
+
+  def communicate(self, message=[]):
+    sols = [] 
+    firstLetter0 = Wordform.Phonology.CV(self.inp[0].wordform[0])
+    det0 = 'a' if firstLetter0 == 'C' else 'az'
+    dict = [('enni', 'aranyos', 'étel'), ('csapni', 'rossz, silány', 'lecsapandó'), ('égetni', 'nagyon gonosz', 'égetendő')]
+    meaning1 = '?'
+    meaning2 = '?'
+    if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('HatarozosJeloletlenKivetel'):
+      sols.append(([''], 'A jelöletlen határozós összetételt mindig egybeírjuk (esetleg kötőjellel, amennyiben érvényesül a szótagszámlálási szabály).', ['125. c)'])) # egybe(1,2)
+    elif self.inp[0].matchPoSSequence('(IK,)?IGE(,_MUV)?,INF') and self.inp[1].wordform == 'való':
+      if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('MelleknevValo') and WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('Rogzult'):
+        if self.state == 0:
+          self.state = 1
+#          for item in dict:
+#            tmp = [s for s in item if self.inp[0].wordform in s]
+#            tmp2 = ''.join(tmp)
+#            if item[0] == tmp2:
+#              meaning1 = item[1]
+#              meaning2 = item[2]
+          return ('?', ('Válasszon a lehetőségek közül!', 
+                        #[('1', "A szó egy melléknév, jelentése: '" + meaning1 + "'."),
+                        [('1', "A szó egy melléknév, jelentése: '" + WordInfo(self.inp[0].wordform + self.inp[1].wordform).lex().RogzultDef1.encode('utf-8') + "'."),
+                        ('2', "A szó főnévi értékben szerepel, jelentése: '" + WordInfo(self.inp[0].wordform + self.inp[1].wordform).lex().RogzultDef2.encode('utf-8') + "'."),
+                        ('3', "A szerkezet jelentése: '" + det0 + ' ' + applyseparators(self.inp, [' ']) + "' [valami] (nem főnévi értékben szerepel a szerkezet egésze).")]))
+        elif self.state == 1:
+          if message == '1':
+            sols.append(([''], 'Ha a -való utótagú kifejezés egésze melléknévi értékben szerepel, és az elő- és utótag jelentése együttesen más, mint külön-külön, a kifejezést egybeírjuk.', ['136.']))
+            self.state = 999
+            return ('!', sols)
+          elif message == '2':
+            sols.append(([''], 'Ha a szerkezet egésze főnévi értékben szerepel, összetételként egybe kell írni.', ['136.']))
+            self.state = 999
+            return ('!', sols)
+          elif message == '3':
+            sols.append(([' '], 'Ha az elő- és utótag jelentése együttesen ugyanaz, mint külön-külön (azaz nincs jelentésváltozás), a kifejezést különírjuk.', ['136.']))
+            self.state = 999
+            return ('!', sols)
+          else:
+            return (None, 'Hiba!')
+      else:       
+        if self.state == 0:
+          self.state = 1
+          return ('?', ('A szerkezet egésze főnévi értékben szerepel? Melyik kifejezéshez hasonlít jobban?',
+                         [('1', applyseparators(self.inp, ['']) + ' (a szerkezet egésze főnévi értékben szerepel)'),
+                          ('2', det0 + ' ' + applyseparators(self.inp, [' ']) + ' [valami] (nem főnévi értékben szerepel a szerkezet egésze)')]))
+        elif self.state == 1:
+          if message == '1':
+            sols.append(([''], 'Ha a szerkezet egésze főnévi értékben szerepel, összetételként egybe kell írni.', ['136.'])) 
+            self.state = 999
+            return ('!', sols)
+          elif message == '2':
+            sols.append(([' '], 'Ha a szerkezet egésze nem főnévi értékben szerepel, külön kell írni.', ['136.']))
+            self.state = 999
+            return ('!', sols)
+        else:
+          return (None, 'Hiba!') 
+#    elif WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('HatarozosKettosJelentes'):
+#      if self.state == 0:
+#        self.state = 1
+#        return ('?', ('Az elő- és utótag jelentése együttesen ugyanaz, mint külön-külön (azaz nincs jelentésváltozás)?', [('1', 'Igen, ugyanaz, nincs jelentésváltozás.'), ('2', 'Nem ugyanaz, van jelentésváltozás.')]))
+#      elif self.state == 1:
+#        if message == '1':
+#          sols.append(([' '], 'Ha az elő- és utótag jelentése együttesen ugyanaz, mint külön-külön (azaz nincs jelentésváltozás), a kifejezést különírjuk.', ['']))
+#          self.state = 999
+#          return ('!', sols)
+#        elif message == '2':
+#          sols.append(([''], 'Ha az elő- és utótag jelentése együttesen más, mint külön-külön (azaz jelentésváltozás van), a kifejezést különírjuk.', ['']))
+#          self.state = 999
+#          return ('!', sols)
+#        else:
+#          return (None, 'Hiba!') 
+    elif WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('Rogzult'):
+      if self.state == 0:
+        self.state = 1
+        return ('?', ('Válasszon a lehetőségek közül!',
+                            [('1', "'" + WordInfo(self.inp[0].wordform + self.inp[1].wordform).lex().RogzultDef1.encode('utf-8') + "'"),
+                             ('2', "'" + WordInfo(self.inp[0].wordform + self.inp[1].wordform).lex().RogzultDef2.encode('utf-8') + "'")]))
+      elif self.state == 1:
+        if message == '1':
+          sols.append(([''], 'Ha az elő- és utótag jelentése együttesen más, mint külön-külön (azaz jelentésváltozás van), a kifejezést különírjuk.', ['']))
+          self.state = 999
+          return ('!', sols)
+        elif message == '2':
+          sols.append(([' '], 'Ha az elő- és utótag jelentése együttesen ugyanaz, mint külön-külön (azaz nincs jelentésváltozás), a kifejezést különírjuk.', ['']))
+          self.state = 999
+          return ('!', sols)
+        else:
+          return (None, 'Hiba!') 
+        
+    elif self.inp[0].matchPoSSequence('IGE,_HIN') and self.inp[1].matchPoSSequence('IGE(,.*)') and not WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('HatarozoiIgeneviElotag'):
+      sols.append(([' '], 'Ha határozói vagy főnévi igenévi szófajú a bővítmény, a határozói viszony jelöletlen. A szerkezet különírandó különírandók.', [''], ['105.'])) # OH. 105.
+    elif self.inp[0].matchPoSSequence('(IK,)?IGE,INF') and self.inp[1].matchPoSSequence('IGE(,.*)'):
+      sols.append(([' '], 'Ha határozói vagy főnévi igenévi szófajú a bővítmény, a határozói viszony jelöletlen. A szerkezet különírandó különírandók.', [''], ['105.'])) # OH. 105.
+    elif self.inp[0].matchPoSSequence('HA') and self.inp[1].matchPoSSequence('IGE,(_OKEP|_HIN|_IF)?'): # hanyatt fekszik, de hanyatt fekve -- nem jó
+      sols.append(([' '], 'Nem összetételről, hanem határozószói bővítményű szószerkezetről van szó, amelyet különírunk. ', [''],['105.'])) # OH. ?
+ 
+         
+    elif self.inp[0].hasLexProp('Occupation') and self.inp[1].wordform == 'jelölt':
+      sols.append(([''], 'A jelöletlen határozós összetételt mindig egybeírjuk (esetleg kötőjellel, amennyiben érvényesül a szótagszámlálási szabály).', ['125.']))     
+    elif self.inp[0].matchPoSSequence('((IK,)?IGE(,_MUV)?,(_HIN|INF))') and self.inp[1].matchPoSSequence('(IK,)?,IGE,e3'):
+      sols.append(([' '], 'Ha a határozói bővítmény szófaját tekintve főnévi vagy határozói igenév, illetőleg határozószó, általában különírást alkalmazunk.', [''], ['105.'])) # OH. 105.
+    else:
+      sols.append(([''], 'A jelöletlen határozós összetételt mindig egybeírjuk (esetleg kötőjellel, amennyiben érvényesül a szótagszámlálási szabály).', ['125. c)'])) # egybe(1,2)
+    
+    self.state = 999
+    return ('!', sols)
+
+# # # end class RuleJeloletlenHatarozos # # #
+
+class RuleJeloletlenBirtokosJelzos(SpellingRuleBase):
+  """
+     Név: jelöletlen birtokos jelzős összetételek (kód: M_EK_JELOLETLEN_BIRTOKOS) (AkH. 128., OH. 119.)
+     
+     Feladat: jelöletlen birtokos jelzős összetételek helyesírása
+     
+     Erőforrás: morfológiai elemzők (MA)
+     
+     Azonosító jegyek: 1:{FN.NOM} + 2:{(FN|(IGE,_IF))}
+     
+     Működés: 
+     
+     if(1 + 2) { % birtokos jelzős alárendelés
+        egybe(1,2) % jelöletlen birtokos jelzős alárendelő összetétel mindig egybe
+        }
+        
+    Ezután meg kell vizsgálni, esetleg a 6:3-as szabály miatt nem kell-e kötőjel.
+     
+     @author: LZS
+  """
+  @staticmethod  
+  def match(inp):
+    if len(inp) != 2:
+      return False
+    if inp[0].matchPoSSequence('IGE,_OKEP,NOM') and inp[0].matchPoSSequence('FN,NOM'):
+      return False # letiltjuk a foly. melléknévi igeneves szerkezetnél a birtokos jelzős összetételes elemzést
+    if not (inp[0].matchPoSSequence('FN,NOM')):
+      return False
+#    if not (inp[1].matchPoSSequence('(FN([^,PSe3])|(IGE,_IF),NOM)')):
+#      return False
+    if not (inp[1].matchPoSSequence('((FN|((IK,)?IGE,_IF)),NOM)')):
+      return False
+     
+#    if not (inp[1].hasPoSCase('(FN|(IGE,_IF),NOM)')):
+#      return False
+#    if (inp[0].hasLexProp('AgeGroup') or inp[0].hasLexProp('Emphasis') or inp[0].hasLexProp('Folk') or inp[0].hasLexProp('Major') or inp[0].hasLexProp('Occupation') or inp[0].hasLexProp('Material')): # kort jelolő főnév, nyomatékosító főnév
+#      return False
+    return True
+  
+  def getId(self):
+    return "M_EK_JELOLETLEN_BIRTOKOS"
+  
+  def getName(self): 
+    return "Jelöletlen birtokos jelzős összetételek (kód: M_EK_JELOLETLEN_BIRTOKOS) (AkH. 128., OH. 119.)"
+
+  def communicate(self, message=None):
+    sols = []
+    sols.append(([''], 'A jelöletlen birtokos jelzői összetételt mindig egybeírjuk (esetleg kötőjellel, amennyiben érvényesül a szótagszámlálási szabály).', ['128. c)'])) # egybe(1,2)
+    self.state = 999
+    return ('!', sols)
+
+# TODO: 3 tagú inputok? nyomás-térfogat diagram, csirke far-hát --> ezek 3. mozgószabállyal írandók
+# bug: fél kilences --> jelöletlen birtokosként elemzi, pedig nem az
+
+# # # end class RuleJeloletlenBirtokos # # #
+
+class RuleJeloletlenMinosegjelzos(SpellingRuleBase):
+  """
+  @author: LZS
+  """
+  @staticmethod  
+  def match(inp):
+    if len(inp) not in [2,3]:
+      return False
+    if len(inp) == 3:
+      if not inp[0].matchPoSSequence('HA'):
+        return False
+      if not (inp[1].matchPoSSequence('(IGE,(_OKEP|_MIB)|FN(,_IKEP|,_SKEP)|MN),NOM')):
+        return False
+      if not (inp[2].matchPoSSequence('FN(,_UKEP)?|MN|SZN|HA')):
+        return False
+    if len(inp) == 2:
+      if not (inp[0].matchPoSSequence('(IGE,(_OKEP|_MIB)|FN(,_IKEP|,_SKEP)|MN),NOM')): # csak FN,_UKEP, önmagában fn nem
+        return False
+      if not (inp[1].matchPoSSequence('FN(,_UKEP)?|MN|SZN|HA')): 
+        return False
+      if WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('Alanyos'):
+        return False
+      if WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('AllSzokapcs'):
+        return False
+    return True
+
+  def getId(self):
+    return "M_EK_JELOLETLEN_MINOSEGJELZOS"
+  
+  def getName(self): 
+    return "Jelöletlen minőségjelzős összetételek (kód: M_EK_JELOLETLEN_MINOSEG) (AkH. 107., OH. 107-111.)"
+
+  def communicate(self, message=[]):
+    sols = []
+    adj = 'kicsi' if self.inp[0].wordform == 'kis' else self.inp[0].wordform
+    FirstLetter0 = Wordform.Phonology.CV(self.inp[0].wordform[0])
+    det0 = 'A' if FirstLetter0 == 'C' else 'Az'
+    FirstLetter1 = Wordform.Phonology.CV(self.inp[1].wordform[0])
+    det1 = 'A' if FirstLetter1 == 'C' else 'Az'
+    dat = 'nak' if self.inp[0].getHarmony() == True else 'nek'
+    
+    if len(self.inp) == 2:
+        if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('MinosegjelzosHagyomany'):
+          sols.append(([''], 'A kialakult szokást megtartva jelentésváltozás nélkül is egybeírjuk számos minőségjelzős kapcsolat tagjait.', ['107. c)']))
+          self.state = 999
+          return ('!', sols)
+        elif WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('Rogzult'):
+          if self.state == 0:
+            self.state = 1 
+            return ('?', ('Válassza ki a megfelelő jelentést!',
+                            [('1', "'" + WordInfo(self.inp[0].wordform + self.inp[1].wordform).lex().RogzultDef1.encode('utf-8') + "'"),
+                             ('2', "'" + WordInfo(self.inp[0].wordform + self.inp[1].wordform).lex().RogzultDef2.encode('utf-8') + "'")]))
+          elif self.state == 1:
+            if message == '1':
+              sols.append(([''], 'Ha a tagok együttes jelentése más, mint az előtag és az utótag jelentésének összege, a minőségjelzős összetételt egybeírjuk.', ['107. b)']))
+              self.state == 999
+              return ('!', sols)
+            elif message == '2':
+              sols.append(([' '], 'Ha a tagok együttes jelentése nem más, mint az előtag és az utótag jelentésének összege, a minőségjelzős szerkezetet különírjuk.', ['107. a, b)']))
+              self.state == 999
+              return ('!', sols)
+            else:
+              return(None, 'Hiba!')
+        elif self.inp[0].hasLexProp('Folk') and self.inp[1].wordform == 'barát':
+          if self.state == 0:
+            self.state = 1
+            return ('?', ('Válasszon a lehetőségek közül!', [('1', "'" + self.inp[0].wordform + " nemzettel rokonszenvező személy'"), ('2', "'" + self.inp[0].wordform + " nemzetiségű ismerős vagy szerzetes'")]))
+          elif self.state == 1:
+            if message == '1':
+              sols.append(([''], "Ha a kifejezés jelentése '" + self.inp[0].wordform + " nemzettel rokonszenvező személy', akkor a kifejezés egybeírandó.", ['?']))
+              self.state = 999
+              return ('!', sols)
+            elif message == '2':
+              sols.append(([' '], "Ha a kifejezés jelentése '" + self.inp[0].wordform + " nemzetiségű ismerős vagy szerzetes', akkor a kifejezés egybeírandó.", ['?']))
+              self.state = 999
+              return ('!', sols)
+            else:
+              return (None, 'Hiba!')
+        elif self.inp[0].hasLexProp('Folk') and self.inp[1].wordform == 'könyv':
+          if self.state == 0:
+            self.state = 1
+            return ('?', ('Válasszon a lehetőségek közül!', [('1', "'" + self.inp[0].wordform + " nyelvi tankönyv'"), ('2', "'(bármilyen) " + self.inp[0].wordform + " nyelvű könyv'")]))
+          elif self.state == 1:
+            if message == '1':
+              sols.append(([''], "Ha a kifejezés jelentése '" + self.inp[0].wordform + " nyelvi tankönyv', akkor a kifejezés egybeírandó.", ['?']))
+              self.state = 999
+              return ('!', sols)
+            elif message == '2':
+              sols.append(([' '], "Ha a kifejezés jelentése '(bármilyen) " + self.inp[0].wordform + " nyelvű könyv', akkor a kifejezés egybeírandó.", ['?']))
+              self.state = 999
+              return ('!', sols)
+            else:
+              return (None, 'Hiba!')
+        elif self.inp[0].hasLexProp('Folk') and self.inp[1].wordform == 'óra':
+          if self.state == 0:
+            self.state = 1
+            return ('?', ('Válasszon a lehetőségek közül!', [('1', "'" + self.inp[0].wordform + " nyelvi tanóra'"), ('2', "'" + self.inp[0].wordform + " gyártmányú óra'")]))
+          elif self.state == 1:
+            if message == '1':
+              sols.append(([''], "Ha a kifejezés jelentése '" + self.inp[0].wordform + " nyelvi tanóra', akkor a kifejezés egybeírandó.", ['?']))
+              self.state = 999
+              return ('!', sols)
+            elif message == '2':
+              sols.append(([' '], "Ha a kifejezés jelentése '" + self.inp[0].wordform + " gyártmányú óra', akkor a kifejezés egybeírandó.", ['?']))
+              self.state = 999
+              return ('!', sols)
+            else:
+              return (None, 'Hiba!')
+        elif self.inp[0].hasLexProp('Folk') and self.inp[1].wordform == 'tanár':
+          if self.state == 0:
+            self.state = 1
+            return ('?', ('Az adott nyelv a tanár szaktárgya, vagy pedig olyan nemzetiségű az adott tanár?', [('1', 'Szaktárgya.'), ('2', 'Nemzetisége.')]))
+          elif self.state == 1:
+            if message == '1':
+              sols.append(([''], 'Ha a nyelv a tanár szaktárgyát jelenti, akkor a kifejezés egybeírandó.', ['?']))
+              self.state = 999
+              return ('!', sols)
+            elif message == '2':
+              sols.append(([' '], 'Ha a nyelv a tanár nemzetiségét jelenti, a kifejezés különírandó.', ['?']))
+              self.state = 999
+              return ('!', sols)
+            else:
+              return (None, 'Hiba!')
+        elif self.inp[0].matchPoSSequence('FN,_SKEP,NOM') and self.inp[1].hasLexProp('Container'):
+          if self.state == 0:
+            self.state = 1
+            return ('?', ('Válasszon a lehetőségek közül!',
+                          [('1', 'Valamit tartalmazó, valamivel szennyezett '+ self.inp[1].wordform + '.'),
+                           ('2', 'Valaminek a felszolgálására, fogyasztására vagy tárolására használt, szokásosan meghatározott méretű és formájú '+ self.inp[1].wordform + '.')]))
+    
+          elif self.state == 1:
+            if message == '2':
+              if self.inp[0].getNCompParts() > 1:
+                sols.append(([' '], 'Ha a jelző összetétel, az alakulatot különírjuk.', ['OH. 108.']))
+                self.state == 999
+                return ('!', sols)
+              else:
+                sols.append(([''], 'Ha az utótag jelentése »valami tartására, tárolására szolgáló (edény)féle«, és sem a jelző, sem a jelzett szó nem összetétel, az alakulatot egybeírjuk.', [''], ['108.'])) # OH. 108.
+                self.state == 999
+                return ('!', sols)
+            elif message == '1':
+              sols.append(([' '], 'Ha nem tároló funkciót lát el az utótagot alkotó fogalom, a kifejezés különírandó.', [''], ['108.'])) # OH. 108.
+              self.state == 999
+              return ('!', sols)
+        if (self.inp[0].wordform == 'kis' and self.inp[1].hasLexProp('Animal')):
+          if self.state == 0:
+            self.state = 1
+            return ('?', ('Válasszon a lehetőségek közül!',
+                          [('1', 'Fiatal ' + self.inp[1].wordform + '.'),
+                           ('2', det1 + ' ' + self.inp[1].wordform + ' mérete ' + adj + '.')]))
+          elif self.state == 1:
+            if message == '1':
+              sols.append(([''], det0 + ' "' + self.inp[0].wordform + '" előtagú minőségjelzős kapcsolatok egy része jelentésváltozás miatt egybeírandó, köztük a "' + self.inp[0].wordform + self.inp[1].wordform +'" is.', [''], ['108--111.'])) # OH. 108--111.
+            elif message == '2':
+              sols.append(([' '], 'Ha a tagok együttes jelentése nem más, mint az előtag és az utótag jelentésének összege, a minőségjelzős szerkezetet különírjuk.', ['107. a, b)'])) 
+        
+        elif WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('FeketeFeherKisNagyEgybe'):
+          if self.state == 0:
+            self.state = 1
+            if (self.inp[0].wordform == 'fehér' or self.inp[0].wordform == 'fekete') and self.inp[1].hasFinalPoS('FN'):
+              return ('?', ('Válasszon a lehetőségek közül!',
+                          [('1', 'Egy speciális ' + self.inp[1].wordform + '.'),
+                           ('2', det1 + ' ' + self.inp[1].wordform + ' ' + self.inp[0].wordform + ' színű(nek tűnik).')]))
+            elif (self.inp[0].wordform == 'kis' or self.inp[0].wordform == 'nagy') and self.inp[1].hasFinalPoS('FN'):
+              return ('?', ('Válasszon a lehetőségek közül!',
+                          [('1', 'Egy speciális ' + self.inp[1].wordform + '.'),
+                           ('2', det1 + ' ' + self.inp[1].wordform + ' mérete ' + adj + '.')]))
+#            elif self.inp[1].matchPoSSequence('FN,_UKEP,NOM'):
+#              meaning1 = ''
+#              meaning2 = ''
+#              for item in dict:
+#                #print(item[2][0])
+#                firstLetterInp = Wordform.Phonology.CV(item[2][0])
+#                detInp1 = 'a' if firstLetterInp == 'C' else 'az'
+#                if self.inp[0].wordform == 'kis' or self.inp[0].wordform == 'nagy':
+#                  tmp3 = 'mérete'
+#                elif self.inp[0].wordform == 'fehér' or self.inp[0].wordform == 'fekete':
+#                  tmp3 = 'színe'
+#                else:
+#                  tmp3 = ''
+#                #tmp3 = 'mérete' if (self.inp[0].wordform == 'kis' or self.inp[0].wordform == 'nagy') else 'színe' if (self.inp[0].wordform == 'kis' or self.inp[0].wordform == 'nagy') else ''
+#                tmp = [s for s in item if self.inp[1].wordform in s]
+#                tmp2 = ''.join(tmp)
+#                if item[0] == tmp2:
+#                  meaning1 = item[1]
+#                  meaning2 = detInp1 + ' ' + item[2] + ' ' + tmp3 + ' ' + self.inp[0].wordform
+#                  return ('?', ('Válasszon a lehetőségek közül!',
+#                            [('1', "A szó jelentése: '" + meaning1 + "'."), 
+#                             ('2', "A szó jelentése: '" + meaning2 + "'.")]))
+              sols.append(([''], 'Összetételről lévén szó a kifejezés egybeírandó.', [''], ['110--111.'])) # OH. 110--111.
+            else:
+    #          return ('?', ('A tagok együttes jelentése más, mint az előtag és az utótag jelentésének összege?',
+    #                      [('1', 'Igen, más, jelentésváltozás van.'),
+    #                       ('2', 'Nem más, nincs jelentésváltozás.')]))
+              sols.append(([''], 'Összetételről lévén szó a kifejezés egybeírandó.', [''])) # OH. 110--111.
+          elif self.state == 1:
+            if message == '1':
+              sols.append(([''], det0 + ' "' + self.inp[0].wordform + '" előtagú minőségjelzős kapcsolatok egy része jelentésváltozás miatt egybeírandó, köztük a "' + self.inp[0].wordform + self.inp[1].wordform +'" is.', [''], ['108--111.'])) # OH. 108--111.
+            elif message == '2':
+              sols.append(([' '], 'Ha a tagok együttes jelentése nem más, mint az előtag és az utótag jelentésének összege, a minőségjelzős szerkezetet különírjuk.', ['107. a, b)']))
+        elif WordInfo(self.inp[0].wordform + ' ' + self.inp[1].wordform).hasLexProp('FeketeFeherKisNagyKulon'):
+          sols.append(([' '], det0 + ' "' + self.inp[0].wordform + '" előtagú minőségjelzős kapcsolatok tagjait bizonyos állandósult szókapcsolatokban különírjuk egymástól.', [''], ['108--111.'])) # OH. 108--111.
+          self.state == 999
+          return ('!', sols)
+        else:
+          sols.append(([' '], 'A minőségjelzős kapcsolatok tagjait általában különírjuk egymástól, különösen olyankor, ha a kapcsolatnak valamelyik vagy mindkét tagja összetett szó.', ['107. a)']))
+          self.state == 999
+          return ('!', sols)
+    #    elif len(self.inp) == 3:
+    #      if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('FeketeFeherKisNagyEgybe') and self.inp[2].wordform == 'bűnözés':  
+    #        pass 
+        self.state = 999
+        return ('!', sols)
+
+    if len(self.inp) == 3:
+      sols = []
+      sols.append(([' ', ' '], 'A minőségjelzős kapcsolatok tagjait általában különírjuk egymástól, ha határozót tartalmaz.', ['?']))
+      self.state = 999
+      return ('!', sols)
+# # # end class RuleJeloletlenMinosegjelzos # # # 
+    
+  
+
+class RuleJelentessurito(SpellingRuleBase):
+  """
+  @author: LZS
+  """
+  @staticmethod  
+  def match(inp):
+    if len(inp) != 2:
+      return False
+    if not (WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('Jelentessurito') and inp[0].matchPoSSequence('(FN|MN),NOM') and inp[1].matchPoSSequence('(FN(,_UKEP|,_SKEP)?|MN),NOM')):
+      return False
+#    if not (inp[0].matchPoSSequence('FN,NOM') and inp[1].matchPoSSequence('FN,NOM')):
+#      return False
+    return True
+
+
+  def getId(self):
+    return "M_EK_JELENTESSURITO"
+  
+  def getName(self): 
+    return "Jelentéssűrítő összetételek (kód: M_EK_JELENTESSURITO) (AkH. 129., OH. 119--120."
+
+  def communicate(self, message=None):
+    sols = []
+    sols.append(([''], 'Az olyan összetett szavakat, amelyek elő- és utótagja között bonyolultabb kapcsolat van, jelentéssűrítő összetételeknek nevezzük. Ezeket mindig egybeírjuk.', 
+                 ['129.']))
+    self.state = 999
+    return ('!', sols)
+
+# # # RuleJelentessurito # # #
+
+class RuleJeloltTargyas(SpellingRuleBase):   
+  """
+    Név: jelölt tárgyas alárendelések (kód: M_EK_JELOLT_TARGYAS), (AkH. 123., OH. 104.)
+
+    Feladat: jelölt tárgyas összetételek egybe vagy külön
+
+    Erőforrás: morfológiai elemzők (MA), jelölt tárgyas alárendelések kivétellistája (LIST1, OH. 104. o.)
+    
+    Azonosító jegyek: 1:{(FN(.PSe3)?|MN|SZN|NM).ACC} + 2:{IGE, INF, MIN, HI}
+    Példák: idejétmúlt (a bővítményen [főnév] birtokos személyjel; nagyothall (a bővítmény melléknév), ellentmond (a bővítmény névutó).
+    
+    Működés:
+    
+    if(1 + 2) { % tárgyas alárendelés
+      if (1 + 2) in(LIST1) { % ilyen nagyon kevés van
+        egybe(1,2)
+    }
+    else {
+      kulon(1,2)
+    }
+  }
+    
+    @author: LZS
+  """
+    
+  @staticmethod  
+  def match(inp):
+    if len(inp) != 2:
+      return False
+    if not (inp[0].matchPoSSequence('(FN(,PSe3)?|MN|SZN|NM|(FN\|NM)),ACC') or WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('JeloltTargyas')):
+      return False
+    if not (inp[1].matchPoSSequence('(IK,)?IGE(,INF|_OKEP|_HI|_MIB|_IF)?(,.*)')):
+      return False
+    return True
+
+  def getId(self):
+    return "M_EK_JELOLT_TARGYAS"
+  
+  def getName(self): 
+    return "Jelölt tárgyas összetételek (kód: M_EK_JELOLT_TARGYAS) (AkH. 123., OH. 104.)"
+
+  def communicate(self, message=None):
+    sols = []
+    if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('Rogzult'):
+      if self.state == 0:
+        self.state = 1
+        return ('?', ('Válassza ki a megfelelő jelentést!',
+                            [('1', "'" + WordInfo(self.inp[0].wordform + self.inp[1].wordform).lex().RogzultDef1.encode('utf-8') + "'"),
+                             ('2', "'" + WordInfo(self.inp[0].wordform + self.inp[1].wordform).lex().RogzultDef2.encode('utf-8') + "'")]))
+      elif self.state == 1:
+        if message == '1':
+          sols.append(([' '], 'Ha az elő- és utótag jelentése együttesen ugyanaz, mint külön-külön (azaz nincs jelentésváltozás), a kifejezést különírjuk.', ['?']))
+          self.state = 999
+          return ('!', sols)
+        elif message == '2':
+          sols.append(([''], 'Ha az elő- és utótag jelentése együttesen más, mint külön-külön (azaz jelentésváltozás van), a kifejezést különírjuk.', ['?']))
+          self.state = 999
+          return ('!', sols)
+        else:
+          return (None, 'Hiba!') 
+    elif WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('JeloltTargyas'):
+      sols.append(([''], 'A raggal jelölt tárgyas kapcsolatok túlnyomó többsége különírandó, eltekintve néhány kivételtől, ahol jelentésváltozás van, és/vagy a tárgyas viszony meglehetősen elhomályosult. Ellenőrizze, hogy konkrét vagy átvitt értelemben használja a szót!', ['123'])) # egybe(1,2
+    #elif not WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('JeloltTargyas'):
+    else:
+      sols.append(([' '], 'A raggal jelölt tárgyas kapcsolatok túlnyomó többsége különírandó.', ['123'])) # kulon(1,2)
+    self.state = 999
+    return ('!', sols)
+
+# TODO: nagyothall <--> nagyot hall -- kellene visszakérdezés
+
+# # # end class RuleJeloltTargyas # # #
+
+class RuleJeloltHatarozos(SpellingRuleBase):
+  """
+  
+    Név: jelölt határozós alárendelések AkH. 125., OH. 105--107.
+
+    Feladat: jelölt határozós összetételek egybe vagy külön
+
+    Erőforrás: morfológiai elemzők (MA), állandósult szókapcsolatokból képzett hagyományos összetételek kivétellistája (határozós)(LIST2) --> OH.-ban megvan (105--106. oldal)
+    
+    Azonosító jegyek:
+
+    Határozói alárendelés: 1:{(FN|MN).DAT, INE, ILL, SUP, DEL, SUB, ADE, ABL, ALL, TER, FOR, FAC, INS, CAU, ESSMOD, TEM, SOC, MUL, _NTA/_NTE, _LAG/_LEG} + 2:{IGE, FN, MN, SZN, HA} // A Humor nem ismer fel néhány módahatározóragot, pl. az ismétlődő időhatározói ragot (-anta/-ente) és a mód-állapot határozói ragot (-lag/-leg).
+    
+    @author: LZS
+  """
+  
+  @staticmethod  
+  def match(inp):
+    if len(inp) != 2:
+      return False
+    if not (inp[0].matchPoSSequence('(((FN|MN(,_FOK)?|SZN|(FN\|NM))(,PSe3)?,(DAT|INE|ILL|SUP|DEL|SUB|ADE|ABL|ALL|TER|FOR|FAC|INS|CAU|_ESSMOD|TEM|SOC|MUL|_NTA/_NTE|_LAG/_LEG)))')): # |IK nem kell a végére
+      return False
+    if not (inp[1].matchPoSSequence('((IK,)?IGE|FN|MN|SZN|HA)(,.*)')):
+      return False
+    return True
+  
+  def getId(self):
+    return "M_EK_JELOLT_HATAROZOS"
+  
+  def getName(self): 
+    return "Jelölt határozós összetételek (kód: M_EK_JELOLT_HATAROZOS) (AkH. 125., OH. 105--107.)"
+
+  def communicate(self, message=[]):
+    sols = []
+    if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('AllSzokapcs'):
+      sols.append(([''], 'A raggal jelölt határozós összetételek egy részét egybeírjuk (jelentésváltozás vagy a hagyomány miatt).', ['125. b, d)']))
+    elif WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('Rogzult'):
+      if self.state == 0:
+        self.state = 1
+        return ('?', ('Válassza ki a megfelelő jelentést!',
+                            [('1', "'" + WordInfo(self.inp[0].wordform + self.inp[1].wordform).lex().RogzultDef1.encode('utf-8') + "'"),
+                             ('2', "'" + WordInfo(self.inp[0].wordform + self.inp[1].wordform).lex().RogzultDef2.encode('utf-8') + "'")]))
+      elif self.state == 1:
+        if message == '1':
+          sols.append(([' '], 'Ha az elő- és utótag jelentése együttesen ugyanaz, mint külön-külön (azaz nincs jelentésváltozás), a kifejezést különírjuk.', ['?']))
+          self.state = 999
+          return ('!', sols)
+        elif message == '2':
+          sols.append(([''], 'Ha az elő- és utótag jelentése együttesen más, mint külön-külön (azaz jelentésváltozás van), a kifejezést különírjuk.', ['?']))
+          self.state = 999
+          return ('!', sols)
+        else:
+          return (None, 'Hiba!')
+    else:
+      sols.append(([' '], 'A valamilyen raggal jelölt határozós kapcsolatok tagjait (az állandó szókapcsolatokban is) általában különírjuk egymástól, különösen akkor, ha a kapcsolatnak valamelyik vagy mindkét tagja összetett szó.', ['125. a)']))
+    self.state=999
+    return ('!', sols)
+
+# # # end class RuleJeloltHatarozos # # #
+  
+class RuleJeloltBirtokos(SpellingRuleBase):   
+  """
+    @author: LZS
+  """
+  @staticmethod  
+  def match(inp):
+    if len(inp) != 2:
+      return False
+    if not (inp[0].matchPoSSequence('(FN|(FM\|NM))(,DAT)?') and inp[1].matchPoSSequence('(((FN|MN),PSe3,NOM)|(FN\|NM))')):
+      return False
+#    elif not (inp[0].matchPoSSequence('(FN|(FM\|NM))') and inp[1].matchPoSSequence('(FN,PSe3,NOM)')):
+#      return False
+    if WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('Alanyos'):
+      return False
+    return True
+  
+  def getId(self):
+    return "M_EK_JELOLT_BIRTOKOS"
+  
+  def getName(self): 
+    return "Jelölt birtokos jelzős összetételek (kód: M_EK_JELOLT_BIRTOKOS) (AkH. 123., OH. 119.)"
+
+  def communicate(self, message=None):
+    sols = []
+    if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('Rogzult'):
+      if self.state == 0:
+        self.state = 1
+        return ('?', ('Válassza ki a megfelelő jelentést!',
+                            [('1', "'" + WordInfo(self.inp[0].wordform + self.inp[1].wordform).lex().RogzultDef1.encode('utf-8') + "'"),
+                             ('2', "'" + WordInfo(self.inp[0].wordform + self.inp[1].wordform).lex().RogzultDef2.encode('utf-8') + "'")]))
+      elif self.state == 1:
+        if message == '1':
+          sols.append(([''], 'A raggal jelölt birtokos jelzős kapcsolatokból keletkezett összetételek egybeírandók, ha az elő- és utótag jelentése együttesen más, mint külön-külön.', ['128. b)']))
+        elif message == '2':
+          sols.append(([' '],'A birtokszón a birtokviszonyra utaló birtokos személyjellel és/vagy a birtokoson -nak/-nek raggal jelölt kapcsolatok tagjait általában különírjuk egymástól.', ['128. a)']))
+    elif WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('JeloltBirtokos1'):
+      sols.append(([''],'A kialakult szokást megtartva jelentésváltozás nélkül is egybeírjuk néhány jelölt birtokos jelzős kapcsolat tagjait.', ['128. d)']))
+    else:
+      sols.append(([' '],'A birtokszón a birtokviszonyra utaló birtokos személyjellel és/vagy a birtokoson -nak/-nek raggal jelölt kapcsolatok tagjait általában különírjuk egymástól.', ['128. a)']))
+    self.state=999
+    return ('!', sols)
+
+# # # end class RuleJeloltBirtokos # # #
+
+class RuleMennyisegjelzosSzerkezet(SpellingRuleBase):   
+  """
+    Név: mennyiségjelzős kapcsolatok (kód: M_EK_MENNYISEG) (AkH. 117--119.)
+
+    Feladat: mennyiségjelzős kapcsolatok egybe vagy külön
+
+    Erőforrás: morfológiai elemzők (MA), határozatlan számnevek listája (LIST)
+
+    Azonosító jegyek: 1:{(HA|FN.INS)*} + 2:{("több mint")*} + 3:{SZN.NOM, SZN.NOM && in(LIST), DIGIT} + 4:{(FN._IKEP, _SKEP|MN)*} + 5:{FN._IKEP, _SKEP, _UKEP} vagy 1:{(HA|FN.INS)*} + 2:{("több mint")*} + 3:{SZN.NOM, SZN.NOM && in(LIST), DIGIT} + 4:{(FN._IKEP|MN)*} + 5:{FN._DIS, _NTA} vagy 1:{(HA|FN.INS)*} + 2:{("több mint")*} + 3:{SZN.NOM, SZN.NOM && in(LIST)} + 4:{(FN._IKEP|MN)*} + 5:{SZN.(_SKEP)?}
+    Megjegyzés:
+
+    Az utolsónál az a lényeg, hogy egy mennyiségjelzős összetétel lehet olyan is, hogy minden összetételi tagja számnév. Ilyenkor az utótag -s képzős is lehet, ezt szemlélteti az utolsó eset az azonosító jegyeknél. Pl.: húszezres, hárommilliárdos. Ezeknél jelentéskülönbség van az egybeírt és különírt alak között.
+    Az azonosító jegyeknél az 1., 2. és 4. tag opcionális. Az 1. tag lehet határozószó (pl. alig) vagy -val/-vel képzős melléknév (pl. kicsivel). A 2. tag a "több mint". A 4. tag az alaptag minőségjelzői bővítménye lehet
+    (pl. alkaioszi strófás -> öt alkaioszi strófás).
+
+    Működés:
+
+    if(exists(1) || exist(2) || exists(4)) { % Ha a leírandó kifejezés legalább 3 szóból áll, azaz valamelyik tag egy szókapcsolat, akkor külön kell írni.
+      kulon(1,2,3,4,5)
+    }
+
+    else { % A leírandó kifejezés 2 tagból áll.
+
+     if (3==DIGIT) { % pl. 30 napos
+       kulon(3,5)
+     }
+     else if (3==osszetett || 5==osszetett) { % pl. egy szótagos, tizenhét emeletes, tizenöt naponként
+       kulon(3,5)
+     }
+     else { % pl. harmincnapi, ötágú, háromhavonként, húszezres ('bankjegy')
+       if(5==SZN.(_SKEP)?) {
+         kerdezd: "A leírt kifejezés egy időpont? Pl. fél kilenc, negyed tízes...
+         if(igen) {
+          kulon(3,5)
+         }
+         kerdezd: "A leírt kifejezés melyikhez áll közelebb? 1. húszezres tartozás, 2. húsz ezres ('húsz darab bankjegy'); 1. hárommilliárdos (hiány), 2. három milliárdos ('három gazdag ember')" 
+       }
+       egybe(3,5)
+     }
+
+    }
+
+    
+    @author: LZS
+  """
+    
+  @staticmethod  
+  def match(inp):
+    if len(inp) not in [2, 3, 4]:
+      return False
+    if len(inp) == 4:
+      match = inp[0].wordform == 'több' and inp[1].wordform == 'mint' and inp[2].matchPoSSequence('SZN,NOM') and inp[3].matchPoSSequence('((FN,(_IKEP|_SKEP|_UKEP|_NTA|_DIS|_MER))|SZN)(,.)*')
+      if not match:
+        return False
+    if len(inp) == 3:
+      match1 = inp[0].matchPoSSequence('SZN,NOM') and inp[1].matchPoSSequence('((FN,(_IKEP|_SKEP|_UKEP|_NTA|_DIS|_MER))|SZN)(,.)*') and inp[2].matchPoSSequence('FN,NOM')
+      match2 = inp[0].matchPoSSequence('SZN,ADE') and inp[1].matchPoSSequence('SZN,_FOK,NOM') and inp[2].matchPoSSequence('((FN,(_IKEP|_SKEP|_UKEP|_NTA|_DIS|_MER))|SZN)(,.)*')
+      match3 = inp[0].matchPoSSequence('SZN') and inp[1].matchPoSSequence('(FN,(_IKEP|_SKEP)|MN),NOM') and inp[2].matchPoSSequence('(FN,(_IKEP|_SKEP|_UKEP|_NTA|_DIS|_MER))')
+      match4 = inp[0].matchPoSSequence('HA') and inp[1].matchPoSSequence('SZN,NOM') and inp[2].matchPoSSequence('(FN,(_IKEP|_SKEP|_UKEP|_NTA|_DIS|_MER))')
+      match5 = inp[0].matchPoSSequence('SZN(,_FOK)?,NOM') and inp[0].hasLexProp('NumeralIndef') and inp[1].matchPoSSequence('SZN,NOM') and inp[2].matchPoSSequence('(FN,(_IKEP|_SKEP|_UKEP|_NTA|_DIS|_MER))')
+      if not (match1 or match2 or match3 or match4 or match5):
+        return False
+    elif len(inp) == 2:
+      if not(inp[0].matchPoSSequence('SZN(,FOK)?|(SZN\|DIGIT)(,SZN\|DIGIT)*,NOM')):
+        return False
+      if not(inp[1].matchPoSSequence('((FN,(_IKEP|_SKEP|_UKEP|_NTA|_DIS|_MER)?)|SZN)(,.)*')):
+        return False
+    return True
+  
+
+  def getId(self):
+    return "M_EK_MENNYISEG"
+  
+  def getName(self): 
+    return "Mennyiségjelzős kapcsolatok (kód: M_EK_MENNYISEG) (AkH. 117--119.)"
+
+  def communicate(self, message=[]):
+    sols = []
+    if len(self.inp) == 2:
+      if (self.inp[0].matchPoSSequence('(SZN\|DIGIT)(,SZN\|DIGIT)*,NOM')):
+        sols.append(([' '], 'Ha a számnévi előtagot számjeggyel írjuk, a kifejezés mindig különírandó.', ['119']))
+      elif (WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('MennyJelzKivetel')):
+        if self.state == 0:
+          self.state = 1
+         
+          return ('?', ('Válasszon a lehetőségek közül!',
+                        [('1', 'A két tag együtte jelentése más, mint az előtag és az utótag jelentésének összege: "' + applyseparators(self.inp, ['']) + '".'),
+                        ('2', 'A kifejezés jelentése: ' + self.inp[0].wordform + ' darab ' + self.inp[1].wordform + ' vagy ' + self.inp[0].wordform + ' fő ' + self.inp[1].wordform + '.')]))
+        elif self.state == 1:
+          if message == '1':
+            sols.append(([''], 'Ha a tagok együttes jelentése más, mint az előtag és az utótag jelentésének összege, szóösszetételről van szó, egybeírást alkalmazunk.', ['107. b)']))
+          elif message == '2':
+            sols.append(([' '], ' A mennyiségjelzős kapcsolatok tagjait általában különírjuk egymástól.', ['117. a)']))
+      elif (self.inp[0].matchPoSSequence('(SZN,)?SZN,_TORT,NOM') or self.inp[0].wordform == 'fél') and self.inp[1].matchPoSSequence('SZN,_SKEP,NOM'):
+        sols.append(([' '], 'Az órát jelölő kapcsolatokat különírjuk.', [''], ['119.'])) # OH. 119.
+      elif (self.inp[0].matchPoSSequence('SZN,NOM') and self.inp[1].matchPoSSequence('SZN,_SKEP,NOM') and self.inp[1].matchPoSSequence('FN,NOM')):
+        if self.state == 0:
+          self.state = 1
+          return ('?', ('Az utótag milyen jelentésben szerepel?',
+                        [('1', applyseparators(self.inp, ['']) + ' bankjegy, ' + applyseparators(self.inp, ['']) + ' tartozás'),
+                        ('2', self.inp[0].wordform + ' darab ' + self.inp[1].wordform) ]))
+        elif self.state == 1:
+          if message == '1':
+            sols.append(([''], 'Egy egyszerű tőszámnévnek és egy -s képzős egyszerű melléknévnek a kapcsolatát egybeírjuk.'
+            , ['119.']))
+          elif message == '2':
+          #print('2')
+            sols.append(([' '], 'A mennyiségjelzős kapcsolatok tagjait általában különírjuk egymástól.', ['117. a)']))
+            # TODO: három tízezres, három milliárdos --> pyhuana.udc-ben kéne a megfelelő elemzés
+      elif (self.inp[1].matchPoSSequence('(FN,(_IKEP|_SKEP|_UKEP|_NTA|_DIS|_MER))')):
+        if (self.inp[0].getNCompParts() >= 2 or self.inp[1].getNCompParts() >= 2):
+          sols.append(([' '], 'Ha a jelzett szó vagy a számnévi jelző, vagy akár mindkettő összetett szó, a szerkezetet különírjuk.', ['119']))
+        else:
+          sols.append(([''], 'Egy egyszerű tőszámnévnek (ill. a sok, több, fél számnévnek), valamint egy -i, -ú, -ű, -jú, -jű, -s, -nyi képzős egyszerű melléknévnek a kapcsolatát egybeírjuk. Hasonlóképpen írjuk az -nként ragos alakulatokat is.'
+        , ['119']))
+      elif (self.inp[0].matchPoSSequence('SZN,NOM') and self.inp[1].matchPoSSequence('SZN,NOM')):
+        return (None, 'Ha mind az előtag, mind az utótag számnév, nem a mennyiségjelzős kapcsolatokra vonatkozó szabályt kell alkalmazni. Használja a "Számnevek helyesírása" funkciót!')
+      elif (self.inp[1].matchPoSSequence('(FN|SZN),NOM')):
+        sols.append(([' '], ' A mennyiségjelzős kapcsolatok tagjait általában különírjuk egymástól; különösen olyankor, ha a kapcsolat valamelyik vagy mindkét tagja összetett szó.', ['117. a)']))
+    elif len(self.inp) == 3: 
+      if self.inp[0].matchPoSSequence('SZN') and self.inp[1].matchPoSSequence('(FN,(_IKEP|_SKEP)|MN),NOM') and self.inp[2].matchPoSSequence('(FN,(_IKEP|_SKEP|_UKEP|_NTA|_DIS|_MER))'):
+        sols.append(([' ', ' '], 'Ha a kifejezés legalább három szóból áll, akkor vagy az előtag vagy az utótag szókapcsolat, tehát mindent külön szóba írunk.', ['?']))
+      elif self.inp[0].matchPoSSequence('SZN,ADE') and self.inp[1].matchPoSSequence('SZN,_FOK,NOM') and self.inp[2].matchPoSSequence('((FN,(_IKEP|_SKEP|_UKEP|_NTA|_DIS|_MER))|SZN)(,.)*'):
+        sols.append(([' ', ' '], 'Ha a kifejezés legalább három szóból áll, akkor vagy az előtag vagy az utótag szókapcsolat, tehát mindent külön szóba írunk.', ['?']))
+      elif self.inp[0].matchPoSSequence('HA') and self.inp[1].matchPoSSequence('SZN,NOM') and self.inp[2].matchPoSSequence('(FN,(_IKEP|_SKEP|_UKEP|_NTA|_DIS|_MER))'):
+        sols.append(([' ', ' '], 'Ha a kifejezés legalább három szóból áll, akkor vagy az előtag vagy az utótag szókapcsolat, tehát mindent külön szóba írunk.', ['?']))
+      elif self.inp[0].matchPoSSequence('SZN') and self.inp[1].matchPoSSequence('((FN,(_IKEP|_SKEP|_UKEP|_NTA|_DIS|_MER))|SZN)(,.)*') and self.inp[2].matchPoSSequence('FN,NOM'):    
+        if self.state == 0:
+          self.state = 1
+          inp1 = self.inp[1].getNominalStem()
+          return ('?', ('Válasszon a lehetőségek közül!',
+                          [('1', self.inp[0].wordform + ' darab ' + inp1),
+                           ('2', self.inp[0].wordform + ' darab ' + self.inp[2].wordform)]))
+          #sols.append(([' ', ' '], 'Ha a kifejezés legalább három szóból áll, akkor vagy az előtag, vagy az utótag szókapcsolat, tehát különírandó.', ['119'])) # kulon(1,2
+        elif self.state == 1:
+          if message == '1':
+            if self.inp[0].getNCompParts() > 1 or self.inp[1].getNCompParts() > 1:
+              sols.append(([' ', ' '], 'Minőségjelzős szerkezet...', ['?']))
+            else:
+              sols.append((['', ' '], 'Egy egyszerű tőszámnévnek (ill. a sok, több, fél számnévnek), valamint egy -i, -ú, -ű, -jú, -jű, -s, -nyi képzős egyszerű melléknévnek a kapcsolatát egybeírjuk. Hasonlóképpen írjuk az -nként ragos alakulatokat is.'
+              , ['119']))
+          elif message == '2':
+            sols.append(([' ', ' '], 'Minőségjelzős szerkezet...', ['?']))
+      elif self.inp[0].matchPoSSequence('SZN(,_FOK)?,NOM') and self.inp[0].hasLexProp('NumeralIndef') and self.inp[1].matchPoSSequence('SZN,NOM') and self.inp[2].matchPoSSequence('(FN,(_IKEP|_SKEP|_UKEP|_NTA|_DIS|_MER))'):
+         if self.state == 0:
+           self.state = 1
+           return ('?', ('Válasszon a lehetőségek közül!',
+                         [('1', applyseparators(self.inp, [' ', '']) + " '" + self.inp[0].wordform + ' olyan valami, amely ' + self.inp[1].wordform + self.inp[2].wordform + "'" ),
+                          ('2', applyseparators(self.inp, [' ', ' ']) + " 'olyan valami, amely " + self.inp[0].wordform + ' ' + self.inp[1].wordform + ' ' + self.inp[2].wordform + "'" )]))
+         elif self.state == 1:
+          if message == '1':
+            sols.append(([' ', ''], 'Minőségjelzős szerkezet...', ['?']))
+          elif message == '2':
+            sols.append(([' ', ' '], 'Minőségjelzős szerkezet...', ['?']))
+    
+    elif len(self.inp) == 4:
+      sols.append(([' ', ' ', ' '], 'Ha a kifejezés legalább három szóból áll, akkor vagy az előtag vagy az utótag szókapcsolat, tehát mindent külön szóba írunk.', ['?']))
+    elif len(self.inp) == 5:
+      sols.append(([' ', ' ', ' ', ' '], 'jkljljlk', ['119']))
+    self.state = 999
+    return ('!', sols)
+
+# # # end class RuleMennyisegjelzosSzerkezet # # #
+
+class RuleFoneviJelzosSzerkezet(SpellingRuleBase):
+  """
+  Név: főnévi jelzős szerkezetek (kód: M_EK_FONEVI_JELZO) (AkH. 114., OH. 114--117.)
+
+  Feladat: Ha az alaptag jelzője főnévi szófajú, akkor is különírjuk a jelzőt a jelzett szótól.
+
+  Erőforrások: morfológiai elemző, foglalkozások listája (LIST1) (van!), kort jelölő főnevek listája (amelyek lehetnek melléknevek is, LIST2, pl. gyermek, nyugdíjas) (nincs!), nyomatékosításra használt főnevek listája (zsír, tök), illetve jellemző utótagok listája (alakú, formájú; néni, úr, LIST3) --> Készítettem egy kezdetleges listát: [[http://salmon.nytud.hu/Nyti/projects/helyesiras/eroforrasok/listak/utotagok.txt/vview]]
+
+  És még kell egy kivétellista is, amely azokat a szóösszetételeket tartalmazza, amelyek egyik összetételi tagja tipikus főnévi jelzős szerkezeti elő- vagy utótag (pl. betűnagyságú, idényjellegű, ajándékkártya). (LIST4) (Csináltam OH. alapján: [[http://salmon.nytud.hu/Nyti/projects/helyesiras/eroforrasok/listak/fonevi-jelzos-szerk-kivetellista.txt/view]] )
+
+  Azonosító jegyek: 1:{FN in(LIST1|LIST2|LIST3)}, 2:{FN} vagy 1:{FN}, 2:{MN, FN in(LIST3)}
+
+  Működés:
+
+ if (1,2) in(LIST4) {
+   egybe(1,2)
+ }
+ else {
+   kulon(1,2)
+ }
+    @author: LZS
+  """
+  
+  @staticmethod  
+  def match(inp):
+    if len(inp) not in [2, 3]:
+      return False
+    if len(inp) == 2:
+      if inp[1].matchPoSSequence('IGE,(_IF|_OKEP),NOM'): # _MIB-et is le lehetne tiltani, de: férfi alkalmazott
+        return False
+      if not (inp[0].matchPoSSequence('.*(FN|MN),NOM')):
+        return False
+      if not (inp[1].matchPoSSequence('.*(FN(,_UKEP)?(,.*)?|MN),(NOM|INE)')):
+        return False
+#      if not (inp[0].wordform == 'férfi' or inp[0].wordform == 'ajándék'):
+#        return False
+      if not ((inp[0].hasLexProp('EgyebFoneviJelzo') or inp[0].hasLexProp('AgeGroup') or inp[0].hasLexProp('Emphasis') or inp[0].hasLexProp('Folk') or inp[0].hasLexProp('Major') or inp[0].hasLexProp('Occupation')) or inp[1].hasLexProp('FoneviJelzosSzerkAlaptag')): # kort jelolő főnév, nyomatékosító főnév
+        return False
+
+    if len(inp) == 3:
+      if not (inp[0].matchPoSSequence('.*(FN|MN|SZN),NOM')):
+        return False
+      if not (inp[1].matchPoSSequence('.*(FN|MN),NOM')):
+        return False
+      if not (inp[2].matchPoSSequence('.*(FN(,_UKEP)?(,.*)?|MN),NOM')):
+        return False
+    return True
+  
+  def getId(self):
+    return "M_EK_FONEVI_JELZO"
+  
+  def getName(self): 
+    return "Főnévi jelzős szerkezetek (kód: M_EK_FONEVI_JELZO) (AkH. 114., OH. 114--117.)"
+
+  def communicate(self, message=[]):
+    sols = []
+    FirstLetter0 = Wordform.Phonology.CV(self.inp[0].wordform[0])
+    FirstLetter1 = Wordform.Phonology.CV(self.inp[1].wordform[0])
+    det1 = 'A' if FirstLetter0 == 'C' else 'Az'
+    det2 = 'A' if FirstLetter1 == 'C' else 'Az'
+    if len(self.inp) == 2:
+#      if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('FoneviJelzosSzerk'):
+#        sols.append(([''], '??', ['OH. 115.']))
+      if self.inp[0].wordform == 'ajándék' or self.inp[0].wordform == 'férfi':
+        if self.inp[0].wordform == 'férfi' and self.inp[1].wordform == 'fodrász':
+          if self.state == 0:
+            self.state = 1
+            return ('?', ('Mit jelent a kifejezés?', [('1', 'Férfiakat kiszolgáló fodrász.'), ('2', 'Hímnemű fodrász.')]))
+          elif self.state == 1:
+            if message == '1':
+              sols.append(([''], 'A főnévi jelző jelentéssűrítő viszonyban van az utótaggal, jelentéssűrítő összetételről van szó, a kifejezést egybeírjuk.', [''], ['115.'])) # OH. 115.
+            elif message == '2':
+              sols.append(([' '], 'Főnévi jelzős szerkezetről lévén szó, a kifejezést különírjuk.', [''], ['115.'])) # OH. 115.
+            self.state = 999
+            return ('!', sols)
+        elif WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('FoneviJelzosSzerk'):
+          sols.append(([''], det1 + ' "' + self.inp[0].wordform + '" főnévi előtag és az utótag között birtokos jelzős vagy jelentéssűrítő viszony van, a kifejezés egybeírandó.',
+                       [''], ['114--115.'])) # OH. 114--115.
+        else:
+          sols.append(([' '], det1 + ' "' + self.inp[0].wordform + '" ebben az esetben főnévi jelző, a szerkezet különírandó.',
+                       [''], ['115.'])) # OH. 115.
+        self.state = 999
+        return ('!', sols)
+      elif self.inp[1].hasLexProp('FoneviJelzosSzerkAlaptag'):
+        if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('Jelentessurito'):
+          sols.append(([''], 'Ha a főnévi előtag birtokos jelzős vagy jelentéssűrítő viszonyt alkot az utótaggal, egybeírást alkalmazunk.',
+                       [''], ['115.'], ['115.'])) # OH. 115.
+          self.state = 999
+          return ('!', sols)
+        elif self.inp[1].wordform == 'értékű':
+          if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('Erteku'):
+            sols.append(([''], 'A főnévi előtag az "értékű" utótaggal jelentéssűrítő összetételt hoz létre, ezért egybeírást alkalmazunk.',
+                         [''], ['116.'])) # OH. 116.
+            self.state = 999
+            return ('!', sols)
+          else:
+            sols.append(([' '], 'Az "értékű" melléknév elsősorban a pénzbeli értékek megnevezésekor alkot szószerkezetet a főnévi jelzővel: "(tízezer) forint értékű". Egyéb: "negyedhang értékű".', [''], ['116.'])) # OH. 116.
+            self.state = 999
+            return ('!', sols)
+        elif self.inp[1].wordform == 'alapú':
+          if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('Alapu'):
+            sols.append(([''], 'Ha az "alapú" melléknév fő összetevőt jelöl, vagy átvitt értelmű, egybeírást alkalmazunk.',
+                         [''], ['116.'])) # OH. 116.
+            self.state = 999
+            return ('!', sols)  
+          elif WordInfo(self.inp[0].wordform + '-' + self.inp[1].wordform).hasLexProp('Alapu'):
+            sols.append((['-'], 'Ha az "alapú" melléknév fő összetevőt jelöl, vagy átvitt értelmű, egybeírást alkalmazunk.',
+                         [''])) # OH. 116.
+            self.state = 999
+            return ('!', sols)  
+          else:
+            if self.state == 0:
+              self.state = 1
+              return ('?', ('Az "alapú" melléknév valaminek a formájára utal, vagy pedig fő összetevőt jelöl, esetleg átvitt értelemben szerepel?', [('1', 'A formájára utal.'), ('2', 'Fő összetevőt jelöl, vagy átvitt értelemben szerepel.')]))
+            elif self.state == 1:
+              if message == '1':
+                sols.append(([' '], 'Ha az "alapú" melléknév valaminek a formájára utal, különírjuk a főnévi jelzőtől. Pl. "négyzet alapú", "képi séma alapú".',
+                         [''])) # OH. 116.
+                self.state = 999
+                return ('!', sols)
+              elif message == '2':
+                sols.append(([''], 'Ha az "alapú" melléknév fő összetevőt jelöl, vagy átvitt értelmű, egybeírást alkalmazunk.',
+                         [''])) # OH. 116.
+                self.state = 999
+                return ('!', sols)
+            # TODO: DNS-alapú
+        elif self.inp[1].wordform == 'értelmű' or self.inp[1].wordform == 'értelemben' or self.inp[1].wordform == 'jelentésű' or self.inp[1].wordform == 'jelentésben':
+          if self.state == 0:
+            self.state = 1
+            return ('?', ('A "' + self.inp[1].wordform + '" alak metanyelvi értékű, azaz a jelentést adja meg?', [('1', 'Igen, metanyelvi értékű, a jelentést adja meg.'), ('2', 'Nem metanyelvi értékű, nem a jelentést adja meg.')]))
+          elif self.state == 1:
+            if message == '1':
+              sols.append(([' '], 'A "' + self.inp[1].wordform + '" alak előtt mindig különírjuk a főnévi jelzőt, ha az metanyelvi értékű.',
+                         [''], ['116.'])) # OH. 116.
+            elif message == '2':
+              sols.append(([''], '******* egybeírást alkalmazunk.',
+                         [''], ['116.'])) # OH. 116.
+              self.state = 999
+              return ('!', sols)
+#        elif self.inp[1].wordform == 'alakú' or self.inp[1].wordform == 'alakban':
+#          sols.append(([' '], 'Az "' + self.inp[1].wordform + '" szó gyakran főnévi minőségjelzős szerkezet alaptagja. A főnevet -- ha megnevező értékű -- különírjuk az alaptagtól.',
+#                       ['OH. 115.']))
+#          self.state = 999
+#          return ('!', sols) 
+        else:
+          sols.append(([' '], det2 + ' "' + self.inp[1].wordform + '" szó gyakran főnévi minőségjelzős szerkezet alaptagja. A főnevet -- ha megnevező értékű -- különírjuk az alaptagtól.',
+                       [''], ['115.'])) # OH. 115.
+          self.state = 999
+      
+      elif self.inp[0].hasLexProp('Emphasis') and self.inp[1].matchPoSSequence('MN'):
+        sols.append(([' '], 'A nyomatékosításra használt főnevet is (csuda, kutya, marha stb.) különírjuk a jelzett szótól.'
+                 , ['114']))
+        
+      elif self.inp[0].hasLexProp('EgyebFoneviJelzo'):
+        if self.inp[0].wordform == 'játék':
+          if self.state == 0:
+            self.state = 1
+            return ('?', ('Válasszon a lehetőségek közül!',
+                          [('1', "Jelentése: 'gyermekeknek való, nem igazi " + self.inp[1].wordform + "'."),
+                           ('2', 'Egyéb jelentés.')]))
+          elif self.state == 1:
+            if message == '1':
+              sols.append(([' '], 'A főnévi jelzőket külön kell írni a jelzett szótól.', ['114.']))
+          elif message == '2':
+            return (None, 'Nem főnévi jelzős szerkezetről van szó.')
+        else:
+          if self.state == 0:
+            self.state = 1
+            return ('?', ('Válasszon a lehetőségek közül!',
+                        [('1', det2 + ' ' + self.inp[1].wordform + ' ' + self.inp[0].wordform + '.'),
+                         ('2', 'Másról van szó. Az összetételi tagok között más (jelentéssűrítő vagy birtokos jelzői) alárendelő viszony van.')]))
+          elif self.state == 1:
+            if message == '1':
+              sols.append(([' '], 'A főnévi jelzőket külön kell írni a jelzett szótól.', ['114.']))
+            elif message == '2':
+              return (None, 'Nem főnévi jelzős szerkezetről van szó.')
+              
+      else:
+        if not WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('Jelentessurito'):
+          sols.append(([' '], 'A foglalkozást, kort, minőséget, csoportot jelölő főnévi jelzőket külön kell írni a jelzett szótól. Ugyanígy a nyomatékosításra használt főneveknél is (csuda, kutya, marha stb.).'
+                 , ['114']))
+        else:
+          return (None, 'Hiba!')                                                                     
+    if len(self.inp) == 3:
+      if WordInfo(self.inp[0].wordform + '-' + self.inp[1].wordform + self.inp[2].wordform).hasLexProp('FoneviJelzosSzerk'):
+        sols.append((['-', ''], '??', [''], ['115.'])) # OH. 115.
+        
+    self.state = 999
+    return ('!', sols)
+
+# # # end class RuleFoneviJelzosSzerkezet # # #
+
+
+
+class RuleGyujtonevek(SpellingRuleBase):
+  """
+    Név: embercsoportok (AkH. 167--168., OH. 170., 220.)
+
+    Feladat: Gyűjtőnévi közszó + egy tulajdonnév összekapcsolásakor egybeírjuk vagy kötőjellel.
+
+    Erőforrások: vezetéknevek listája (LIST1), keresztnevek listája (LIST2), gyűjtőnévi közszók listája (LIST3) (Nincs ilyen!)
+
+    Azonosító jegyek: 1:{in(LIST1)} + 2:{in(LIST2)}? + 3:{in(LIST3)}
+
+    Működés: Az, hogy kötőjellel kapcsoljuk-e a gyűjtőnévi közszói utótagot a tulajdonnévi előtaghoz, attól függ, hogy felvett/kapott tulajdonnévről van-e szó, vagy pedig az illető tulajdonnév viselője az adott csoport vezetője. Ezt gépi módszerekkel eldönteni nem tudjuk, meg kell kérdezni a felhasználót.
+
+    print("(1+(2)?) a (3)-at vezető személy?")
+    if (igen) {
+      kotojel(1+(2)?,3) % Illés-együttes, Szemere-kormány
+    }
+    else {
+      kulon(1+(2)?,3) % Omega együttes, Kölcsey Ferenc olvasókör)
+    }
+
+
+    @author: LZS
+  """
+  
+  @staticmethod  
+  def match(inp):
+    if len(inp) not in [2, 3]:
+      return False
+    alaptag = 1 if len(inp) == 2 else 2 # index of the alaptag in inp
+    if not (inp[alaptag].matchPoSSequence('.*FN,NOM')):
+        return False
+    if len(inp) == 2: 
+      if not (inp[alaptag - 1].hasLexProp('FamilyName') or inp[alaptag - 1].hasLexProp('PersFirst')):
+        return False
+      if not inp[alaptag].hasLexProp('Group'):
+        return False
+    if len(inp) == 3:
+      if not (inp[alaptag - 2].hasLexProp('FamilyName') and inp[alaptag - 1].hasLexProp('PersFirst') and inp[alaptag].hasLexProp('Group')):
+        return False
+#      if not (inp[alaptag - 1].hasLexProp('PersFirst')):
+#        return False
+#      if not inp[alaptag].hasLexProp('Group'):
+#        return False
+    
+    return True
+
+  def getId(self):
+    return "M_EK_GYUJTONEVEK"
+  
+  def getName(self): 
+    return "Embercsoportok gyűjtőnévi jellegű szavai (kód: M_EK_GYUJTONEVEK) (AkH. 167--168., OH. 170., 220.)"
+
+  def communicate(self, message=[]):
+    sols = []
+    if len(self.inp) == 2:
+      if self.state == 0:
+        self.state = 1
+        return ('?', ('Az adott személy vezetője a csoportnak, vagy csupán elnevezték azt róla?', [('1', 'Vezetője.'), ('2', 'Nem vezetője, csak róla nevezték el.')]))
+      elif self.state == 1:
+        if message == '1':
+          sols.append((['-'], 'A gyűjtőnévi közszókat (család, nemzetség, együttes, párt stb.) kötőjellel kapcsoljuk a tulajdonnévhez, ha az a csoportot vezető személynek a neve.', ['168.']))
+          self.state = 999
+          return ('!', sols)
+        elif message == '2':
+          sols.append(([' '], 'A gyűjtőnévi közszókat (család, nemzetség, együttes, párt stb.) külírjuk a tulajdonnévtől, ha az egy felvett vagy kapott név, nem pedig a csoportot vezető személy neve.', ['167.']))
+          self.state = 999
+          return ('!', sols)      
+        else:
+          return (None, 'Hibauzi')
+    if len(self.inp) == 3:
+      if self.state == 0:
+        self.state = 1
+        return ('?', ('Az adott személy vezetője a csoportnak, vagy csupán elnevezték azt róla?', [('1', 'Vezetője.'), ('2', 'Nem vezetője, csak róla nevezték el.')]))
+      elif self.state == 1:
+        if message == '1':
+          sols.append(([' ', '-'], 'A gyűjtőnévi közszókat (család, nemzetség, együttes, párt stb.) kötőjellel kapcsoljuk a tulajdonnévhez, ha az a csoportot vezető személynek a neve.', ['168.']))
+          self.state = 999
+          return ('!', sols)
+        elif message == '2':
+          sols.append(([' ', ' '], 'A gyűjtőnévi közszókat (család, nemzetség, együttes, párt stb.) külírjuk a tulajdonnévtől, ha az egy felvett vagy kapott név, nem pedig a csoportot vezető személy neve.', ['167.']))
+          self.state = 999
+          return ('!', sols)      
+        else:
+          return (None, 'Hibauzi')
+    
+        
+    
+# # # end Class RuleFoneviJelzosSzerkezet # # #
+
+class RuleNagykotojel(SpellingRuleBase):
+  """
+    @author: LZS
+  """
+  
+  @staticmethod  
+  def match(inp):
+    if len(inp) not in [2, 6]:
+      return False
+    if len(inp) == 2:
+      if not (inp[0].hasLexProp('Folk') or inp[0].hasLexProp('Major') or inp[0].hasLexProp('isGeoSettlement')): # nép, nyelv, szaknév
+        return False
+      if not (inp[1].hasLexProp('Folk') or inp[1].hasLexProp('Major') or inp[1].hasLexProp('isGeoSettlement')): # nép, nyelv, szaknév
+        return False
+      if not (inp[0].matchPoSSequence('.*(FN|MN),NOM')):
+        return False 
+      if not (inp[1].matchPoSSequence('.*(FN|MN),NOM')):
+        return False
+    return True
+    
+  def getId(self):
+    return "M_EK_NAGYKOTOJEL"
+  
+  def getName(self): 
+    return "Nagykötőjellel írandó kifejezések (kód: M_EK_NAGYKOTOJEL) (AkH. 263., OH. 353--354.)"
+
+  def communicate(self, message=None):
+    sols = []
+    sols.append((['--'], 'Nagykötőjellel kapcsoljuk két vagy több nép (nyelv) nevének kapcsolatát, felsőoktatási szakpárokat, tulajdonnnevek kapcsolatát és tól-ig viszonyt kifejező szavakat.', ['263']))
+    # TODO: tulajdonnevek kapcsolata, tól-ig viszonyt kifejező szerkezetek
+    self.state = 999
+    return ('!', sols)
+
+# # # end class RuleNagykotojel # # #
+
+class RuleFolyamatosMellekneviIgenev(SpellingRuleBase):
+  """
+    @author: LZS
+  """
+  
+  @staticmethod  
+  def match(inp):
+#    if len(inp) not in [2, 3]:
+#      return False
+    if len(inp) != 2:
+      return False
+    alaptag = 1 if len(inp) == 2 else 2 # index of the alaptag in inp
+    #if alaptag == 1 and not (WordInfo(inp[alaptag - 1].wordform + inp[alaptag].wordform).hasLexProp('')
+    if alaptag == 1 and not ((inp[alaptag - 1].matchPoSSequence('(FN,)?(IK,)?IGE,(_MUV,)?_OKEP,NOM') or inp[alaptag - 1].hasLexProp('FolyamatosMellekneviIgenevFonevesult') or WordInfo(inp[alaptag - 1].wordform + inp[alaptag].wordform).hasLexProp('FolyamatosMellekneviIgenevHagyomany')) and inp[alaptag].matchPoSSequence('FN')):
+      return False
+    if alaptag == 2 and not (inp[alaptag - 2].matchPoSSequence('FN,NOM') and inp[alaptag - 1].matchPoSSequence('(FN,)?(IK,)?IGE,_OKEP,NOM') and inp[alaptag].matchPoSSequence('FN')):
+      return False # ? ütve fúró gép, gyorsan ölő méreg
+    return True
+  
+
+  def getId(self):
+    return "M_EK_FOLYAMATOS_MELLEKNEVI_IGENEV"
+  
+  def getName(self): 
+    return "Folyamatos melléknévi igenévi tagot tartalmazó kifejezések (kód: M_EK_FOLYAMATOS_MELLEKNEVI_IGENEV) (AkH. 112., OH. 113.)"
+
+  def communicate(self, message=[]):
+    
+    #print(self.inp[0].getNSyllables())  
+      
+    sols = []
+    alaptag = 1 if len(self.inp) == 2 else 2 # index of the alaptag in inp
+    FirstLetter0 = Wordform.Phonology.CV(self.inp[alaptag - 1].wordform[0])
+    Det0 = 'A' if FirstLetter0 == 'C' else 'Az'
+    firstLetter0 = Wordform.Phonology.CV(self.inp[alaptag - 1].wordform[0])
+    det0 = 'a' if firstLetter0 == 'C' else 'az'
+    FirstLetter1 = Wordform.Phonology.CV(self.inp[alaptag].wordform[0])
+    det1 = 'A' if FirstLetter1 == 'C' else 'Az'
+    _if = 'ás' if self.inp[alaptag - 1].getHarmony() == True else 'és'
+    if WordInfo(self.inp[alaptag - 1].wordform + self.inp[alaptag].wordform).hasLexProp('FolyamatosMellekneviIgenevHagyomany'):
+      sols.append(([''], 'Azok az összetett alaptagot tartalmazó szerkezetek, amelyekben az alaptag összetétel mivolta elhomályosult, egybeírandók. Ugyanígy néhány szóban az egybeírás pusztán írásszokáson alapul.', ['112.'])) # , OH. 114.
+    elif self.inp[alaptag].getNCompParts() > 1 or self.inp[alaptag - 1].getNCompParts() > 1: # 2==osszetett | 3==osszetett
+      if self.inp[alaptag - 1].hasLexProp('FolyamatosMellekneviIgenevFonevesult'):
+        if self.state == 0:
+          self.state = 1
+          return('?', (Det0 + ' "'+ self.inp[alaptag - 1].wordform + '" előtag főnevesült?',
+                       [('1', 'Igen, az előtag ("' + self.inp[alaptag - 1].wordform + '") itt főnév.'),
+                        ('2', 'Nem. Szófaja folyamatos melléknévi igenév.')]))
+        elif self.state == 1:
+          if message == '1':
+            sols.append(([''], 'Ha az -ó/-ő képzős melléknévi igenév főnevesült, a kifejezés egybeírandó.', [''], ['114.'])) # OH. 114.
+          elif message == '2':  
+            sols.append(([' '], 'Ha akár a jelző, akár a jelzett szó önmagában is összetett szó, illetőleg ha mindkét tag összetétel, a jelentésváltozás ellenére többnyire különírást alkalmazunk.', ['112.'])) # , OH. 113--114.
+      else:
+        sols.append(([' '], 'Ha akár a jelző, akár a jelzett szó önmagában is összetett szó, illetőleg ha mindkét tag összetétel, a jelentésváltozás ellenére többnyire különírást alkalmazunk.', ['112.'])) # , OH. 113--114.         
+    elif self.inp[alaptag].getNCompParts() == 1 and self.inp[alaptag - 1].getNCompParts() == 1: # 2==egyszeru & 3==egyszeru
+      if self.inp[alaptag - 1].hasLexProp('FolyamatosMellekneviIgenevFonevesult'):
+        sols.append(([''], 'Ha az -ó/-ő képzős melléknévi igenév főnevesült, a kifejezés egybeírandó.', ['?']))
+      elif self.state == 0:
+#        print('getHarmony')
+#        print(self.inp[0].getHarmony())
+        self.state = 1
+        return ('?', ('Az -ó/-ő képzős igenév folyamatra utal (alkalmi jelző), vagy pedig valamilyen képességre, rendeltetésre vonatkozik (jelentésváltozás van)?',
+                      [('1', det1 + ' "'+ self.inp[alaptag].wordform + '" éppen a cselekvést, tevékenységet végzi, esetleg a folyamatot átéli, elszenvedi. "' + det1 + ' ' + self.inp[alaptag].wordform + ' éppen ' + self.inp[alaptag - 1].getVerbLex() + '."'),
+                      ('2', 'Valamire rendeltetett, valamit általában, foglalkozásszerűen űz, nem vagy nem pusztán pillanatnyi cselekvést, tevékenységet végez, illetve folyamatot átél, elszenved. "' + det1 + ' ' + self.inp[alaptag].wordform + ' rendeltetése ' + det0 + ' ' + self.inp[alaptag - 1].getVerbalStem() + _if + '."'), # TODO -ás/-és képző illeszkedése
+                      ('3', 'Nem tudom eldönteni.'),   
+                      ('4', 'Egyik sem. ' + Det0 + ' "'+ self.inp[alaptag - 1].wordform + '" itt nem folyamatos melléknévi igenévi szófajú.')]))
+      elif self.state == 1:
+        if message == '1':
+          sols.append(([' '], 'Ha az -ó/-ő képzős igenév alkalmai jelző, a szerkezetet különírjuk.', ['112.']))
+        elif message == '2':
+          sols.append(([''], 'Ha az -ó/-ő képzős igenév nem alkalmi jelző, hanem valamilyen képességre, rendeltetésre vonatkozik, illetőleg ha a jelzős kapcsolat tagjai a jelentés alapján összeforrtak, egybeírást alkalmazunk.', ['112.'])) # , OH. 113.
+        elif message == '4':
+          return (None, 'Erre az esetre nem ez a szabály vonatkozik.') 
+        elif message == '3':
+          if self.state == 1:
+            self.state = 2
+            return ('?', ('Melyikhez hasonlít?', [('1', 'nevelőnő'), ('2', 'a gyermekét nevelő nő')]))
+      elif self.state == 2:
+        #print('self.state = 2')
+        if message == '1':
+          sols.append(([''], 'Ha az -ó/-ő képzős igenév nem alkalmi jelző, hanem valamilyen képességre, rendeltetésre vonatkozik, illetőleg ha a jelzős kapcsolat tagjai a jelentés alapján összeforrtak, egybeírást alkalmazunk.', ['112.'])) # , OH. 113.
+          self.state = 999
+          return ('!', sols)
+        elif message == '2':
+          sols.append(([' '], 'Ha az -ó/-ő képzős igenév alkalmai jelző, a szerkezetet különírjuk.', ['112.']))
+          self.state = 999
+          return ('!', sols)
+    
+    else:
+      self.state = 999
+      return (None, 'Az összetételi tagok számát nem lehetett meghatározni.')
+    self.state = 999
+    return ('!', sols)
+
+# # # end class RuleFolyamatosMellekneviIgenev # # # 
+
+
+class RuleBefejezettMellekneviIgenev(SpellingRuleBase):
+  """
+    @author: LZS
+  """
+  
+  @staticmethod  
+  def match(inp):
+    if len(inp) != 2:
+      return False
+    if not (inp[0].matchPoSSequence('.*IGE,_MIB,NOM') or (WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('BefejezettMellekneviIgenev'))):
+      return False
+    return True
+
+  def getId(self):
+    return "M_EK_BEFEJEZETT_MELLEKNEVI_IGENEV"
+  
+  def getName(self): 
+    return "Befejezetti melléknévi igenévi tagot tartalmazó kifejezések (kód: M_EK_BEFEJEZETT_MELLEKNEVI_IGENEV) (AkH. 113., OH. 114.)"
+
+  def communicate(self, message=None):
+    sols = []
+    if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('BefejezettMellekneviIgenev'):
+      sols.append(([''], 'Befejezett melléknévi igenévi jelzők esetén néhány kivételes alakot egybe kell írni. Ilyen esetekben jelentésváltozásról van szó.', ['113.']))
+    else:
+      sols.append(([' '], 'A befejezett melléknévi igenévi jelzős szerkezetek tipikusan (állandó vagy alkalmai) szókapcsolatok, tehát különírandók.', ['113.']))
+    self.state = 999
+    return ('!', sols)
+
+# # # end class RuleBefejezettMellekneviIgenev # # #
+
+
+class RuleRovidites(SpellingRuleBase):
+  """
+    @author: LZS
+  """
+  
+  @staticmethod  
+  def match(inp):
+    if len(inp) not in [2,3]:
+      return False
+    if len(inp) == 2:
+      if not (inp[0].hasLexProp('Abbr') or inp[1].hasLexProp('Abbr') or (inp[0].wordform[-1] == '.') or (inp[1].wordform[-1] == '.') or (inp[0].matchPoSSequence('((FN\|ROV\|VEGY)|(FN\|ME\|ROV)),NOM')) or (inp[0].matchPoSSequence('((FN\|ROV\|VEGY)|(FN\|ME\|ROV)),NOM'))):
+        return False
+
+    if len(inp) == 3:
+      if not (inp[0].hasLexProp('Abbr') or inp[0].matchPoSSequence('((FN\|ROV\|VEGY)|(FN\|ME\|ROV)),NOM') or inp[0].wordform[-1] == '.'):
+        return False
+    return True
+
+
+  def getId(self):
+    return "M_EK_ROVIDITES"
+  
+  def getName(self): 
+    return "Rövidítést tartalmazó összetételek (kód: M_EK_ROVIDITES) (AkH. 281., OH. 135--136.)"
+    
+  def communicate(self, message=[]):
+    sols = []
+    pattern = re.compile(u'[a-záéíóöőúüűA-ZÁÉÍÓÖŐÚÜŰ]+\.')
+    if len(self.inp) == 2:
+      if self.inp[0].hasLexProp('Abbr') or self.inp[0].matchPoSSequence('((FN\|ROV\|VEGY)|(FN\|ME\|ROV)),NOM'):
+        sols.append((['-'], 'Ha a rövidítés valamely teljes szóval alkot összetételt (mint előtag), az elő- és az utótagot kötőjellel fűzzük össze.', ['281.']))
+      elif self.inp[1].hasLexProp('Abbr'):
+        sols.append(([''], 'Ha a rövidítés összetétel utótagja, kötőjel nélkül kapcsolódik az előtaghoz, hiszen az összekapcsolás nem írásjelnél történik.', [''], ['136.'])) # OH. 136.
+      elif re.match(pattern, self.inp[0].wordform):
+        if self.state == 0:
+          self.state = 1
+          return ('?', ('Az előtag egy rövidítés?', [('1', 'Igen.'), ('2', 'Nem.')]))
+        elif self.state == 1:
+          if message == '1':
+            sols.append((['-'], 'Ha a rövidítés valamely teljes szóval alkot összetételt (mint előtag), az elő- és az utótagot kötőjellel fűzzük össze.', ['281.']))
+          elif message == '2':
+            return (None, 'Az előtag pontra végződik, és nem rövidítés. Ellenőrizze, hogy jól gépelte-e be a keresett szót!')
+      elif re.match(pattern, self.inp[1].wordform):
+        if self.state == 0:
+          self.state = 1
+          return('?', ('Az utótag egy rövidítés?', [('1', 'Igen.'), ('2', 'Nem.')]))
+        elif self.state == 1:
+          if message == '1':
+            sols.append(([''], 'Ha a rövidítés összetétel utótagja, kötőjel nélkül kapcsolódik az előtaghoz, hiszen az összekapcsolás nem írásjelnél történik.', [''], ['136.'])) # OH. 136.
+          elif message == '2':
+            return (None, 'Az utótag pontra végződik, és nem rövidítés. Ellenőrizze, hogy jól gépelte-e be a keresett szót!')
+      else:
+        self.state = 999
+        return (None, 'Hiba!')  
+    elif len(self.inp) == 3:
+      if re.match(pattern, self.inp[0].wordform):
+        if self.state == 0:
+          self.state = 1
+          return (('?', ('Az előtag egy rövidítés?', [('1', 'Igen.'), ('2', 'Nem.')])))
+        elif self.state == 1:
+          if message == '1':
+            sols.append((['-'], 'Ha a rövidítés valamely teljes szóval alkot összetételt (mint előtag), az elő- és az utótagot kötőjellel fűzzük össze.', ['281.']))
+          elif message == '2':
+            return (None, 'Az előtag pontra végződik, és nem rövidítés. Ellenőrizze, hogy jól gépelte-e be a keresett szót!')
+        
+      sols.append((['-', '-'], 'Ha a kifejezés kettőnél több tagból áll, az újabb összetételi tagokat is kötőjellel kapcsoljuk.', ['?']))
+    self.state = 999
+    return ('!', sols)
+
+# # # end class RuleRovidites # # #
+
+
+class RuleBetuszo(SpellingRuleBase):
+  """
+    @author: LZS
+  """
+  
+  @staticmethod  
+  def match(inp):
+    if len(inp) not in [2,3]:
+      return False
+    pattern = re.compile('[A-ZÁÉÍÓÖŐÚÜŰ]{2,}')
+    match0 = re.match(pattern, inp[0].wordform)
+    match1 = re.match(pattern, inp[1].wordform) 
+    if len(inp) == 2:
+      if not (match0 or match1 or inp[0].hasLexProp('KozszoiBetuszo') or inp[1].hasLexProp('KozszoiBetuszo') or inp[0].hasLexProp('KozszoiBetuszoKivetel') or inp[1].hasLexProp('KozszoiBetuszoKivetel')):
+        return False
+    if len(inp) == 3: 
+      if not (match0 or match1 or inp[0].hasLexProp('KozszoiBetuszo') or inp[1].hasLexProp('KozszoiBetuszo') or inp[0].hasLexProp('KozszoiBetuszoKivetel') or inp[1].hasLexProp('KozszoiBetuszoKivetel')): # 3. tag nem szokott betűszó lenni
+        return False
+    return True
+
+  def getId(self):
+    return "M_EK_BETUSZO"
+  
+  def getName(self): 
+    return "Betűszót tartalmazó összetételek (kód: M_EK_BETUSZO) (AkH. 287., OH. 136.)"
+    
+  def communicate(self, message=[]):
+    sols = []
+    pattern = re.compile('[A-ZÁÉÍÓÖŐÚÜŰ]{2,}')
+    if len(self.inp) == 2:
+      if self.inp[0].matchPoSSequence('(MN|(FN,_IKEP)|(IGE(,MIB|_OKEP)),NOM)') and self.inp[1].hasLexProp('KozszoiBetuszo'):
+        sols.append(([' '], 'Ha az előtag jelző, a köszói betűszói utótagot különírjuk.', ['?']))
+        self.state = 999
+        return ('!', sols)
+      elif self.inp[0].hasLexProp('KozszoiBetuszo') or self.inp[1].hasLexProp('KozszoiBetuszo'):
+        sols.append((['-'], 'A betűszókhoz és a tulajdonnévi szóösszevonásokhoz kötőjellel fűzzük az utótagot (esetleg előtagot).', ['287. a)']))
+        self.state = 999
+        return ('!', sols)
+      elif self.inp[0].hasLexProp('KozszoiBetuszoKivetel'):
+        sols.append(([''], 'Az "áfa", "eva" és a "taj" betűszókhoz az összetételi tagok kötőjel nélkül járulnak, azaz a szót egybeírjuk.', [''], ['403.']))  # OH. 403.
+        self.state = 999
+        return ('!', sols)
+      if re.match(pattern, self.inp[0].wordform):
+        if self.state == 0:
+          self.state = 1
+          return ('?', ('Az előtag egy betűszó?', [('1', 'Igen.'), ('2', 'Nem.')]))
+        elif self.state == 1:
+          if message == '1':
+            sols.append((['-'], 'A betűszókhoz és a tulajdonnévi szóösszevonásokhoz kötőjellel fűzzük az utótagokat.', ['287. a)']))
+          elif message == '2':
+            return (None, 'Az előtag csupa nagybetűvel íródott, mégsem betűszó. Ellenőrizze!')
+      elif re.match(pattern, self.inp[1].wordform):
+        if self.state == 0:
+          self.state = 1
+          return ('?', ('Az utótag egy betűszó?', [('1', 'Igen.'), ('2', 'Nem.')]))
+        elif self.state == 1:
+          if message == '1':
+            if self.inp[0].matchPoSSequence('(MN|(FN,_IKEP)|(IGE(,MIB|_OKEP)),NOM)'):
+              sols.append(([' '], 'Ha az előtag jelző, a betűszói utótagot különírjuk.', ['?']))
+            else:  
+              sols.append((['-'], 'A betűszókhoz és a tulajdonnévi szóösszevonásokhoz kötőjellel fűzzük az előtagot.', ['287. a)']))
+          elif message == '2':
+            return (None, 'Az előtag csupa nagybetűvel íródott, mégsem betűszó. Ellenőrizze!')
+      else:
+        return (None, 'Hiba!')
+    elif len(self.inp) == 3:
+      if self.inp[0].matchPoSSequence('(MN|(FN,_IKEP)|(IGE(,MIB|_OKEP)),NOM)') and self.inp[1].hasLexProp('KozszoiBetuszo'):
+        sols.append(([' ', ' '], 'Ha a (különírt) jelzős szerkezet alaptagja betűszó, a mozgószabály nem alkalmazható: az utótag különírandó.', [''], ['133.'])) # OH. 133.
+        self.state = 999
+        return ('!', sols)
+      elif self.inp[0].hasLexProp('KozszoiBetuszo'):
+        sols.append((['-', '-'], 'Ha a kifejezés kettőnél több tagból áll, az újabb összetételi tagokat is kötőjellel kapcsoljuk.', [''], ['136.'])) # OH. 136.
+        self.state = 999
+        return ('!', sols)
+      elif self.inp[0].hasLexProp('KozszoiBetuszoKivetel'):
+        sols.append((['', ''], 'Az "áfa", "eva" és "taj" betűszókhoz az összetételi tagok kötőjel nélkül járulnak: a kifejezést egybeírjuk, esetleg kötőjellel, ha a szótagszámlálási szabály érvénybe lép.', [''], ['403.'])) # OH. 403.
+        self.state = 999
+        return ('!', sols)
+      elif re.match(pattern, self.inp[0].wordform) or re.match(pattern, self.inp[1].wordform) or re.match(pattern, self.inp[2].wordform):
+        if self.state == 0:
+          self.state = 1
+          return ('?', ('Valamelyik összetételi tag egy betűszó?', [('1', 'Igen.'), ('2', 'Nem.')]))
+        elif self.state == 1:
+          if message == '1':
+            if self.inp[0].matchPoSSequence('(MN|(FN,_IKEP)|(IGE(,MIB|_OKEP)),NOM)') and re.match(pattern, self.inp[1].wordform):
+              sols.append(([' ', ' '], 'Ha a (különírt) jelzős szerkezet alaptagja betűszó, a mozgószabály nem alkalmazható: az utótag különírandó.', [''], ['133.'])) # OH. 133.
+              self.state == 999
+              return ('!', sols)
+            
+            elif (self.inp[0].matchPoSSequence('MN,NOM') and re.match(pattern, self.inp[1].wordform)) or (re.match(pattern, self.inp[0].wordform) and self.inp[1].matchPoSSequence('MN,NOM')) and self.inp[2].matchPoSSequence('FN,NOM'):
+              sols.append(([' ', ' '], 'Ha', [''], ['?'])) # OH. ?
+            elif self.inp[0].matchPoSSequence('FN,NOM') and (re.match(pattern, self.inp[0].wordform) or re.match(pattern, self.inp[1].wordform)):
+              sols.append((['-', '-'], 'Ha a kifejezés kettőnél több tagból áll, az újabb összetételi tagokat is kötőjellel kapcsoljuk.', [''])) # OH. 136.
+              self.state == 999
+              return ('!', sols)
+            elif re.match(pattern, self.inp[0].wordform) and self.inp[1].matchPoSSequence('(MN|(FN,_IKEP)|(IGE(,MIB|_OKEP)),NOM)') and self.inp[2].matchPoSSequence('FN,NOM'):
+              sols.append(([' ', ' '], 'Ha a tulajdonnévi betűszóhoz jelzős szerkezet kapcsolódik, mindent külön szóba írunk.', [''])) # OH. 136.
+              self.state == 999
+              return ('!', sols)
+          elif message == '2':
+            return (None, 'Valamely összetételi tag csupa nagybetűvel íródott, mégsem betűszó. Ellenőrizze!')
+    self.state == 999
+    return ('!', sols)
+
+# # # end class RuleBetuszo # # #
+  
+      
+class RuleBetujelElotag(SpellingRuleBase):
+  """
+    @author: LZS
+  """
+
+  
+  @staticmethod  
+  def match(inp):
+    if len(inp) not in [2,3]:
+      return False
+    #pattern = re.compile(u'[a-záéíóöőúüűA-ZÁÉÍÓÖŐÚÜŰ]')
+    if len(inp) == 2:
+      #if (len(inp[0].wordform)) != 1 and not re.match(pattern, inp[0].wordform) and not inp[1].hasFinalPoS('FN|MN'):
+      if len(inp[0].wordform) > 2 or not inp[0].matchPoSSequence('(FN\|BETU),NOM'):
+        return False
+      
+    if len(inp) == 3:
+      #if (len(inp[0].wordform)) != 1 and not re.match(pattern, inp[0].wordform) and not inp[1].hasFinalPoS('FN|MN') and not inp[2].hasFinalPoS('FN|MN'):
+      if len(inp[0].wordform) > 2 or not inp[0].matchPoSSequence('(FN\|BETU),NOM') and not inp[1].hasFinalPoS('FN|MN') and not inp[2].hasFinalPoS('FN|MN'):
+        return False 
+#      if not inp[1].hasFinalPoS('FN|MN'):
+#        return False
+    return True
+
+  def getId(self):
+    return "M_EK_BETUJEL_ELOTAG"
+  
+  def getName(self): 
+    return "Különírt betűjelből és főnévből/melléknévből álló összetételek (kód: M_EK_BETUJEL_ELOTAG) (AkH. ?., OH. 133.)"
+    
+  def communicate(self, message=[]):
+    sols = []
+    firstLetter0 = Wordform.Phonology.CV(self.inp[0].wordform[0])
+    firstLetter1 = Wordform.Phonology.CV(self.inp[1].wordform[0])
+    FirstLetter0 = Wordform.Phonology.CV(self.inp[0].wordform[0])
+    det1 = 'a' if firstLetter0 == 'C' else 'az'
+    det2 = 'A' if FirstLetter0 == 'C' else 'Az'
+    det3 = 'a' if firstLetter1 == 'C' else 'az'
+    if self.state == 0:
+      self.state = 1
+      return ('?', ('Milyen szerepet tölt be ' + det1 + ' "' + self.inp[0].wordform + '" betűjel?',
+                    [('1', 'A jelzőszerű betűjel egyet jelöl a sok hasonló/azonos fajta közül, semmilyen formában nem utal a jelzett főnév, ' + det3 + ' "' + self.inp[1].wordform + '" minőségére.'),
+                     ('2', det2 + ' "' + self.inp[0].wordform + '-' + self.inp[1].wordform + '" egy külön fajta, nem pedig egy a sokféle egyforma "' + self.inp[1].wordform + '" közül.')]))
+    elif self.state == 1:
+      if message == '1':
+        if len(self.inp) == 2:
+          sols.append(([' '], 'Egy betűjelből és egy főnévből vagy melléknévből álló kapcsolatot különírunk.', [''])) # OH. 133.
+        elif len(self.inp) == 3:
+          sols.append(([' ', ' '], 'Azokban a szerkezetekben, amelyek egy különírt betűjelből és egy főnévből/melléknévből állnak, nem alkalmazható a mozgószabály. A további összetételi tagokat is különírjuk.', [''])) # OH. 133.
+      elif message == '2':
+        return (None, 'A betűjel fajtát jelöl, nem ez a szabály vonatkozik rá.')
+    self.state = 999
+    return ('!', sols)
+
+# DE: A-vitamin, X-kromoszóma -- Bősze, Mártonfi alapján
+
+# # # end class RuleBetujelElotag # # #
+    
+
+class RuleToismetles(SpellingRuleBase):
+  """
+    @author: LZS
+  """
+  
+  @staticmethod  
+  def match(inp):
+    if len(inp) != 2:
+      return False
+    #if len(inp) == 2:
+      #if not ((WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('ToismetlesEgybe') or WordInfo(inp[0].wordform + '-' + inp[1].wordform).hasLexProp('ToismetlesKotojel')) or (inp[0].getParseHumorData()[0][0][0] != inp[1].getParseHumorData()[0][0][0] or inp[1].getParseHumorData()[1][0][0] or inp[1].getParseHumorData()[2][0][0])):
+    if not (WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('ToismetlesEgybe') or WordInfo(inp[0].wordform + '-' + inp[1].wordform).hasLexProp('ToismetlesKotojel')): 
+      return False
+    return True
+  
+  def getId(self):
+    return "M_EK_TOISMETLES"
+  
+  def getName(self): 
+    return "Tőismétlés (kód: M_EK_TOISMETLES) (AkH. ?., OH. 100.)"
+    
+  def communicate(self, message=None):
+    sols = []
+    #szoto1 = self.inp[0].getParseHumorData()[0][0][0])
+    #print(self.inp[1].getParseHumorData()[0][0][0])
+    if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('ToismetlesEgybe'):
+      sols.append(([''], 'Néhány tőismétléses mellérendelést egybe kell írni.', [''])) # OH. 100.
+    elif WordInfo(self.inp[0].wordform + '-' + self.inp[1].wordform).hasLexProp('ToismetlesKotojel'):
+      sols.append((['-'], 'Néhány tőismétléses mellérendelést kötőjellel kell írni.', [''])) # OH. 100.
+#    elif self.inp[0].getParseHumorData()[0][0][0] == (self.inp[1].getParseHumorData()[0][0][0] or self.inp[1].getParseHumorData()[1][0][0] or self.inp[1].getParseHumorData()[2][0][0]):
+#      sols.append(([' '] ,'Ugyanannak a szónak különböző toldalékokkal ellátott alakjait külön kell írni egymástól.', ['OH. 100.']))
+    else:
+      return (None, 'Hiba!')
+    self.state = 999
+    return ('!', sols)
+
+# # # end class RuleToismetles # # #
+  
+class RuleSzervetlen(SpellingRuleBase):
+  """
+    @author: LZS
+  """
+  
+  @staticmethod  
+  def match(inp):
+    if len(inp) not in [2,3]:
+      return False
+    if len(inp) == 2 and not WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('Szervetlen'):
+      return False
+    if len(inp) == 3 and not WordInfo(inp[0].wordform + inp[1].wordform + inp[2].wordform).hasLexProp('Szervetlen'):
+      return False
+    return True
+
+  def getId(self):
+    return "M_EK_SZERVETLEN"
+  
+  def getName(self): 
+    return "A hagyományosan szervetlennek nevezett összetételek (kód: M_EK_SZERVETLEN) (AkH. 132--136., OH. 126--128.)"
+  
+  def communicate(self, message=None):
+    sols = []
+    if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('Szervetlen'):
+      sols.append(([''], 'A hagyományosan szervetlennek nevezett összetételeket egybeírjuk.', ['AkH. 132--136.']))
+    else:
+      return (None, 'Hiba!')
+    self.state = 999
+    return ('!', sols)
+
+# # # end class RuleSzervetlen # # #
+
+class RuleFoglalkozasnev(SpellingRuleBase):
+  """
+    @author: LZS
+  """
+  
+  @staticmethod  
+  def match(inp):
+    if len(inp) != 2:
+      return False
+#    if not ((inp[0].hasLexProp('Occupation') or inp[0].hasLexProp('Ecclesiastic')) and (inp[1].hasLexProp('Occupation') or inp[1].hasLexProp('Ecclesiastic'))):
+#      return False
+    if not (WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('EcclesiasticException') or ((inp[0].hasLexProp('Occupation') or inp[0].hasLexProp('Ecclesiastic')) and (inp[1].hasLexProp('Occupation') or inp[1].hasLexProp('Ecclesiastic'))) ):
+      return False
+    return True
+
+  def getId(self):
+    return "M_EK_FOGLALKOZAS"
+  
+  def getName(self): 
+    return "Foglalkozásnevek, tisztségek, rangok, fokozatok, beosztások megnevezése (kód: M_EK_FOGLALKOZAS) (AkH. 101. a), 114., 152., OH. 114., 144., 167., 353.)"
+  
+  def communicate(self, message=[]):
+    sols = []
+    FirstLetter1 = Wordform.Phonology.CV(self.inp[1].wordform[0]) # utótag (alaptag)
+    det1 = 'A' if FirstLetter1 == 'C' else 'Az'
+    if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('EcclesiasticException'):
+      sols.append(([''], 'Néhány kettős foglalkozásnevet -- elsősorban egyházi területen -- hagyományosan egybeírunk.', ['?']))
+    elif self.inp[0].hasLexProp('Ecclesiastic') or self.inp[1].hasLexProp('Ecclesiastic'):
+      sols.append(([' '], 'Az egyházi fokozatokat nem kötőjellel kapcsoljuk, hanem külön szóba írjuk őket. Egyházi és világi foglalkozások esetén is különírást alkalmazunk.', ['?']))
+    else:
+      if self.state == 0:
+        self.state = 1
+        return ('?', ('Válasszon a lehetőségek közül!',
+                      [('1', 'Valaki ' + self.inp[0].wordform + ' és ' + self.inp[1].wordform + ' egyszerre.'),
+                       ('2', det1 + ' ' + self.inp[1].wordform + ' (egy) ' + self.inp[0].wordform + '.'),
+                       ('3', 'A kérdés nem értelmezhető. Nem két foglalkozás összekapcsolásáról van szó.')]))
+      elif self.state == 1:
+        if message == '1':
+          sols.append((['-'], 'Számos olyan mellérendelő kapcsolatunk van, amely nem vagy csak kivételesen -- és csak az utótagon -- látható el toldalékokkal. Két foglalkozásnevet kötőjellel szokás egymáshoz kapcsolni.', [['101. a), 114.']))
+        elif message == '2':
+          sols.append(([' '], 'Főnévi jelzős szerkezetről lévén szó, a kifejezést különírjuk.', [''])) # OH. 115.
+        elif message == '3':
+          return (None, 'Nem két foglalkozás összekapcsolásáról van szó.')
+    self.state = 999
+    return ('!', sols)
+
+# # # end class RuleFoglalkozasnev
+    
+
+
+class RuleSzotagszamlalas(SpellingRuleBase):
+
+  @staticmethod  
+  def match(inp):
+#    print('Szotagszam:')
+#    print(inp[0].getNSyllables())
+    if len(inp) != 1:
+      return False
+    if [c for c in inp[0].wordform if c in '-'] != []: # kötőjelezett alakra nem illeszkedik
+      return False
+    if inp[0].getNSyllables() == -99:
+      return False
+    if not inp[0].getNSyllables() > 6:
+      if not inp[0].getNCompParts() >= 3:
+        return False
+    return True
+  
+  def getId(self):
+    return "M_EK_SZOTAGSZAML"
+  
+  def getName(self): 
+    return "Szótagszámlálási szabály, 6:3-as szabály (kód: M_EK_SZOTAGSZAML) (AkH. 138., OH. 128--131.)"
+  
+  def communicate(self, message=None):
+    for anal in self.inp[0].getParseHumorData():
+      match = [c for c in anal[0][0] if c in '*']
+      if match != ['']:
+        tmp = anal[0][0].split('*')
+        print(tmp)
+#      for morph in anal:
+#        print(morph)
+    return (None, 'Under construction')
+    
+# # # end class RuleSzotagszamlalas # # #
+
+
+class RuleMozgo1(SpellingRuleBase):
+    
+  @staticmethod  
+  def match(inp):
+    if len(inp) != 2:
+      return False
+    match = [c for c in inp[0].wordform if c in '-']
+    #print(match)
+    if match == []:
+      return False
+    return True
+
+  def getId(self):
+    return "M_EK_MOZGO1"
+  
+  def getName(self): 
+    return "1. mozgószabály (kód: M_EK_MOZGO1) (AkH. 139. a), OH. 131.)"
+
+  def communicate(self, message=None):
+    sols = []
+    tmp = self.inp[0].wordform.split('-')
+    if len(tmp) == 2:
+#      print(tmp[0][-2])
+#      print(tmp[1][0])
+      if tmp[0][-2] == tmp[0][-1]:
+        if tmp[0][-1] == tmp[1][0]:
+          sols.append((['-'], 'Ha egy olyan kötőjeles írásmódú összetett szóhoz járul újabb előtag, amelyikben a kötőjelet nem a szótagszámlálási vagy egyéb mozgószabály írja elő, nem hajtható végre az első mozgószabály. Az újabb összetételi tagot is kötőjellel kapcsoljuk.',
+                       [''], ['131.']))
+      else:
+        tmp = ''.join(tmp)
+        inp0 = WordInfo(tmp)
+        self.inp[0] = inp0
+        sols.append((['-'],
+                 'Ha egy kötőjellel már tagolt szóhoz újabb, szintén kötőjellel kapcsolandó utótag járul, az első kötőjelet kihagyjuk, vagyis az eredetileg kötőjelezett szórészt az új alakulatokban egybeírjuk.',
+                 ['139. a)']))
+    self.state = 999
+    return ('!', sols)
+
+# # # end class RuleMozgo1 # # #
+
+
+class RuleDebuggerConsole:
+  """Sample class for managing a pool of rule classes (descendants of SpellingRuleBase) and interacting with the user via stdin and stdout.
+  """
+
+  def __init__(self, ruleset):
+    """Initialises the class with ruleset, an array of SpellingRuleBase descendant class names.
+    """
+    self.rules = ruleset
+
+  def getAnswer(self, question):
+    """Parameter question is a structure: ('question prompt', [(answer_id, 'answer text'), ...])
+       Displays question prompt and answer texts and repeats reading user's answer until it is one of the valid answer_id's specified in question.
+       Returns the answer_id from given by the user.
+    """
+    print('Question: "{0}"'.format(question[0]))
+    valid = []
+    for aid, atxt in question[1]:
+      print('{0} - {1}'.format(aid, atxt))
+      valid.append(aid)
+    while True:
+      print('Your answer>', end='')
+      ans = sys.stdin.readline().rstrip()
+      if ans in valid:
+        break
+      else:
+        print('Please type one of [{0}]'.format(','.join(valid)))
+    return ans
+
+  def applyMatchingRules(self, inp):
+    """For each rule class in self.rules, calls its match() on inp (an array of WordInfo instances).
+       If a rule class matches, it is instantiated with the input and its communicate() method is invoked.
+       If answers to interim questions are required, the question texts are displayed on stdout and answers are expected from stdin.
+       Returns a dictionary {<ruleId>: <solutions>, ...} where <solutions> is an array containing all the solutions (e.g.: ('!', <verdict>)) returned by rule with ruleId.
+       Debug data is dumped to stdout.
+    """
+    ret = dict()
+    for rname in self.rules:
+      if rname.match(inp):
+        rule = rname(inp)
+        rid = rule.getId()
+        print('-matching rule found: id={0} class={1} name="{2}"'.format(rid, str(rname), rule.getName()))
+        r = rule.communicate()
+        print('-rule {0} returned: {1}'.format(rid, r))
+        while r[0] == '?': # while rule asks back
+          aid = self.getAnswer(r[1]) # get answer from user
+          r = rule.communicate(message=aid) # send it back to rule
+          print('-rule {0} returned: {1}'.format(rid, r))
+        if r[0] == None: # rule returned error message
+          print('-rule {0} returned error message: {1}'.format(rid, r[1]))
+        elif r[0] == '!': # rule returned verdict
+          if rid not in ret:
+            ret[rid] = []
+          ret[rid] += r[1]
+    return ret	
+
+  def interact(self):
+    """Start an interactive session with the user via stdout and stdin."""
+    import readline
+    print('Enter words to check, blank line to exit')
+    while(True):
+      print('>', end='')
+      inp = sys.stdin.readline().rstrip()
+      if not inp:
+        break
+      toks = [WordInfo(x) for x in inp.split(' ')]
+      print('\nInput tokens information:\n{0}\n'.format('\n'.join([x.toStr() for x in toks])))
+      print('Applying rules...')
+      outp = self.applyMatchingRules(toks)
+      print("\nSolutions:\n")
+      if len(outp) == 0:
+        print('No solutions found')
+      i = 1
+      for rid, sols in outp.items():
+        for sol in sols:
+          print('{0}. solution'.format(i))
+          print('Suggested form: "{0}"'.format(applyseparators(toks, sol[0])))
+          print('Comment: "{0}"'.format(sol[1]))
+          print('Related AKH Id(s): {0}'.format(','.join(sol[2])))
+          if len(sol) == 4:
+            print('Related page(s) in Osiris: {0}'.format(','.join(sol[3])))
+          print('Id of applied rule: "{0}"'.format(rid)) 
+          print('')
+          i += 1
+
+# # # end class RuleDebuggerConsole # # #
+
+
+def applyseparators(inp, seps):
+  """Parameter inp: array of WordInfo instances
+     Parameter seps: array of ' ' or '-' or '--' or ''
+     Returns string which is wordforms of inp with elements of seps "between" them.
+     Note: len(inp) - 1 == len(seps) is required, returns None otherwise
+  """
+  if len(inp) - 1 != len(seps):
+    return None
+  ret = ''
+  for i in range(0, len(inp) - 1):
+    ret += inp[i].wordform + seps[i]
+  ret += inp[-1].wordform
+  return ret
+
+
+def _test_LexicalEntry():
+  # look up id for myword
+  myword = 'sárga'
+  print(myword)
+  ids = Wordform.forToken(mydb, myword)
+  myid = None
+  for id, word in ids:
+    if word == unicode(myword, "utf-8"):
+      myid = id
+      break
+  print(myid)
+  # create a LexicalEntry object from the id
+  l = Wordform.loadLexicalEntry(mydb, myid)
+  # dump
+  print(vars(l))
+
+
+def _test_WordInfo(word):
+  print(WordInfo(word).toStr())
+
+def _test_WordInfo_interactive():
+  while True:
+    inp = sys.stdin.readline().rstrip()
+    if not inp:
+      break
+    w = WordInfo(inp)
+    print(w.toStr())
+    print(w.morph().getMorphsHumor())
+
+
+
+if __name__ == "__main__":
+  
+  #_test_LexicalEntry()
+  #_test_WordInfo('sárga')
+  
+  RuleDebuggerConsole([RuleSzinneviAlaptag, RuleAnyagneviMozgoszabaly, RuleSorszamneviJelzosSzerk,
+                       RuleJelzoiElotag,
+                       RuleJeloletlenAlanyos,
+                       RuleJeloletlenTargyas, RuleJeloletlenHatarozos,
+                       RuleJeloletlenBirtokosJelzos, RuleJeloletlenMinosegjelzos,
+                       RuleJelentessurito,
+                       RuleJeloltTargyas, RuleJeloltHatarozos, RuleJeloltBirtokos,
+                       RuleMennyisegjelzosSzerkezet, RuleFoneviJelzosSzerkezet, RuleGyujtonevek,
+                       RuleNagykotojel, RuleBefejezettMellekneviIgenev, RuleFolyamatosMellekneviIgenev,
+                       RuleRovidites, 
+                       RuleToismetles,
+                       RuleSzervetlen, RuleBetuszo, RuleBetujelElotag,
+                       RuleFoglalkozasnev,
+                       RuleSzotagszamlalas, RuleMozgo1
+                       ]).interact()

Deleted: trunk/web2py/applications/helyesiras_webdev/modules/egybekulon.py
===================================================================
--- trunk/web2py/applications/helyesiras_webdev/modules/egybekulon.py	2013-06-03 13:45:34 UTC (rev 802)
+++ trunk/web2py/applications/helyesiras_webdev/modules/egybekulon.py	2013-06-03 13:47:25 UTC (rev 803)
@@ -1,2670 +0,0 @@
-#!/usr/bin/env python
-# coding: utf8
-
-"""
-Module for the egybeírás-különírás functionalities
-
- at author: MM, LZS, ...
-"""
-
-from __future__ import print_function
-import re
-import sys
-import morfologia
-import Wordform
-
-
-# If this module is run or used outside of a web2py framework instance (i.e. from the command line),
-# we have to connect to the database manually (it would be taken care of in models/db.py)
-# TODO: more standard test to see if we're in web2py and db.py was loaded?
-try:
-  mydb
-except NameError:
-  sys.path.append('/opt/web2py')
-  from gluon import *
-  mydb = DAL('mysql://dbdicter:dbdicter123@localhost/dbdict', migrate_enabled=False)
-  #TODO: create a load_my_database() function in db.py and call that instead (so future modifications will not affect us)
-
-
-class WordInfo:
-  """Class for encapsulating morphologia.MorphInfo and Wordform.LexicalEntry instances for a specific wordform.
-     @author: MM
-  """
-  
-  def __init__(self, wordform):
-    """Initialize for wordform (UTF-8 string).
-    """  
-    self.wordform = wordform
-    self.morphInfo = None
-    self.morphInfo = morfologia.MorphInfo(wordform, use_humor=True, use_humor_6_3=True, use_xerox=False, use_ocamorph=False)
-    self.lexicalEntry = None
-    myid = None
-    for id, word in Wordform.forToken(mydb, wordform):
-      if word == unicode(wordform, "utf-8"):
-        myid = id
-        break
-    if myid != None:
-      self.lexicalEntry = Wordform.loadLexicalEntry(mydb, myid)
-    self.parseHumorCache = None # for caching output of MorphInfo.parseHumorData()	
-    
-  def morph(self):
-    """Returns the associated MorphInfo object, or None if there was an error initializing it"""  
-    return self.morphInfo
-    
-  def lex(self):
-    """Returns the associated LexicalEntry object, or None if wordform is unknown or if there was an error initializing the object"""
-    return self.lexicalEntry
-
-  def getParseHumorData(self):
-    """Wrapper for accessing self.morph().parseHumorData() via a cache to avoid overhead with multiple calls.
-       Returns (the cached or computed) value of self.morph().parseHumorData().
-    """
-    if self.parseHumorCache == None:
-      self.parseHumorCache = self.morphInfo.parseHumorData()
-    return self.parseHumorCache  
-    
-  def hasLexProp(self, prop):
-    """Returns True iff the value for the lexical property name is not None in wordform's LexicalPropery instance
-       @see Wordform.LexicalProperty for property names and their meanings
-    """
-    if self.lexicalEntry != None and prop in vars(self.lexicalEntry) and vars(self.lexicalEntry)[prop] != None:
-      return True
-    return False
-    
-  def hasPoSCase(self, pos, case=None):
-    """Returns True iff wordform has a Humor analysis whose PoS is pos and whose case is case.
-       If case=None it is not checked. pos and case are Humor codes.
-       Note: consider using matchPoSSequence() instead, it gives more control
-       TODO: use humor2005_stemmer + python API in morfologia instead...
-    """
-    if self.morphInfo == None or 'humor' not in self.morphInfo.getGoodIds():
-      return False
-    if pos not in morfologia.POSNORM:
-      return False
-    hpos = '[' + pos + ']'
-    hcase = '[' + case + ']' if case != None else None
-    for anal in self.morphInfo.getRawData()['humor']:
-      if not anal:
-        continue
-      if case == None and hpos in anal:
-        return True
-      elif case != None and hpos in anal and anal.endswith(hcase):
-        return True
-    return False
-    
-  def hasFinalPoS(self, pos):
-    """Returns True iff wordform has a Humor analysis whose final PoS (after derivations) is pos (a Humor PoS code).
-    """
-    if self.morphInfo == None or 'humor' not in self.morphInfo.getGoodIds():
-      return False
-    if pos not in morfologia.POSNORM:
-      return False
-    for anal in self.morphInfo.getMorphs():
-      if anal[0] == morfologia.POSNORM[pos]:
-        return True
-    return False
-    
-  def matchPoSSequence(self, expr):
-    """Returns True iff wordform has a Humor analysis whose morphs' PoS's concatenated by ',' is matched by regular expression expr.
-       Example:
-       >>WordInfo('ezrediket').matchPoSSequence('SZN,_SORSZ,.*')
-       True
-    """
-    if self.morphInfo == None or 'humor' not in self.morphInfo.getGoodIds():
-      return False
-    x = self.getParseHumorData()
-    if x == []:
-      return False
-    for anal in x:
-      if re.match(expr, ','.join([x[2] for x in anal])):
-        return True
-    return False
-    
-  def getNCompParts(self):
-    """Return number of compound parts of wordform, based on humor analyses.
-       Note: adds up n. of comp. parts for each morpheme and returns maximum over all analyses.
-       Note2: calculated value may not be exact (e.g. igekotos are always worth 1, tobbtagu szamnevs are always worth 2 comp. parts),
-       use it rather to test whether wordform is a compound or not (returns >1 or ==1).
-       Returns None if no humor data was available.
-    """
-    if self.morphInfo == None:
-      return None
-    x = self.getParseHumorData()
-    if x == []:
-      return None
-    max = 0
-    for anal in x:
-      sum = 0
-      for morph in anal:
-        if morph[3] == -1: # egytagu szamnev
-          sum += 1
-        elif morph[3] == -3 or morph[2] == 'IK': # igekoto
-          if int(morph[4]) > 1: # more than 1 syllable
-            sum += 1
-        elif morph[3] == -2: # tobbtagu szamnev
-          sum += 2
-        else:
-          sum += morph[3]
-      if sum > max:
-        max = sum
-    return max
-
-
-  def getNSyllables(self):
-    """Returns number of syllables of wordform, based on humor analyses.
-       Note: inflexions make no difference (but formating elements do!).
-       Note: getNSyllables() returns -99 if a morph's number of syllabes isn't available.
-       @author: LZS
-    """
-    if self.morphInfo == None:
-      return None
-    x = self.getParseHumorData()
-    if x == []:
-      return None
-    for anal in x:
-      syll = 0
-      for morph in anal:
-        if morph[4] == -99:
-          syll = -99
-        else:
-          syll += int(morph[4])
-    return syll
-  
-  
-
-  def getVerbLex(self):
-    """ A helper method which returns the lexical form of a verb (E/3 in Hungarian), based on humor analyses.
-        @author: LZS
-    """
-    lex = ''
-    ige = ''
-    tmp = ''
-    ik = ''
-    isMuv = False
-    if self.getParseHumorData() == []:
-      return None
-    for ls in self.getParseHumorData():
-      muv = False
-      if self.matchPoSSequence('IGE,_MUV,_OKEP,NOM'):
-        muv = True 
-      for l in ls:
-        if muv == True:
-          _muv = [s for s in l if type(s).__name__ == 'str' and '_MUV' in s]
-          if _muv == ['_MUV']:
-            isMuv = True
-            if tmp == '':
-              tmp = l[0]
-    for ls in self.getParseHumorData():
-      for l in ls:
-        matching0 = [s for s in l if type(s).__name__ == 'str' and 'IK' in s]
-        if matching0 == ['IK']:
-          if ik == '':
-            ik = l[0]
-        matching1 = [s for s in l if type(s).__name__ == 'str' and 'IGE' in s]
-        if matching1 == ['IGE']:
-          if ige == '':
-            if l[0][-2:] == 'ik' and isMuv == True:
-              ige = l[1]
-            elif isMuv == True:
-              ige = l[0]
-            else:
-              ige = l[0]
-    lex = ik + ige + tmp if muv == True else ik + ige
-    return lex
-
-
-  def getNominalStem(self):
-    """ A helper method which returns the stem of a noun, based on humor analyses.
-        @author: LZS
-    """
-    stem = ''
-    if self.getParseHumorData() == []:
-      return None
-    for ls in self.getParseHumorData():
-      for l in ls:
-        fn = [s for s in l if type(s).__name__ == 'str' and 'FN' in s]
-        if fn != []:
-          tmp = l[0]
-          stem = ''.join([c for c in tmp if c not in '*'])
-          return stem
-      
-            
-  def getVerbalStem(self):
-    """ A helper method which returns the stem of a verb, based on humor analyses.
-        @author: LZS
-    """
-    stem = ''
-    ige = ''
-    ik = ''
-    tmp = ''
-    if self.getParseHumorData() == []:
-      return None
-    for ls in self.getParseHumorData():
-      muv = False
-      if self.matchPoSSequence('IGE,_MUV,_OKEP,NOM'):
-        muv = True
-      for l in ls:
-        if muv == True:
-          _muv = [s for s in l if type(s).__name__ == 'str' and '_MUV' in s]
-          if _muv == ['_MUV']:
-            if tmp == '':
-              tmp = l[0]
-        matching0 = [s for s in l if type(s).__name__ == 'str' and 'IK' in s]
-        if matching0 == ['IK']:
-          if ik == '':
-            ik = l[0]
-        matching1 = [s for s in l if type(s).__name__ == 'str' and 'IGE' in s]
-        if matching1 == ['IGE']:
-          if ige == '':
-            ige = l[1] if l[1] != '' else l[0]
-    stem = ik + ige + tmp if muv == True else ik + ige
-    return stem  
-        
-
-  def getVocals(self):
-    voc = []
-    unicodeString = self.wordform.decode('utf-8')
-    for i in range(len(unicodeString)):
-      if Wordform.Phonology.CV(unicodeString[i]) == 'V':
-        voc.append(unicodeString[i])
-    return voc
-
-
-      
-  def getHarmony(self):
-    vocalList = []
-    velar = False
-    velarWordHarmony = False
-    voc = self.getVocals()
-    exc = re.compile(u'[eéií]')
-    mely = re.compile(u'[aáoóuú]')
-    magas = re.compile(u'[eéiíöőüű]')
-    for v in voc:
-      if re.match(mely, v):
-        velar = True
-        tmp = (v, velar)
-        vocalList.append(tmp)
-      elif re.match(magas, v):
-        velar = False
-        tmp = (v, velar)
-        vocalList.append(tmp)
-    for v in vocalList:
-      if v[1] == True:
-        velarWordHarmony = True
-    return velarWordHarmony
-          
-      
-  def toStr(self):
-    """Return string representation of (basic information stored in) object."""
-    s = {}
-    s['wordform'] = self.wordform
-    s['morph'] = self.morph().getRawData() if self.morph() else str(None)
-    if not self.lex():
-      s['lex'] = str(None)
-    else:
-      slex = {}
-      for k, v in vars(self.lex()).items():
-        if v:
-          slex[k] = v
-      s['lex'] = slex
-    return str(s)
-
-# # # end class WordInfo # # #
-
-
-class SpellingRuleBase:
-  """Base Class for AKH egybeírás-különírás spelling rule implementation classes.
-     The derived classes provide a verdict (spelling solutions: egybe, külön, kötőjellel) for an input (arrays of WordInfo instances),
-     permitting dialogs consisting of turns consisting of interim questions (by class) and answers (by user). 
-     @author: MM     
-  """
-  
-
-  @staticmethod
-  def match(inp):
-    """Use this static method to test whether the rule represented by this class is applicable to a specific input.
-       Parameter inp is an array of WordInfo instances, corresponding to input tokens (completely segmented?).
-       Returns True iff the requirements for the application of this spelling rule are matched by inp.
-    """
-    pass
-
-  def __init__(self, inp):
-    """Constructor. Initializes self.inp (copy of input) and self.state (status of dialog between class and user).
-       self.state values:
-         0: object was initialized but dialog has not yet started
-         1,2,3,...: 1st, 2nd, 3rd etc. turn of conversation
-         999: object provided verdict, dialog ended
-    """
-    self.inp = inp
-    self.state = 0
-    
-  def getId(self):
-    """Return a string which is the unique id of this rule."""
-    pass
-
-  def getName(self):
-    """Return a string giving the human-understandable name of the rule."""
-    pass
-    
-  def communicate(self, message=None):
-    """Parameter answer: array holding the answer(s) by the user to the question asked by the class in the previous turn. If message==[] a new dialog is started.
-       Returns either tuple ('!', <verdict>) or tuple ('?', <question>) or tuple (None, 'error_message').
-       <verdict> is an array of solutions: [([separators], 'comment', [AKH-ids]), ...]
-         where [separators] contains N-1 instances (iff len(self.inp)==N) of either '' or ' ' or '-' (kiskotojel) or '--' (nagykotojel).
-         [AKH-ids] contains (string) ids of AKH paragraphs that played a role in this solution, 'comment' is an optional textual explanation for this solution.
-       <question> is a structure that represents an interim question asked by class with possible answers and their ids:
-         ('question prompt', [(answer_id, 'answer text'), ...]). 
-         One of answer_id's (strings) should be provided in parameter message when calling communicate() in the next turn.
-    """
-    pass
-    
-# # # end class SpellingRuleBase # # #
-
-class RuleSzinneviAlaptag(SpellingRuleBase):
-  """
-     Név: színnévi alaptag (M_EK_SZIN) (AkH. 110)
-
-     Feladat: minőségjelzős színnevek egybe v. külön
-
-     Erőforrás: MA, lista színárnyalatot kifejező melléknevekről (LIST1), lista színnevekről (LIST2)
-
-     Azonosító jegyek: 1:{HA}?+2:{MN.NOM & in(LIST1)}+3:{MN.NOM & in(LIST2)};
-
-     Működés:
-
-     if (2==egyszeru & 3==egyszeru) {
-      if (exists(1)) { 
-       kulon(1,2,3); %rendkívül sötét zöld
-       } else {
-        egybe(2,3); %sötétzöld
-       }
-     } else { % 2==osszetett | 3==osszetett => xerox kod = ^CB
-       kulon(1?,2,3) %nagyon? világos narancssárga
-     }
-     Megjegyzés:  -
-  
-     TODO: if alaptag is összetett but was split: e.g. rózsa szín, narancs sárga
-     
-     @author: MM     
-  """
-
-  @staticmethod
-  def match(inp):
-    if len(inp) not in [2, 3]:
-      return False
-    alaptag = 1 if len(inp) == 2 else 2 # index of the alaptag in inp
-    if not inp[alaptag].hasLexProp('Color1'): # színnév
-      return False
-    if not inp[alaptag - 1].hasLexProp('Color3'): # színárnyalat
-      return False
-    #if not inp[alaptag].hasPoSCase('MN', 'NOM'):
-    if not inp[alaptag].matchPoSSequence('.*MN,NOM'):
-      return False
-    #if not inp[alaptag-1].hasPoSCase('MN', 'NOM'):
-    if not inp[alaptag - 1].matchPoSSequence('.*MN,NOM'):    
-      return False
-    if alaptag == 2 and not inp[alaptag - 2].hasPoSCase('HA'):
-      return False
-    return True
-   
-  def getId(self):
-    return "M_EK_SZIN"
-   
-  def getName(self):
-    return "Színnévi alaptag (M_EK_SZIN) (AkH. 110)"
-    
-  def communicate(self, message=None):
-    sols = []
-    alaptag = 1 if len(self.inp) == 2 else 2 # index of the alaptag in inp
-    if self.inp[alaptag].getNCompParts() == 1 and self.inp[alaptag - 1].getNCompParts() == 1: # 2==egyszeru & 3==egyszeru
-      if alaptag == 2: # len(inp)==3
-        sols.append(([' ', ' '], 'A szókapcsolat határozót is tartalmaz, ezért külön írjuk a jelzőt és a színnévi alaptagot', ['110'])) # kulon(1,2,3)
-      else: # len(inp)==2
-        sols.append(([''], 'A színárnyalatot kifejező melléknévi jelzőt egybeírjuk a színt jelölő melléknévvel, ha mindkettő egyszerű szó.', ['110.'])) # egybe(2,3)
-    elif self.inp[alaptag].getNCompParts() > 1 or self.inp[alaptag - 1].getNCompParts() > 1: # 2==osszetett | 3==osszetett
-      sols.append(([' ', ' '] if alaptag == 2 else [' '], 'A színnévi alaptag vagy minőségjelzője összetett, ezért külön írjuk őket', ['110.'])) # kulon(1,2,3) or kulon(2,3)
-    else:
-      self.state = 999
-      return (None, 'A színnév vagy a minőségjelző összetételi tagjainak számát nem lehetett meghatározni')
-    self.state = 999
-    return ('!', sols)
-
-# # # end class RuleSzinneviAlaptag # # #
-
-
-class RuleAnyagneviMozgoszabaly(SpellingRuleBase):
-  """
-     Név: anyagnévi mozgószabály (M_EK_ANYAGNEV) (AkH. 115., OH. 134.)
-
-     Feladat: anyagnevet tartalmazó szerkezetek egybe v. külön, anyagnévi mozgószabály
-
-     Erőforrás: MA, lista anyagnevekről (LIST)
-
-     Azonosító jegyek: 1:in LIST + 2:{FN,NOM} or 1:in LIST + 2:{.*(FN(,_IKEP)?|MN),NOM')} + 3:{FN,NOM} or      1:.*(FN(,_IKEP)?|MN),NOM + 2:in LIST + 3:{FN,NOM}
-
-     Működés:
-     
-    if (not exists(3) { % 2 tagú bemenet) {
-      if (1 == osszetett && 2 == osszetett) {
-        if (1 in(LIST1) && 1 in(LIST2)) { % az előtag egyszerre szín- és anyagnév, pl. arany
-          kerdezd: "Az előtag anyagnév vagy színnév?"
-          if (anyagnev) {
-           egybe(1,2)
-          }
-          else if (színnév) {
-           kulon(1,2)
-          }
-       }
-      else {
-        egybe(1,2)
-       }
-    }
-    if (1 == osszetett || 2 == osszetett) {
-      kulon(1,2)
-    }
-
- }
-
-
-     else {  % 3 tagú bemenet
-       if (1 == .*(FN(,_IKEP)?|MN|(IGE,_MIB)),NOM && not in LIST1) {
-         if (1 in LIST3) { % -i képzős földrajzi név, carrarai márvány szobor
-           kulon(1,2,3)
-        } 
-         else {    % tisztaselyem ruha vs. tiszta selyemruha
-           kerdezd: "A jelző az anyag nevére vagy az alaptagra vonatkozik?" 
-           if (anyag nevere) {
-             kulon(egybe(1,2), 3)
-           }
-           else if (alaptagra) {
-             kulon(1, egybe(2,3))
-           }
-         }
-      else if (1 in(LIST1) && 2 == .*(FN(,_IKEP)?|MN|(IGE,_MIB)),NOM { % bőr átmeneti kabát
-        kulon(1,2,3)
-       }
-    }
-}
-  
-  
-    @author: LZS
-  """
-    
-  @staticmethod
-  def match(inp):
-    if len(inp) not in [2, 3]:
-      return False
-    alaptag = 1 if len(inp) == 2 else 2 # index of the alaptag in inp
-#    if alaptag == 1 and not (inp[alaptag - 1].hasLexProp('Material1') or inp[alaptag - 1].hasLexProp('Material2')) and not inp[alaptag].matchPoSSequence('.*FN,NOM'): # anyagnév
-#      return False
-    if alaptag == 1 and not (inp[alaptag - 1].hasLexProp('Material1') or inp[alaptag - 1].hasLexProp('Material2')) and not inp[alaptag].hasPoSCase('.*FN,NOM'): # anyagnév
-      return False
-    if alaptag == 1 and (inp[alaptag - 1].hasLexProp('Material1') or inp[alaptag - 1].hasLexProp('Material2')) and WordInfo(inp[alaptag - 1].wordform + inp[alaptag].wordform).hasLexProp('Jelentessurito'):
-      return False
-    if alaptag == 2 and not (((inp[alaptag - 2].hasLexProp('Material1') or inp[alaptag - 2].hasLexProp('Material2')) and inp[alaptag - 1].matchPoSSequence('.*(FN(,_IKEP|,_UKEP)?|MN),NOM') and inp[alaptag].matchPoSSequence('.*FN,NOM')) or (inp[alaptag - 2].matchPoSSequence('.*(FN(,_IKEP)?|MN),NOM') and (inp[alaptag - 1].hasLexProp('Material1') or inp[alaptag - 1].hasLexProp('Material2')) and inp[alaptag].matchPoSSequence('.*FN,NOM'))):
-      return False
-    return True
-   
-  def getId(self):
-    return "M_EK_ANYAGNEV"
-   
-  def getName(self):
-    return "Anyagnévi mozgószabály (M_EK_ANYAGNEV) (AkH. 115., OH. 117.)"
-    
-  def communicate(self, message=[]):
-    sols = []
-    alaptag = 1 if len(self.inp) == 2 else 2 # index of the alaptag in inp
-    FirstLetter0 = Wordform.Phonology.CV(self.inp[alaptag - 1].wordform[0]) # anyagnév/színnév
-    FirstLetter1 = Wordform.Phonology.CV(self.inp[alaptag].wordform[0]) # utótag (alaptag)
-    det1 = 'A' if FirstLetter0 == 'C' else 'Az'
-    det2 = 'A' if FirstLetter1 == 'C' else 'Az'
-    if len(self.inp) == 2:
-      if self.inp[alaptag].getNCompParts() == 1 and self.inp[alaptag - 1].getNCompParts() == 1: # 2==egyszeru & 3==egyszeru: bőröv, selyeming
-        if ((self.inp[alaptag - 1].hasLexProp('Material1') or self.inp[alaptag - 1].hasLexProp('Material2')) and (self.inp[alaptag - 1].hasLexProp('Color1') or self.inp[alaptag - 1].hasLexProp('Color2') or self.inp[alaptag - 1].hasLexProp('Color3'))):
-          if self.state == 0:
-            self.state = 1
-            return('?', (det1 + ' "' + self.inp[alaptag - 1].wordform + '" anyagnév vagy színnév?',
-                         [('1', det2 + ' ' + self.inp[alaptag].wordform + ' ebből az anyagból készült.'),
-                          ('2', det2 + ' ' + self.inp[alaptag].wordform + ' ilyen színű.'),
-                          ('3', 'A kérdés nem értelmezhető. Nem anyagnévi jelzős szerkezetről van szó.')]))
-          elif self.state == 1:
-            if message == '1':
-              sols.append(([''], 'Az anyagnévi jelzőt, ha egyszerű szó, egybeírjuk a nem összetett főnevekkel.', ['115.'])) # egybe(2,3)
-              self.state = 999
-              return ('!', sols)
-            elif message == '2':
-              sols.append(([' '], 'Ha a jelző a jelzett szó színére, nem pedig az anyagára vonatkozik, a kifejezést különírjuk, minőségjelzős szerkezetről lévén szó.', ['107. a)']))
-              self.state = 999
-              return ('!', sols)
-            elif message == '3':
-              return (None, 'Nem anyagnévi jelzős szerkezetről van szó.')          
-          else:
-            return (None, 'Hiba!')
-        elif self.inp[alaptag - 1].hasLexProp('Material1') or self.inp[alaptag - 1].hasLexProp('Material2'):
-          #print('anyagnevi elotag')
-          sols.append(([''], 'Az anyagnévi jelzőt, ha egyszerű szó, egybeírjuk a nem összetett főnevekkel.', ['115.']))
-          self.state = 999
-          return ('!', sols)
-      elif self.inp[alaptag].getNCompParts() > 1 or self.inp[alaptag - 1].getNCompParts() > 1: # 2==osszetett | 3==osszetett
-        sols.append(([' '], 'Ha az anyagnévi jelzős kapcsolatnak valamelyik vagy mindkét tagja összetett szó, az anyagnevet különírjuk jelzett szavától.', ['115.']))
-    elif len(self.inp) > 2:
-      FirstLetter0 = Wordform.Phonology.CV(self.inp[alaptag - 2].wordform[0]) # jelző
-      det0 = 'A' if FirstLetter0 == 'C' else 'Az'
-      FirstLetter1 = Wordform.Phonology.CV(self.inp[alaptag - 1].wordform[0]) # anyagnév
-      det1 = 'A' if FirstLetter1 == 'C' else 'Az'
-      FirstLetter2 = Wordform.Phonology.CV(self.inp[alaptag].wordform[0]) # alaptag
-      det2 = 'A' if FirstLetter2 == 'C' else 'Az'
-      sub0 = 'ra' if self.inp[alaptag].getHarmony() == True else 're'
-      sub1 = 'ra' if self.inp[alaptag - 1].getHarmony() == True else 're'
-      if self.inp[alaptag - 2].matchPoSSequence('.*(FN(,_IKEP)?|MN|(IGE,_MIB)),NOM') and not (self.inp[alaptag - 2].hasLexProp('Material1') or self.inp[alaptag - 2].hasLexProp('Material2')):
-        if self.inp[alaptag - 2].hasLexProp('ProperGeo'):
-          if self.state == 0:
-            self.state = 1
-            return('?', (det0 + ' "' + self.inp[alaptag - 2].wordform + '" jelző mire vonatkozik?',
-                         [('1', det2 + ' ' + self.inp[alaptag].wordform + sub0 + '. ' + det2 + ' ' + self.inp[alaptag].wordform + ' ' + self.inp[alaptag - 2].wordform + '.'),
-                          ('2', det1 + ' ' + self.inp[alaptag - 1].wordform + sub1 + '. ' + det1 + ' ' + self.inp[alaptag - 1].wordform + ' ' + self.inp[alaptag - 2].wordform + '.'),
-                          ('3', 'A kérdés nem értelmezhető. Nem anyagnévi jelzős szerkezetről van szó.')]))    
-            
-          elif self.state == 1:
-            if message == '1':
-              sols.append(([' ', ' '], '...', ['']))  
-              self.state = 999
-              return ('!', sols)
-            elif message == '2':   
-              sols.append(([' ', ' '], 'Ha az anyagnévi jelzős szerkezetben az anyagnév jelzője melléknévképzővel ellátott földrajzi név, minden tagot külön szóba írunk.', [''], ['134.'])) # OH. 134.
-              self.state = 999
-              return ('!', sols)
-            elif message == '3':
-              return (None, 'Nem az anyagnévi jelzős szerkezetről van szó.')
-        elif self.state == 0:
-          self.state = 1
-          return('?', (det0 + ' "' + self.inp[alaptag - 2].wordform + '" az anyag nevére vagy az alaptagra vonatkozik?',
-                       [('1', 'Az anyag nevére. ' + det1 + ' ' + self.inp[alaptag - 1].wordform + ' ' + self.inp[alaptag - 2].wordform + '.'),
-                        ('2', 'Az alaptagra. ' + det2 + ' ' + self.inp[alaptag].wordform + ' ' + self.inp[alaptag - 2].wordform + '.')]))
-        elif self.state == 1:
-          if message == '1':
-            sols.append((['', ' '], 'Ha az anyagnévi jelző szerepét különírt szószerkezet tölti be, az eredetileg különírt szerkezetet egybeírjuk, az alkalmi összetétellé váltó jelző és a jelzett szó azonban különírandó.', [''], ['134.'])) # OH. 134.
-            self.state = 999
-            return ('!', sols)
-          elif message == '2':
-            sols.append(([' ', ''], 'Ha a jelző a szerkezet alaptagjára vonatkozik, az anyagnévi jelzőt egybeírjuk az alaptaggal, az alkalmi jelzőt pedig különírjuk az anyagnevet tartalmzó összetételtől.', ['?']))
-            self.state = 999
-            return ('!', sols)
-          else:
-           return ('Hiba!')
-      elif (self.inp[alaptag - 2].hasLexProp('Material1') or self.inp[alaptag - 2].hasLexProp('Material2')) and self.inp[alaptag - 1].matchPoSSequence('.*(FN(,_IKEP|,_UKEP)|MN|(IGE,_MIB)),NOM'):
-        sols.append(([' ', ' '], 'Ha az anyagnévi jelző egy különírt szószerkezetre vonatkozik, a jelzőt is különírjuk.', ['']))
-    else:
-      self.state = 999
-      return (None, 'Az összetételi tagok számát nem lehetett meghatározni.')
-    self.state = 999
-    return ('!', sols)
-
-# # # end class RuleAnyagneviMozgoszabaly # # #
-
-
-class RuleSorszamneviJelzosSzerk(SpellingRuleBase):
-  """
-     Név: sorszámnévi jelzős szerkezetek (kód: M_EK_SORSZAMNEV) (AkH. 120.)
-
-     Feladat: sorszámnévi/törtszámnévi jelzős szerkezetek egybe vagy külön
-
-     Erőforrás: morfológiai elemzők (MA)
-
-     Azonosító jegyek: 1:{SZN+_SORSZ, SZN+_TORT} + 2:{FN, MN(FN+_IKEP, FN+_SKEP, FN+_UKEP), SZN}
-
-     Működés:
-
-     if (1: SZN+_SORSZ) { % ezredik év
-       kulon(1,2)
-     }
-     else { % ötödévben
-       egybe(1,2)
-     }
-     
-     @author: MM    
-  """
-
-  @staticmethod
-  def match(inp):
-    if len(inp) != 2:
-      return False
-    if not (inp[0].matchPoSSequence('SZN,_SORSZ,NOM') or inp[0].matchPoSSequence('SZN,_TORT,NOM')): # 1:{SZN+_SORSZ, SZN+_TORT}
-      return False
-    if not (inp[1].hasFinalPoS('FN') or inp[1].hasFinalPoS('SZN') or inp[1].matchPoSSequence('FN,_IKEP,.+') or inp[1].matchPoSSequence('FN,_SKEP,.+') or inp[1].matchPoSSequence('FN,_UKEP,.+') or inp[1].matchPoSSequence('FN\|NM,.*')): # 2:{FN, MN(FN+_IKEP, FN+_SKEP, FN+_UKEP), SZN}
-      return False
-    return True
-   
-  def getId(self):
-    return "M_EK_SORSZAMNEV"
-   
-  def getName(self):
-    return "Sorszámnévi jelzős szerkezetek (kód: M_EK_SORSZAMNEV) (AKH 120)"
-    
-  def communicate(self, message=None):
-    sols = []
-    if self.inp[0].matchPoSSequence('SZN,_SORSZ,NOM'): # if (1: SZN+_SORSZ) { % ezredik év
-      sols.append(([' '], 'A -dik képzős sorszámnévi jelzőt nem írjuk egybe sem a jelzett főnévvel, sem a (rendszerint -i, -s, -ú, -ű képzős) melléknévvel', ['120.'])) # kulon(1,2)
-    else: # else { % ötödévben
-      sols.append(([''], 'A -d képzős sorszámnévi jelzőt egybeírjuk mind a főnevekkel, mind a melléknevekkel, mind a számnevekkel', ['120'])) # egybe(1,2)
-    self.state = 999
-    return ('!', sols)
-
-# # # end class RuleSorszamneviJelzosSzerk # # #
-
-class RuleJelzoiElotag(SpellingRuleBase):
-  """Név: jelzői előtag (kód: M_EK_ELOTAG) (AkH. 111.)
-
-     Feladat: önállóan nem használt jelzői előtagos összetételek kezelése 
-
-     Erőforrás: morfológiai elemzők (MA), önállóan nem használt jelzői előtagok listája (LIST)
-     
-     Azonosító jegyek: 1: in(LIST), 2: (bármi)
-
-     Működés:
-     
-     if (1 in(LIST) {
-       egybe(1,2)
-     }
-  
-     @author: LZS
-     
-  """
-    
-  @staticmethod
-  def match(inp):
-    if len(inp) != 2:
-      return False
-    if not (inp[0].hasLexProp('CompoundPrefix2') and inp[1].matchPoSSequence('FN,NOM')):
-      return False
-    return True
-
-  def getId(self):
-    return "M_EK_ELOTAG"
-   
-  def getName(self):
-    return "Önállóan nem használt jelzői előtagos összetételek kezelése (kód: M_EK_ELOTAG) (AkH. 111)."
-    
-  def communicate(self, message=None):
-    sols = []
-    sols.append(([''], 'Az olyan összetételeket, amelyekben a főnév minőségjelzője összetételi alakjában vagy jelentésében önálló szóként nem használatos, mindig egybe kell írni.',
-                 [''], ['111.'])) # OH. 111.
-    self.state = 999
-    return ('!', sols)
-
-# TODO: össz-szövetségi
-    
-
-# # # end class RuleJelzoiElotag # # #
-
-class RuleJeloletlenAlanyos(SpellingRuleBase):
-  """
-    Név: alanyos alárendelés (kód: M_EK_ALANY) (AkH. 106.)
-
-    Feladat: alanyos alárendelések egybe vagy külön
-
-    Erőforrás: morfológiai elemzők (MA); kivétellista az egybeírandókról (LIST)
-
-    Azonosító jegyek: 1:{MN.NOM}?+2:{FN.NOM,FN.PSe3}+3:{IGE.TMe3,MIB.NOM,MIF.NOM,HIN}
-
-    Működés:
-
-    if (2+3 in LIST) { 
-     if (exists(1)) { 
-      kulon(1,2,3); %magyar ember lakta
-     } else {
-      egybe(2,3); %emberlakta
-     }
-    } else {
-     kulon(1?,2,3) %magyar? traktor szántotta
-    }
-
-    @author: LZS
-  """
-  
-  @staticmethod
-  def match(inp):
-    if len(inp) not in [2,3]:
-      return False
-    alaptag = 1 if len(inp) == 2 else 2 # index of the alaptag in inp
-    if len(inp) == 3:
-      if not inp[alaptag - 2].matchPoSSequence('(MN|(FN,_IKEP)|(IGE,_(MIB|_OKEP)))') and not inp[alaptag - 1].matchPoSSequence('FN(,PSe3)?,NOM') and not inp[alaptag].matchPoSSequence('((IGE(,_OKEP|_MIB|_HIN))|(IGE,TMe3))'):
-        return False
-    if len(inp) == 2:
-      if not (WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('Alanyos') or (inp[alaptag - 1].matchPoSSequence('FN,(PSe3,)?NOM') and inp[alaptag].matchPoSSequence('IGE,TMe3'))):
-        return False
-    return True
-  
-  def getId(self):
-    return "M_EK_JELOLETLEN_ALANYOS"
-  
-  def getName(self): 
-    return "Jelöletlen alanyos alárendelő összetételek (kód: M_EK_JELOLETLEN_ALANYOS) (AkH. 106.)"
-
-  def communicate(self, message=None):
-    sols = []
-    if len(self.inp) == 3:
-      if self.inp[0].matchPoSSequence('(MN|(FN,_IKEP)|(IGE,_(MIB|_OKEP)))') and self.inp[1].matchPoSSequence('FN(,PSe3)?,NOM') and self.inp[2].matchPoSSequence('((IGE(,_OKEP|_MIB|_HIN))|(IGE,TMe3))'):
-        sols.append(([' ', ' '], 'Ha az alanyi bővítménynek jelzője van, minden tagot külön szóba írunk.', ['']))
-    else:
-      if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('Alanyos'):
-        sols.append(([''], 'Az alanyos alárendelő összetételek egybeírandók (jelentésváltozás, vagy csupán a hagyomány miatt).', ['106. b, c)']))
-      else:
-        sols.append(([' '], 'Az alanyos kapcsolatok tagjait különírjuk egymástól.', ['106. a)']))
-    self.state = 999
-    return ('!', sols)
-
-# # # end class RuleJeloletlenAlanyos # # #
-                
-
-class RuleJeloletlenTargyas(SpellingRuleBase):
-  """
-     Név: jelöletlen tárgyas összetételek (kód: M_EK_JELOLETLEN_TARGYAS) (AkH. 123., OH. 104.)
-     
-     Feladat: jelöletlen tárgyas összetételek helyesírása
-     
-     Erőforrás: morfológiai elemzők (MA)
-     
-     Azonosító jegyek: 1:{(FN(PSe3)?, MN, NU} + 2:{MIB, MIN, HI}
-     
-     Működés: 
-     
-     if(1 + 2) { % tárgyas alárendelés
-        egybe(1,2) % jelöletlen tárgyas alárendelő összetétel mindig egybe
-        }
-        
-    Ezután meg kell vizsgálni, esetleg a 6:3-as szabály miatt nem kell-e kötőjel.
-     
-     @author: LZS    
-  """
-  @staticmethod
-  def match(inp):
-    if len(inp) != 2:
-      return False
-    if inp[0].matchPoSSequence('HA') and inp[0].matchPoSSequence('FN,NOM'):
-      return False # pl. otthon + maradó nem tárgyas
-    if not(inp[0].matchPoSSequence('((FN\|NM)|FN|NM)(,(PS)?e3)?,NOM')):
-      return False
-    if not (inp[1].matchPoSSequence('(IK,)?IGE,(_MIB|_OKEP|_HIN)')):
-      return False
-    if WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('Alanyos'):
-      return False
-    if WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('AllSzokapcs'):
-      return False
-    return True
-  
-  def getId(self):
-    return "M_EK_JELOLETLEN_TARGYAS"
-  
-  def getName(self): 
-    return "Jelöletlen tárgyas összetételek (kód: M_EK_JELOLETLEN_TARGYAS) (AkH. 123., OH. 204.)"
-
-  def communicate(self, message=None):
-    sols = []
-    sols.append(([''], 'A jelöletlen tárgyas összetételt mindig egybeírjuk (esetleg kötőjellel, amennyiben érvényesül a szótagszámlálási szabály).', ['123.'])) # egybe(1,2)
-    self.state = 999
-    return ('!', sols)
-
-# # # end class RuleJeloletlenTargyas # # #    
-
-
-class RuleJeloletlenHatarozos(SpellingRuleBase):
-  """
-     Név: jelöletlen határozós összetételek (kód: M_EK_JELOLETLEN_TARGYAS) (AkH. 123., OH. 104.)
-     
-     Feladat: jelöletlen határozós összetételek helyesírása
-     
-     Erőforrás: morfológiai elemzők (MA)
-     
-     Azonosító jegyek: 1:{FN, MN, HA, INF, HI} + 2:{FN, MN, HA, MIF, MIB, HI} + (3:{FN, MN})?
-     
-     Működés: 
-     
-     if(1 + 2) { % határozós alárendelés
-        egybe(1,2) % jelöletlen határozós alárendelő összetétel mindig egybe
-        }
-        
-    Ezután meg kell vizsgálni, esetleg a 6:3-as szabály miatt nem kell-e kötőjel.
-     
-     @author: LZS
-  """
-  @staticmethod  
-  def match(inp):
-    if len(inp) != 2:
-      return False
-    match1 = inp[0].matchPoSSequence('FN,NOM') and inp[1].hasLexProp('HatarozosMelleknev')
-    #match2 = inp[0].matchPoSSequence('((FN(,PSe3)?|MN),NOM|HA|NU|IK|((IK,)?IGE(,_MUV)?,(_HIN|INF)))') and inp[1].matchPoSSequence('MN,NOM|HA|((IK,)?IGE,((_MIB|_IF|Me3)|_HIN(,.*))?)?')
-    match2 = inp[0].matchPoSSequence('((FN(,PSe3)?|MN),NOM|HA|NU|IK|((IK,)?IGE(,_MUV)?,(_HIN|INF)))') and inp[1].matchPoSSequence('MN,NOM|HA|(IK)?IGE,(_MIB|_IF|HIN)?')
-    match3 = WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('HatarozosJeloletlenKivetel')
-    match4 = WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('HatarozoiIgeneviElotag')
-    
-#    print(match1)
-#    print(match2)
-#    print(match3)
-#    print(match4)
-#    
-    if inp[0].matchPoSSequence('FN,NOM') and inp[1].matchPoSSequence('IGE,_OKEP,NOM') and inp[1].matchPoSSequence('FN,NOM') and not match3: # -ó/-ő igeképzős utótagúak általában tárgyasak, nem határozósak
-      return False
-  
-    if not (match1 or match2 or match3 or match4):
-      return False
-  
-#    if not (WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('AllSzokapcs')):
-#      return False
-#    if not (inp[0].matchPoSSequence('FN,NOM') and inp[1].hasLexProp('HatarozosMelleknev')):
-#      return False
-#    if not (inp[0].matchPoSSequence('((FN(,PSe3)?|MN),NOM|HA|NU|((IK,)?IGE(,_MUV)?,(_HIN|INF)))')):
-#      return False
-#    if not (inp[1].matchPoSSequence('MN,NOM|HA|((IK,)?IGE,((_OKEP|_MIB|_IF|Me3)|_HIN(,.*))?)?')):
-#      return False   
-
-#      if ((inp[0].hasLexProp('Folk') or inp[0].hasLexProp('Major')) and (inp[1].hasLexProp('Folk') or inp[1].hasLexProp('Major'))): # nép, nyelv, szaknév
-#        return False 
-#    if (inp[0].hasLexProp('AgeGroup') or inp[0].hasLexProp('Emphasis') or inp[0].hasLexProp('Folk') or inp[0].hasLexProp('Major') or inp[0].hasLexProp('Material')): # kort jelolő főnév, nyomatékosító főnév
-#      return False
-
-
-    if WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('Alanyos'):
-      return False
-    return True
-    
-    
-  def getId(self):
-    return "M_EK_JELOLETLEN_HATAROZOS"
-  
-  def getName(self): 
-    return "Jelöletlen határozós összetételek (kód: M_EK_JELOLETLEN_HATAROZOS) (AkH. 125., OH. 105--107.)"    
-
-  def communicate(self, message=[]):
-    sols = [] 
-    firstLetter0 = Wordform.Phonology.CV(self.inp[0].wordform[0])
-    det0 = 'a' if firstLetter0 == 'C' else 'az'
-    dict = [('enni', 'aranyos', 'étel'), ('csapni', 'rossz, silány', 'lecsapandó'), ('égetni', 'nagyon gonosz', 'égetendő')]
-    meaning1 = '?'
-    meaning2 = '?'
-    if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('HatarozosJeloletlenKivetel'):
-      sols.append(([''], 'A jelöletlen határozós összetételt mindig egybeírjuk (esetleg kötőjellel, amennyiben érvényesül a szótagszámlálási szabály).', ['125. c)'])) # egybe(1,2)
-    elif self.inp[0].matchPoSSequence('(IK,)?IGE(,_MUV)?,INF') and self.inp[1].wordform == 'való':
-      if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('MelleknevValo') and WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('Rogzult'):
-        if self.state == 0:
-          self.state = 1
-#          for item in dict:
-#            tmp = [s for s in item if self.inp[0].wordform in s]
-#            tmp2 = ''.join(tmp)
-#            if item[0] == tmp2:
-#              meaning1 = item[1]
-#              meaning2 = item[2]
-          return ('?', ('Válasszon a lehetőségek közül!', 
-                        #[('1', "A szó egy melléknév, jelentése: '" + meaning1 + "'."),
-                        [('1', "A szó egy melléknév, jelentése: '" + WordInfo(self.inp[0].wordform + self.inp[1].wordform).lex().RogzultDef1.encode('utf-8') + "'."),
-                        ('2', "A szó főnévi értékben szerepel, jelentése: '" + WordInfo(self.inp[0].wordform + self.inp[1].wordform).lex().RogzultDef2.encode('utf-8') + "'."),
-                        ('3', "A szerkezet jelentése: '" + det0 + ' ' + applyseparators(self.inp, [' ']) + "' [valami] (nem főnévi értékben szerepel a szerkezet egésze).")]))
-        elif self.state == 1:
-          if message == '1':
-            sols.append(([''], 'Ha a -való utótagú kifejezés egésze melléknévi értékben szerepel, és az elő- és utótag jelentése együttesen más, mint külön-külön, a kifejezést egybeírjuk.', ['136.']))
-            self.state = 999
-            return ('!', sols)
-          elif message == '2':
-            sols.append(([''], 'Ha a szerkezet egésze főnévi értékben szerepel, összetételként egybe kell írni.', ['136.']))
-            self.state = 999
-            return ('!', sols)
-          elif message == '3':
-            sols.append(([' '], 'Ha az elő- és utótag jelentése együttesen ugyanaz, mint külön-külön (azaz nincs jelentésváltozás), a kifejezést különírjuk.', ['136.']))
-            self.state = 999
-            return ('!', sols)
-          else:
-            return (None, 'Hiba!')
-      else:       
-        if self.state == 0:
-          self.state = 1
-          return ('?', ('A szerkezet egésze főnévi értékben szerepel? Melyik kifejezéshez hasonlít jobban?',
-                         [('1', applyseparators(self.inp, ['']) + ' (a szerkezet egésze főnévi értékben szerepel)'),
-                          ('2', det0 + ' ' + applyseparators(self.inp, [' ']) + ' [valami] (nem főnévi értékben szerepel a szerkezet egésze)')]))
-        elif self.state == 1:
-          if message == '1':
-            sols.append(([''], 'Ha a szerkezet egésze főnévi értékben szerepel, összetételként egybe kell írni.', ['136.'])) 
-            self.state = 999
-            return ('!', sols)
-          elif message == '2':
-            sols.append(([' '], 'Ha a szerkezet egésze nem főnévi értékben szerepel, külön kell írni.', ['136.']))
-            self.state = 999
-            return ('!', sols)
-        else:
-          return (None, 'Hiba!') 
-#    elif WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('HatarozosKettosJelentes'):
-#      if self.state == 0:
-#        self.state = 1
-#        return ('?', ('Az elő- és utótag jelentése együttesen ugyanaz, mint külön-külön (azaz nincs jelentésváltozás)?', [('1', 'Igen, ugyanaz, nincs jelentésváltozás.'), ('2', 'Nem ugyanaz, van jelentésváltozás.')]))
-#      elif self.state == 1:
-#        if message == '1':
-#          sols.append(([' '], 'Ha az elő- és utótag jelentése együttesen ugyanaz, mint külön-külön (azaz nincs jelentésváltozás), a kifejezést különírjuk.', ['']))
-#          self.state = 999
-#          return ('!', sols)
-#        elif message == '2':
-#          sols.append(([''], 'Ha az elő- és utótag jelentése együttesen más, mint külön-külön (azaz jelentésváltozás van), a kifejezést különírjuk.', ['']))
-#          self.state = 999
-#          return ('!', sols)
-#        else:
-#          return (None, 'Hiba!') 
-    elif WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('Rogzult'):
-      if self.state == 0:
-        self.state = 1
-        return ('?', ('Válasszon a lehetőségek közül!',
-                            [('1', "'" + WordInfo(self.inp[0].wordform + self.inp[1].wordform).lex().RogzultDef1.encode('utf-8') + "'"),
-                             ('2', "'" + WordInfo(self.inp[0].wordform + self.inp[1].wordform).lex().RogzultDef2.encode('utf-8') + "'")]))
-      elif self.state == 1:
-        if message == '1':
-          sols.append(([''], 'Ha az elő- és utótag jelentése együttesen más, mint külön-külön (azaz jelentésváltozás van), a kifejezést különírjuk.', ['']))
-          self.state = 999
-          return ('!', sols)
-        elif message == '2':
-          sols.append(([' '], 'Ha az elő- és utótag jelentése együttesen ugyanaz, mint külön-külön (azaz nincs jelentésváltozás), a kifejezést különírjuk.', ['']))
-          self.state = 999
-          return ('!', sols)
-        else:
-          return (None, 'Hiba!') 
-        
-    elif self.inp[0].matchPoSSequence('IGE,_HIN') and self.inp[1].matchPoSSequence('IGE(,.*)') and not WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('HatarozoiIgeneviElotag'):
-      sols.append(([' '], 'Ha határozói vagy főnévi igenévi szófajú a bővítmény, a határozói viszony jelöletlen. A szerkezet különírandó különírandók.', [''], ['105.'])) # OH. 105.
-    elif self.inp[0].matchPoSSequence('(IK,)?IGE,INF') and self.inp[1].matchPoSSequence('IGE(,.*)'):
-      sols.append(([' '], 'Ha határozói vagy főnévi igenévi szófajú a bővítmény, a határozói viszony jelöletlen. A szerkezet különírandó különírandók.', [''], ['105.'])) # OH. 105.
-    elif self.inp[0].matchPoSSequence('HA') and self.inp[1].matchPoSSequence('IGE,(_OKEP|_HIN|_IF)?'): # hanyatt fekszik, de hanyatt fekve -- nem jó
-      sols.append(([' '], 'Nem összetételről, hanem határozószói bővítményű szószerkezetről van szó, amelyet különírunk. ', [''],['105.'])) # OH. ?
- 
-         
-    elif self.inp[0].hasLexProp('Occupation') and self.inp[1].wordform == 'jelölt':
-      sols.append(([''], 'A jelöletlen határozós összetételt mindig egybeírjuk (esetleg kötőjellel, amennyiben érvényesül a szótagszámlálási szabály).', ['125.']))     
-    elif self.inp[0].matchPoSSequence('((IK,)?IGE(,_MUV)?,(_HIN|INF))') and self.inp[1].matchPoSSequence('(IK,)?,IGE,e3'):
-      sols.append(([' '], 'Ha a határozói bővítmény szófaját tekintve főnévi vagy határozói igenév, illetőleg határozószó, általában különírást alkalmazunk.', [''], ['105.'])) # OH. 105.
-    else:
-      sols.append(([''], 'A jelöletlen határozós összetételt mindig egybeírjuk (esetleg kötőjellel, amennyiben érvényesül a szótagszámlálási szabály).', ['125. c)'])) # egybe(1,2)
-    
-    self.state = 999
-    return ('!', sols)
-
-# # # end class RuleJeloletlenHatarozos # # #
-
-class RuleJeloletlenBirtokosJelzos(SpellingRuleBase):
-  """
-     Név: jelöletlen birtokos jelzős összetételek (kód: M_EK_JELOLETLEN_BIRTOKOS) (AkH. 128., OH. 119.)
-     
-     Feladat: jelöletlen birtokos jelzős összetételek helyesírása
-     
-     Erőforrás: morfológiai elemzők (MA)
-     
-     Azonosító jegyek: 1:{FN.NOM} + 2:{(FN|(IGE,_IF))}
-     
-     Működés: 
-     
-     if(1 + 2) { % birtokos jelzős alárendelés
-        egybe(1,2) % jelöletlen birtokos jelzős alárendelő összetétel mindig egybe
-        }
-        
-    Ezután meg kell vizsgálni, esetleg a 6:3-as szabály miatt nem kell-e kötőjel.
-     
-     @author: LZS
-  """
-  @staticmethod  
-  def match(inp):
-    if len(inp) != 2:
-      return False
-    if inp[0].matchPoSSequence('IGE,_OKEP,NOM') and inp[0].matchPoSSequence('FN,NOM'):
-      return False # letiltjuk a foly. melléknévi igeneves szerkezetnél a birtokos jelzős összetételes elemzést
-    if not (inp[0].matchPoSSequence('FN,NOM')):
-      return False
-#    if not (inp[1].matchPoSSequence('(FN([^,PSe3])|(IGE,_IF),NOM)')):
-#      return False
-    if not (inp[1].matchPoSSequence('((FN|((IK,)?IGE,_IF)),NOM)')):
-      return False
-     
-#    if not (inp[1].hasPoSCase('(FN|(IGE,_IF),NOM)')):
-#      return False
-#    if (inp[0].hasLexProp('AgeGroup') or inp[0].hasLexProp('Emphasis') or inp[0].hasLexProp('Folk') or inp[0].hasLexProp('Major') or inp[0].hasLexProp('Occupation') or inp[0].hasLexProp('Material')): # kort jelolő főnév, nyomatékosító főnév
-#      return False
-    return True
-  
-  def getId(self):
-    return "M_EK_JELOLETLEN_BIRTOKOS"
-  
-  def getName(self): 
-    return "Jelöletlen birtokos jelzős összetételek (kód: M_EK_JELOLETLEN_BIRTOKOS) (AkH. 128., OH. 119.)"
-
-  def communicate(self, message=None):
-    sols = []
-    sols.append(([''], 'A jelöletlen birtokos jelzői összetételt mindig egybeírjuk (esetleg kötőjellel, amennyiben érvényesül a szótagszámlálási szabály).', ['128. c)'])) # egybe(1,2)
-    self.state = 999
-    return ('!', sols)
-
-# TODO: 3 tagú inputok? nyomás-térfogat diagram, csirke far-hát --> ezek 3. mozgószabállyal írandók
-# bug: fél kilences --> jelöletlen birtokosként elemzi, pedig nem az
-
-# # # end class RuleJeloletlenBirtokos # # #
-
-class RuleJeloletlenMinosegjelzos(SpellingRuleBase):
-  """
-  @author: LZS
-  """
-  @staticmethod  
-  def match(inp):
-    if len(inp) not in [2,3]:
-      return False
-    if len(inp) == 3:
-      if not inp[0].matchPoSSequence('HA'):
-        return False
-      if not (inp[1].matchPoSSequence('(IGE,(_OKEP|_MIB)|FN(,_IKEP|,_SKEP)|MN),NOM')):
-        return False
-      if not (inp[2].matchPoSSequence('FN(,_UKEP)?|MN|SZN|HA')):
-        return False
-    if len(inp) == 2:
-      if not (inp[0].matchPoSSequence('(IGE,(_OKEP|_MIB)|FN(,_IKEP|,_SKEP)|MN),NOM')): # csak FN,_UKEP, önmagában fn nem
-        return False
-      if not (inp[1].matchPoSSequence('FN(,_UKEP)?|MN|SZN|HA')): 
-        return False
-      if WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('Alanyos'):
-        return False
-      if WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('AllSzokapcs'):
-        return False
-    return True
-
-  def getId(self):
-    return "M_EK_JELOLETLEN_MINOSEGJELZOS"
-  
-  def getName(self): 
-    return "Jelöletlen minőségjelzős összetételek (kód: M_EK_JELOLETLEN_MINOSEG) (AkH. 107., OH. 107-111.)"
-
-  def communicate(self, message=[]):
-    sols = []
-    adj = 'kicsi' if self.inp[0].wordform == 'kis' else self.inp[0].wordform
-    FirstLetter0 = Wordform.Phonology.CV(self.inp[0].wordform[0])
-    det0 = 'A' if FirstLetter0 == 'C' else 'Az'
-    FirstLetter1 = Wordform.Phonology.CV(self.inp[1].wordform[0])
-    det1 = 'A' if FirstLetter1 == 'C' else 'Az'
-    dat = 'nak' if self.inp[0].getHarmony() == True else 'nek'
-    
-    if len(self.inp) == 2:
-        if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('MinosegjelzosHagyomany'):
-          sols.append(([''], 'A kialakult szokást megtartva jelentésváltozás nélkül is egybeírjuk számos minőségjelzős kapcsolat tagjait.', ['107. c)']))
-          self.state = 999
-          return ('!', sols)
-        elif WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('Rogzult'):
-          if self.state == 0:
-            self.state = 1 
-            return ('?', ('Válassza ki a megfelelő jelentést!',
-                            [('1', "'" + WordInfo(self.inp[0].wordform + self.inp[1].wordform).lex().RogzultDef1.encode('utf-8') + "'"),
-                             ('2', "'" + WordInfo(self.inp[0].wordform + self.inp[1].wordform).lex().RogzultDef2.encode('utf-8') + "'")]))
-          elif self.state == 1:
-            if message == '1':
-              sols.append(([''], 'Ha a tagok együttes jelentése más, mint az előtag és az utótag jelentésének összege, a minőségjelzős összetételt egybeírjuk.', ['107. b)']))
-              self.state == 999
-              return ('!', sols)
-            elif message == '2':
-              sols.append(([' '], 'Ha a tagok együttes jelentése nem más, mint az előtag és az utótag jelentésének összege, a minőségjelzős szerkezetet különírjuk.', ['107. a, b)']))
-              self.state == 999
-              return ('!', sols)
-            else:
-              return(None, 'Hiba!')
-        elif self.inp[0].hasLexProp('Folk') and self.inp[1].wordform == 'barát':
-          if self.state == 0:
-            self.state = 1
-            return ('?', ('Válasszon a lehetőségek közül!', [('1', "'" + self.inp[0].wordform + " nemzettel rokonszenvező személy'"), ('2', "'" + self.inp[0].wordform + " nemzetiségű ismerős vagy szerzetes'")]))
-          elif self.state == 1:
-            if message == '1':
-              sols.append(([''], "Ha a kifejezés jelentése '" + self.inp[0].wordform + " nemzettel rokonszenvező személy', akkor a kifejezés egybeírandó.", ['?']))
-              self.state = 999
-              return ('!', sols)
-            elif message == '2':
-              sols.append(([' '], "Ha a kifejezés jelentése '" + self.inp[0].wordform + " nemzetiségű ismerős vagy szerzetes', akkor a kifejezés egybeírandó.", ['?']))
-              self.state = 999
-              return ('!', sols)
-            else:
-              return (None, 'Hiba!')
-        elif self.inp[0].hasLexProp('Folk') and self.inp[1].wordform == 'könyv':
-          if self.state == 0:
-            self.state = 1
-            return ('?', ('Válasszon a lehetőségek közül!', [('1', "'" + self.inp[0].wordform + " nyelvi tankönyv'"), ('2', "'(bármilyen) " + self.inp[0].wordform + " nyelvű könyv'")]))
-          elif self.state == 1:
-            if message == '1':
-              sols.append(([''], "Ha a kifejezés jelentése '" + self.inp[0].wordform + " nyelvi tankönyv', akkor a kifejezés egybeírandó.", ['?']))
-              self.state = 999
-              return ('!', sols)
-            elif message == '2':
-              sols.append(([' '], "Ha a kifejezés jelentése '(bármilyen) " + self.inp[0].wordform + " nyelvű könyv', akkor a kifejezés egybeírandó.", ['?']))
-              self.state = 999
-              return ('!', sols)
-            else:
-              return (None, 'Hiba!')
-        elif self.inp[0].hasLexProp('Folk') and self.inp[1].wordform == 'óra':
-          if self.state == 0:
-            self.state = 1
-            return ('?', ('Válasszon a lehetőségek közül!', [('1', "'" + self.inp[0].wordform + " nyelvi tanóra'"), ('2', "'" + self.inp[0].wordform + " gyártmányú óra'")]))
-          elif self.state == 1:
-            if message == '1':
-              sols.append(([''], "Ha a kifejezés jelentése '" + self.inp[0].wordform + " nyelvi tanóra', akkor a kifejezés egybeírandó.", ['?']))
-              self.state = 999
-              return ('!', sols)
-            elif message == '2':
-              sols.append(([' '], "Ha a kifejezés jelentése '" + self.inp[0].wordform + " gyártmányú óra', akkor a kifejezés egybeírandó.", ['?']))
-              self.state = 999
-              return ('!', sols)
-            else:
-              return (None, 'Hiba!')
-        elif self.inp[0].hasLexProp('Folk') and self.inp[1].wordform == 'tanár':
-          if self.state == 0:
-            self.state = 1
-            return ('?', ('Az adott nyelv a tanár szaktárgya, vagy pedig olyan nemzetiségű az adott tanár?', [('1', 'Szaktárgya.'), ('2', 'Nemzetisége.')]))
-          elif self.state == 1:
-            if message == '1':
-              sols.append(([''], 'Ha a nyelv a tanár szaktárgyát jelenti, akkor a kifejezés egybeírandó.', ['?']))
-              self.state = 999
-              return ('!', sols)
-            elif message == '2':
-              sols.append(([' '], 'Ha a nyelv a tanár nemzetiségét jelenti, a kifejezés különírandó.', ['?']))
-              self.state = 999
-              return ('!', sols)
-            else:
-              return (None, 'Hiba!')
-        elif self.inp[0].matchPoSSequence('FN,_SKEP,NOM') and self.inp[1].hasLexProp('Container'):
-          if self.state == 0:
-            self.state = 1
-            return ('?', ('Válasszon a lehetőségek közül!',
-                          [('1', 'Valamit tartalmazó, valamivel szennyezett '+ self.inp[1].wordform + '.'),
-                           ('2', 'Valaminek a felszolgálására, fogyasztására vagy tárolására használt, szokásosan meghatározott méretű és formájú '+ self.inp[1].wordform + '.')]))
-    
-          elif self.state == 1:
-            if message == '2':
-              if self.inp[0].getNCompParts() > 1:
-                sols.append(([' '], 'Ha a jelző összetétel, az alakulatot különírjuk.', ['OH. 108.']))
-                self.state == 999
-                return ('!', sols)
-              else:
-                sols.append(([''], 'Ha az utótag jelentése »valami tartására, tárolására szolgáló (edény)féle«, és sem a jelző, sem a jelzett szó nem összetétel, az alakulatot egybeírjuk.', [''], ['108.'])) # OH. 108.
-                self.state == 999
-                return ('!', sols)
-            elif message == '1':
-              sols.append(([' '], 'Ha nem tároló funkciót lát el az utótagot alkotó fogalom, a kifejezés különírandó.', [''], ['108.'])) # OH. 108.
-              self.state == 999
-              return ('!', sols)
-        if (self.inp[0].wordform == 'kis' and self.inp[1].hasLexProp('Animal')):
-          if self.state == 0:
-            self.state = 1
-            return ('?', ('Válasszon a lehetőségek közül!',
-                          [('1', 'Fiatal ' + self.inp[1].wordform + '.'),
-                           ('2', det1 + ' ' + self.inp[1].wordform + ' mérete ' + adj + '.')]))
-          elif self.state == 1:
-            if message == '1':
-              sols.append(([''], det0 + ' "' + self.inp[0].wordform + '" előtagú minőségjelzős kapcsolatok egy része jelentésváltozás miatt egybeírandó, köztük a "' + self.inp[0].wordform + self.inp[1].wordform +'" is.', [''], ['108--111.'])) # OH. 108--111.
-            elif message == '2':
-              sols.append(([' '], 'Ha a tagok együttes jelentése nem más, mint az előtag és az utótag jelentésének összege, a minőségjelzős szerkezetet különírjuk.', ['107. a, b)'])) 
-        
-        elif WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('FeketeFeherKisNagyEgybe'):
-          if self.state == 0:
-            self.state = 1
-            if (self.inp[0].wordform == 'fehér' or self.inp[0].wordform == 'fekete') and self.inp[1].hasFinalPoS('FN'):
-              return ('?', ('Válasszon a lehetőségek közül!',
-                          [('1', 'Egy speciális ' + self.inp[1].wordform + '.'),
-                           ('2', det1 + ' ' + self.inp[1].wordform + ' ' + self.inp[0].wordform + ' színű(nek tűnik).')]))
-            elif (self.inp[0].wordform == 'kis' or self.inp[0].wordform == 'nagy') and self.inp[1].hasFinalPoS('FN'):
-              return ('?', ('Válasszon a lehetőségek közül!',
-                          [('1', 'Egy speciális ' + self.inp[1].wordform + '.'),
-                           ('2', det1 + ' ' + self.inp[1].wordform + ' mérete ' + adj + '.')]))
-#            elif self.inp[1].matchPoSSequence('FN,_UKEP,NOM'):
-#              meaning1 = ''
-#              meaning2 = ''
-#              for item in dict:
-#                #print(item[2][0])
-#                firstLetterInp = Wordform.Phonology.CV(item[2][0])
-#                detInp1 = 'a' if firstLetterInp == 'C' else 'az'
-#                if self.inp[0].wordform == 'kis' or self.inp[0].wordform == 'nagy':
-#                  tmp3 = 'mérete'
-#                elif self.inp[0].wordform == 'fehér' or self.inp[0].wordform == 'fekete':
-#                  tmp3 = 'színe'
-#                else:
-#                  tmp3 = ''
-#                #tmp3 = 'mérete' if (self.inp[0].wordform == 'kis' or self.inp[0].wordform == 'nagy') else 'színe' if (self.inp[0].wordform == 'kis' or self.inp[0].wordform == 'nagy') else ''
-#                tmp = [s for s in item if self.inp[1].wordform in s]
-#                tmp2 = ''.join(tmp)
-#                if item[0] == tmp2:
-#                  meaning1 = item[1]
-#                  meaning2 = detInp1 + ' ' + item[2] + ' ' + tmp3 + ' ' + self.inp[0].wordform
-#                  return ('?', ('Válasszon a lehetőségek közül!',
-#                            [('1', "A szó jelentése: '" + meaning1 + "'."), 
-#                             ('2', "A szó jelentése: '" + meaning2 + "'.")]))
-              sols.append(([''], 'Összetételről lévén szó a kifejezés egybeírandó.', [''], ['110--111.'])) # OH. 110--111.
-            else:
-    #          return ('?', ('A tagok együttes jelentése más, mint az előtag és az utótag jelentésének összege?',
-    #                      [('1', 'Igen, más, jelentésváltozás van.'),
-    #                       ('2', 'Nem más, nincs jelentésváltozás.')]))
-              sols.append(([''], 'Összetételről lévén szó a kifejezés egybeírandó.', [''])) # OH. 110--111.
-          elif self.state == 1:
-            if message == '1':
-              sols.append(([''], det0 + ' "' + self.inp[0].wordform + '" előtagú minőségjelzős kapcsolatok egy része jelentésváltozás miatt egybeírandó, köztük a "' + self.inp[0].wordform + self.inp[1].wordform +'" is.', [''], ['108--111.'])) # OH. 108--111.
-            elif message == '2':
-              sols.append(([' '], 'Ha a tagok együttes jelentése nem más, mint az előtag és az utótag jelentésének összege, a minőségjelzős szerkezetet különírjuk.', ['107. a, b)']))
-        elif WordInfo(self.inp[0].wordform + ' ' + self.inp[1].wordform).hasLexProp('FeketeFeherKisNagyKulon'):
-          sols.append(([' '], det0 + ' "' + self.inp[0].wordform + '" előtagú minőségjelzős kapcsolatok tagjait bizonyos állandósult szókapcsolatokban különírjuk egymástól.', [''], ['108--111.'])) # OH. 108--111.
-          self.state == 999
-          return ('!', sols)
-        else:
-          sols.append(([' '], 'A minőségjelzős kapcsolatok tagjait általában különírjuk egymástól, különösen olyankor, ha a kapcsolatnak valamelyik vagy mindkét tagja összetett szó.', ['107. a)']))
-          self.state == 999
-          return ('!', sols)
-    #    elif len(self.inp) == 3:
-    #      if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('FeketeFeherKisNagyEgybe') and self.inp[2].wordform == 'bűnözés':  
-    #        pass 
-        self.state = 999
-        return ('!', sols)
-
-    if len(self.inp) == 3:
-      sols = []
-      sols.append(([' ', ' '], 'A minőségjelzős kapcsolatok tagjait általában különírjuk egymástól, ha határozót tartalmaz.', ['?']))
-      self.state = 999
-      return ('!', sols)
-# # # end class RuleJeloletlenMinosegjelzos # # # 
-    
-  
-
-class RuleJelentessurito(SpellingRuleBase):
-  """
-  @author: LZS
-  """
-  @staticmethod  
-  def match(inp):
-    if len(inp) != 2:
-      return False
-    if not (WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('Jelentessurito') and inp[0].matchPoSSequence('(FN|MN),NOM') and inp[1].matchPoSSequence('(FN(,_UKEP|,_SKEP)?|MN),NOM')):
-      return False
-#    if not (inp[0].matchPoSSequence('FN,NOM') and inp[1].matchPoSSequence('FN,NOM')):
-#      return False
-    return True
-
-
-  def getId(self):
-    return "M_EK_JELENTESSURITO"
-  
-  def getName(self): 
-    return "Jelentéssűrítő összetételek (kód: M_EK_JELENTESSURITO) (AkH. 129., OH. 119--120."
-
-  def communicate(self, message=None):
-    sols = []
-    sols.append(([''], 'Az olyan összetett szavakat, amelyek elő- és utótagja között bonyolultabb kapcsolat van, jelentéssűrítő összetételeknek nevezzük. Ezeket mindig egybeírjuk.', 
-                 ['129.']))
-    self.state = 999
-    return ('!', sols)
-
-# # # RuleJelentessurito # # #
-
-class RuleJeloltTargyas(SpellingRuleBase):   
-  """
-    Név: jelölt tárgyas alárendelések (kód: M_EK_JELOLT_TARGYAS), (AkH. 123., OH. 104.)
-
-    Feladat: jelölt tárgyas összetételek egybe vagy külön
-
-    Erőforrás: morfológiai elemzők (MA), jelölt tárgyas alárendelések kivétellistája (LIST1, OH. 104. o.)
-    
-    Azonosító jegyek: 1:{(FN(.PSe3)?|MN|SZN|NM).ACC} + 2:{IGE, INF, MIN, HI}
-    Példák: idejétmúlt (a bővítményen [főnév] birtokos személyjel; nagyothall (a bővítmény melléknév), ellentmond (a bővítmény névutó).
-    
-    Működés:
-    
-    if(1 + 2) { % tárgyas alárendelés
-      if (1 + 2) in(LIST1) { % ilyen nagyon kevés van
-        egybe(1,2)
-    }
-    else {
-      kulon(1,2)
-    }
-  }
-    
-    @author: LZS
-  """
-    
-  @staticmethod  
-  def match(inp):
-    if len(inp) != 2:
-      return False
-    if not (inp[0].matchPoSSequence('(FN(,PSe3)?|MN|SZN|NM|(FN\|NM)),ACC') or WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('JeloltTargyas')):
-      return False
-    if not (inp[1].matchPoSSequence('(IK,)?IGE(,INF|_OKEP|_HI|_MIB|_IF)?(,.*)')):
-      return False
-    return True
-
-  def getId(self):
-    return "M_EK_JELOLT_TARGYAS"
-  
-  def getName(self): 
-    return "Jelölt tárgyas összetételek (kód: M_EK_JELOLT_TARGYAS) (AkH. 123., OH. 104.)"
-
-  def communicate(self, message=None):
-    sols = []
-    if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('Rogzult'):
-      if self.state == 0:
-        self.state = 1
-        return ('?', ('Válassza ki a megfelelő jelentést!',
-                            [('1', "'" + WordInfo(self.inp[0].wordform + self.inp[1].wordform).lex().RogzultDef1.encode('utf-8') + "'"),
-                             ('2', "'" + WordInfo(self.inp[0].wordform + self.inp[1].wordform).lex().RogzultDef2.encode('utf-8') + "'")]))
-      elif self.state == 1:
-        if message == '1':
-          sols.append(([' '], 'Ha az elő- és utótag jelentése együttesen ugyanaz, mint külön-külön (azaz nincs jelentésváltozás), a kifejezést különírjuk.', ['?']))
-          self.state = 999
-          return ('!', sols)
-        elif message == '2':
-          sols.append(([''], 'Ha az elő- és utótag jelentése együttesen más, mint külön-külön (azaz jelentésváltozás van), a kifejezést különírjuk.', ['?']))
-          self.state = 999
-          return ('!', sols)
-        else:
-          return (None, 'Hiba!') 
-    elif WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('JeloltTargyas'):
-      sols.append(([''], 'A raggal jelölt tárgyas kapcsolatok túlnyomó többsége különírandó, eltekintve néhány kivételtől, ahol jelentésváltozás van, és/vagy a tárgyas viszony meglehetősen elhomályosult. Ellenőrizze, hogy konkrét vagy átvitt értelemben használja a szót!', ['123'])) # egybe(1,2
-    #elif not WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('JeloltTargyas'):
-    else:
-      sols.append(([' '], 'A raggal jelölt tárgyas kapcsolatok túlnyomó többsége különírandó.', ['123'])) # kulon(1,2)
-    self.state = 999
-    return ('!', sols)
-
-# TODO: nagyothall <--> nagyot hall -- kellene visszakérdezés
-
-# # # end class RuleJeloltTargyas # # #
-
-class RuleJeloltHatarozos(SpellingRuleBase):
-  """
-  
-    Név: jelölt határozós alárendelések AkH. 125., OH. 105--107.
-
-    Feladat: jelölt határozós összetételek egybe vagy külön
-
-    Erőforrás: morfológiai elemzők (MA), állandósult szókapcsolatokból képzett hagyományos összetételek kivétellistája (határozós)(LIST2) --> OH.-ban megvan (105--106. oldal)
-    
-    Azonosító jegyek:
-
-    Határozói alárendelés: 1:{(FN|MN).DAT, INE, ILL, SUP, DEL, SUB, ADE, ABL, ALL, TER, FOR, FAC, INS, CAU, ESSMOD, TEM, SOC, MUL, _NTA/_NTE, _LAG/_LEG} + 2:{IGE, FN, MN, SZN, HA} // A Humor nem ismer fel néhány módahatározóragot, pl. az ismétlődő időhatározói ragot (-anta/-ente) és a mód-állapot határozói ragot (-lag/-leg).
-    
-    @author: LZS
-  """
-  
-  @staticmethod  
-  def match(inp):
-    if len(inp) != 2:
-      return False
-    if not (inp[0].matchPoSSequence('(((FN|MN(,_FOK)?|SZN|(FN\|NM))(,PSe3)?,(DAT|INE|ILL|SUP|DEL|SUB|ADE|ABL|ALL|TER|FOR|FAC|INS|CAU|_ESSMOD|TEM|SOC|MUL|_NTA/_NTE|_LAG/_LEG)))')): # |IK nem kell a végére
-      return False
-    if not (inp[1].matchPoSSequence('((IK,)?IGE|FN|MN|SZN|HA)(,.*)')):
-      return False
-    return True
-  
-  def getId(self):
-    return "M_EK_JELOLT_HATAROZOS"
-  
-  def getName(self): 
-    return "Jelölt határozós összetételek (kód: M_EK_JELOLT_HATAROZOS) (AkH. 125., OH. 105--107.)"
-
-  def communicate(self, message=[]):
-    sols = []
-    if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('AllSzokapcs'):
-      sols.append(([''], 'A raggal jelölt határozós összetételek egy részét egybeírjuk (jelentésváltozás vagy a hagyomány miatt).', ['125. b, d)']))
-    elif WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('Rogzult'):
-      if self.state == 0:
-        self.state = 1
-        return ('?', ('Válassza ki a megfelelő jelentést!',
-                            [('1', "'" + WordInfo(self.inp[0].wordform + self.inp[1].wordform).lex().RogzultDef1.encode('utf-8') + "'"),
-                             ('2', "'" + WordInfo(self.inp[0].wordform + self.inp[1].wordform).lex().RogzultDef2.encode('utf-8') + "'")]))
-      elif self.state == 1:
-        if message == '1':
-          sols.append(([' '], 'Ha az elő- és utótag jelentése együttesen ugyanaz, mint külön-külön (azaz nincs jelentésváltozás), a kifejezést különírjuk.', ['?']))
-          self.state = 999
-          return ('!', sols)
-        elif message == '2':
-          sols.append(([''], 'Ha az elő- és utótag jelentése együttesen más, mint külön-külön (azaz jelentésváltozás van), a kifejezést különírjuk.', ['?']))
-          self.state = 999
-          return ('!', sols)
-        else:
-          return (None, 'Hiba!')
-    else:
-      sols.append(([' '], 'A valamilyen raggal jelölt határozós kapcsolatok tagjait (az állandó szókapcsolatokban is) általában különírjuk egymástól, különösen akkor, ha a kapcsolatnak valamelyik vagy mindkét tagja összetett szó.', ['125. a)']))
-    self.state=999
-    return ('!', sols)
-
-# # # end class RuleJeloltHatarozos # # #
-  
-class RuleJeloltBirtokos(SpellingRuleBase):   
-  """
-    @author: LZS
-  """
-  @staticmethod  
-  def match(inp):
-    if len(inp) != 2:
-      return False
-    if not (inp[0].matchPoSSequence('(FN|(FM\|NM))(,DAT)?') and inp[1].matchPoSSequence('(((FN|MN),PSe3,NOM)|(FN\|NM))')):
-      return False
-#    elif not (inp[0].matchPoSSequence('(FN|(FM\|NM))') and inp[1].matchPoSSequence('(FN,PSe3,NOM)')):
-#      return False
-    if WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('Alanyos'):
-      return False
-    return True
-  
-  def getId(self):
-    return "M_EK_JELOLT_BIRTOKOS"
-  
-  def getName(self): 
-    return "Jelölt birtokos jelzős összetételek (kód: M_EK_JELOLT_BIRTOKOS) (AkH. 123., OH. 119.)"
-
-  def communicate(self, message=None):
-    sols = []
-    if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('Rogzult'):
-      if self.state == 0:
-        self.state = 1
-        return ('?', ('Válassza ki a megfelelő jelentést!',
-                            [('1', "'" + WordInfo(self.inp[0].wordform + self.inp[1].wordform).lex().RogzultDef1.encode('utf-8') + "'"),
-                             ('2', "'" + WordInfo(self.inp[0].wordform + self.inp[1].wordform).lex().RogzultDef2.encode('utf-8') + "'")]))
-      elif self.state == 1:
-        if message == '1':
-          sols.append(([''], 'A raggal jelölt birtokos jelzős kapcsolatokból keletkezett összetételek egybeírandók, ha az elő- és utótag jelentése együttesen más, mint külön-külön.', ['128. b)']))
-        elif message == '2':
-          sols.append(([' '],'A birtokszón a birtokviszonyra utaló birtokos személyjellel és/vagy a birtokoson -nak/-nek raggal jelölt kapcsolatok tagjait általában különírjuk egymástól.', ['128. a)']))
-    elif WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('JeloltBirtokos1'):
-      sols.append(([''],'A kialakult szokást megtartva jelentésváltozás nélkül is egybeírjuk néhány jelölt birtokos jelzős kapcsolat tagjait.', ['128. d)']))
-    else:
-      sols.append(([' '],'A birtokszón a birtokviszonyra utaló birtokos személyjellel és/vagy a birtokoson -nak/-nek raggal jelölt kapcsolatok tagjait általában különírjuk egymástól.', ['128. a)']))
-    self.state=999
-    return ('!', sols)
-
-# # # end class RuleJeloltBirtokos # # #
-
-class RuleMennyisegjelzosSzerkezet(SpellingRuleBase):   
-  """
-    Név: mennyiségjelzős kapcsolatok (kód: M_EK_MENNYISEG) (AkH. 117--119.)
-
-    Feladat: mennyiségjelzős kapcsolatok egybe vagy külön
-
-    Erőforrás: morfológiai elemzők (MA), határozatlan számnevek listája (LIST)
-
-    Azonosító jegyek: 1:{(HA|FN.INS)*} + 2:{("több mint")*} + 3:{SZN.NOM, SZN.NOM && in(LIST), DIGIT} + 4:{(FN._IKEP, _SKEP|MN)*} + 5:{FN._IKEP, _SKEP, _UKEP} vagy 1:{(HA|FN.INS)*} + 2:{("több mint")*} + 3:{SZN.NOM, SZN.NOM && in(LIST), DIGIT} + 4:{(FN._IKEP|MN)*} + 5:{FN._DIS, _NTA} vagy 1:{(HA|FN.INS)*} + 2:{("több mint")*} + 3:{SZN.NOM, SZN.NOM && in(LIST)} + 4:{(FN._IKEP|MN)*} + 5:{SZN.(_SKEP)?}
-    Megjegyzés:
-
-    Az utolsónál az a lényeg, hogy egy mennyiségjelzős összetétel lehet olyan is, hogy minden összetételi tagja számnév. Ilyenkor az utótag -s képzős is lehet, ezt szemlélteti az utolsó eset az azonosító jegyeknél. Pl.: húszezres, hárommilliárdos. Ezeknél jelentéskülönbség van az egybeírt és különírt alak között.
-    Az azonosító jegyeknél az 1., 2. és 4. tag opcionális. Az 1. tag lehet határozószó (pl. alig) vagy -val/-vel képzős melléknév (pl. kicsivel). A 2. tag a "több mint". A 4. tag az alaptag minőségjelzői bővítménye lehet
-    (pl. alkaioszi strófás -> öt alkaioszi strófás).
-
-    Működés:
-
-    if(exists(1) || exist(2) || exists(4)) { % Ha a leírandó kifejezés legalább 3 szóból áll, azaz valamelyik tag egy szókapcsolat, akkor külön kell írni.
-      kulon(1,2,3,4,5)
-    }
-
-    else { % A leírandó kifejezés 2 tagból áll.
-
-     if (3==DIGIT) { % pl. 30 napos
-       kulon(3,5)
-     }
-     else if (3==osszetett || 5==osszetett) { % pl. egy szótagos, tizenhét emeletes, tizenöt naponként
-       kulon(3,5)
-     }
-     else { % pl. harmincnapi, ötágú, háromhavonként, húszezres ('bankjegy')
-       if(5==SZN.(_SKEP)?) {
-         kerdezd: "A leírt kifejezés egy időpont? Pl. fél kilenc, negyed tízes...
-         if(igen) {
-          kulon(3,5)
-         }
-         kerdezd: "A leírt kifejezés melyikhez áll közelebb? 1. húszezres tartozás, 2. húsz ezres ('húsz darab bankjegy'); 1. hárommilliárdos (hiány), 2. három milliárdos ('három gazdag ember')" 
-       }
-       egybe(3,5)
-     }
-
-    }
-
-    
-    @author: LZS
-  """
-    
-  @staticmethod  
-  def match(inp):
-    if len(inp) not in [2, 3, 4]:
-      return False
-    if len(inp) == 4:
-      match = inp[0].wordform == 'több' and inp[1].wordform == 'mint' and inp[2].matchPoSSequence('SZN,NOM') and inp[3].matchPoSSequence('((FN,(_IKEP|_SKEP|_UKEP|_NTA|_DIS|_MER))|SZN)(,.)*')
-      if not match:
-        return False
-    if len(inp) == 3:
-      match1 = inp[0].matchPoSSequence('SZN,NOM') and inp[1].matchPoSSequence('((FN,(_IKEP|_SKEP|_UKEP|_NTA|_DIS|_MER))|SZN)(,.)*') and inp[2].matchPoSSequence('FN,NOM')
-      match2 = inp[0].matchPoSSequence('SZN,ADE') and inp[1].matchPoSSequence('SZN,_FOK,NOM') and inp[2].matchPoSSequence('((FN,(_IKEP|_SKEP|_UKEP|_NTA|_DIS|_MER))|SZN)(,.)*')
-      match3 = inp[0].matchPoSSequence('SZN') and inp[1].matchPoSSequence('(FN,(_IKEP|_SKEP)|MN),NOM') and inp[2].matchPoSSequence('(FN,(_IKEP|_SKEP|_UKEP|_NTA|_DIS|_MER))')
-      match4 = inp[0].matchPoSSequence('HA') and inp[1].matchPoSSequence('SZN,NOM') and inp[2].matchPoSSequence('(FN,(_IKEP|_SKEP|_UKEP|_NTA|_DIS|_MER))')
-      match5 = inp[0].matchPoSSequence('SZN(,_FOK)?,NOM') and inp[0].hasLexProp('NumeralIndef') and inp[1].matchPoSSequence('SZN,NOM') and inp[2].matchPoSSequence('(FN,(_IKEP|_SKEP|_UKEP|_NTA|_DIS|_MER))')
-      if not (match1 or match2 or match3 or match4 or match5):
-        return False
-    elif len(inp) == 2:
-      if not(inp[0].matchPoSSequence('SZN(,FOK)?|(SZN\|DIGIT)(,SZN\|DIGIT)*,NOM')):
-        return False
-      if not(inp[1].matchPoSSequence('((FN,(_IKEP|_SKEP|_UKEP|_NTA|_DIS|_MER)?)|SZN)(,.)*')):
-        return False
-    return True
-  
-
-  def getId(self):
-    return "M_EK_MENNYISEG"
-  
-  def getName(self): 
-    return "Mennyiségjelzős kapcsolatok (kód: M_EK_MENNYISEG) (AkH. 117--119.)"
-
-  def communicate(self, message=[]):
-    sols = []
-    if len(self.inp) == 2:
-      if (self.inp[0].matchPoSSequence('(SZN\|DIGIT)(,SZN\|DIGIT)*,NOM')):
-        sols.append(([' '], 'Ha a számnévi előtagot számjeggyel írjuk, a kifejezés mindig különírandó.', ['119']))
-      elif (WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('MennyJelzKivetel')):
-        if self.state == 0:
-          self.state = 1
-         
-          return ('?', ('Válasszon a lehetőségek közül!',
-                        [('1', 'A két tag együtte jelentése más, mint az előtag és az utótag jelentésének összege: "' + applyseparators(self.inp, ['']) + '".'),
-                        ('2', 'A kifejezés jelentése: ' + self.inp[0].wordform + ' darab ' + self.inp[1].wordform + ' vagy ' + self.inp[0].wordform + ' fő ' + self.inp[1].wordform + '.')]))
-        elif self.state == 1:
-          if message == '1':
-            sols.append(([''], 'Ha a tagok együttes jelentése más, mint az előtag és az utótag jelentésének összege, szóösszetételről van szó, egybeírást alkalmazunk.', ['107. b)']))
-          elif message == '2':
-            sols.append(([' '], ' A mennyiségjelzős kapcsolatok tagjait általában különírjuk egymástól.', ['117. a)']))
-      elif (self.inp[0].matchPoSSequence('(SZN,)?SZN,_TORT,NOM') or self.inp[0].wordform == 'fél') and self.inp[1].matchPoSSequence('SZN,_SKEP,NOM'):
-        sols.append(([' '], 'Az órát jelölő kapcsolatokat különírjuk.', [''], ['119.'])) # OH. 119.
-      elif (self.inp[0].matchPoSSequence('SZN,NOM') and self.inp[1].matchPoSSequence('SZN,_SKEP,NOM') and self.inp[1].matchPoSSequence('FN,NOM')):
-        if self.state == 0:
-          self.state = 1
-          return ('?', ('Az utótag milyen jelentésben szerepel?',
-                        [('1', applyseparators(self.inp, ['']) + ' bankjegy, ' + applyseparators(self.inp, ['']) + ' tartozás'),
-                        ('2', self.inp[0].wordform + ' darab ' + self.inp[1].wordform) ]))
-        elif self.state == 1:
-          if message == '1':
-            sols.append(([''], 'Egy egyszerű tőszámnévnek és egy -s képzős egyszerű melléknévnek a kapcsolatát egybeírjuk.'
-            , ['119.']))
-          elif message == '2':
-          #print('2')
-            sols.append(([' '], 'A mennyiségjelzős kapcsolatok tagjait általában különírjuk egymástól.', ['117. a)']))
-            # TODO: három tízezres, három milliárdos --> pyhuana.udc-ben kéne a megfelelő elemzés
-      elif (self.inp[1].matchPoSSequence('(FN,(_IKEP|_SKEP|_UKEP|_NTA|_DIS|_MER))')):
-        if (self.inp[0].getNCompParts() >= 2 or self.inp[1].getNCompParts() >= 2):
-          sols.append(([' '], 'Ha a jelzett szó vagy a számnévi jelző, vagy akár mindkettő összetett szó, a szerkezetet különírjuk.', ['119']))
-        else:
-          sols.append(([''], 'Egy egyszerű tőszámnévnek (ill. a sok, több, fél számnévnek), valamint egy -i, -ú, -ű, -jú, -jű, -s, -nyi képzős egyszerű melléknévnek a kapcsolatát egybeírjuk. Hasonlóképpen írjuk az -nként ragos alakulatokat is.'
-        , ['119']))
-      elif (self.inp[0].matchPoSSequence('SZN,NOM') and self.inp[1].matchPoSSequence('SZN,NOM')):
-        return (None, 'Ha mind az előtag, mind az utótag számnév, nem a mennyiségjelzős kapcsolatokra vonatkozó szabályt kell alkalmazni. Használja a "Számnevek helyesírása" funkciót!')
-      elif (self.inp[1].matchPoSSequence('(FN|SZN),NOM')):
-        sols.append(([' '], ' A mennyiségjelzős kapcsolatok tagjait általában különírjuk egymástól; különösen olyankor, ha a kapcsolat valamelyik vagy mindkét tagja összetett szó.', ['117. a)']))
-    elif len(self.inp) == 3: 
-      if self.inp[0].matchPoSSequence('SZN') and self.inp[1].matchPoSSequence('(FN,(_IKEP|_SKEP)|MN),NOM') and self.inp[2].matchPoSSequence('(FN,(_IKEP|_SKEP|_UKEP|_NTA|_DIS|_MER))'):
-        sols.append(([' ', ' '], 'Ha a kifejezés legalább három szóból áll, akkor vagy az előtag vagy az utótag szókapcsolat, tehát mindent külön szóba írunk.', ['?']))
-      elif self.inp[0].matchPoSSequence('SZN,ADE') and self.inp[1].matchPoSSequence('SZN,_FOK,NOM') and self.inp[2].matchPoSSequence('((FN,(_IKEP|_SKEP|_UKEP|_NTA|_DIS|_MER))|SZN)(,.)*'):
-        sols.append(([' ', ' '], 'Ha a kifejezés legalább három szóból áll, akkor vagy az előtag vagy az utótag szókapcsolat, tehát mindent külön szóba írunk.', ['?']))
-      elif self.inp[0].matchPoSSequence('HA') and self.inp[1].matchPoSSequence('SZN,NOM') and self.inp[2].matchPoSSequence('(FN,(_IKEP|_SKEP|_UKEP|_NTA|_DIS|_MER))'):
-        sols.append(([' ', ' '], 'Ha a kifejezés legalább három szóból áll, akkor vagy az előtag vagy az utótag szókapcsolat, tehát mindent külön szóba írunk.', ['?']))
-      elif self.inp[0].matchPoSSequence('SZN') and self.inp[1].matchPoSSequence('((FN,(_IKEP|_SKEP|_UKEP|_NTA|_DIS|_MER))|SZN)(,.)*') and self.inp[2].matchPoSSequence('FN,NOM'):    
-        if self.state == 0:
-          self.state = 1
-          inp1 = self.inp[1].getNominalStem()
-          return ('?', ('Válasszon a lehetőségek közül!',
-                          [('1', self.inp[0].wordform + ' darab ' + inp1),
-                           ('2', self.inp[0].wordform + ' darab ' + self.inp[2].wordform)]))
-          #sols.append(([' ', ' '], 'Ha a kifejezés legalább három szóból áll, akkor vagy az előtag, vagy az utótag szókapcsolat, tehát különírandó.', ['119'])) # kulon(1,2
-        elif self.state == 1:
-          if message == '1':
-            if self.inp[0].getNCompParts() > 1 or self.inp[1].getNCompParts() > 1:
-              sols.append(([' ', ' '], 'Minőségjelzős szerkezet...', ['?']))
-            else:
-              sols.append((['', ' '], 'Egy egyszerű tőszámnévnek (ill. a sok, több, fél számnévnek), valamint egy -i, -ú, -ű, -jú, -jű, -s, -nyi képzős egyszerű melléknévnek a kapcsolatát egybeírjuk. Hasonlóképpen írjuk az -nként ragos alakulatokat is.'
-              , ['119']))
-          elif message == '2':
-            sols.append(([' ', ' '], 'Minőségjelzős szerkezet...', ['?']))
-      elif self.inp[0].matchPoSSequence('SZN(,_FOK)?,NOM') and self.inp[0].hasLexProp('NumeralIndef') and self.inp[1].matchPoSSequence('SZN,NOM') and self.inp[2].matchPoSSequence('(FN,(_IKEP|_SKEP|_UKEP|_NTA|_DIS|_MER))'):
-         if self.state == 0:
-           self.state = 1
-           return ('?', ('Válasszon a lehetőségek közül!',
-                         [('1', applyseparators(self.inp, [' ', '']) + " '" + self.inp[0].wordform + ' olyan valami, amely ' + self.inp[1].wordform + self.inp[2].wordform + "'" ),
-                          ('2', applyseparators(self.inp, [' ', ' ']) + " 'olyan valami, amely " + self.inp[0].wordform + ' ' + self.inp[1].wordform + ' ' + self.inp[2].wordform + "'" )]))
-         elif self.state == 1:
-          if message == '1':
-            sols.append(([' ', ''], 'Minőségjelzős szerkezet...', ['?']))
-          elif message == '2':
-            sols.append(([' ', ' '], 'Minőségjelzős szerkezet...', ['?']))
-    
-    elif len(self.inp) == 4:
-      sols.append(([' ', ' ', ' '], 'Ha a kifejezés legalább három szóból áll, akkor vagy az előtag vagy az utótag szókapcsolat, tehát mindent külön szóba írunk.', ['?']))
-    elif len(self.inp) == 5:
-      sols.append(([' ', ' ', ' ', ' '], 'jkljljlk', ['119']))
-    self.state = 999
-    return ('!', sols)
-
-# # # end class RuleMennyisegjelzosSzerkezet # # #
-
-class RuleFoneviJelzosSzerkezet(SpellingRuleBase):
-  """
-  Név: főnévi jelzős szerkezetek (kód: M_EK_FONEVI_JELZO) (AkH. 114., OH. 114--117.)
-
-  Feladat: Ha az alaptag jelzője főnévi szófajú, akkor is különírjuk a jelzőt a jelzett szótól.
-
-  Erőforrások: morfológiai elemző, foglalkozások listája (LIST1) (van!), kort jelölő főnevek listája (amelyek lehetnek melléknevek is, LIST2, pl. gyermek, nyugdíjas) (nincs!), nyomatékosításra használt főnevek listája (zsír, tök), illetve jellemző utótagok listája (alakú, formájú; néni, úr, LIST3) --> Készítettem egy kezdetleges listát: [[http://salmon.nytud.hu/Nyti/projects/helyesiras/eroforrasok/listak/utotagok.txt/vview]]
-
-  És még kell egy kivétellista is, amely azokat a szóösszetételeket tartalmazza, amelyek egyik összetételi tagja tipikus főnévi jelzős szerkezeti elő- vagy utótag (pl. betűnagyságú, idényjellegű, ajándékkártya). (LIST4) (Csináltam OH. alapján: [[http://salmon.nytud.hu/Nyti/projects/helyesiras/eroforrasok/listak/fonevi-jelzos-szerk-kivetellista.txt/view]] )
-
-  Azonosító jegyek: 1:{FN in(LIST1|LIST2|LIST3)}, 2:{FN} vagy 1:{FN}, 2:{MN, FN in(LIST3)}
-
-  Működés:
-
- if (1,2) in(LIST4) {
-   egybe(1,2)
- }
- else {
-   kulon(1,2)
- }
-    @author: LZS
-  """
-  
-  @staticmethod  
-  def match(inp):
-    if len(inp) not in [2, 3]:
-      return False
-    if len(inp) == 2:
-      if inp[1].matchPoSSequence('IGE,(_IF|_OKEP),NOM'): # _MIB-et is le lehetne tiltani, de: férfi alkalmazott
-        return False
-      if not (inp[0].matchPoSSequence('.*(FN|MN),NOM')):
-        return False
-      if not (inp[1].matchPoSSequence('.*(FN(,_UKEP)?(,.*)?|MN),(NOM|INE)')):
-        return False
-#      if not (inp[0].wordform == 'férfi' or inp[0].wordform == 'ajándék'):
-#        return False
-      if not ((inp[0].hasLexProp('EgyebFoneviJelzo') or inp[0].hasLexProp('AgeGroup') or inp[0].hasLexProp('Emphasis') or inp[0].hasLexProp('Folk') or inp[0].hasLexProp('Major') or inp[0].hasLexProp('Occupation')) or inp[1].hasLexProp('FoneviJelzosSzerkAlaptag')): # kort jelolő főnév, nyomatékosító főnév
-        return False
-
-    if len(inp) == 3:
-      if not (inp[0].matchPoSSequence('.*(FN|MN|SZN),NOM')):
-        return False
-      if not (inp[1].matchPoSSequence('.*(FN|MN),NOM')):
-        return False
-      if not (inp[2].matchPoSSequence('.*(FN(,_UKEP)?(,.*)?|MN),NOM')):
-        return False
-    return True
-  
-  def getId(self):
-    return "M_EK_FONEVI_JELZO"
-  
-  def getName(self): 
-    return "Főnévi jelzős szerkezetek (kód: M_EK_FONEVI_JELZO) (AkH. 114., OH. 114--117.)"
-
-  def communicate(self, message=[]):
-    sols = []
-    FirstLetter0 = Wordform.Phonology.CV(self.inp[0].wordform[0])
-    FirstLetter1 = Wordform.Phonology.CV(self.inp[1].wordform[0])
-    det1 = 'A' if FirstLetter0 == 'C' else 'Az'
-    det2 = 'A' if FirstLetter1 == 'C' else 'Az'
-    if len(self.inp) == 2:
-#      if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('FoneviJelzosSzerk'):
-#        sols.append(([''], '??', ['OH. 115.']))
-      if self.inp[0].wordform == 'ajándék' or self.inp[0].wordform == 'férfi':
-        if self.inp[0].wordform == 'férfi' and self.inp[1].wordform == 'fodrász':
-          if self.state == 0:
-            self.state = 1
-            return ('?', ('Mit jelent a kifejezés?', [('1', 'Férfiakat kiszolgáló fodrász.'), ('2', 'Hímnemű fodrász.')]))
-          elif self.state == 1:
-            if message == '1':
-              sols.append(([''], 'A főnévi jelző jelentéssűrítő viszonyban van az utótaggal, jelentéssűrítő összetételről van szó, a kifejezést egybeírjuk.', [''], ['115.'])) # OH. 115.
-            elif message == '2':
-              sols.append(([' '], 'Főnévi jelzős szerkezetről lévén szó, a kifejezést különírjuk.', [''], ['115.'])) # OH. 115.
-            self.state = 999
-            return ('!', sols)
-        elif WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('FoneviJelzosSzerk'):
-          sols.append(([''], det1 + ' "' + self.inp[0].wordform + '" főnévi előtag és az utótag között birtokos jelzős vagy jelentéssűrítő viszony van, a kifejezés egybeírandó.',
-                       [''], ['114--115.'])) # OH. 114--115.
-        else:
-          sols.append(([' '], det1 + ' "' + self.inp[0].wordform + '" ebben az esetben főnévi jelző, a szerkezet különírandó.',
-                       [''], ['115.'])) # OH. 115.
-        self.state = 999
-        return ('!', sols)
-      elif self.inp[1].hasLexProp('FoneviJelzosSzerkAlaptag'):
-        if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('Jelentessurito'):
-          sols.append(([''], 'Ha a főnévi előtag birtokos jelzős vagy jelentéssűrítő viszonyt alkot az utótaggal, egybeírást alkalmazunk.',
-                       [''], ['115.'], ['115.'])) # OH. 115.
-          self.state = 999
-          return ('!', sols)
-        elif self.inp[1].wordform == 'értékű':
-          if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('Erteku'):
-            sols.append(([''], 'A főnévi előtag az "értékű" utótaggal jelentéssűrítő összetételt hoz létre, ezért egybeírást alkalmazunk.',
-                         [''], ['116.'])) # OH. 116.
-            self.state = 999
-            return ('!', sols)
-          else:
-            sols.append(([' '], 'Az "értékű" melléknév elsősorban a pénzbeli értékek megnevezésekor alkot szószerkezetet a főnévi jelzővel: "(tízezer) forint értékű". Egyéb: "negyedhang értékű".', [''], ['116.'])) # OH. 116.
-            self.state = 999
-            return ('!', sols)
-        elif self.inp[1].wordform == 'alapú':
-          if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('Alapu'):
-            sols.append(([''], 'Ha az "alapú" melléknév fő összetevőt jelöl, vagy átvitt értelmű, egybeírást alkalmazunk.',
-                         [''], ['116.'])) # OH. 116.
-            self.state = 999
-            return ('!', sols)  
-          elif WordInfo(self.inp[0].wordform + '-' + self.inp[1].wordform).hasLexProp('Alapu'):
-            sols.append((['-'], 'Ha az "alapú" melléknév fő összetevőt jelöl, vagy átvitt értelmű, egybeírást alkalmazunk.',
-                         [''])) # OH. 116.
-            self.state = 999
-            return ('!', sols)  
-          else:
-            if self.state == 0:
-              self.state = 1
-              return ('?', ('Az "alapú" melléknév valaminek a formájára utal, vagy pedig fő összetevőt jelöl, esetleg átvitt értelemben szerepel?', [('1', 'A formájára utal.'), ('2', 'Fő összetevőt jelöl, vagy átvitt értelemben szerepel.')]))
-            elif self.state == 1:
-              if message == '1':
-                sols.append(([' '], 'Ha az "alapú" melléknév valaminek a formájára utal, különírjuk a főnévi jelzőtől. Pl. "négyzet alapú", "képi séma alapú".',
-                         [''])) # OH. 116.
-                self.state = 999
-                return ('!', sols)
-              elif message == '2':
-                sols.append(([''], 'Ha az "alapú" melléknév fő összetevőt jelöl, vagy átvitt értelmű, egybeírást alkalmazunk.',
-                         [''])) # OH. 116.
-                self.state = 999
-                return ('!', sols)
-            # TODO: DNS-alapú
-        elif self.inp[1].wordform == 'értelmű' or self.inp[1].wordform == 'értelemben' or self.inp[1].wordform == 'jelentésű' or self.inp[1].wordform == 'jelentésben':
-          if self.state == 0:
-            self.state = 1
-            return ('?', ('A "' + self.inp[1].wordform + '" alak metanyelvi értékű, azaz a jelentést adja meg?', [('1', 'Igen, metanyelvi értékű, a jelentést adja meg.'), ('2', 'Nem metanyelvi értékű, nem a jelentést adja meg.')]))
-          elif self.state == 1:
-            if message == '1':
-              sols.append(([' '], 'A "' + self.inp[1].wordform + '" alak előtt mindig különírjuk a főnévi jelzőt, ha az metanyelvi értékű.',
-                         [''], ['116.'])) # OH. 116.
-            elif message == '2':
-              sols.append(([''], '******* egybeírást alkalmazunk.',
-                         [''], ['116.'])) # OH. 116.
-              self.state = 999
-              return ('!', sols)
-#        elif self.inp[1].wordform == 'alakú' or self.inp[1].wordform == 'alakban':
-#          sols.append(([' '], 'Az "' + self.inp[1].wordform + '" szó gyakran főnévi minőségjelzős szerkezet alaptagja. A főnevet -- ha megnevező értékű -- különírjuk az alaptagtól.',
-#                       ['OH. 115.']))
-#          self.state = 999
-#          return ('!', sols) 
-        else:
-          sols.append(([' '], det2 + ' "' + self.inp[1].wordform + '" szó gyakran főnévi minőségjelzős szerkezet alaptagja. A főnevet -- ha megnevező értékű -- különírjuk az alaptagtól.',
-                       [''], ['115.'])) # OH. 115.
-          self.state = 999
-      
-      elif self.inp[0].hasLexProp('Emphasis') and self.inp[1].matchPoSSequence('MN'):
-        sols.append(([' '], 'A nyomatékosításra használt főnevet is (csuda, kutya, marha stb.) különírjuk a jelzett szótól.'
-                 , ['114']))
-        
-      elif self.inp[0].hasLexProp('EgyebFoneviJelzo'):
-        if self.inp[0].wordform == 'játék':
-          if self.state == 0:
-            self.state = 1
-            return ('?', ('Válasszon a lehetőségek közül!',
-                          [('1', "Jelentése: 'gyermekeknek való, nem igazi " + self.inp[1].wordform + "'."),
-                           ('2', 'Egyéb jelentés.')]))
-          elif self.state == 1:
-            if message == '1':
-              sols.append(([' '], 'A főnévi jelzőket külön kell írni a jelzett szótól.', ['114.']))
-          elif message == '2':
-            return (None, 'Nem főnévi jelzős szerkezetről van szó.')
-        else:
-          if self.state == 0:
-            self.state = 1
-            return ('?', ('Válasszon a lehetőségek közül!',
-                        [('1', det2 + ' ' + self.inp[1].wordform + ' ' + self.inp[0].wordform + '.'),
-                         ('2', 'Másról van szó. Az összetételi tagok között más (jelentéssűrítő vagy birtokos jelzői) alárendelő viszony van.')]))
-          elif self.state == 1:
-            if message == '1':
-              sols.append(([' '], 'A főnévi jelzőket külön kell írni a jelzett szótól.', ['114.']))
-            elif message == '2':
-              return (None, 'Nem főnévi jelzős szerkezetről van szó.')
-              
-      else:
-        if not WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('Jelentessurito'):
-          sols.append(([' '], 'A foglalkozást, kort, minőséget, csoportot jelölő főnévi jelzőket külön kell írni a jelzett szótól. Ugyanígy a nyomatékosításra használt főneveknél is (csuda, kutya, marha stb.).'
-                 , ['114']))
-        else:
-          return (None, 'Hiba!')                                                                     
-    if len(self.inp) == 3:
-      if WordInfo(self.inp[0].wordform + '-' + self.inp[1].wordform + self.inp[2].wordform).hasLexProp('FoneviJelzosSzerk'):
-        sols.append((['-', ''], '??', [''], ['115.'])) # OH. 115.
-        
-    self.state = 999
-    return ('!', sols)
-
-# # # end class RuleFoneviJelzosSzerkezet # # #
-
-
-
-class RuleGyujtonevek(SpellingRuleBase):
-  """
-    Név: embercsoportok (AkH. 167--168., OH. 170., 220.)
-
-    Feladat: Gyűjtőnévi közszó + egy tulajdonnév összekapcsolásakor egybeírjuk vagy kötőjellel.
-
-    Erőforrások: vezetéknevek listája (LIST1), keresztnevek listája (LIST2), gyűjtőnévi közszók listája (LIST3) (Nincs ilyen!)
-
-    Azonosító jegyek: 1:{in(LIST1)} + 2:{in(LIST2)}? + 3:{in(LIST3)}
-
-    Működés: Az, hogy kötőjellel kapcsoljuk-e a gyűjtőnévi közszói utótagot a tulajdonnévi előtaghoz, attól függ, hogy felvett/kapott tulajdonnévről van-e szó, vagy pedig az illető tulajdonnév viselője az adott csoport vezetője. Ezt gépi módszerekkel eldönteni nem tudjuk, meg kell kérdezni a felhasználót.
-
-    print("(1+(2)?) a (3)-at vezető személy?")
-    if (igen) {
-      kotojel(1+(2)?,3) % Illés-együttes, Szemere-kormány
-    }
-    else {
-      kulon(1+(2)?,3) % Omega együttes, Kölcsey Ferenc olvasókör)
-    }
-
-
-    @author: LZS
-  """
-  
-  @staticmethod  
-  def match(inp):
-    if len(inp) not in [2, 3]:
-      return False
-    alaptag = 1 if len(inp) == 2 else 2 # index of the alaptag in inp
-    if not (inp[alaptag].matchPoSSequence('.*FN,NOM')):
-        return False
-    if len(inp) == 2: 
-      if not (inp[alaptag - 1].hasLexProp('FamilyName') or inp[alaptag - 1].hasLexProp('PersFirst')):
-        return False
-      if not inp[alaptag].hasLexProp('Group'):
-        return False
-    if len(inp) == 3:
-      if not (inp[alaptag - 2].hasLexProp('FamilyName') and inp[alaptag - 1].hasLexProp('PersFirst') and inp[alaptag].hasLexProp('Group')):
-        return False
-#      if not (inp[alaptag - 1].hasLexProp('PersFirst')):
-#        return False
-#      if not inp[alaptag].hasLexProp('Group'):
-#        return False
-    
-    return True
-
-  def getId(self):
-    return "M_EK_GYUJTONEVEK"
-  
-  def getName(self): 
-    return "Embercsoportok gyűjtőnévi jellegű szavai (kód: M_EK_GYUJTONEVEK) (AkH. 167--168., OH. 170., 220.)"
-
-  def communicate(self, message=[]):
-    sols = []
-    if len(self.inp) == 2:
-      if self.state == 0:
-        self.state = 1
-        return ('?', ('Az adott személy vezetője a csoportnak, vagy csupán elnevezték azt róla?', [('1', 'Vezetője.'), ('2', 'Nem vezetője, csak róla nevezték el.')]))
-      elif self.state == 1:
-        if message == '1':
-          sols.append((['-'], 'A gyűjtőnévi közszókat (család, nemzetség, együttes, párt stb.) kötőjellel kapcsoljuk a tulajdonnévhez, ha az a csoportot vezető személynek a neve.', ['168.']))
-          self.state = 999
-          return ('!', sols)
-        elif message == '2':
-          sols.append(([' '], 'A gyűjtőnévi közszókat (család, nemzetség, együttes, párt stb.) külírjuk a tulajdonnévtől, ha az egy felvett vagy kapott név, nem pedig a csoportot vezető személy neve.', ['167.']))
-          self.state = 999
-          return ('!', sols)      
-        else:
-          return (None, 'Hibauzi')
-    if len(self.inp) == 3:
-      if self.state == 0:
-        self.state = 1
-        return ('?', ('Az adott személy vezetője a csoportnak, vagy csupán elnevezték azt róla?', [('1', 'Vezetője.'), ('2', 'Nem vezetője, csak róla nevezték el.')]))
-      elif self.state == 1:
-        if message == '1':
-          sols.append(([' ', '-'], 'A gyűjtőnévi közszókat (család, nemzetség, együttes, párt stb.) kötőjellel kapcsoljuk a tulajdonnévhez, ha az a csoportot vezető személynek a neve.', ['168.']))
-          self.state = 999
-          return ('!', sols)
-        elif message == '2':
-          sols.append(([' ', ' '], 'A gyűjtőnévi közszókat (család, nemzetség, együttes, párt stb.) külírjuk a tulajdonnévtől, ha az egy felvett vagy kapott név, nem pedig a csoportot vezető személy neve.', ['167.']))
-          self.state = 999
-          return ('!', sols)      
-        else:
-          return (None, 'Hibauzi')
-    
-        
-    
-# # # end Class RuleFoneviJelzosSzerkezet # # #
-
-class RuleNagykotojel(SpellingRuleBase):
-  """
-    @author: LZS
-  """
-  
-  @staticmethod  
-  def match(inp):
-    if len(inp) not in [2, 6]:
-      return False
-    if len(inp) == 2:
-      if not (inp[0].hasLexProp('Folk') or inp[0].hasLexProp('Major') or inp[0].hasLexProp('isGeoSettlement')): # nép, nyelv, szaknév
-        return False
-      if not (inp[1].hasLexProp('Folk') or inp[1].hasLexProp('Major') or inp[1].hasLexProp('isGeoSettlement')): # nép, nyelv, szaknév
-        return False
-      if not (inp[0].matchPoSSequence('.*(FN|MN),NOM')):
-        return False 
-      if not (inp[1].matchPoSSequence('.*(FN|MN),NOM')):
-        return False
-    return True
-    
-  def getId(self):
-    return "M_EK_NAGYKOTOJEL"
-  
-  def getName(self): 
-    return "Nagykötőjellel írandó kifejezések (kód: M_EK_NAGYKOTOJEL) (AkH. 263., OH. 353--354.)"
-
-  def communicate(self, message=None):
-    sols = []
-    sols.append((['--'], 'Nagykötőjellel kapcsoljuk két vagy több nép (nyelv) nevének kapcsolatát, felsőoktatási szakpárokat, tulajdonnnevek kapcsolatát és tól-ig viszonyt kifejező szavakat.', ['263']))
-    # TODO: tulajdonnevek kapcsolata, tól-ig viszonyt kifejező szerkezetek
-    self.state = 999
-    return ('!', sols)
-
-# # # end class RuleNagykotojel # # #
-
-class RuleFolyamatosMellekneviIgenev(SpellingRuleBase):
-  """
-    @author: LZS
-  """
-  
-  @staticmethod  
-  def match(inp):
-#    if len(inp) not in [2, 3]:
-#      return False
-    if len(inp) != 2:
-      return False
-    alaptag = 1 if len(inp) == 2 else 2 # index of the alaptag in inp
-    #if alaptag == 1 and not (WordInfo(inp[alaptag - 1].wordform + inp[alaptag].wordform).hasLexProp('')
-    if alaptag == 1 and not ((inp[alaptag - 1].matchPoSSequence('(FN,)?(IK,)?IGE,(_MUV,)?_OKEP,NOM') or inp[alaptag - 1].hasLexProp('FolyamatosMellekneviIgenevFonevesult') or WordInfo(inp[alaptag - 1].wordform + inp[alaptag].wordform).hasLexProp('FolyamatosMellekneviIgenevHagyomany')) and inp[alaptag].matchPoSSequence('FN')):
-      return False
-    if alaptag == 2 and not (inp[alaptag - 2].matchPoSSequence('FN,NOM') and inp[alaptag - 1].matchPoSSequence('(FN,)?(IK,)?IGE,_OKEP,NOM') and inp[alaptag].matchPoSSequence('FN')):
-      return False # ? ütve fúró gép, gyorsan ölő méreg
-    return True
-  
-
-  def getId(self):
-    return "M_EK_FOLYAMATOS_MELLEKNEVI_IGENEV"
-  
-  def getName(self): 
-    return "Folyamatos melléknévi igenévi tagot tartalmazó kifejezések (kód: M_EK_FOLYAMATOS_MELLEKNEVI_IGENEV) (AkH. 112., OH. 113.)"
-
-  def communicate(self, message=[]):
-    
-    #print(self.inp[0].getNSyllables())  
-      
-    sols = []
-    alaptag = 1 if len(self.inp) == 2 else 2 # index of the alaptag in inp
-    FirstLetter0 = Wordform.Phonology.CV(self.inp[alaptag - 1].wordform[0])
-    Det0 = 'A' if FirstLetter0 == 'C' else 'Az'
-    firstLetter0 = Wordform.Phonology.CV(self.inp[alaptag - 1].wordform[0])
-    det0 = 'a' if firstLetter0 == 'C' else 'az'
-    FirstLetter1 = Wordform.Phonology.CV(self.inp[alaptag].wordform[0])
-    det1 = 'A' if FirstLetter1 == 'C' else 'Az'
-    _if = 'ás' if self.inp[alaptag - 1].getHarmony() == True else 'és'
-    if WordInfo(self.inp[alaptag - 1].wordform + self.inp[alaptag].wordform).hasLexProp('FolyamatosMellekneviIgenevHagyomany'):
-      sols.append(([''], 'Azok az összetett alaptagot tartalmazó szerkezetek, amelyekben az alaptag összetétel mivolta elhomályosult, egybeírandók. Ugyanígy néhány szóban az egybeírás pusztán írásszokáson alapul.', ['112.'])) # , OH. 114.
-    elif self.inp[alaptag].getNCompParts() > 1 or self.inp[alaptag - 1].getNCompParts() > 1: # 2==osszetett | 3==osszetett
-      if self.inp[alaptag - 1].hasLexProp('FolyamatosMellekneviIgenevFonevesult'):
-        if self.state == 0:
-          self.state = 1
-          return('?', (Det0 + ' "'+ self.inp[alaptag - 1].wordform + '" előtag főnevesült?',
-                       [('1', 'Igen, az előtag ("' + self.inp[alaptag - 1].wordform + '") itt főnév.'),
-                        ('2', 'Nem. Szófaja folyamatos melléknévi igenév.')]))
-        elif self.state == 1:
-          if message == '1':
-            sols.append(([''], 'Ha az -ó/-ő képzős melléknévi igenév főnevesült, a kifejezés egybeírandó.', [''], ['114.'])) # OH. 114.
-          elif message == '2':  
-            sols.append(([' '], 'Ha akár a jelző, akár a jelzett szó önmagában is összetett szó, illetőleg ha mindkét tag összetétel, a jelentésváltozás ellenére többnyire különírást alkalmazunk.', ['112.'])) # , OH. 113--114.
-      else:
-        sols.append(([' '], 'Ha akár a jelző, akár a jelzett szó önmagában is összetett szó, illetőleg ha mindkét tag összetétel, a jelentésváltozás ellenére többnyire különírást alkalmazunk.', ['112.'])) # , OH. 113--114.         
-    elif self.inp[alaptag].getNCompParts() == 1 and self.inp[alaptag - 1].getNCompParts() == 1: # 2==egyszeru & 3==egyszeru
-      if self.inp[alaptag - 1].hasLexProp('FolyamatosMellekneviIgenevFonevesult'):
-        sols.append(([''], 'Ha az -ó/-ő képzős melléknévi igenév főnevesült, a kifejezés egybeírandó.', ['?']))
-      elif self.state == 0:
-#        print('getHarmony')
-#        print(self.inp[0].getHarmony())
-        self.state = 1
-        return ('?', ('Az -ó/-ő képzős igenév folyamatra utal (alkalmi jelző), vagy pedig valamilyen képességre, rendeltetésre vonatkozik (jelentésváltozás van)?',
-                      [('1', det1 + ' "'+ self.inp[alaptag].wordform + '" éppen a cselekvést, tevékenységet végzi, esetleg a folyamatot átéli, elszenvedi. "' + det1 + ' ' + self.inp[alaptag].wordform + ' éppen ' + self.inp[alaptag - 1].getVerbLex() + '."'),
-                      ('2', 'Valamire rendeltetett, valamit általában, foglalkozásszerűen űz, nem vagy nem pusztán pillanatnyi cselekvést, tevékenységet végez, illetve folyamatot átél, elszenved. "' + det1 + ' ' + self.inp[alaptag].wordform + ' rendeltetése ' + det0 + ' ' + self.inp[alaptag - 1].getVerbalStem() + _if + '."'), # TODO -ás/-és képző illeszkedése
-                      ('3', 'Nem tudom eldönteni.'),   
-                      ('4', 'Egyik sem. ' + Det0 + ' "'+ self.inp[alaptag - 1].wordform + '" itt nem folyamatos melléknévi igenévi szófajú.')]))
-      elif self.state == 1:
-        if message == '1':
-          sols.append(([' '], 'Ha az -ó/-ő képzős igenév alkalmai jelző, a szerkezetet különírjuk.', ['112.']))
-        elif message == '2':
-          sols.append(([''], 'Ha az -ó/-ő képzős igenév nem alkalmi jelző, hanem valamilyen képességre, rendeltetésre vonatkozik, illetőleg ha a jelzős kapcsolat tagjai a jelentés alapján összeforrtak, egybeírást alkalmazunk.', ['112.'])) # , OH. 113.
-        elif message == '4':
-          return (None, 'Erre az esetre nem ez a szabály vonatkozik.') 
-        elif message == '3':
-          if self.state == 1:
-            self.state = 2
-            return ('?', ('Melyikhez hasonlít?', [('1', 'nevelőnő'), ('2', 'a gyermekét nevelő nő')]))
-      elif self.state == 2:
-        #print('self.state = 2')
-        if message == '1':
-          sols.append(([''], 'Ha az -ó/-ő képzős igenév nem alkalmi jelző, hanem valamilyen képességre, rendeltetésre vonatkozik, illetőleg ha a jelzős kapcsolat tagjai a jelentés alapján összeforrtak, egybeírást alkalmazunk.', ['112.'])) # , OH. 113.
-          self.state = 999
-          return ('!', sols)
-        elif message == '2':
-          sols.append(([' '], 'Ha az -ó/-ő képzős igenév alkalmai jelző, a szerkezetet különírjuk.', ['112.']))
-          self.state = 999
-          return ('!', sols)
-    
-    else:
-      self.state = 999
-      return (None, 'Az összetételi tagok számát nem lehetett meghatározni.')
-    self.state = 999
-    return ('!', sols)
-
-# # # end class RuleFolyamatosMellekneviIgenev # # # 
-
-
-class RuleBefejezettMellekneviIgenev(SpellingRuleBase):
-  """
-    @author: LZS
-  """
-  
-  @staticmethod  
-  def match(inp):
-    if len(inp) != 2:
-      return False
-    if not (inp[0].matchPoSSequence('.*IGE,_MIB,NOM') or (WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('BefejezettMellekneviIgenev'))):
-      return False
-    return True
-
-  def getId(self):
-    return "M_EK_BEFEJEZETT_MELLEKNEVI_IGENEV"
-  
-  def getName(self): 
-    return "Befejezetti melléknévi igenévi tagot tartalmazó kifejezések (kód: M_EK_BEFEJEZETT_MELLEKNEVI_IGENEV) (AkH. 113., OH. 114.)"
-
-  def communicate(self, message=None):
-    sols = []
-    if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('BefejezettMellekneviIgenev'):
-      sols.append(([''], 'Befejezett melléknévi igenévi jelzők esetén néhány kivételes alakot egybe kell írni. Ilyen esetekben jelentésváltozásról van szó.', ['113.']))
-    else:
-      sols.append(([' '], 'A befejezett melléknévi igenévi jelzős szerkezetek tipikusan (állandó vagy alkalmai) szókapcsolatok, tehát különírandók.', ['113.']))
-    self.state = 999
-    return ('!', sols)
-
-# # # end class RuleBefejezettMellekneviIgenev # # #
-
-
-class RuleRovidites(SpellingRuleBase):
-  """
-    @author: LZS
-  """
-  
-  @staticmethod  
-  def match(inp):
-    if len(inp) not in [2,3]:
-      return False
-    if len(inp) == 2:
-      if not (inp[0].hasLexProp('Abbr') or inp[1].hasLexProp('Abbr') or (inp[0].wordform[-1] == '.') or (inp[1].wordform[-1] == '.') or (inp[0].matchPoSSequence('((FN\|ROV\|VEGY)|(FN\|ME\|ROV)),NOM')) or (inp[0].matchPoSSequence('((FN\|ROV\|VEGY)|(FN\|ME\|ROV)),NOM'))):
-        return False
-
-    if len(inp) == 3:
-      if not (inp[0].hasLexProp('Abbr') or inp[0].matchPoSSequence('((FN\|ROV\|VEGY)|(FN\|ME\|ROV)),NOM') or inp[0].wordform[-1] == '.'):
-        return False
-    return True
-
-
-  def getId(self):
-    return "M_EK_ROVIDITES"
-  
-  def getName(self): 
-    return "Rövidítést tartalmazó összetételek (kód: M_EK_ROVIDITES) (AkH. 281., OH. 135--136.)"
-    
-  def communicate(self, message=[]):
-    sols = []
-    pattern = re.compile(u'[a-záéíóöőúüűA-ZÁÉÍÓÖŐÚÜŰ]+\.')
-    if len(self.inp) == 2:
-      if self.inp[0].hasLexProp('Abbr') or self.inp[0].matchPoSSequence('((FN\|ROV\|VEGY)|(FN\|ME\|ROV)),NOM'):
-        sols.append((['-'], 'Ha a rövidítés valamely teljes szóval alkot összetételt (mint előtag), az elő- és az utótagot kötőjellel fűzzük össze.', ['281.']))
-      elif self.inp[1].hasLexProp('Abbr'):
-        sols.append(([''], 'Ha a rövidítés összetétel utótagja, kötőjel nélkül kapcsolódik az előtaghoz, hiszen az összekapcsolás nem írásjelnél történik.', [''], ['136.'])) # OH. 136.
-      elif re.match(pattern, self.inp[0].wordform):
-        if self.state == 0:
-          self.state = 1
-          return ('?', ('Az előtag egy rövidítés?', [('1', 'Igen.'), ('2', 'Nem.')]))
-        elif self.state == 1:
-          if message == '1':
-            sols.append((['-'], 'Ha a rövidítés valamely teljes szóval alkot összetételt (mint előtag), az elő- és az utótagot kötőjellel fűzzük össze.', ['281.']))
-          elif message == '2':
-            return (None, 'Az előtag pontra végződik, és nem rövidítés. Ellenőrizze, hogy jól gépelte-e be a keresett szót!')
-      elif re.match(pattern, self.inp[1].wordform):
-        if self.state == 0:
-          self.state = 1
-          return('?', ('Az utótag egy rövidítés?', [('1', 'Igen.'), ('2', 'Nem.')]))
-        elif self.state == 1:
-          if message == '1':
-            sols.append(([''], 'Ha a rövidítés összetétel utótagja, kötőjel nélkül kapcsolódik az előtaghoz, hiszen az összekapcsolás nem írásjelnél történik.', [''], ['136.'])) # OH. 136.
-          elif message == '2':
-            return (None, 'Az utótag pontra végződik, és nem rövidítés. Ellenőrizze, hogy jól gépelte-e be a keresett szót!')
-      else:
-        self.state = 999
-        return (None, 'Hiba!')  
-    elif len(self.inp) == 3:
-      if re.match(pattern, self.inp[0].wordform):
-        if self.state == 0:
-          self.state = 1
-          return (('?', ('Az előtag egy rövidítés?', [('1', 'Igen.'), ('2', 'Nem.')])))
-        elif self.state == 1:
-          if message == '1':
-            sols.append((['-'], 'Ha a rövidítés valamely teljes szóval alkot összetételt (mint előtag), az elő- és az utótagot kötőjellel fűzzük össze.', ['281.']))
-          elif message == '2':
-            return (None, 'Az előtag pontra végződik, és nem rövidítés. Ellenőrizze, hogy jól gépelte-e be a keresett szót!')
-        
-      sols.append((['-', '-'], 'Ha a kifejezés kettőnél több tagból áll, az újabb összetételi tagokat is kötőjellel kapcsoljuk.', ['?']))
-    self.state = 999
-    return ('!', sols)
-
-# # # end class RuleRovidites # # #
-
-
-class RuleBetuszo(SpellingRuleBase):
-  """
-    @author: LZS
-  """
-  
-  @staticmethod  
-  def match(inp):
-    if len(inp) not in [2,3]:
-      return False
-    pattern = re.compile('[A-ZÁÉÍÓÖŐÚÜŰ]{2,}')
-    match0 = re.match(pattern, inp[0].wordform)
-    match1 = re.match(pattern, inp[1].wordform) 
-    if len(inp) == 2:
-      if not (match0 or match1 or inp[0].hasLexProp('KozszoiBetuszo') or inp[1].hasLexProp('KozszoiBetuszo') or inp[0].hasLexProp('KozszoiBetuszoKivetel') or inp[1].hasLexProp('KozszoiBetuszoKivetel')):
-        return False
-    if len(inp) == 3: 
-      if not (match0 or match1 or inp[0].hasLexProp('KozszoiBetuszo') or inp[1].hasLexProp('KozszoiBetuszo') or inp[0].hasLexProp('KozszoiBetuszoKivetel') or inp[1].hasLexProp('KozszoiBetuszoKivetel')): # 3. tag nem szokott betűszó lenni
-        return False
-    return True
-
-  def getId(self):
-    return "M_EK_BETUSZO"
-  
-  def getName(self): 
-    return "Betűszót tartalmazó összetételek (kód: M_EK_BETUSZO) (AkH. 287., OH. 136.)"
-    
-  def communicate(self, message=[]):
-    sols = []
-    pattern = re.compile('[A-ZÁÉÍÓÖŐÚÜŰ]{2,}')
-    if len(self.inp) == 2:
-      if self.inp[0].matchPoSSequence('(MN|(FN,_IKEP)|(IGE(,MIB|_OKEP)),NOM)') and self.inp[1].hasLexProp('KozszoiBetuszo'):
-        sols.append(([' '], 'Ha az előtag jelző, a köszói betűszói utótagot különírjuk.', ['?']))
-        self.state = 999
-        return ('!', sols)
-      elif self.inp[0].hasLexProp('KozszoiBetuszo') or self.inp[1].hasLexProp('KozszoiBetuszo'):
-        sols.append((['-'], 'A betűszókhoz és a tulajdonnévi szóösszevonásokhoz kötőjellel fűzzük az utótagot (esetleg előtagot).', ['287. a)']))
-        self.state = 999
-        return ('!', sols)
-      elif self.inp[0].hasLexProp('KozszoiBetuszoKivetel'):
-        sols.append(([''], 'Az "áfa", "eva" és a "taj" betűszókhoz az összetételi tagok kötőjel nélkül járulnak, azaz a szót egybeírjuk.', [''], ['403.']))  # OH. 403.
-        self.state = 999
-        return ('!', sols)
-      if re.match(pattern, self.inp[0].wordform):
-        if self.state == 0:
-          self.state = 1
-          return ('?', ('Az előtag egy betűszó?', [('1', 'Igen.'), ('2', 'Nem.')]))
-        elif self.state == 1:
-          if message == '1':
-            sols.append((['-'], 'A betűszókhoz és a tulajdonnévi szóösszevonásokhoz kötőjellel fűzzük az utótagokat.', ['287. a)']))
-          elif message == '2':
-            return (None, 'Az előtag csupa nagybetűvel íródott, mégsem betűszó. Ellenőrizze!')
-      elif re.match(pattern, self.inp[1].wordform):
-        if self.state == 0:
-          self.state = 1
-          return ('?', ('Az utótag egy betűszó?', [('1', 'Igen.'), ('2', 'Nem.')]))
-        elif self.state == 1:
-          if message == '1':
-            if self.inp[0].matchPoSSequence('(MN|(FN,_IKEP)|(IGE(,MIB|_OKEP)),NOM)'):
-              sols.append(([' '], 'Ha az előtag jelző, a betűszói utótagot különírjuk.', ['?']))
-            else:  
-              sols.append((['-'], 'A betűszókhoz és a tulajdonnévi szóösszevonásokhoz kötőjellel fűzzük az előtagot.', ['287. a)']))
-          elif message == '2':
-            return (None, 'Az előtag csupa nagybetűvel íródott, mégsem betűszó. Ellenőrizze!')
-      else:
-        return (None, 'Hiba!')
-    elif len(self.inp) == 3:
-      if self.inp[0].matchPoSSequence('(MN|(FN,_IKEP)|(IGE(,MIB|_OKEP)),NOM)') and self.inp[1].hasLexProp('KozszoiBetuszo'):
-        sols.append(([' ', ' '], 'Ha a (különírt) jelzős szerkezet alaptagja betűszó, a mozgószabály nem alkalmazható: az utótag különírandó.', [''], ['133.'])) # OH. 133.
-        self.state = 999
-        return ('!', sols)
-      elif self.inp[0].hasLexProp('KozszoiBetuszo'):
-        sols.append((['-', '-'], 'Ha a kifejezés kettőnél több tagból áll, az újabb összetételi tagokat is kötőjellel kapcsoljuk.', [''], ['136.'])) # OH. 136.
-        self.state = 999
-        return ('!', sols)
-      elif self.inp[0].hasLexProp('KozszoiBetuszoKivetel'):
-        sols.append((['', ''], 'Az "áfa", "eva" és "taj" betűszókhoz az összetételi tagok kötőjel nélkül járulnak: a kifejezést egybeírjuk, esetleg kötőjellel, ha a szótagszámlálási szabály érvénybe lép.', [''], ['403.'])) # OH. 403.
-        self.state = 999
-        return ('!', sols)
-      elif re.match(pattern, self.inp[0].wordform) or re.match(pattern, self.inp[1].wordform) or re.match(pattern, self.inp[2].wordform):
-        if self.state == 0:
-          self.state = 1
-          return ('?', ('Valamelyik összetételi tag egy betűszó?', [('1', 'Igen.'), ('2', 'Nem.')]))
-        elif self.state == 1:
-          if message == '1':
-            if self.inp[0].matchPoSSequence('(MN|(FN,_IKEP)|(IGE(,MIB|_OKEP)),NOM)') and re.match(pattern, self.inp[1].wordform):
-              sols.append(([' ', ' '], 'Ha a (különírt) jelzős szerkezet alaptagja betűszó, a mozgószabály nem alkalmazható: az utótag különírandó.', [''], ['133.'])) # OH. 133.
-              self.state == 999
-              return ('!', sols)
-            
-            elif (self.inp[0].matchPoSSequence('MN,NOM') and re.match(pattern, self.inp[1].wordform)) or (re.match(pattern, self.inp[0].wordform) and self.inp[1].matchPoSSequence('MN,NOM')) and self.inp[2].matchPoSSequence('FN,NOM'):
-              sols.append(([' ', ' '], 'Ha', [''], ['?'])) # OH. ?
-            elif self.inp[0].matchPoSSequence('FN,NOM') and (re.match(pattern, self.inp[0].wordform) or re.match(pattern, self.inp[1].wordform)):
-              sols.append((['-', '-'], 'Ha a kifejezés kettőnél több tagból áll, az újabb összetételi tagokat is kötőjellel kapcsoljuk.', [''])) # OH. 136.
-              self.state == 999
-              return ('!', sols)
-            elif re.match(pattern, self.inp[0].wordform) and self.inp[1].matchPoSSequence('(MN|(FN,_IKEP)|(IGE(,MIB|_OKEP)),NOM)') and self.inp[2].matchPoSSequence('FN,NOM'):
-              sols.append(([' ', ' '], 'Ha a tulajdonnévi betűszóhoz jelzős szerkezet kapcsolódik, mindent külön szóba írunk.', [''])) # OH. 136.
-              self.state == 999
-              return ('!', sols)
-          elif message == '2':
-            return (None, 'Valamely összetételi tag csupa nagybetűvel íródott, mégsem betűszó. Ellenőrizze!')
-    self.state == 999
-    return ('!', sols)
-
-# # # end class RuleBetuszo # # #
-  
-      
-class RuleBetujelElotag(SpellingRuleBase):
-  """
-    @author: LZS
-  """
-
-  
-  @staticmethod  
-  def match(inp):
-    if len(inp) not in [2,3]:
-      return False
-    #pattern = re.compile(u'[a-záéíóöőúüűA-ZÁÉÍÓÖŐÚÜŰ]')
-    if len(inp) == 2:
-      #if (len(inp[0].wordform)) != 1 and not re.match(pattern, inp[0].wordform) and not inp[1].hasFinalPoS('FN|MN'):
-      if len(inp[0].wordform) > 2 or not inp[0].matchPoSSequence('(FN\|BETU),NOM'):
-        return False
-      
-    if len(inp) == 3:
-      #if (len(inp[0].wordform)) != 1 and not re.match(pattern, inp[0].wordform) and not inp[1].hasFinalPoS('FN|MN') and not inp[2].hasFinalPoS('FN|MN'):
-      if len(inp[0].wordform) > 2 or not inp[0].matchPoSSequence('(FN\|BETU),NOM') and not inp[1].hasFinalPoS('FN|MN') and not inp[2].hasFinalPoS('FN|MN'):
-        return False 
-#      if not inp[1].hasFinalPoS('FN|MN'):
-#        return False
-    return True
-
-  def getId(self):
-    return "M_EK_BETUJEL_ELOTAG"
-  
-  def getName(self): 
-    return "Különírt betűjelből és főnévből/melléknévből álló összetételek (kód: M_EK_BETUJEL_ELOTAG) (AkH. ?., OH. 133.)"
-    
-  def communicate(self, message=[]):
-    sols = []
-    firstLetter0 = Wordform.Phonology.CV(self.inp[0].wordform[0])
-    firstLetter1 = Wordform.Phonology.CV(self.inp[1].wordform[0])
-    FirstLetter0 = Wordform.Phonology.CV(self.inp[0].wordform[0])
-    det1 = 'a' if firstLetter0 == 'C' else 'az'
-    det2 = 'A' if FirstLetter0 == 'C' else 'Az'
-    det3 = 'a' if firstLetter1 == 'C' else 'az'
-    if self.state == 0:
-      self.state = 1
-      return ('?', ('Milyen szerepet tölt be ' + det1 + ' "' + self.inp[0].wordform + '" betűjel?',
-                    [('1', 'A jelzőszerű betűjel egyet jelöl a sok hasonló/azonos fajta közül, semmilyen formában nem utal a jelzett főnév, ' + det3 + ' "' + self.inp[1].wordform + '" minőségére.'),
-                     ('2', det2 + ' "' + self.inp[0].wordform + '-' + self.inp[1].wordform + '" egy külön fajta, nem pedig egy a sokféle egyforma "' + self.inp[1].wordform + '" közül.')]))
-    elif self.state == 1:
-      if message == '1':
-        if len(self.inp) == 2:
-          sols.append(([' '], 'Egy betűjelből és egy főnévből vagy melléknévből álló kapcsolatot különírunk.', [''])) # OH. 133.
-        elif len(self.inp) == 3:
-          sols.append(([' ', ' '], 'Azokban a szerkezetekben, amelyek egy különírt betűjelből és egy főnévből/melléknévből állnak, nem alkalmazható a mozgószabály. A további összetételi tagokat is különírjuk.', [''])) # OH. 133.
-      elif message == '2':
-        return (None, 'A betűjel fajtát jelöl, nem ez a szabály vonatkozik rá.')
-    self.state = 999
-    return ('!', sols)
-
-# DE: A-vitamin, X-kromoszóma -- Bősze, Mártonfi alapján
-
-# # # end class RuleBetujelElotag # # #
-    
-
-class RuleToismetles(SpellingRuleBase):
-  """
-    @author: LZS
-  """
-  
-  @staticmethod  
-  def match(inp):
-    if len(inp) != 2:
-      return False
-    #if len(inp) == 2:
-      #if not ((WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('ToismetlesEgybe') or WordInfo(inp[0].wordform + '-' + inp[1].wordform).hasLexProp('ToismetlesKotojel')) or (inp[0].getParseHumorData()[0][0][0] != inp[1].getParseHumorData()[0][0][0] or inp[1].getParseHumorData()[1][0][0] or inp[1].getParseHumorData()[2][0][0])):
-    if not (WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('ToismetlesEgybe') or WordInfo(inp[0].wordform + '-' + inp[1].wordform).hasLexProp('ToismetlesKotojel')): 
-      return False
-    return True
-  
-  def getId(self):
-    return "M_EK_TOISMETLES"
-  
-  def getName(self): 
-    return "Tőismétlés (kód: M_EK_TOISMETLES) (AkH. ?., OH. 100.)"
-    
-  def communicate(self, message=None):
-    sols = []
-    #szoto1 = self.inp[0].getParseHumorData()[0][0][0])
-    #print(self.inp[1].getParseHumorData()[0][0][0])
-    if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('ToismetlesEgybe'):
-      sols.append(([''], 'Néhány tőismétléses mellérendelést egybe kell írni.', [''])) # OH. 100.
-    elif WordInfo(self.inp[0].wordform + '-' + self.inp[1].wordform).hasLexProp('ToismetlesKotojel'):
-      sols.append((['-'], 'Néhány tőismétléses mellérendelést kötőjellel kell írni.', [''])) # OH. 100.
-#    elif self.inp[0].getParseHumorData()[0][0][0] == (self.inp[1].getParseHumorData()[0][0][0] or self.inp[1].getParseHumorData()[1][0][0] or self.inp[1].getParseHumorData()[2][0][0]):
-#      sols.append(([' '] ,'Ugyanannak a szónak különböző toldalékokkal ellátott alakjait külön kell írni egymástól.', ['OH. 100.']))
-    else:
-      return (None, 'Hiba!')
-    self.state = 999
-    return ('!', sols)
-
-# # # end class RuleToismetles # # #
-  
-class RuleSzervetlen(SpellingRuleBase):
-  """
-    @author: LZS
-  """
-  
-  @staticmethod  
-  def match(inp):
-    if len(inp) not in [2,3]:
-      return False
-    if len(inp) == 2 and not WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('Szervetlen'):
-      return False
-    if len(inp) == 3 and not WordInfo(inp[0].wordform + inp[1].wordform + inp[2].wordform).hasLexProp('Szervetlen'):
-      return False
-    return True
-
-  def getId(self):
-    return "M_EK_SZERVETLEN"
-  
-  def getName(self): 
-    return "A hagyományosan szervetlennek nevezett összetételek (kód: M_EK_SZERVETLEN) (AkH. 132--136., OH. 126--128.)"
-  
-  def communicate(self, message=None):
-    sols = []
-    if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('Szervetlen'):
-      sols.append(([''], 'A hagyományosan szervetlennek nevezett összetételeket egybeírjuk.', ['AkH. 132--136.']))
-    else:
-      return (None, 'Hiba!')
-    self.state = 999
-    return ('!', sols)
-
-# # # end class RuleSzervetlen # # #
-
-class RuleFoglalkozasnev(SpellingRuleBase):
-  """
-    @author: LZS
-  """
-  
-  @staticmethod  
-  def match(inp):
-    if len(inp) != 2:
-      return False
-#    if not ((inp[0].hasLexProp('Occupation') or inp[0].hasLexProp('Ecclesiastic')) and (inp[1].hasLexProp('Occupation') or inp[1].hasLexProp('Ecclesiastic'))):
-#      return False
-    if not (WordInfo(inp[0].wordform + inp[1].wordform).hasLexProp('EcclesiasticException') or ((inp[0].hasLexProp('Occupation') or inp[0].hasLexProp('Ecclesiastic')) and (inp[1].hasLexProp('Occupation') or inp[1].hasLexProp('Ecclesiastic'))) ):
-      return False
-    return True
-
-  def getId(self):
-    return "M_EK_FOGLALKOZAS"
-  
-  def getName(self): 
-    return "Foglalkozásnevek, tisztségek, rangok, fokozatok, beosztások megnevezése (kód: M_EK_FOGLALKOZAS) (AkH. 101. a), 114., 152., OH. 114., 144., 167., 353.)"
-  
-  def communicate(self, message=[]):
-    sols = []
-    FirstLetter1 = Wordform.Phonology.CV(self.inp[1].wordform[0]) # utótag (alaptag)
-    det1 = 'A' if FirstLetter1 == 'C' else 'Az'
-    if WordInfo(self.inp[0].wordform + self.inp[1].wordform).hasLexProp('EcclesiasticException'):
-      sols.append(([''], 'Néhány kettős foglalkozásnevet -- elsősorban egyházi területen -- hagyományosan egybeírunk.', ['?']))
-    elif self.inp[0].hasLexProp('Ecclesiastic') or self.inp[1].hasLexProp('Ecclesiastic'):
-      sols.append(([' '], 'Az egyházi fokozatokat nem kötőjellel kapcsoljuk, hanem külön szóba írjuk őket. Egyházi és világi foglalkozások esetén is különírást alkalmazunk.', ['?']))
-    else:
-      if self.state == 0:
-        self.state = 1
-        return ('?', ('Válasszon a lehetőségek közül!',
-                      [('1', 'Valaki ' + self.inp[0].wordform + ' és ' + self.inp[1].wordform + ' egyszerre.'),
-                       ('2', det1 + ' ' + self.inp[1].wordform + ' (egy) ' + self.inp[0].wordform + '.'),
-                       ('3', 'A kérdés nem értelmezhető. Nem két foglalkozás összekapcsolásáról van szó.')]))
-      elif self.state == 1:
-        if message == '1':
-          sols.append((['-'], 'Számos olyan mellérendelő kapcsolatunk van, amely nem vagy csak kivételesen -- és csak az utótagon -- látható el toldalékokkal. Két foglalkozásnevet kötőjellel szokás egymáshoz kapcsolni.', [['101. a), 114.']))
-        elif message == '2':
-          sols.append(([' '], 'Főnévi jelzős szerkezetről lévén szó, a kifejezést különírjuk.', [''])) # OH. 115.
-        elif message == '3':
-          return (None, 'Nem két foglalkozás összekapcsolásáról van szó.')
-    self.state = 999
-    return ('!', sols)
-
-# # # end class RuleFoglalkozasnev
-    
-
-
-class RuleSzotagszamlalas(SpellingRuleBase):
-
-  @staticmethod  
-  def match(inp):
-#    print('Szotagszam:')
-#    print(inp[0].getNSyllables())
-    if len(inp) != 1:
-      return False
-    if [c for c in inp[0].wordform if c in '-'] != []: # kötőjelezett alakra nem illeszkedik
-      return False
-    if inp[0].getNSyllables() == -99:
-      return False
-    if not inp[0].getNSyllables() > 6:
-      if not inp[0].getNCompParts() >= 3:
-        return False
-    return True
-  
-  def getId(self):
-    return "M_EK_SZOTAGSZAML"
-  
-  def getName(self): 
-    return "Szótagszámlálási szabály, 6:3-as szabály (kód: M_EK_SZOTAGSZAML) (AkH. 138., OH. 128--131.)"
-  
-  def communicate(self, message=None):
-    for anal in self.inp[0].getParseHumorData():
-      match = [c for c in anal[0][0] if c in '*']
-      if match != ['']:
-        tmp = anal[0][0].split('*')
-        print(tmp)
-#      for morph in anal:
-#        print(morph)
-    return (None, 'Under construction')
-    
-# # # end class RuleSzotagszamlalas # # #
-
-
-class RuleMozgo1(SpellingRuleBase):
-    
-  @staticmethod  
-  def match(inp):
-    if len(inp) != 2:
-      return False
-    match = [c for c in inp[0].wordform if c in '-']
-    #print(match)
-    if match == []:
-      return False
-    return True
-
-  def getId(self):
-    return "M_EK_MOZGO1"
-  
-  def getName(self): 
-    return "1. mozgószabály (kód: M_EK_MOZGO1) (AkH. 139. a), OH. 131.)"
-
-  def communicate(self, message=None):
-    sols = []
-    tmp = self.inp[0].wordform.split('-')
-    if len(tmp) == 2:
-#      print(tmp[0][-2])
-#      print(tmp[1][0])
-      if tmp[0][-2] == tmp[0][-1]:
-        if tmp[0][-1] == tmp[1][0]:
-          sols.append((['-'], 'Ha egy olyan kötőjeles írásmódú összetett szóhoz járul újabb előtag, amelyikben a kötőjelet nem a szótagszámlálási vagy egyéb mozgószabály írja elő, nem hajtható végre az első mozgószabály. Az újabb összetételi tagot is kötőjellel kapcsoljuk.',
-                       [''], ['131.']))
-      else:
-        tmp = ''.join(tmp)
-        inp0 = WordInfo(tmp)
-        self.inp[0] = inp0
-        sols.append((['-'],
-                 'Ha egy kötőjellel már tagolt szóhoz újabb, szintén kötőjellel kapcsolandó utótag járul, az első kötőjelet kihagyjuk, vagyis az eredetileg kötőjelezett szórészt az új alakulatokban egybeírjuk.',
-                 ['139. a)']))
-    self.state = 999
-    return ('!', sols)
-
-# # # end class RuleMozgo1 # # #
-
-
-class RuleDebuggerConsole:
-  """Sample class for managing a pool of rule classes (descendants of SpellingRuleBase) and interacting with the user via stdin and stdout.
-  """
-
-  def __init__(self, ruleset):
-    """Initialises the class with ruleset, an array of SpellingRuleBase descendant class names.
-    """
-    self.rules = ruleset
-
-  def getAnswer(self, question):
-    """Parameter question is a structure: ('question prompt', [(answer_id, 'answer text'), ...])
-       Displays question prompt and answer texts and repeats reading user's answer until it is one of the valid answer_id's specified in question.
-       Returns the answer_id from given by the user.
-    """
-    print('Question: "{0}"'.format(question[0]))
-    valid = []
-    for aid, atxt in question[1]:
-      print('{0} - {1}'.format(aid, atxt))
-      valid.append(aid)
-    while True:
-      print('Your answer>', end='')
-      ans = sys.stdin.readline().rstrip()
-      if ans in valid:
-        break
-      else:
-        print('Please type one of [{0}]'.format(','.join(valid)))
-    return ans
-
-  def applyMatchingRules(self, inp):
-    """For each rule class in self.rules, calls its match() on inp (an array of WordInfo instances).
-       If a rule class matches, it is instantiated with the input and its communicate() method is invoked.
-       If answers to interim questions are required, the question texts are displayed on stdout and answers are expected from stdin.
-       Returns a dictionary {<ruleId>: <solutions>, ...} where <solutions> is an array containing all the solutions (e.g.: ('!', <verdict>)) returned by rule with ruleId.
-       Debug data is dumped to stdout.
-    """
-    ret = dict()
-    for rname in self.rules:
-      if rname.match(inp):
-        rule = rname(inp)
-        rid = rule.getId()
-        print('-matching rule found: id={0} class={1} name="{2}"'.format(rid, str(rname), rule.getName()))
-        r = rule.communicate()
-        print('-rule {0} returned: {1}'.format(rid, r))
-        while r[0] == '?': # while rule asks back
-          aid = self.getAnswer(r[1]) # get answer from user
-          r = rule.communicate(message=aid) # send it back to rule
-          print('-rule {0} returned: {1}'.format(rid, r))
-        if r[0] == None: # rule returned error message
-          print('-rule {0} returned error message: {1}'.format(rid, r[1]))
-        elif r[0] == '!': # rule returned verdict
-          if rid not in ret:
-            ret[rid] = []
-          ret[rid] += r[1]
-    return ret	
-
-  def interact(self):
-    """Start an interactive session with the user via stdout and stdin."""
-    import readline
-    print('Enter words to check, blank line to exit')
-    while(True):
-      print('>', end='')
-      inp = sys.stdin.readline().rstrip()
-      if not inp:
-        break
-      toks = [WordInfo(x) for x in inp.split(' ')]
-      print('\nInput tokens information:\n{0}\n'.format('\n'.join([x.toStr() for x in toks])))
-      print('Applying rules...')
-      outp = self.applyMatchingRules(toks)
-      print("\nSolutions:\n")
-      if len(outp) == 0:
-        print('No solutions found')
-      i = 1
-      for rid, sols in outp.items():
-        for sol in sols:
-          print('{0}. solution'.format(i))
-          print('Suggested form: "{0}"'.format(applyseparators(toks, sol[0])))
-          print('Comment: "{0}"'.format(sol[1]))
-          print('Related AKH Id(s): {0}'.format(','.join(sol[2])))
-          if len(sol) == 4:
-            print('Related page(s) in Osiris: {0}'.format(','.join(sol[3])))
-          print('Id of applied rule: "{0}"'.format(rid)) 
-          print('')
-          i += 1
-
-# # # end class RuleDebuggerConsole # # #
-
-
-def applyseparators(inp, seps):
-  """Parameter inp: array of WordInfo instances
-     Parameter seps: array of ' ' or '-' or '--' or ''
-     Returns string which is wordforms of inp with elements of seps "between" them.
-     Note: len(inp) - 1 == len(seps) is required, returns None otherwise
-  """
-  if len(inp) - 1 != len(seps):
-    return None
-  ret = ''
-  for i in range(0, len(inp) - 1):
-    ret += inp[i].wordform + seps[i]
-  ret += inp[-1].wordform
-  return ret
-
-
-def _test_LexicalEntry():
-  # look up id for myword
-  myword = 'sárga'
-  print(myword)
-  ids = Wordform.forToken(mydb, myword)
-  myid = None
-  for id, word in ids:
-    if word == unicode(myword, "utf-8"):
-      myid = id
-      break
-  print(myid)
-  # create a LexicalEntry object from the id
-  l = Wordform.loadLexicalEntry(mydb, myid)
-  # dump
-  print(vars(l))
-
-
-def _test_WordInfo(word):
-  print(WordInfo(word).toStr())
-
-def _test_WordInfo_interactive():
-  while True:
-    inp = sys.stdin.readline().rstrip()
-    if not inp:
-      break
-    w = WordInfo(inp)
-    print(w.toStr())
-    print(w.morph().getMorphsHumor())
-
-
-
-if __name__ == "__main__":
-  
-  #_test_LexicalEntry()
-  #_test_WordInfo('sárga')
-  
-  RuleDebuggerConsole([RuleSzinneviAlaptag, RuleAnyagneviMozgoszabaly, RuleSorszamneviJelzosSzerk,
-                       RuleJelzoiElotag,
-                       RuleJeloletlenAlanyos,
-                       RuleJeloletlenTargyas, RuleJeloletlenHatarozos,
-                       RuleJeloletlenBirtokosJelzos, RuleJeloletlenMinosegjelzos,
-                       RuleJelentessurito,
-                       RuleJeloltTargyas, RuleJeloltHatarozos, RuleJeloltBirtokos,
-                       RuleMennyisegjelzosSzerkezet, RuleFoneviJelzosSzerkezet, RuleGyujtonevek,
-                       RuleNagykotojel, RuleBefejezettMellekneviIgenev, RuleFolyamatosMellekneviIgenev,
-                       RuleRovidites, 
-                       RuleToismetles,
-                       RuleSzervetlen, RuleBetuszo, RuleBetujelElotag,
-                       RuleFoglalkozasnev,
-                       RuleSzotagszamlalas, RuleMozgo1
-                       ]).interact()




More information about the Hejes-devel mailing list