diff --git a/src/yapsut/__init__.py b/src/yapsut/__init__.py
index 58fe84160441ac74c171cea05aad0ca1a8f8cd6a..2728e81fdc90c93fbf41c8be28cefe925fbf57b4 100644
--- a/src/yapsut/__init__.py
+++ b/src/yapsut/__init__.py
@@ -12,6 +12,7 @@ from .struct import struct
 from .DummyCLI import DummyCLI
 from .nearly_even_split import nearly_even_split
 from .geometry import ElipsoidTriangulation 
+from .template_subs import discoverKeys, templateFiller
 
 #from import .grep
 #import .intervalls
diff --git a/src/yapsut/template_subs.py b/src/yapsut/template_subs.py
new file mode 100644
index 0000000000000000000000000000000000000000..703bff51b03a9cbe3166fc7c5e992a60027fc398
--- /dev/null
+++ b/src/yapsut/template_subs.py
@@ -0,0 +1,118 @@
+___DESCRIPTION__=""" a library to handle template substitution """
+
+def discoverKeys(template,kbraeket,verbose=False) :
+   """discover keys to be replaced inside a template
+      template is the template
+      kbraeket = (left , right) delimites
+      
+      example:
+      
+      > keywords = discoverKeys("demo=$DEMO$",("$","$")
+      > print(keywords)
+      ['$DEMO']
+   """
+   out=[]
+   i1=0
+   while True : 
+      try :  
+         i1=template.index(kbraeket[0],i1) 
+      except : 
+         break 
+      try : 
+         i2=template.index(kbraeket[1],i1+1) 
+      except : 
+         raise Exception('file ended while scanning end of keyword')
+      if verbose : print(i1,i2)
+      out.append(template[i1:i2+1])
+      i1=i2+1
+   return out
+   
+class templateFiller:
+   """
+   Handles filling o template keywords and generation of document with template replaced
+   
+   tF=templateFiller(template)
+   
+   Example:
+   
+   > tF=templateFiller("prova=$PROVA$")
+   > tF['PROVA']='PROVED'
+   > print(tf.generate())
+   prova=PROVED
+   
+   """
+   @property 
+   def template(self) :
+      return self._t
+   @property 
+   def keywords(self) :
+      return self._k
+   #
+   def __init__(self,template,keywords=None,kbraeket=('$','$')) :
+      """ template = template string
+          keywords = list of template keywords to be replaced (default None)
+                     if None keywords are extracted from template
+          kbraeket = (left delimiter, right delimiter), default ('$','$')
+      """
+      self._kbraeket=kbraeket
+      self._t=template
+      #
+      if keywords is None :
+         self._kfill=discoverKeys(template,kbraeket)
+         out=[]
+         for k in self._kfill :
+            oo=k
+            if kbraeket[0]!='' :
+               oo=oo.split(kbraeket[0])[1]
+            if kbraeket[1]!='' :
+               oo=oo.split(kbraeket[1])[0]
+            out.append(oo)
+         self._k=out
+      elif type(keywords) == type([]) :
+         self._k=keywords
+         self._kfill=[kbraeket[0]+k+kbraeket[1] for k in keywords]
+      else :
+         raise Exception('kewords must be list or None','')
+      #
+      self._d={}
+      self._set={}
+      self.reset()
+   #
+   def keys(self) :
+      """returns valid keywords"""
+      return self._k
+   #
+   def reset(self) :
+      """reset filled keywords"""
+      for k in self._k :
+         self._set[k]=False
+         self._d[k]=None
+   #
+   def isfilled(self) :
+      """True if all the keywords are filled"""
+      for k in self._k :
+         if not self._set[k] :
+            return False
+      return True
+   #
+   def __setitem__(self,this,that) :
+      if not this in self._k :
+         raise Exception('Error, keyword %s not defined'%this)
+      if self._set[this] == True :
+         raise Exception('Error, keyword %s already set'%this)
+      self._set[this]=True
+      self._d[this]=that
+   #
+   def generate(self,autoReset=True) :
+      """generate the document from the replaced template"""
+      if not self.isfilled() :
+         raise Exception('Error, not all the keywords are filled')
+      #
+      tout=template
+      for ik,k in enumerate(self._k) :
+         keyName=self._kfill[ik]
+         tout=tout.replace(keyName,self._d[k])
+      #
+      if autoReset : self.reset()
+      #
+      return tout