diff --git a/parser/parser-lib-atoms/libAtomsParser.py b/parser/parser-lib-atoms/libAtomsParser.py
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..39ba92c1539cf115aa0a1371b1d347c91f7a8405 100644
--- a/parser/parser-lib-atoms/libAtomsParser.py
+++ b/parser/parser-lib-atoms/libAtomsParser.py
@@ -0,0 +1,110 @@
+from builtins import range
+import os
+import sys
+import re
+import json
+#import logging
+import setup_paths
+import numpy as np
+
+from nomadcore.local_meta_info import loadJsonFile, InfoKindEl
+from nomadcore.parser_backend import JsonParseEventsWriterBackend
+from contextlib import contextmanager
+
+from libLibAtomsParser import *
+
+try:
+    from libMomo import osio, endl, flush
+    osio.ConnectToFile('parser.osio.log')
+    green = osio.mg
+except:
+    osio = endl = flush = None
+    green = None
+
+parser_info = {
+    "name": "parser-lib-atoms", 
+    "version": "0.0",
+    "json": "../../../../nomad-meta-info/meta_info/nomad_meta_info/lib_atoms.nomadmetainfo.json"
+}
+
+# LOGGING
+def log(msg, highlight=None, enter=endl):
+    if osio:
+        if highlight==None: hightlight = osio.ww
+        osio << highlight << msg << enter
+    return
+
+# CONTEXT GUARD
+@contextmanager
+def open_section(p, name):
+    gid = p.openSection(name)
+    yield gid
+    p.closeSection(name, gid)   
+
+def push(jbe, terminal, key1, fct=lambda x: x.As(), key2=None):
+    if key2 == None: key2 = key1
+    value =  fct(terminal[key2])
+    jbe.addValue(key1, value)
+    return value
+
+def push_array(jbe, terminal, key1, fct=lambda x: x.As(), key2=None):
+    if key2 == None: key2 = key1
+    value =  np.asarray(fct(terminal[key2]))
+    jbe.addArrayValues(key1, value)
+    return value
+
+def push_value(jbe, value, key):
+    jbe.addValue(key, value)
+    return value
+
+def push_array_values(jbe, value, key):
+    jbe.addArrayValues(key, value)
+    return value
+
+def parse(output_file_name):
+    jbe = JsonParseEventsWriterBackend(meta_info_env)
+    jbe.startedParsingSession(output_file_name, parser_info)
+
+    base_dir = os.path.dirname(os.path.abspath(output_file_name))
+    terminal = LibAtomsParser(osio)
+    terminal_trj = LibAtomsTrajectory(osio)
+    terminal_trj.ParseOutput(output_file_name)
+    out = terminal
+    trj = terminal_trj
+   
+    log("Start parsing ...")
+    log("Base directory = '%s'" % base_dir)
+
+    with open_section(jbe, 'section_run') as gid_run:
+        push(jbe, trj, 'program_name')
+        push(jbe, trj, 'program_version')
+
+    jbe.finishedParsingSession("ParseSuccess", None)
+    return
+
+if __name__ == '__main__':
+
+    # CALCULATE PATH TO META-INFO FILE
+    this_py_file = os.path.abspath(__file__)
+    this_py_dirname = os.path.dirname(this_py_file)
+    json_supp_file = parser_info["json"]
+    meta_info_path = os.path.normpath(os.path.join(this_py_dirname, json_supp_file))
+
+    # LOAD META-INFO FILE
+    log("Meta-info from '%s'" % meta_info_path)
+    meta_info_env, warns = loadJsonFile(
+        filePath=meta_info_path,
+        dependencyLoader=None,
+        extraArgsHandling=InfoKindEl.ADD_EXTRA_ARGS,
+        uri=None)
+
+    output_file_name = sys.argv[1]
+    parse(output_file_name)
+
+
+
+
+
+
+
+
diff --git a/parser/parser-lib-atoms/libLibAtomsParser.py b/parser/parser-lib-atoms/libLibAtomsParser.py
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..800e7331223ec58d280547468cacf26dbd75e4dc 100644
--- a/parser/parser-lib-atoms/libLibAtomsParser.py
+++ b/parser/parser-lib-atoms/libLibAtomsParser.py
@@ -0,0 +1,343 @@
+from __future__ import print_function
+from builtins import zip
+from builtins import str
+from builtins import map
+from builtins import range
+from builtins import object
+import os
+import sys
+import re
+import numpy as np
+
+try:
+    import ase
+    import ase.io
+    HAVE_ASE = True
+except ImportError:
+    HAVE_ASE = False
+    pass
+
+class LibAtomsParser(object):
+    def __init__(self, log=None):
+        self.log = log
+        self.data = {}
+        self.logtag = 'main'
+        # KEY DEFAULT DICTIONARIES
+        self.missing_keys_lh = [] # Transform keys that were not found in output
+        self.missing_keys_rh = []
+        self.ignored_keys = [] # Raw keys that did not have a transform
+        self.keys_not_found = [] # Searches that failed
+        return
+    def __getitem__(self, key):
+        self.selected_data_item = self.data[key]
+        return self
+    def As(self, typ=None):
+        if typ == None:
+            typ = type(self.selected_data_item)
+        return typ(self.selected_data_item)
+    def SummarizeKeyDefaults(self):
+        if not self.log: return
+        if len(self.missing_keys_lh):
+            self.log << self.log.my \
+                << "[%s] Keys from transformation maps that went unused (=> set to 'None'):" \
+                % self.logtag << self.log.endl
+            for lh, rh in zip(self.missing_keys_lh, self.missing_keys_rh):
+                self.log << self.log.item << "Key = %-25s <> %25s" % (rh, lh) << self.log.endl
+        if len(self.ignored_keys):
+            self.log << self.log.mb \
+                << "[%s] Keys from XY mapping that were not transformed (=> not stored):" \
+                % self.logtag << self.log.endl
+            for key in self.ignored_keys:
+                self.log << self.log.item << "Key =" << key << self.log.endl
+        if len(self.keys_not_found):
+            self.log << self.log.mr \
+                << "[%s] Keys from searches that failed (=> set to 'None'):" \
+                % self.logtag << self.log.endl
+            for key in self.keys_not_found:
+                self.log << self.log.item << "Key =" << key << self.log.endl
+        return
+    def Set(self, key, value):
+        if self.log:
+            self.log << "Set [%s]   %-40s = %s" % (self.logtag, key, str(value)) << self.log.endl
+        if key not in self.data:
+            self.data[key] = value
+        else:
+            raise KeyError("Key already exists: '%s'" % key)
+        return
+    def SearchMapKeys(self, expr, ln, keys):
+        s = re.search(expr, ln)
+        try:
+            for i in range(len(keys)):
+                self.Set(keys[i], s.group(i+1).strip())
+        except AttributeError:
+            for i in range(len(keys)):
+                self.Set(keys[i], None)
+                self.keys_not_found.append(keys[i])
+        return
+    def ReadBlockXy(self, block):
+        lns = block.lns
+        block_data = {}
+        for ln in lns:
+            ln = ln.replace('\n','')
+            if ln == '':
+                continue
+            if ':' in ln:
+                sp = ln.split(':')
+                x = sp[0].strip().split()
+                y = sp[1].strip()
+            elif '=' in ln:
+                sp = ln.split('=')
+                x = sp[0].strip().split()
+                y = sp[1].strip()
+            else:
+                sp = ln.split()
+                x = sp[:-1]
+                y = sp[-1]
+            key = ''
+            for i in range(len(x)-1):                
+                xi = x[i].replace('(','').replace(')','').lower()
+                key += '%s_' % xi
+            key += '%s' % x[-1].replace('(','').replace(')','').lower()
+            value = y
+            block_data[key] = value
+        return block_data
+    def ApplyBlockXyData(self, block_data, key_map):
+        for key_in in key_map:
+            key_out = key_map[key_in]            
+            if key_in not in block_data:
+                # Missing key in output
+                self.missing_keys_lh.append(key_in)
+                self.missing_keys_rh.append(key_out)
+                value = None
+            else:
+                value = block_data[key_in]
+            if key_out == None:
+                key_out = key_in
+            self.Set(key_out, value)
+        for key in block_data:
+            if key not in key_map:
+                # Missing key in transform map
+                self.ignored_keys.append(key)
+        return
+    def ParseOutput(self, output_file):        
+        if self.log: 
+            self.log << self.log.mg << "libAtomsParser::ParseOutput ..." << self.log.endl
+        
+        if HAVE_ASE:
+            read_fct = ase.io.read
+            read_fct_args = { 'index':':' }
+        else:
+            raise NotImplementedError("None-ASE read function requested, but not yet available.")
+            read_fct = None
+            read_fct_args = None
+
+        # PARSE CONFIGURATIONS
+        self.ase_configs = read_fct(output_file, **read_fct_args)
+        for config in ase_configs:
+            print(config)
+        
+        self.Set('program_name', 'libAtoms')
+        self.Set('program_version', 'n/a')
+        return
+
+class LibAtomsTrajectory(LibAtomsParser):
+    def __init__(self, log=None):
+        super(LibAtomsTrajectory, self).__init__(log)
+        self.ase_configs = None
+        self.frames = []
+    def ParseOutput(self, output_file):        
+        if self.log: 
+            self.log << self.log.mg << "libAtomsParser::ParseOutput ..." << self.log.endl
+        
+        if HAVE_ASE:
+            read_fct = ase.io.read
+            read_fct_args = { 'index':':' }
+        else:
+            raise NotImplementedError("None-ASE read function requested, but not yet available.")
+            read_fct = None
+            read_fct_args = None
+
+        # PARSE CONFIGURATIONS
+        self.ase_configs = read_fct(output_file, **read_fct_args)
+        self.LoadAseConfigs(self.ase_configs)
+        
+        self.Set('program_name', 'libAtoms')
+        self.Set('program_version', 'n/a')
+        return
+    def LoadAseConfigs(self, ase_configs):
+        for config in ase_configs:
+            frame = LibAtomsFrame(self.log)
+            frame.LoadAseConfig(config)
+            self.frames.append(frame)
+        if self.log: log << "Loaded %d configurations" % len(self.frames) << log.endl
+        return
+
+class LibAtomsFrame(LibAtomsParser):
+    def __init__(self, log=None):
+        super(LibAtomsFrame, self).__init__(log)
+        self.ase_config = None
+    def LoadAseConfig(self, ase_config):
+        self.ase_atoms = ase_config
+        return
+
+# ===================
+# FILE & BLOCK STREAM
+# ===================
+
+class FileStream(object):
+    def __init__(self, filename=None):
+        if filename:
+            self.ifs = open(filename, 'r')
+        else:
+            self.ifs = None
+        return
+    def SkipTo(self, expr):
+        while True:
+            ln = self.ifs.readline()
+            if expr in ln:
+                break
+            if self.all_read():
+                break
+        return ln
+    def SkipToMatch(self, expr):
+        while True:            
+            ln = self.ifs.readline()
+            m = re.search(expr, ln)
+            if m:
+                return ln
+            if self.all_read(): break
+        return None
+    def GetBlock(self, expr1, expr2):
+        inside = False
+        outside = False
+        block = ''
+        block_stream = BlockStream()
+        while True:
+            last_pos = self.ifs.tell()
+            ln = self.ifs.readline()
+            if expr1 in ln: inside = True
+            if expr2 in ln: outside = True
+            if inside and not outside:
+                # Inside the block
+                block += ln
+                block_stream.append(ln)
+            elif inside and outside:
+                self.ifs.seek(last_pos)
+                # Block finished
+                break
+            else:
+                # Block not started yet
+                pass
+            if self.all_read(): break
+        return block_stream  
+    def GetBlockSequence(self, 
+            expr_start, 
+            expr_new, 
+            expr_end, 
+            remove_eol=True, 
+            skip_empty=True):
+        inside = False
+        outside = False
+        # Setup dictionary to collect blocks
+        blocks = { expr_start : [] }
+        for e in expr_new:
+            blocks[e] = []
+        # Assume structure like this (i <> inside, o <> outside)
+        # Lines with 'i' get "eaten"
+        # """
+        # o ...
+        # i <expr_start>
+        # i ...
+        # i <expr_new[1]>
+        # i ...
+        # i <expr_new[0]>
+        # i ...
+        # o <expr_end>
+        # o ...
+        # """
+        key = None
+        while True:
+            # Log line position
+            last_pos = self.ifs.tell()
+            ln = self.ifs.readline()            
+            # Figure out where we are
+            if not inside and expr_start in ln:
+                #print "Enter", expr_start
+                inside = True
+                key = expr_start
+                new_block = BlockStream(key)
+                blocks[key].append(new_block)
+            for expr in expr_new:
+                if inside and expr in ln:
+                    #print "Enter", expr
+                    key = expr
+                    new_block = BlockStream(key)
+                    blocks[key].append(new_block)
+            if inside and expr_end != None and expr_end in ln:
+                outside = True
+            if inside and not outside:
+                # Inside a block
+                if remove_eol: ln = ln.replace('\n', '')
+                if skip_empty and ln == '': pass
+                else: blocks[key][-1].append(ln)
+            elif inside and outside:
+                # All blocks finished
+                self.ifs.seek(last_pos)
+                break
+            else:
+                # No blocks started yet
+                pass
+            if self.all_read(): break
+        return blocks
+    def all_read(self):
+        return self.ifs.tell() == os.fstat(self.ifs.fileno()).st_size
+    def readline(self):
+        return ifs.readline()
+    def close(self):
+        self.ifs.close()
+    def nextline(self):
+        while True:
+            ln = self.ifs.readline()
+            if ln.strip() != '':
+                return ln
+            else: pass
+            if self.all_read(): break
+        return ln
+    def ln(self):
+        return self.nextline()
+    def sp(self):
+        return self.ln().split()
+    def skip(self, n):
+        for i in range(n):
+            self.ln()
+        return
+    
+class BlockStream(FileStream):
+    def __init__(self, label=None):
+        super(BlockStream, self).__init__(None)
+        self.ifs = self
+        self.lns = []
+        self.idx = 0
+        self.label = label
+    def append(self, ln):
+        self.lns.append(ln)
+    def readline(self):
+        if self.all_read():
+            return ''        
+        ln = self.lns[self.idx]
+        self.idx += 1
+        return ln
+    def all_read(self):
+        return self.idx > len(self.lns)-1
+    def tell(self):
+        return self.idx
+    def cat(self, remove_eol=True, add_eol=False):
+        cat = ''
+        for ln in self.lns:
+            if remove_eol:
+                cat += ln.replace('\n', '')
+            elif add_eol:
+                cat += ln+'\n'
+            else:
+                cat += ln
+        return cat
diff --git a/parser/parser-lib-atoms/libMomo.py b/parser/parser-lib-atoms/libMomo.py
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..6d56d50d12fb1fcf05d5bcbe702cc50e040e14ae 100644
--- a/parser/parser-lib-atoms/libMomo.py
+++ b/parser/parser-lib-atoms/libMomo.py
@@ -0,0 +1,552 @@
+from __future__ import print_function
+from __future__ import division
+from future import standard_library
+standard_library.install_aliases()
+from builtins import zip
+from builtins import str
+from past.utils import old_div
+from builtins import object
+# See git https://github.com/capoe/momo.git
+import os
+import sys
+import subprocess
+import argparse
+import time
+import numpy as np
+try:
+	from lxml import etree
+except ImportError:
+    pass
+
+boolean_dict = \
+    {'true' : True,   '1' : True,  'yes' : True,
+     'false' : False, '0' : False, 'no' : False, 'none' : False }
+
+# =============================================================================
+# XML WRAPPERS
+# =============================================================================
+
+class ExtendableNamespace(argparse.Namespace):
+	def AddNamespace(self,  **kwargs):
+		for name in kwargs:
+			att = getattr(self, name, None)
+			if att is None:
+				setattr(self, name, kwargs[name])
+			else:
+				setattr(self, name, kwargs[name].As(type(att)))
+		return
+	def Add(self, name, value):
+		att = getattr(self, name, None)
+		if att is None:
+			setattr(self, name, value)
+		else:
+			att.Add(name, value)
+		return value
+
+def GenerateTreeDict(tree, element, path='', paths_rel_to=None):
+	if type(element) == etree._Comment: return [], {}
+	# Update path
+	if path == '':
+		if element.tag != paths_rel_to:
+			path += element.tag
+	else:
+		path += '/' + element.tag
+	# Containers for lower levels
+	tag_node = {}
+	nodes = []
+	# Construct Node
+	xmlnode = XmlNode(element, path) # tree.getpath(element))
+	nodes.append(xmlnode)
+	if len(element) == 0:
+		tag_node[path] = xmlnode
+	#else:
+	#	print "len 0", xmlnode.path
+	#	tag_node[path] = xmlnode
+	# Iterate over children
+	for child in element:
+		child_elements, childtag_element = GenerateTreeDict(tree, child, path)
+		nodes = nodes + child_elements
+		for key in childtag_element.keys():
+			if key in tag_node:
+				if type(tag_node[key]) != list:
+					tag_node[key] = [ tag_node[key], childtag_element[key] ]
+				else:
+					tag_node[key].append(childtag_element[key])
+			else:
+				tag_node[key] = childtag_element[key]
+	return nodes, tag_node
+
+def NamespaceFromDict(tree_dict):
+	nspace = ExtendableNamespace()
+	for key in tree_dict.keys():
+		#print "NSPACE Path = %s" % key
+		sections = key.split('/')
+		values = [ None for s in sections ]
+		values[-1] = tree_dict[key]
+		add_to_nspace = nspace
+		for s,v in zip(sections, values):
+			if v == None:
+				#print "NSPACE Check for existing"
+				if getattr(add_to_nspace, s, None):
+					#print "NSPACE '%s' already exists" % s
+					add_to_nspace = getattr(add_to_nspace, s, None)
+				else:
+					#print "NSPACE '%s' created" % s
+					sub_nspace = ExtendableNamespace()
+					add_to_nspace = add_to_nspace.Add(s, sub_nspace)
+			else:
+				#print "NSPACE '%s' value added" % s
+				add_to_nspace.Add(s, v)
+	return nspace
+				
+
+class XmlTree(list):
+	def __init__(self, xmlfile, paths_rel_to=None):
+		self.xmlfile = xmlfile
+		self.xtree = etree.parse(xmlfile)
+		self.xroot = self.xtree.getroot()
+		self.nodes, self.tag_node = GenerateTreeDict(self.xtree, self.xroot, '', paths_rel_to)
+		self.xspace = NamespaceFromDict(self.tag_node)
+	def SelectByTag(self, tag):
+		selection = [ e for e in self.nodes if e.tag == tag ]
+		return selection
+	def __getitem__(self, key):
+		return self.tag_node[key]
+	def keys(self):
+		return list(self.tag_node.keys())
+
+
+class XmlNode(object):
+	def __init__(self, element, path):
+		self.path = path
+		self.node = element
+		self.tag = element.tag		
+		self.value = element.text
+		self.attributes = element.attrib
+	def As(self, typ):
+		if typ == np.array:
+			sps = self.value.split()
+			return typ([ float(sp) for sp in sps ])
+		elif typ == bool:
+			return boolean_dict.get(self.value.lower())
+		else:
+			return typ(self.value)
+	def AsArray(self, typ, sep=' ', rep='\t\n'):
+		for r in rep:
+			self.value = self.value.replace(r, sep)
+		sp = self.value.split(sep)
+		return [ typ(s) for s in sp if str(s) != '' ]
+	def SetNodeValue(self, new_value):
+		self.value = new_value
+		if self.node != None:
+			self.node.firstChild.nodeValue = new_value
+		return
+	def __getitem__(self, key):
+		return self.node.get(key)
+
+
+# =============================================================================
+# COMMAND LINE & XML INPUT INTERFACE
+# =============================================================================
+
+class CLIO_HelpFormatter(argparse.HelpFormatter):
+	def _format_usage(self, usage, action, group, prefix):
+		return "%s : Command Line Interface\n" % sys.argv[0]
+
+
+class OptionsInterface(object):
+	def __init__(self):
+		# COMMAND-LINE ARGUMENTS
+		self.is_connected_to_cmd_ln = False
+		self.cmd_ln_args = None
+		self.cmd_ln_opts = None
+		self.cmd_ln_nicknames = [ '-h' ]
+		self.boolean_translator = boolean_dict
+		self.subtype = str
+		# XML OPTIONS FILE
+		self.is_connected_to_xml = False
+		self.xmlfile = None
+		self.tree = None
+		self.xdict = None
+		self.xspace = None
+		# JOINED OPTIONS
+		self.opts = ExtendableNamespace()
+	def Connect(self, xmlfile=None):
+		self.ConnectToCmdLn()
+		self.ConnectToOptionsFile(xmlfile)
+	def Parse(self, xkey='options'):
+		if self.is_connected_to_cmd_ln:
+			self.ParseCmdLn()
+		if self.is_connected_to_xml:
+			self.ParseOptionsFileXml(xkey)
+		if self.is_connected_to_cmd_ln and not self.is_connected_to_xml:
+			return self.cmd_ln_opts
+		elif self.is_connected_to_xml and not self.is_connected_to_cmd_ln:
+			return self.xspace
+		else:
+			return self.cmd_ln_opts, self.xspace
+	def ParseOptionsFile(self, xmlfile, xkey):
+		self.xmlfile = xmlfile
+		self.is_connected_to_xml = True
+		self.ParseOptionsFileXml(xkey)
+		return self.xspace
+	# COMMAND-LINE CONVENIENCE ================================================
+	def __call__(self):
+		return self.cmd_ln_opts
+	def ConnectToCmdLn(self, prog=sys.argv[0], descr=None):
+		self.cmd_ln_args = argparse.ArgumentParser(prog=sys.argv[0],
+			formatter_class=lambda prog: CLIO_HelpFormatter(prog,max_help_position=70))
+		self.is_connected_to_cmd_ln = True
+		return
+	def ParseCmdLn(self):
+		self.cmd_ln_opts = self.cmd_ln_args.parse_args()
+	def InterpretAsBoolean(self, expr):
+		try:
+			return self.boolean_translator.get(expr.lower())
+		except KeyError:
+			raise ValueError('CLIO does not know how to convert %s into a boolean.' % expr)
+	def InterpretAsNumpyArray(self, expr):
+		print("Interpret", expr)
+		array = [ float(e) for e in expr ]
+		array = np.array(array)
+		return array
+	def InterpretAsList(self, expr):
+		array = [ self.subtype(e) for e in expr ]
+		return array
+	def AddArg(self, name, typ=str, nickname=None, 
+			default=None, destination=None, help=None):
+		# Sort out <name> (e.g. --time) vs <destination> (e.g., time)
+		if '--' != name[0:2]:
+			dest = name
+			name = '--' + name
+		else:
+			dest = name[2:]
+		# Sort out <default> vs <required>
+		if default == None: required = True
+		else: required = False
+		# Construct default <help> it not given
+		if help == None: help = str(typ)
+		# Construct <nickname> if not given
+		if nickname == None:
+			nickname = '-'
+			for char in dest:
+				nickname += char
+				if not nickname in self.cmd_ln_nicknames:
+					break
+			if nickname in self.cmd_ln_nicknames:
+				raise ValueError('CLIO could not construct nickname from %s option'\
+					% name)
+			self.cmd_ln_nicknames.append(nickname)
+		# Process type
+		if typ in [int, float, str]:
+			nargs = None
+		elif typ == bool:
+			typ = self.InterpretAsBoolean
+			nargs = None
+		elif typ == np.array:
+			raise NotImplementedError
+			typ = float # self.InterpretAsNumpyArray
+			nargs = 3
+		elif typ == list:
+			typ = str
+			nargs = '*'
+		elif len(typ) == 2 and typ[0] == list:
+			typ = typ[1]
+			nargs = '*'
+		else:
+			raise NotImplementedError("CLIO does not know how to generate type '%s'"\
+				 % typ)
+		self.cmd_ln_args.add_argument(nickname, name, 
+				dest=dest,
+				action='store',
+				nargs=nargs,
+				required=required,
+				type=typ,
+				metavar=dest[0:1].upper(),
+				default=default,
+				help=help)
+		return
+	# COMMAND-LINE CONVENIENCE ================================================
+	def ConnectToOptionsFile(self, xmlfile):
+		if xmlfile == None or xmlfile == '': return
+		self.xmlfile = xmlfile
+		self.is_connected_to_xml = True
+		return
+	def ParseOptionsFileXml(self, xkey='options'):
+		if self.xmlfile == None: return
+		self.tree = XmlTree(self.xmlfile, paths_rel_to=xkey)
+		self.xdict = self.tree.tag_node
+		self.xspace = self.tree.xspace
+		return
+	def __getitem__(self, key):
+		try:
+			return self.xspace.__dict__[key]			
+		except KeyError:
+			return self.cmd_ln_opts.__dict__[key]
+		except KeyError:
+			raise AttributeError('No such option registered: \'%s\'' % key)
+		return None
+		
+
+# =============================================================================
+# OS SHELL INTERFACE
+# =============================================================================
+
+class ShellInterface(object):
+	def __init__(self):
+		# =====================================================================
+		# PRINTER ATTRIBUTES
+		self.color_dict = { \
+			'pp' : '\033[95m',
+			'mb' : '\033[34m',
+			'lb' : '\033[1;34m',
+			'my' : '\033[1;33m',
+			'mg' : '\033[92m',			
+			'mr' : '\033[91m',
+			'ww' : '\033[0;1m',
+			'ok' : '\033[92m',
+			'xx' : '\033[91m',
+			'warning' : '\033[93m',
+			'error' : '\033[95m',
+			'endcolor' : '\033[0;1m' }
+		self.justify_dict = { \
+			'o' : '  o ',
+			'.' : '... ',
+            'r' : '\r',
+			'ro' : '\r  o '}
+		self.pp = OS_COLOR('pp')
+		self.lb = OS_COLOR('lb')
+		self.mb = OS_COLOR('mb')		
+		self.mg = OS_COLOR('mg')
+		self.my = OS_COLOR('my')		
+		self.mr = OS_COLOR('mr')
+		self.ww = OS_COLOR('ww')
+		self.ok = OS_COLOR('ok')
+		self.xx = OS_COLOR('xx')
+		self.colors = [ OS_COLOR(c) for c in sorted(self.color_dict.keys()) ]
+		self.item = '  o '
+		self.iitem = '      - '
+		self.endl = OS_LINE_CHAR('\n')
+		self.flush = OS_LINE_CHAR('')
+		self.back = OS_LINE_CHAR('\r')
+		self.trail = ' '
+		# CURRENT STYLE SELECTION
+		self.sel_color = None
+		self.sel_justify = None
+		self.sel_header = False
+		self.sel_trim = "="
+		# EXE ATTRIBUTES
+		self.catch = OS_EXE_CATCH()
+		self.assert_zero = OS_EXE_ASSERT()
+		self.dev = OS_EXE_DEV('')
+		self.nodev = OS_EXE_DEV('')
+		self.devnull = OS_EXE_DEV()
+		self.devfile = OS_EXE_DEV('')
+		self.os_exe_get = False
+		self.os_exe_assert_zero = False
+		self.os_exe_dev = ''
+		self.os_exe_verbose = False
+		# LOGGING
+		self.logfile = None
+		# DIRECTORY HOPPING
+		self.paths_visited = [ os.getcwd() ]
+		self.exe_root_path = self.paths_visited[0]
+		self.N_store_paths_visited = 1+5
+	def __call__(self, mssg, c=None, j=None, h=False, t="="):
+		# c=color, j=justify, h=header, t=trim, u=upper-case
+		if j:
+			mssg = self.justify_dict[j] + mssg
+		if c != None:
+			mssg = self.color_dict[c] + mssg + self.color_dict['endcolor']
+		if h:
+			mssg = self.os_generate_header(mssg, t)
+		print(mssg)
+	# LOGFILE ADAPTOR =========================================================
+	def ConnectToFile(self, logfile):
+		self.logfile = logfile
+		sys.stdout = open(logfile, 'w')
+		self.devfile = OS_EXE_DEV(' >> {log} 2>> {log}'.format(log=logfile))
+		return
+	def DisconnectFromFile(self):
+		if self.logfile != None:
+			self.devfile = OS_EXE_DEV('')
+			self.logfile = None
+			sys.stdout = sys.__stdout__
+		else: pass
+		return
+	# PRINTER METHODS =========================================================
+	def __lshift__(self, mssg):
+		if type(mssg) == OS_LINE_CHAR:
+			# <LOG MESSAGE HERE>
+			sys.stdout.write(str(mssg))
+			sys.stdout.flush()
+			self.sel_color = None
+			return self
+		elif type(mssg) == OS_COLOR:
+			self.sel_color = str(mssg)
+			return self
+		mssg = str(mssg)
+		if self.sel_justify != None:
+			mssg = self.justify_dict[j] + mssg
+		mssg += self.trail
+		if self.sel_color != None:
+			mssg = self.color_dict[self.sel_color] \
+				+ mssg + self.color_dict['endcolor']
+		if self.sel_header:
+			mssg = self.os_generate_header(mssg, self.sel_trim)
+		# <LOG MESSAGE HERE>
+		sys.stdout.write(mssg)
+		return self
+	def os_print(self, mssg, c=None, j=None, h=False, t="="):
+		# c=color, j=justify, h=header, t=trim, u=upper-case
+		if j:
+			mssg = OS_JUSTIFY_DICT[j] + mssg
+		if c != None:
+			mssg = OS_COLOR_DICT[c] + mssg + OS_COLOR_DICT['endcolor']
+		if h:
+			mssg = os_generate_header(mssg, t)
+		print(mssg)
+		return
+	def os_print_config(self, c=None, j=None, h=False, t="=", tl=' '):
+		self.sel_color = c
+		self.sel_justify = j
+		self.sel_header = h
+		self.sel_trim = t
+		self.trail = tl
+		return
+	def os_print_reset(self):
+		self.sel_color = None
+		self.sel_justify = None
+		self.sel_header = False
+		self.sel_trim = "="
+		self.trail = ' '
+		return
+	def os_generate_header(title, trim="="):
+		try:
+		    height, width = os.popen('stty size', 'r').read().split()
+		    width = int(width)
+		    leftright = ((width - len(title)-2) // 2
+		except ValueError:
+		    leftright = 40
+		return trim*leftright + " " + title + " " + trim*leftright
+	# EXECUTE METHODS =========================================================
+	def __rshift__(self, cmmd):
+		if type(cmmd) == OS_EXE_CATCH:
+			self.os_exe_get = True
+			return self
+		elif type(cmmd) == OS_EXE_DEV:
+			self.dev = cmmd
+			return self
+		elif type(cmmd) == OS_EXE_ASSERT:
+			self.os_exe_assert_zero = True
+			return self
+		# Redirect command as requested (not applicable if output is asked for)
+		if not self.os_exe_get:
+			if str(self.dev) != '':
+				cmmd += str(self.dev)
+				self.dev = self.nodev
+			else:
+				cmmd += str(self.devfile)
+		# Execute
+		if self.debug: self << self.my << "exe:" << cmmd << endl
+		if self.os_exe_get:
+			output = subprocess.getoutput(cmmd)
+			self.os_exe_get = False		
+			return output
+		else:
+			sign = os.system(cmmd)
+		if self.os_exe_assert_zero:
+			if str(sign) != '0':
+				raise RuntimeError("<OSIO> '%s' returned '%s'" % (cmmd, sign))
+			self.os_exe_assert_zero = False
+		return sign
+	# EXIT PROTOCOLS ==========================================================
+	def okquit(self, what=''):
+		if what != '': self << self.ok << what << self.endl
+		self.DisconnectFromFile()
+		sys.exit(0)
+		return
+	def xxquit(self, what=''):
+		if what != '': self << self.xx << "ERROR" << what << self.endl
+		self.DisconnectFromFile()
+		sys.exit(1)
+		return
+	# DIRECTORY HOPPING =======================================================
+	def cd(self, d):
+		# Current working directory, for archiving ... =>
+		cwd = os.getcwd()
+		if type(d) == int:
+			# Change to previously visited path
+			os.chdir(self.paths_visited[d])
+		elif type(d) == str:
+			# Change to path as specified explicitly
+			os.chdir(d)
+		else:
+			raise NotImplementedError
+		# <= ... previous path
+		self.paths_visited.append(cwd)
+		if len(self.paths_visited) > self.N_store_paths_visited:
+			self.paths_visited.pop(1) # 0 stores root
+		if self.debug: self << self.my << "cd: " << os.getcwd() << self.endl
+		return
+	def pwd(self):
+		return self.cwd()
+	def cwd(self):
+		return os.getcwd()
+	def root(self):
+		self.cd(self.exe_root_path)
+		return
+	def abspath(self, file):
+		if not os.path.exists(file):
+			raise IOError("<osio::abspath> No such item in local directory: '%s'" % file)
+		return os.path.join(self.cwd(), file)
+	def mkcd(self, directory):
+		self >> self.assert_zero >> 'mkdir -p %s' % directory
+		self.cd(directory)
+		return directory
+
+class OS_EXE_DEV(object):
+	def __init__(self, dev=' > /dev/null 2> /dev/null'):
+		self.dev = dev
+	def __str__(self):
+		return self.dev
+
+class OS_EXE_CATCH(object):
+	def __init__(self):
+		self.catch = True
+		
+class OS_EXE_ASSERT(object):
+	def __init__(self):
+		self.assert_0 = True
+
+class OS_COLOR(object):
+	def __init__(self, colstr):
+		self.colstr = colstr
+	def __str__(self):
+		return self.colstr
+
+class OS_LINE_CHAR(object):
+	def __init__(self, char):
+		self.char = char
+	def __str__(self):
+		return self.char
+
+
+class OSIO(ShellInterface, OptionsInterface):
+	def __init__(self):
+		self.debug = False
+		ShellInterface.__init__(self)
+		OptionsInterface.__init__(self)
+		return
+	def sleep(self, dt):
+		time.sleep(dt)
+		return
+
+
+osio = OSIO()
+endl = OS_LINE_CHAR('\n')
+flush = OS_LINE_CHAR('')
+back = OS_LINE_CHAR('\r')
+catch = OS_EXE_CATCH()
+devnull = OS_EXE_DEV()
+
diff --git a/src/main/scala/eu/nomad_lab/parsers/LibAtomsParser.scala b/src/main/scala/eu/nomad_lab/parsers/LibAtomsParser.scala
index 654aa4d60386103398a9bf88bbac8d113cb7d834..87a058fd2555aa0c9b7e2a8cbc9a3a3d5747d08a 100644
--- a/src/main/scala/eu/nomad_lab/parsers/LibAtomsParser.scala
+++ b/src/main/scala/eu/nomad_lab/parsers/LibAtomsParser.scala
@@ -21,7 +21,7 @@ object LibAtomsParser extends SimpleExternalParserGenerator(
       )) :: Nil
   ),
   mainFileTypes = Seq("text/.*"),
-  mainFileRe = """ ???? """.r,
+  mainFileRe = """ ll """.r,
   cmd = Seq(DefaultPythonInterpreter.pythonExe(), "${envDir}/parsers/lib-atoms/parser/parser-lib-atoms/libAtomsParser.py",
     "${mainFilePath}"),
   resList = Seq(