#-*- coding: utf-8 -*-

# Copyright 2008-2012 Calculate Ltd. http://www.calculate-linux.org
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

import sys
import os
import stat
import re
import errno
import xml.dom.minidom as minidom
import xml
import importlib
if hasattr(xml,"use_pyxml"):
    xml.use_pyxml()
from xml import xpath
import subprocess
import types
import random
import string
import time
import glob
import hashlib
import fcntl
from itertools import *
#                    <   <=  ==  !=  >=  >
from operator import lt, le, eq, ne, ge, gt

from utils.common import _error, _warning,getTupleVersion,getPortageUidGid
from utils.text import  _toUNICODE, convertStrListDict
from utils.portage import  isPkgInstalled,reVerSplitToPV
from utils.content import PkgContents,checkContents,getCfgFiles,fillContents
from utils.files import (getModeFile, listDirectory,removeDir, typeFile,
                        scanDirectory,timeout,
                        pathJoin,readFile,readLinesFile,process,STDOUT)
from datavars import DataVarsError

from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_lib3',sys.modules[__name__])

PORTAGEUID,PORTAGEGID = getPortageUidGid()

class TemplatesInterrupt(Exception):
    """
    Interrupt templates appling
    """
    EXIT,ABORT=1,2

    def __init__(self,*args):
        self.message = args[0]
        self.args = args
    
    def __str__(self):
        return str(self.message)

    def isExit(self): return self.isInterrupt() and self.args[1] == self.EXIT

    def isAbort(self): return self.isInterrupt() and self.args[1] == self.ABORT

    def status(self): return self.args[1] if self.isInterrupt() else 0

    def isInterrupt(self): return len(self.args)>1

class TemplatesError(TemplatesInterrupt):
    """
    Error on templates appling
    """

class _shareTermsFunction:
    """Общие аттрибуты для классов _terms и templateFunctions"""
    # Символы допустимые в скобках функции шаблона
    _reFunctionArgvInSquareBrackets = "a-zA-Z0-9_:;\-\+\,\*\/\.\'\"~\\\\ "
    _reFunctionArgvText = "[%s]"%_reFunctionArgvInSquareBrackets
    # регулярное выражение для поиска функции в шаблоне 
    _reFunctionText = "([a-zA-Z0-9\_\-]+)\((%s+|)\)" %_reFunctionArgvText


class _terms(_error, _shareTermsFunction):
    """Вычисление условий применяемых в шаблонах

    """
    # регулярное выражение для поиска функции в шаблоне
    _reFunction = re.compile(_shareTermsFunction._reFunctionText)
    # регулярное выражение для не версии
    _re_not_Version = re.compile("[^0-9\.]")
    # регулярное выражение не номер
    _re_not_Number = re.compile("[^0-9]")
    _suffixDict = {"pre": -2, "p": 0, "alpha": -4, "beta": -3, "rc": -1}
    _lenSuffixDict = len(_suffixDict)
    # Регулярное выражение для названия переменной
    _reRightName = re.compile("^(?:[a-z\_\-]+\.)?(?:[a-zA-Z0-9\_\-]+)$")
    # Регулярное выражение для сравниваемого значения
    _reDenyValue = re.compile("[^0-9a-zA-Z_/\.-]")
    # латинские буквы в нижнем регистре
    _letters = list(string.ascii_lowercase)

    def _splitVersion(self, strVersion):
        """
        Split version. Version, addition letter, list suffixes with version,
        revision.
        Examples:
          3.0.0_beta2
            ("3.0.0_beta2","",[],"")
          3.0.0_beta2-r1
            ("3.0.0_beta2","",[],"r1")
          3.0.0_beta2a-r1
            ("3.0.0_beta2","a",[],"r1")
          3.0.0_beta2a_rc1-r1
            ("3.0.0_beta2","a",[("rc","1")],"r1")
          3.0.0_beta2a_rc1_p20111212-r1 
            ("3.0.0_beta2","a",[("rc1","1"),("p","20111212")],"r1")
        """
        # get revision from version
        strWorkVersion, spl, rVersion = strVersion.rpartition("-")
        if rVersion == strVersion:
            strWorkVersion = rVersion
            rVersion = ""

        suffixes = []
        # get suffixes from version
        while "_" in strWorkVersion:
            # 2.3_p45 ('2.3','_','p43')
            # 2.3_rc4_p45 ('2.3_rc4','_','p43')
            strWorkVersion, spl, suffix = strWorkVersion.rpartition("_")
            suffSplList = filter(lambda x: suffix.startswith(x),
                                 self._suffixDict.keys())
            if suffSplList:
                suffSpl = suffSplList[0]
                lenSuffSpl = len(suffSpl)
                suffixVersion = suffix[lenSuffSpl:]
                suffixes.append((suffSpl,suffixVersion))
        letters = ""
        numberVersion = strWorkVersion
        if numberVersion and numberVersion[-1:] in self._letters:
            letters = numberVersion[-1:]
            numberVersion = numberVersion[:-1]
        return numberVersion, letters, suffixes, rVersion

    def _notVersion(self, strVersion):
        """strVersion is not version - True"""
        numberVersion, letters, suffixes, rVersion =\
            self._splitVersion(strVersion)
        if not numberVersion.strip():
            return True
        if self._re_not_Version.search(numberVersion):
            return True
        if letters and not letters in self._letters:
            return True
        for suffix,suffixVersion in suffixes:
            if suffixVersion and self._re_not_Number.search(suffixVersion):
                return True
        if rVersion:
            if rVersion[0] != "r" or len(rVersion) == 1:
                return True
            if self._re_not_Number.search(rVersion[1:]):
                return True
        return False

    def _convertVers(self, verA, verB):
        """Конвертирование номеров версий для корректного сравнения
        """
        def fillZero(elemA, elemB):
            #elemA, elemB = elemA[], elemB[]
            if len(elemA) > len(elemB):
                maxElemB = len(elemB)-1
                for i in range(len(elemA)):
                    if i > maxElemB:
                        elemB.append("0")
            else:
                maxElemA = len(elemA)-1
                for i in range(len(elemB)):
                    if i > maxElemA:
                        elemA.append("0")
            for i in range(len(elemB)):
                lenA = len(elemA[i])
                lenB = len(elemB[i])
                if lenA == lenB:
                    pass
                elif lenA > lenB:
                    res = lenA - lenB
                    for z in range(res):
                        elemB[i] = "0" + elemB[i]
                elif lenB > lenA:
                    res = lenB - lenA
                    for z in range(res):
                        elemA[i] = "0" + elemA[i]

        def fillSuffix(elemA,elemB,sA,svA,sB,svB):
            if str(sA) or str(sB):
                svA, svB =  map(lambda x: [x] if x else ['0'], (svA, svB))
                fillZero(svA, svB)
                sA, sB = map(lambda x: x if x else 0, (sA, sB))
                elemA.append(str(self._lenSuffixDict + sA))
                elemA.extend(svA)
                elemB.append(str(self._lenSuffixDict + sB))
                elemB.extend(svB)

        #Version, letters, suffix, suffixVersion, rVersion
        vA, lA, ssA, rvA = self._splitVersion(verA)
        vB, lB, ssB, rvB = self._splitVersion(verB)
        elemA = vA.split(".")
        elemB = vB.split(".")
        fillZero(elemA, elemB)
        if lA or lB:
            lA, lB = map(lambda x: x if x else '0', (lA, lB))
            elemA.append(lA)
            elemB.append(lB)

        # dereferencing suffix in suffixes list
        ssA = map(lambda x:(self._suffixDict.get(x[0],0),x[1]),ssA)
        ssB = map(lambda x:(self._suffixDict.get(x[0],0),x[1]),ssB)
        for suffix,sufVer in reversed(ssA):
            if ssB:
                sB,svB = ssB.pop()
            else:
                sB,svB = "",""
            fillSuffix(elemA,elemB,suffix,sufVer,sB,svB)
        while ssB:
            sB,svB = ssB.pop()
            fillSuffix(elemA,elemB,"","",sB,svB)

        if rvA or rvB:
            rvA, rvB = map(lambda x: [x[1:]], (rvA, rvB))
            fillZero(rvA, rvB)
            elemA += rvA
            elemB += rvB
        return  (".".join(elemA), ".".join(elemB))


    def _equalTerm(self, term, textError, function=False):
        """Вычисление логических выражений для условий

        Для корректной работы в классе который наследует этот класс
        должен быть объявлен аттрибут self.objVar
        (объект для работы с переменными)
        function - функция для  для обработки функций в заголовке блока
        """
        rpl = lambda x: x.replace("@@"," ")
        trm = {"&&":"@@and@@","||":"@@or@@"}
        dictRuleFunc = {"==":eq, "!=":ne, ">=":ge, "<=":le, ">":gt, "<":lt}
        rule = dictRuleFunc.keys()
        listEqual = []
        for k in trm.keys():
            if k in term:
               term = term.replace(k,trm[k])
        trs = term.split("@@")
        listSplitOr = []
        if "or" in trs:
            lst = []
            for t in trs:
                if t != "or":
                    lst.append(t)
                else:
                    listSplitOr.append(lst)
                    lst = []
            if lst:
                listSplitOr.append(lst)
        else:
            listSplitOr = [trs]
        for trsAnd in listSplitOr:
            listEqual = []
            for t in trsAnd:
                flagRule = False
                for sepF in rule:
                    if sepF in t:
                        flagRule = True
                        vals = t.split(sepF)
                        break
                if flagRule:
                    #проверка на допустимость названия переменной
                    flagFunction = False
                    if not self._reRightName.search(vals[0]):
                        #проверка на допустимость функции
                        flagError = True
                        if function:
                            searchFunct = self._reFunction.search(vals[0])
                            if searchFunct:
                                flagError = False
                                flagFunction = True
                        if flagError:
                            self.setError("'%s'"%rpl(term)+" "+ _("incorrect"))
                            self.setError(textError)
                            return False
                    #проверка на допустимость значения
                    if self._reDenyValue.search(vals[1]):
                        self.setError("'%s'"%rpl(term) + " " + _("incorrect"))
                        self.setError(textError)
                        return False
                    flagIntTypeVar = None
                    if flagFunction:
                        valVars = function("#-%s-#"%vals[0])
                        if valVars is False:
                            self.setError("'%s'"%rpl(term)+" "+ _("incorrect"))
                            self.setError(textError)
                            return False
                        if "load" == searchFunct.group(1) and\
                            re.search("\(\s*num\s*,",vals[0]):
                            if valVars:
                                try:
                                    valVars = int(valVars)
                                except:
                                    self.setError("'%s'"%rpl(term) + " " + \
                                    _("incorrect"))
                                    self.setError(textError)
                                    return False
                                flagIntTypeVar = True
                            else:
                                flagIntTypeVar = False
                        else:
                            if valVars == "" and\
                                not self._notVersion(vals[1]):
                                    valVars = "0"
                            elif vals[1] == "" and\
                                not self._notVersion(valVars):
                                    vals[1] = "0"
                    else:
                        try:
                            valVars = self.objVar.Get(vals[0])
                            if not valVars:
                                valVars = ""
                        except DataVarsError, e:
                            raise TemplatesError("{header}\n{body}".format(
                                header=textError,body=str(e)))
                    # Номера версий для ini
                    flagNotIniFunct = True
                    # Два значения не пусты
                    flagNotEmptyVals = not (valVars == "" and vals[1] == "")
                    if flagFunction and flagNotEmptyVals and\
                        searchFunct.group(1) == "ini":
                        # Проверка значения на версию
                        if not self._notVersion(valVars) and\
                            not self._notVersion(vals[1]):
                            verFile, verVar = self._convertVers(vals[1],valVars)
                            res = dictRuleFunc[sepF](verVar,verFile)
                            if res:
                                listEqual.append(True)
                            else:
                                listEqual.append(False)
                                break
                            flagNotIniFunct = False
                    # Cравниваем номера версий
                    if flagNotIniFunct:
                        if flagNotEmptyVals and\
                            ("_ver" in vals[0] or\
                            (flagFunction and searchFunct.group(1) in \
                                ("pkg","merge")) or\
                            (flagFunction and searchFunct.group(1)=="load" and\
                            re.search("\(\s*ver\s*,",vals[0]))):
                            # Проверка значения на версию
                            if self._notVersion(vals[1]):
                                self.setError("'%s'"%rpl(term)+" "+\
                                              _("incorrect"))
                                self.setError(
                                    _("This value is not a version"))
                                return False
                            # Проверка значения функции на версию
                            if self._notVersion(valVars):
                                self.setError("'%s'"%rpl(term)+" "+\
                                              _("incorrect"))
                                self.setError(\
                                    _("The function value is not a version"))
                                return False
                            verFile, verVar = self._convertVers(vals[1],valVars)
                            res = dictRuleFunc[sepF](verVar,verFile)
                            if res:
                                listEqual.append(True)
                            else:
                                listEqual.append(False)
                                break
                            flagNotIniFunct = False
                        else:
                            if flagIntTypeVar is None:
                                flagIntTypeVar = True
                                try:
                                    valVars = int(valVars)
                                except:
                                    flagIntTypeVar = False
                            if flagIntTypeVar:
                                if not vals[1].strip():
                                    vals[1] = 0
                                try:
                                    valFile = int(vals[1])
                                    valVar = valVars
                                    res = dictRuleFunc[sepF](valVar, valFile)
                                    if res:
                                        listEqual.append(True)
                                    else:
                                        listEqual.append(False)
                                        break
                                except:
                                    flagIntTypeVar = False
                            if not flagIntTypeVar:
                                if sepF == "!=" or sepF == "==":
                                    if not vals[1].strip():
                                        vals[1] = ""
                                    valFile = vals[1]
                                    valVar = valVars
                                    res = dictRuleFunc[sepF](valVar, valFile)
                                    if res:
                                        listEqual.append(True)
                                    else:
                                        listEqual.append(False)
                                        break
                                else:
                                    if not flagNotEmptyVals:
                                        listEqual.append(False)
                                        break
                                    else:
                                        self.setError("'%s'"%rpl(term) + " "\
                                            + _("incorrect"))
                                        self.setError(textError)
                                        return False
                else:
                    if t == "and":
                        if listEqual == [] or False in listEqual:
                            listEqual = [False]
                            break
                        else:
                            listEqual = [True]
                    else:
                        self.setError("'%s'"%rpl(term) + " " + _("incorrect"))
                        self.setError(textError)
                        return False
            if not (listEqual == [] or False in listEqual):
                break
        if listEqual == [] or False in listEqual:
            return False
        return True

    def splitParLine(self, linePar):
        '''Split params line'''
        def splitQuote(listPar, quoteSymbol):
            listTerm = map(lambda x: x+quoteSymbol, ("=",">","<"))
            flagQ = False
            mass = []
            v = ""
            for i in listPar:
                if i.count(quoteSymbol)==1:
                    if flagQ and i.endswith(quoteSymbol):
                        v = v + " " + i
                        mass.append(v)
                        v = ""
                        flagQ = False
                    elif filter(lambda x: x in i, listTerm):
                        flagQ = True
                        v = i
                    else:
                        mass.append(i)  
                elif flagQ:
                    v = v + " " + i
                else:
                    mass.append(i)
            foundPar = list(set(mass)-set(listPar))
            return not flagQ, filter(lambda x: not x in foundPar, mass),foundPar

        listPar = re.split("\s+",linePar)
        flagFoundQ = "'" in linePar
        flagFoundQQ = '"' in linePar
        if flagFoundQ and flagFoundQQ:
            flagQ, listSplQPar, listFoundQPar =  splitQuote(listPar, "'")
            if flagQ:
                flagQQ, listSplQQPar, listFoundQQPar = splitQuote(listSplQPar,
                                                                  '"')
                if flagQQ:
                    listPar = listSplQQPar + listFoundQPar + listFoundQQPar
        elif flagFoundQQ:
            flagQQ, listSplQQPar, listFoundQQPar =  splitQuote(listPar, '"')
            if flagQQ:
                listPar = listSplQQPar + listFoundQQPar
        elif flagFoundQ:
            flagQ, listSplQPar, listFoundQPar =  splitQuote(listPar, "'")
            if flagQ:
                listPar = listSplQPar + listFoundQPar
        if flagFoundQ:
            listQPar = []
            for par in listPar:
                if par.endswith("'"):
                    listQPar.append(par.replace("'",""))
                else:
                    listQPar.append(par)
            listPar = listQPar
        if flagFoundQQ:
            listQQPar = []
            for par in listPar:
                if par.endswith('"'):
                    listQQPar.append(par.replace('"',''))
                else:
                    listQQPar.append(par)
            listPar = listQQPar
        return listPar

class fileHeader(_terms):
    """Обработка заголовков шаблонов и конфигурационных файлов

    """
    # Допустимые параметры заголовка
    allowParam = ["format", "format_conf", "comment", "append", "force",
                  "link", "mirror", "symbolic", "chmod", "chown", "name",
                  "path", "autoupdate","protected", "run","exec","merge",
                  "module","env"]

    # Тип шаблона
    fileType = ""
    # Тип вставки шаблона
    typeAppend = ""
    # Возможные типы вставки шаблонов
    _fileAppend = "join", "before", "after", "replace", "remove", "skip",\
                  "patch", "clear"
    # Интерпретатор (#!/bin/bash) (#!/usr/bin/python)
    execStr = ""
    # Символ комментария
    comment = False
    # Выражение для поиска строки интерпретатора
    reExecStr = re.compile("^(#!.+\s)",re.M)
    # условные операторы
    terms = ('>', '<', '==', '!=', '>=', '<=')
    # параметры без значения
    listParNotVal = ("symbolic", "force", "mirror", "autoupdate", "protected")
    # Результат вычисления условия в заголовке
    headerTerm = True

    def __init__(self, templateName, text, comment=False, fileType=False, 
                 objVar=False, function=False, templateObj=None):
        self.body = text
        # Объект с переменными
        self.objVar=objVar
        # Параметры описанные в заголовке файла шаблона
        self.params = {}
        # некорректные параметры
        incorrectParams = []
        # Поиск строки запустка  (#!/bin/bash и.т. д)
        if comment or fileType!="bin":
            reExecRes = self.reExecStr.search(self.body)
            if reExecRes:
                self.execStr = self.body[reExecRes.start():reExecRes.end()]
                self.body = self.body[:reExecRes.start()] +\
                            self.body[reExecRes.end():]
        # Удаление Заголовка Calculate
        if comment:
            titleFirst = "Modified"
            # В случае текста XML
            if type(comment) == types.TupleType and len(comment) == 2:
                reCalcHeader =\
                    re.compile("\s*%s\s+%s.+\s+(.+\n)+%s\s?"\
                    %(comment[0], titleFirst, comment[1]),re.M|re.I)
                reS = reCalcHeader.search(self.body)
                if reS:
                    self.body =  self.body[:reS.start()]+self.body[reS.end():]
            else:
                reCalcHeader = re.compile(\
                    "\s*%s\-+\s+%s\s+%s.+\s+(%s.+\s+)+%s\-+\s?"\
                    %(comment, comment, titleFirst ,comment,comment),
                    re.M|re.I)
                reS = reCalcHeader.search(self.body)
                if reS:
                    self.body = self.body[reS.end():]
        if fileType != False:
            if fileType=="bin":
                self.params["format"] = fileType
                self.fileType = self._getType()
                self.typeAppend = self._getAppend()
            else:
                textLines = self.body.splitlines()
                if textLines:
                    textLine = textLines[0]
                    rePar = re.compile(\
                        "\s*#\s*calculate\s+\\\\?|\s*#\s*calculate\\\\?$", re.I)
                    reP = rePar.search(textLine)
                    if reP:
                        reL = False
                        reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*",re.M)
                        reLs = reLns.search(self.body)
                        if reLs:
                            reL = reLs
                            paramLine = self.body[reP.end():reLs.end()]
                            paramLine = paramLine.replace("\\"," ")
                        else:
                            reLn = re.compile("\n")
                            reL = reLn.search(self.body)
                            paramLine = textLine[reP.end():]
                        if reL:
                            self.body = self.body[reL.end():]
                        else:
                            self.body = ""
                        paramLine = templateObj.applyFuncTemplate(paramLine,templateName)
                        paramList = self.splitParLine(paramLine)
                        if paramList:
                            for i in paramList:
                                foundTerm = False
                                for term in self.terms:
                                    if term in i:
                                        foundTerm = True
                                        errorMsg = _("Incorrect template") +\
                                                     ": "+ templateName +"\n"+\
                                               _("template header not valid")+\
                                                 ": "+ i
                                        if function:
                                            rezTerm = self._equalTerm(i,
                                                                      errorMsg,
                                                                      function)
                                        else:
                                            rezTerm = self._equalTerm(i,
                                                                      errorMsg)
                                        if not rezTerm:
                                            self.headerTerm = False
                                        break
                                if not foundTerm:
                                    par = i.split("=")
                                    if len(par) == 1:
                                        if i in self.listParNotVal:
                                            self.params[i] = "True"
                                        else:
                                            if i.strip():
                                                incorrectParams = set([i])
                                    elif len(par) == 2:
                                        self.params[par[0]] = par[1]
                                        if par[0] == "env":
                                            try:
                                                varModule = \
                                                    importlib.import_module(
                                                    "calculate.%s.variables"
                                                    %par[1])
                                            except (ImportError,
                                                    AttributeError),e:
                                                self.headerTerm = False
                    self.comment = self._getComment()
                self.fileType = self._getType()
                typeAppend = self._getAppend()
                if typeAppend:
                    self.typeAppend = typeAppend
                else:
                    self.headerTerm = False
                    self.setError(_("incorrect header parameter: '%s'")\
                                    %"append=%s"%self.params["append"])
        if any(x in self.params for x in ('exec','run')):
            if 'exec' in self.params:
                self.execStr = "#!%s\n"%self.params['exec']
            if 'run' in self.params:
                self.execStr = "#!%s\n"%self.params['run']
            if "python" in self.execStr:
                self.execStr += "# -*- coding: utf-8 -*-\n"

        if not incorrectParams and self.params:
            incorrectParams = set(self.params.keys()) - set(self.allowParam)
        if incorrectParams:
            self.headerTerm = False
            self.setError(_("incorrect header parameter: '%s'")\
                          %" ".join(list(incorrectParams)))

    def _getType(self):
        """Выдать тип файла"""
        if "format" in self.params:
            return self.params["format"]
        else:
            return "raw"

    def _getAppend(self):
        """Выдать тип добавления файла"""
        if self.params.has_key("append"):
            if self.params["append"] in self._fileAppend:
                return self.params["append"]
            else:
                return False
        else:
            if self.fileType != "raw" and self.fileType != "bin" and\
                self.fileType != "":
                if "format" in self.params and self.params["format"] in \
                    ("patch","diff"):
                    self.params["append"] = "patch"
                    return "patch"
                self.params["append"] = "join"
                return "join"
            self.params["append"] = "replace"
            return "replace"

    def _getComment(self):
        """Выдать символ комментария файла"""
        if self.params.has_key("comment"):
            if self.params["comment"] in ("xml", "XML"):
                return ("<!--","-->")
            else:
                return self.params["comment"]
        else:
            return False


class dirHeader(_terms):
    """Обработка заголовков шаблонов директорий

    """
    # Допустимые параметры заголовка
    allowParam = ["append", "chmod", "chown", "name", "path", "autoupdate",
                  "module","env","merge"]

    # Тип вставки шаблона
    typeAppend = ""

    # Возможные типы вставки шаблонов
    _fileAppend = "join", "remove", "skip", "clear"

    # условные операторы
    terms = ('>', '<', '==', '!=', '>=', '<=')

    # параметры без значения
    listParNotVal = ("symbolic", "force", "autoupdate")

    # Результат вычисления условия в заголовке
    headerTerm = True

    def __init__(self, templateName, text, objVar=False, function=False):
        self.body = text
        # Объект с переменными
        self.objVar=objVar
        # Параметры описанные в заголовке файла шаблона
        self.params = {}
        # некорректные параметры
        incorrectParams = set([])

        textLines = text.splitlines()
        flagErrorBody = False
        if textLines:
            textLine = textLines[0]
            rePar = re.compile(\
                "\s*#\s*calculate\s+\\\\?|\s*#\s*calculate\\\\?$",re.I)
            reP = rePar.search(textLine)
            if reP:
                reL = False
                reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*",re.M)
                reLs = reLns.search(text)
                if reLs:
                    reL = reLs
                    paramLine = text[reP.end():reLs.end()]
                    paramLine = paramLine.replace("\\"," ")
                else:
                    reLn = re.compile("\n")
                    reL = reLn.search(text)
                    paramLine = textLine[reP.end():]
                if reL:
                    self.body = text[reL.end():]
                else:
                    self.body = ""
                if self.body.strip():
                    self.headerTerm = False
                    self.setError(_("incorrect text in the template: '%s'")\
                                    %self.body)
                    flagErrorBody = True
                if not flagErrorBody:
                    paramList = self.splitParLine(paramLine)
                    if paramList:
                        for i in paramList:
                            foundTerm = False
                            for term in self.terms:
                                if term in i:
                                    foundTerm = True
                                    errorMsg = _("Incorrect template") +\
                                        ": "+ templateName +"\n"+\
                                        _("template header not valid")+ ": "+ i
                                    if function:
                                        rezTerm = self._equalTerm(i, errorMsg,
                                                                  function)
                                    else:
                                        rezTerm = self._equalTerm(i, errorMsg)
                                    if not rezTerm:
                                        self.headerTerm = False
                                    break
                            if not foundTerm:
                                par = i.split("=")
                                if len(par) == 1:
                                    if i in self.listParNotVal:
                                        self.params[i] = "True"
                                    else:
                                        if i.strip():
                                            incorrectParams = set([i])
                                elif len(par) == 2:
                                    self.params[par[0]] = par[1]
                                    if par[0] == "env":
                                        try:
                                            varModule = \
                                                importlib.import_module(
                                                "calculate.%s.variables"%par[1])
                                        except (ImportError,AttributeError),e:
                                            self.headerTerm = False
                                        self.objVar.defaultModule = \
                                            self.params['env']
                    typeAppend = self._getAppend()
                    if typeAppend:
                        self.typeAppend = typeAppend
                    else:
                        self.headerTerm = False
                        self.setError(_("incorrect header parameter: '%s'")\
                                      %"append=%s"%self.params["append"])
        if not flagErrorBody:
            if not incorrectParams:
                incorrectParams = set(self.params.keys()) - set(self.allowParam)
            if incorrectParams:
                self.headerTerm = False
                self.setError(_("incorrect header parameter: '%s'")\
                              %" ".join(list(incorrectParams)))

    def _getAppend(self):
        """Выдать тип добавления директории"""
        if self.params.has_key("append"):
            if self.params["append"] in self._fileAppend:
                return self.params["append"]
            else:
                return False
        else:
            return "join"

class objShare:
    """Общий клас для объектов, наследуем

    """

    def createFieldTerm(self, name, value, quote, docObj):
        """Создание поля переменная - значение

        при создании поля проверяется первый символ названия переменной
        и добавляется тег action
        "!" - <action>drop</action> удаляет
        "+" - <action>join</action> добавляет
        "-" - <action>replace</action> заменяет
        """
        fieldAction = False
        if name:
            if name[0] == "!" or name[0] == "-" or name[0] == "+":
                qnt = self.removeSymbolTerm(quote)
                fieldXML = docObj.createField("var",[qnt],
                                              name[1:], [value],
                                              False, False)
                if name[0] == "!":
                    fieldAction = "drop"
                elif name[0] == "+":
                    fieldXML.setAttribute("type", "seplist")
                    fieldAction = "join"
            else:
                fieldXML = docObj.createField("var",
                                              [quote.replace("\n","")],
                                              name, [value],
                                              False, False)
        else:
            fieldXML = docObj.createField("var",
                                          [quote.replace("\n","")],
                                          name, [value],
                                          False, False)
        if fieldAction:
            docObj.setActionField(fieldXML, fieldAction)
        return fieldXML

    def removeSymbolTerm(self, text):
        """Удаляет первый символ названия переменной в строке

        Если первый встречающийся символ с начала строки
        '+', '-', '!' то он из этой строки будет удален,
        если перед этим символом были пробельные символы,
        то они будут сохранены, так-же если в строке есть символ
        перевода строки он будет удален.
        """
        reTerm = re.compile("^[ \t]*(\!|\+|\-)")
        textNS = text.replace("\n","")
        res = reTerm.search(textNS)
        if res:
            textNS = textNS[res.start():res.end()-1] + textNS[res.end():]
        return textNS

    def getConfig(self,joinChar=""):
        """Выдает конфигурационный файл"""
        listConfigTxt = []
        childNodes = self.docObj.getNodeBody().childNodes
        for node in childNodes:
            if node.nodeType == node.ELEMENT_NODE:
                if node.tagName == "field":
                    listConfigTxt.append(self.docObj.getQuoteField(node))
                elif node.tagName == "area":
                    self.docObj.xmlToText([node], listConfigTxt)
        return joinChar.join(listConfigTxt)


    def splitToFields(self, txtBloc):
        """Разбиваем текст на поля (объекты) которые имеют следующие аттрибуты

        self.name  - если переменная то имя переменной
        self.value  - если у переменной есть значение то значение переменной
        self.comment - если комментарий то текст комментария
        self.br - если перевод строки то текст перед переводом из пробелов

        Результат список объектов полей
        """
        finBloc = "\n"
        if txtBloc[-1] != "\n":
            finBloc = ""

        linesBlocTmp = txtBloc.splitlines()
        linesBloc = []
        brBloc = []
        z = 0
        lenLines = len(linesBlocTmp)
        for i in linesBlocTmp:

            if self.reComment.split(i)[0]:
                findCooment = self.reComment.search(i)
                comment = False
                par = i
                if findCooment:
                    par = i[:findCooment.start()]
                    comment = i[findCooment.start():]
                fields = self.reSepFields.split(par)
                lenFields = len(fields)

                if lenFields>1:
                    for fi in range(lenFields-1):
                        linesBloc.append(fields[fi]+ self.sepFields)
                        if fi == lenFields-2:
                            if comment:
                                brBloc.append("")
                            else:
                                if (lenLines-1)== z:
                                    brBloc.append(finBloc)
                                else:
                                    brBloc.append("\n")
                        else:
                            brBloc.append("")
                    if comment:
                        linesBloc.append(comment)
                        if (lenLines-1)== z:
                            brBloc.append(finBloc)
                        else:
                            brBloc.append("\n")
                else:
                    linesBloc.append(i)
                    if (lenLines-1)== z:
                        brBloc.append(finBloc)
                    else:
                        brBloc.append("\n")
            else:
                linesBloc.append(i)
                if (lenLines-1)== z:
                    brBloc.append(finBloc)
                else:
                    brBloc.append("\n")
            z +=1
        fields = self.setDataField(linesBloc, brBloc)
        return fields

class xmlShare:
    """Общий класс для объектов XML, наследуем

    """
    def _createElement(self, doc, tagName, text="", attributes={}):
        """Создание нового XML элемента"""
        element = doc.createElement(tagName)
        if text:
            txtNode = doc.createTextNode(_toUNICODE(text))
            element.appendChild(txtNode)
        for attr in attributes.keys():
            attribute = doc.createAttribute(attr)
            attribute.nodeValue = attributes[attr]
            element.setAttributeNode(attribute)
        return element


class xmlNode(xmlShare):
    """Класс для создания нод без аттрибутов

    """
    def __init__(self):
        self.node = False


    def createNode(self, doc, tagName, text=""):
        """Создает XML элемент без аттрибутов"""
        self.node=self._createElement(doc, tagName, text)
        return self.node

    def getNode(self):
        return self.node


class xmlCaption:
    """Класс XML заголовок

    """
    def __init__(self):
        #Заголовок области XML нода
        self.caption = False


    def createCaption(self, doc, name, quotes, action=False):
        """Создание заголовка области"""
        tmpNode = xmlNode()
        self.caption = tmpNode.createNode(doc, "caption")
        nameNode = tmpNode.createNode(doc, "name",name)
        self.caption.appendChild(nameNode)
        if action:
           actNode = tmpNode.createNode(doc, "action", action)
           self.caption.appendChild(actNode)
        for q in quotes:
            quoteNode = tmpNode.createNode(doc, "quote", q)
            self.caption.appendChild(quoteNode)
        return self.caption

    def getCaption(self):
        """Выдает XML ноду заголовка области"""
        return self.caption

class xmlField(xmlShare):
    """Класс для работы с XML полем

    """
    def __init__(self):
        # XML нода поле
        self.field = False


    def createField(self, doc, typeField, quotes, name="",
                    values=[],action=False):
        """Cоздание XML ноды поле"""
        self.field = self._createElement(doc, "field", "", {"type":typeField})
        if name:
            nameNode = self._createElement(doc, "name", name)
            self.field.appendChild(nameNode)
        for v in values:
            valueNode = self._createElement(doc, "value", v)
            self.field.appendChild(valueNode)
        if action:
           actNode = self._createElement(doc, "action", action)
           self.field.appendChild(actNode)
        for q in quotes:
            quoteNode = self._createElement(doc, "quote", q)
            self.field.appendChild(quoteNode)
        return self.field



class xmlFields:
    """Класс, в котором находится список ХМL нод field

    """
    def __init__(self):
        self.fields = []

    def appendField(self, field):
        """Добавить XML ноду field"""
        self.fields.append(field)
        return self.fields

    def getFields(self):
        """Выдать список XML нод"""
        return self.fields


class xmlArea:
    """Класс для работы с XML областью

    """
    def __init__(self):
        # Область
        self.area = False

    def createArea(self, doc, xmlCaption, xmlFields):
        """Создание XML области"""
        tmpNode = xmlNode()
        self.area = tmpNode.createNode(doc, "area")
        if xmlCaption and xmlCaption.getCaption():
            self.area.appendChild(xmlCaption.getCaption())
        if xmlFields:
            fields = xmlFields.getFields()
            for field in fields:
                self.area.appendChild(field)
        return self.area

class xmlDoc:
    """Класс для работы с XML документом

    """
    def __init__(self):
        # документ
        self.doc = False
        # главная нода
        self.root = False
        # тело документа
        self.body = False
        # Заголовок области - временный (в реальности один объект заголовок)
        self.tmpCaption = False
        # Поля - временные (в реальности один объект поля)
        self.tmpFields = False
        # Разделитель областей - по умолчанию перевод строки "\n"
        self.sepAreas  = False
        # Разделитель разделенных списков - по умолчанию перевод строки "\n"
        #self.sepSplitFields  = False


    def createDoc(self, typeDoc, version):
        """Создание нового документа новый документ"""
        docTxt = '<?xml version="1.0" encoding="UTF-8"?><cxmlconf><head>'
        docTxt += '<ver>%s</ver>'% version
        docTxt += '<format>%s</format>' % typeDoc
        docTxt += '</head><body></body></cxmlconf>'
        self.doc = minidom.parseString(docTxt)
        self.root = self.doc.documentElement
        self.body = xpath.Evaluate('child::body',self.root)[0]
        # установка разделителя областей
        self.sepAreas  = self.createField("br",[],"",[],False,False)
        # установка разделителя областей разделенных списков
        #self.sepSplitFields  = self.createField("br",[],"",[],False,False)
        return self.doc

    def addField(self, field):
        """Добавляет поле во временный список

        Из этого списка в дальнейшем формируется XML область
        """
        if not self.tmpFields:
            self.tmpFields = xmlFields()
        self.tmpFields.appendField(field)

    def createCaption(self, name, quotes, action=False):
        """Cоздает заголовок области

        Помещает заголовок в временный артибут
        Используется при создании области
        """
        self.tmpCaption = xmlCaption()
        return self.tmpCaption.createCaption(self.doc, name, quotes, action)

    def createField(self, typeField, quotes=[], name="",
                    values=[] ,action=False,addTmpField=True):
        """Cоздает поле

        Если установлена переменнная addTmpField
        добавляет поле во временный список
        """
        fieldObj = xmlField()
        field = fieldObj.createField(self.doc, typeField, quotes, name,
                                    values, action)
        if addTmpField:
            self.addField(field)
        return field

    def clearTmpFields(self):
        """Очищает временный список"""
        self.tmpFields = False

    def createArea(self):
        """Cоздает область

        Область создается на основании временного атрибута и временного списка
        """
        areaObj = xmlArea()
        area = areaObj.createArea(self.doc, self.tmpCaption, self.tmpFields)
        self.clearTmpCaptionAndFields()
        return area

    def clearTmpCaptionAndFields(self):
        """Очищает временный аттрибут и временный список"""
        self.tmpCaption = False
        self.tmpFields = False

    def getNodeRoot(self):
        """Выдает корневую ноду"""
        return self.root

    def getNodeBody(self):
        """Выдает ноду body"""
        return self.body

    def setActionField(self, xmlField, actionTxt):
        """Устанавливает свойство action для XML поля"""
        xmlActions = xpath.Evaluate('child::action',xmlField)
        if xmlActions and xmlActions[0].firstChild:
            xmlActions[0].firstChild.nodeValue = actionTxt
        else:
            nodeObj = xmlNode()
            newNode = nodeObj.createNode(self.doc, "action", actionTxt)
            xmlField.appendChild(newNode)


    def setActionArea(self, xmlArea, actionTxt):
        """Устанавливает свойство action для XML области"""
        xmlActions = xpath.Evaluate('child::caption/action',xmlArea)
        xmlCaptions = xpath.Evaluate('child::caption',xmlArea)
        if xmlActions and xmlActions[0].firstChild:
            xmlActions[0].firstChild.nodeValue = actionTxt
        else:
            if xmlCaptions:
                nodeObj = xmlNode()
                newNode = nodeObj.createNode(self.doc, "action", actionTxt)
                xmlCaptions[0].appendChild(newNode)

    def joinField(self, xmlArea, xmlNewField):
        """Объединяет XML ноду область и XML ноду поле"""
        newNameField = self.getNameField(xmlNewField)
        if not newNameField or not newNameField.strip():
            return False
        fieldsOldComp = xpath.Evaluate("child::field[child::name='%s']"\
                                    %(newNameField), xmlArea)
        # Если поле не найдено добавляем его
        typeNewField = self.getTypeField(xmlNewField)
        if not fieldsOldComp and typeNewField  != "seplist":
            if self.getActionField(xmlNewField) != "drop":
                self.setActionField(xmlNewField, "append")
                xmlArea.appendChild(xmlNewField)
            return True
        newFieldsAction = self.getActionField(xmlNewField)
        newValues = self.getFieldValues(xmlNewField)
        flagCompare = True

        for nodeFieldOld in fieldsOldComp:
            if newFieldsAction == "drop":
                if nodeFieldOld.nextSibling and\
                    self.getTypeField(nodeFieldOld.nextSibling) == "br":
                        xmlArea.removeChild(nodeFieldOld.nextSibling)
                elif nodeFieldOld.previousSibling and\
                    self.getTypeField(nodeFieldOld.previousSibling) == "br":
                        xmlArea.removeChild(nodeFieldOld.previousSibling)
                xmlArea.removeChild(nodeFieldOld)
                continue
            oldValues = self.getFieldValues(nodeFieldOld)
            # Сравнение значений переменной шаблона и файла
            if set(newValues) != set(oldValues):
                flagCompare = False
        if self.getActionField(xmlNewField) == "drop":
            return True
        appSplLst = []
        insSplLst = []
        if typeNewField  == "seplist":
            if fieldsOldComp:
                xmlOldField = fieldsOldComp[-1]
            else:
                xmlOldField = False
            seplistNewXML = self.getSepListToField(xmlNewField)
            if seplistNewXML:
                for nodeSeplist in seplistNewXML:
                    if self.getActionField(nodeSeplist) != "drop":
                        if newFieldsAction == "join":
                            flagCompareSeplist = False
                            newValues = self.getFieldValues(nodeSeplist)
                            for nodeFieldOld in fieldsOldComp:
                                oldValues = self.getFieldValues(nodeFieldOld)
                                for newValue in newValues:
                                    if newValue in oldValues:
                                        flagCompareSeplist = True
                                        break
                            if not flagCompareSeplist:
                                nextNode = xmlOldField.nextSibling
                                newInsNode = nodeSeplist.cloneNode(True)
                                self.setActionField(newInsNode,"append")

                                if nextNode:
                                    appSplLst.append((newInsNode,
                                                        nextNode,
                                                        "insert"))
                                else:
                                    appSplLst.append((newInsNode,
                                                        False,
                                                        "append"))
                        else:
                            newInsNode = nodeSeplist.cloneNode(True)
                            if self.getActionField(newInsNode) == "join":
                                self.setActionField(newInsNode,"append")
                            if xmlOldField:
                                insSplLst.append((newInsNode,
                                                  xmlOldField,
                                                  "insert"))
                            else:
                                insSplLst.append((newInsNode,
                                                  False,
                                                  "append"))

                            #xmlArea.insertBefore(\
                                #nodeSeplist.cloneNode(True),
                                #xmlOldField)

                        parentNode = nodeSeplist.parentNode
                        parentNode.removeChild(nodeSeplist)

                insNodesRepl = []
                for newNode, nxtNode, app in insSplLst:
                    flagCompareSeplist = False
                    newValues = self.getFieldValues(newNode)
                    for nodeRepl, nxtNode, app in insNodesRepl:
                        oldValues = self.getFieldValues(nodeRepl)
                        for newValue in newValues:
                            if newValue in oldValues:
                                flagCompareSeplist = True
                                break
                    if not flagCompareSeplist:
                        if xmlOldField:
                            insNodesRepl.append((newNode, nxtNode, app))

                for newNode, nxtNode, app in insNodesRepl:
                    if app == "insert":
                        xmlArea.insertBefore(newNode,nxtNode)
                    elif app == "append":
                        xmlArea.appendChild(newNode)
                if xmlOldField:
                    parentNode = xmlOldField.parentNode
                    if parentNode and newFieldsAction != "join":
                        parentNode.removeChild(xmlOldField)

        for newNode, nxtNode, app in appSplLst:
            if app == "insert":
                xmlArea.insertBefore(newNode,nxtNode)
            elif app == "append":
                xmlArea.appendChild(newNode)

        if not flagCompare and typeNewField  != "seplist":
            # Устанавливаем action=replace
            self.setActionField(xmlNewField, "replace")
            # Если параметры поля не сходятся заменяем поле
            xmlArea.replaceChild(xmlNewField.cloneNode(True),
                                             fieldsOldComp[-1])

        if newFieldsAction == "join":
            fieldsOldRemove = []
        else:
            fieldsOldRemove = fieldsOldComp[:-1]

        for nodeFieldOld in fieldsOldRemove:
            actionOldNode = self.getActionField(nodeFieldOld)
            if actionOldNode == "insert" or actionOldNode == "append":
                pass
            else:
                if nodeFieldOld.nextSibling and\
                    self.getTypeField(nodeFieldOld.nextSibling) == "br":
                        xmlArea.removeChild(nodeFieldOld.nextSibling)
                xmlArea.removeChild(nodeFieldOld)
        return True


    def getSepListToField(self, xmlField):
        """Выдает элементы распределенного массива

        Область предок поля, в этой области ищутся
        элементы распределенного массива
        """
        nameField = self.getNameField(xmlField)
        if not nameField:
            return []
        parentNode = xmlField.parentNode
        if parentNode:
            fieldsVal = xpath.Evaluate(\
            "child::field[attribute::type='seplist'][child::name='%s'] "\
            %(nameField), parentNode)
            return fieldsVal
        else:
            return []

    def removeComment(self, xmlArea):
        """Удаляет комментарии в XML области"""
        fieldNodes = xpath.Evaluate('descendant::field',xmlArea)
        for fieldNode in fieldNodes:
            if fieldNode.hasAttribute("type"):
                if fieldNode.getAttribute("type") == "comment" or\
                    fieldNode.getAttribute("type") == "br":
                    parentNode = fieldNode.parentNode
                    parentNode.removeChild(fieldNode)
                else:
                    if self.getActionField(fieldNode) == "drop":
                        pass
                    elif self.getActionField(fieldNode) == "join":
                        pass
                    else:
                        self.setActionField(fieldNode,"append")


    def joinBody(self, baseBody, newBody):
        """Объединяет две области Body"""
        newFields = xpath.Evaluate('child::field',newBody)
        xmlNewAreas = xpath.Evaluate('child::area',newBody)
        for xmlNewArea in xmlNewAreas:
            self.joinArea(baseBody,xmlNewArea)
        joinNewFields = xpath.Evaluate("child::field[child::action='join']"
                                       ,newBody)
        self.addNewFielsOldArea(newFields, joinNewFields, baseBody)


    def getRemoveNodeSepList(self, removeNodesDict, baseNode, xmNewlField):
        """Находит элементы разделенного списка

        Параметры:
        removeNodesDict - Cловарь удаляемых полей разделенного списка
                          формируется программой
        baseNode        - Нода в которой идет поиск
        xmNewlField     - Нода field которая проверяется на принадлежность
                          к разделенному списку
        """
        flagNewNodeSeplist = False
        if self.getTypeField(xmNewlField) == "seplist":
            flagNewNodeSeplist = True
        nameNewField = self.getNameField(xmNewlField)
        if nameNewField:
            if removeNodesDict.has_key(nameNewField):
                return removeNodesDict[nameNewField]
            else:
                oldFields = xpath.Evaluate('child::field', baseNode)
                removeNodes = []
                lenOldFields = len(oldFields)
                for i in range(lenOldFields):
                    oldNode = oldFields[i]
                    flagSep = self.getTypeField(oldNode) == "seplist"
                    if flagNewNodeSeplist:
                        flagSep = True
                    if  flagSep and\
                        nameNewField == self.getNameField(oldNode):
                        removeNodes.append(oldNode)
                        if i+1<lenOldFields:
                            nextNode = oldFields[i+1]
                            if self.getTypeField(nextNode) == "br":
                                removeNodes.append(nextNode)
                removeNodesDict[nameNewField] = removeNodes
                return removeNodes


    def addNewFielsOldArea(self, newFields, joinNewFields, xmlOldArea):
        """Добавляет новые XML поля в область шаблона"""
        removeNodesDict = {}
        notRemoveNodesDict = {}
        for notRemNode in joinNewFields:
            nameField = self.getNameField(notRemNode)
            if not notRemoveNodesDict.has_key(nameField):
                notRemoveNodesDict[nameField] = []
                notRemoveNodesDict[nameField].append(notRemNode)
            else:
                notRemoveNodesDict[nameField].append(notRemNode)
        notSepListField = []
        sepListField = []
        for nField in newFields:
            if self.getRemoveNodeSepList(removeNodesDict, xmlOldArea,
                                         nField):
                sepListField.append(nField)
            else:
                if self.getNameField(nField):
                    notSepListField.append(nField)
        for name in notRemoveNodesDict.keys():
            if removeNodesDict.has_key(name):
                removeNodesDict[name] = []
        for removeNodes in  removeNodesDict.values():
            if removeNodes:
                if self.getTypeField(removeNodes[-1]) == "seplist":
                    removeNodes = removeNodes[:-1]
                else:
                    removeNodes = removeNodes[:-2]

            for removeNode in removeNodes:
                xmlOldArea.removeChild(removeNode)
        for node in sepListField:
            node.setAttribute("type", "seplist")
            if not (self.getActionField(node) == "join" or\
            self.getActionField(node) == "drop"):
                self.setActionField(node,"insert")
            self.joinField(xmlOldArea, node)
        for node in notSepListField:
            if self.getTypeField(node) == "seplist":
                self.setActionField(node, "append")
                xmlOldArea.appendChild(node)
            else:
                self.joinField(xmlOldArea, node)

    def insertBeforeSepAreas(self, xmlArea):
        """Добавляет разделитель областей перед каждой областью"""
        if not self.sepAreas:
            return False
        areaNodes = xpath.Evaluate('descendant::area',xmlArea)
        for areaNode in areaNodes:
            prevNode = areaNode.previousSibling
            if prevNode:
                parentNode = areaNode.parentNode
                parentNode.insertBefore(self.sepAreas.cloneNode(True),
                                        areaNode)
        return True

    def getAreaFields(self, nameArea, xmlArea, allVars=False):
        """По имени области выводит названия и значения всех переменных

        поиск ведется только в 1-х потомках области xmlArea
        на выход словарь переменных {имя:значение}
        """
        namesAreaCompareAll = xpath.Evaluate(\
            "child::area/child::caption[child::name='%s']" %(nameArea),
                    xmlArea)
        if not namesAreaCompareAll:
            return False
        dictVar = {}
        for namesAreaCompare in namesAreaCompareAll:
            fields = xpath.Evaluate("child::field/child::name",
                                     namesAreaCompare.parentNode)
            for fieldName in fields:
                nodeField = fieldName.parentNode
                fieldValue = xpath.Evaluate("child::value",nodeField)
                name = fieldName.firstChild.nodeValue
                value = ""
                if fieldValue and fieldValue[0].firstChild:
                    value = fieldValue[0].firstChild.nodeValue
                dictVar[name] = value
            if not allVars:
                break
        return dictVar

    def getAreaFieldValues(self, nameArea, nameField, xmlArea):
        """По имени области и имени переменной выводит значениe переменной

        поиск ведется только в 1-х потомках области xmlArea
        """
        namesAreaComare = xpath.Evaluate(\
            "child::area/child::caption[child::name='%s']" %(nameArea),
                    xmlArea)
        fieldsVal = False
        for areaComp in namesAreaComare:
            fieldsVal = xpath.Evaluate(\
            "child::field[child::name='%s'] "\
            %(nameField), areaComp.parentNode)
            if fieldsVal:
                break
        if not fieldsVal:
            return False
        fieldValue = xpath.Evaluate("child::value",
             fieldsVal[0])
        if not fieldValue:
            return False
        if fieldValue[0].firstChild:
            return fieldValue[0].firstChild.nodeValue
        else:
            return ""

    def getAllAreas(self):
        """Выдает все области"""
        return xpath.Evaluate('descendant::area', self.body)

    def getArea(self, nameArea, xmlArea):
        """По имени области находит области (первый потомок xmlArea)"""
        namesAreaComare = xpath.Evaluate(\
            "child::area/child::caption[child::name='%s']" %(nameArea),
                    xmlArea)
        return map(lambda x: x.parentNode, namesAreaComare)


    def joinArea(self, baseNode, xmlNewArea):
        """Объединяет область c областью Body (xmlNewArea c baseNode)"""
        def appendArea(baseNode, xmlNewArea):
            fieldsRemove = xpath.Evaluate(\
            "descendant::field[child::action='drop']", xmlNewArea)
            for rmNode in fieldsRemove:
                parentNode = rmNode.parentNode
                parentNode.removeChild(rmNode)
            captionAreasRemove = xpath.Evaluate(\
                    "descendant::area/child::caption[child::action='drop']",
                    xmlNewArea)
            for rmNodeCapt in captionAreasRemove:
                rmNode = rmNodeCapt.parentNode
                parentNode = rmNode.parentNode
                parentNode.removeChild(rmNode)
            self.setActionArea(xmlNewArea, "append")
            # Добавляем разделитель областей во вложенные области
            areaNodes = xpath.Evaluate('descendant::area',xmlNewArea)
            for areaNode in areaNodes:
                self.setActionArea(areaNode,"append")
                parentNode = areaNode.parentNode
                parentNode.insertBefore(self.sepAreas.cloneNode(True),
                                        areaNode)
            baseNode.appendChild(xmlNewArea)
            # Добавляем разделитель областей
            baseNode.insertBefore(self.sepAreas.cloneNode(True), xmlNewArea)

        nodesNames = xpath.Evaluate('child::area/caption/name',baseNode)
        nodesNewArea = xpath.Evaluate('child::caption/name',xmlNewArea)
        if not nodesNames:
            # Добавляем область
            if nodesNewArea:
                newAreaAction = self.getActionArea(xmlNewArea)
                if not (newAreaAction == "drop" or newAreaAction == "replace"):
                    appendArea(baseNode, xmlNewArea)
            return True
        if not nodesNames or not nodesNewArea:
            return False
        nameArea = ""
        if nodesNewArea[0].firstChild:
            nameArea = nodesNewArea[0].firstChild.nodeValue.strip()
        flagFindArea = False
        baseNodes = []
        for oName in nodesNames:
            newAreaAction = self.getActionArea(xmlNewArea)
            oArea = oName.parentNode.parentNode
            oNameTxt = ""
            if oName.firstChild:
                oNameTxt = oName.firstChild.nodeValue
            if nameArea == oNameTxt:
                flagFindArea = True
                # При использовании удаления
                if newAreaAction == "drop":
                    prevNode = oName.parentNode.parentNode.previousSibling
                    removePrevNodes = []
                    while (prevNode) and self.getTypeField(prevNode) == "br":
                        removePrevNodes.append(prevNode)
                        prevNode = prevNode.previousSibling
                    for removeNode in removePrevNodes:
                        baseNode.removeChild(removeNode)
                    baseNode.removeChild(oName.parentNode.parentNode)
                    continue
                elif newAreaAction == "replace":
                    oldAreaNode = oName.parentNode.parentNode
                    newAreaCaption = xpath.Evaluate('child::caption',
                                                    xmlNewArea)[0]
                    oldAreaCaption = xpath.Evaluate('child::caption',
                                                    oldAreaNode)[0]
                    if newAreaCaption and oldAreaCaption:
                        xmlNewArea.replaceChild(oldAreaCaption,newAreaCaption)
                        self.setActionArea(xmlNewArea,"replace")
                    baseNode.replaceChild(xmlNewArea,
                                          oldAreaNode)
                    continue
                baseNodes.append(oName.parentNode.parentNode)
                newFields = xpath.Evaluate('child::field',xmlNewArea)

                joinNewFields = xpath.Evaluate(\
                    "child::field[child::action='join']"
                                       ,xmlNewArea)
                self.addNewFielsOldArea(newFields, joinNewFields, oArea)


        if not flagFindArea:
            # Добавляем область
            if not (newAreaAction == "drop" or\
                    newAreaAction == "replace"):
                appendArea(baseNode, xmlNewArea)
        else:
            tmpXmlNewAreas = xpath.Evaluate('child::area',xmlNewArea)
            for na in tmpXmlNewAreas:
                for bn in baseNodes:
                    self.joinArea(bn, na)
        return True

    def joinDoc(self, xmlNewDoc):
        """Объединяет два документа"""
        newRootNode = xmlNewDoc.documentElement
        newBodyNode = xpath.Evaluate('child::body',newRootNode)[0]
        newImportBodyNode = self.doc.importNode(newBodyNode, True)
        # Перед объединение области с документом
        # удаляем комментарии
        self.removeComment(newImportBodyNode)
        self.joinBody(self.body, newImportBodyNode)
        # расставляем BR
        self.insertBRtoBody(self.body)

    def getQuoteField(self, xmlField):
        """Выдает текст из поля"""
        xmlQuotes = xpath.Evaluate('child::quote',xmlField)
        br = ""
        if xmlField.hasAttribute("type") and\
            xmlField.getAttribute("type") == "br":
            br = "\n"
        if xmlQuotes:
            field = xmlQuotes[0]
            if field.firstChild:
                return field.firstChild.nodeValue + br
        return "" + br

    def getFieldsArea(self, xmlArea):
        """Выдает потомков XML области"""
        xmlFields = []
        childNodes = xmlArea.childNodes
        for node in childNodes:
            if node.nodeType == node.ELEMENT_NODE:
                if node.tagName == "area" or node.tagName == "field":
                    xmlFields.append(node)
        return xmlFields

    def getTypeField(self, xmlField):
        """Выдает тип поля"""
        if xmlField.hasAttribute("type"):
            return xmlField.getAttribute("type")
        else:
            return False

    def getNameField(self, xmlField):
        """Выдает имя поля"""
        xmlNameFields = xpath.Evaluate('child::name', xmlField)
        if xmlNameFields and xmlNameFields[0].firstChild:
            return xmlNameFields[0].firstChild.nodeValue
        else:
            return False

    def getNameArea(self, xmlArea):
        """Выдает имя области"""
        xmlNameAreas = xpath.Evaluate('child::caption/name', xmlArea)
        if xmlNameAreas and xmlNameAreas[0].firstChild:
            return xmlNameAreas[0].firstChild.nodeValue
        else:
            return False

    def xmlToText(self, xmlAreas, text):
        """Преобразует список XML областей в текст"""
        def getQuotesArea(xmlArea):
            quotes = []
            xmlQuotes = xpath.Evaluate('child::caption/quote',xmlArea)
            for node in xmlQuotes:
                if node.firstChild:
                    quotes.append(node.firstChild.nodeValue)
            if len(quotes) == 0:
                quotes.append("")
                quotes.append("")
            elif len(quotes) == 1:
                quotes.append("")
            return quotes

        for i in xmlAreas:
            if i.tagName == "area":
                quotesI = getQuotesArea(i)
                startAreaI = quotesI[0]
                endAreaI = quotesI[1]
                text.append(startAreaI)
                xmlFieldsI = self.getFieldsArea(i)
                for f in xmlFieldsI:
                    if f.tagName == "area":
                        quotesF = getQuotesArea(f)
                        startAreaF = quotesF[0]
                        endAreaF = quotesF[1]
                        text.append(startAreaF)
                        xmlFieldsF = self.getFieldsArea(f)
                        self.xmlToText(xmlFieldsF, text)
                        text.append(endAreaF)
                    else:
                        fieldF = self.getQuoteField(f)
                        text.append(fieldF)
                text.append(endAreaI)
            else:
                fieldI = self.getQuoteField(i)
                text.append(fieldI)

    def getActionField(self, xmlField):
        """Выдает свойство action XML поля"""
        xmlActions = xpath.Evaluate('child::action',xmlField)
        if xmlActions and xmlActions[0].firstChild:
            return xmlActions[0].firstChild.nodeValue
        else:
            return False

    def getFieldValues(self, xmlField):
        """Выдает значения XML поля в виде массива"""
        vals = []
        xmlValues = xpath.Evaluate('child::value',xmlField)
        if xmlValues:
            for node in xmlValues:
                if node.firstChild:
                    vals.append(node.firstChild.nodeValue)
        return vals

    def getActionArea(self, xmlArea):
        """Выдает свойство action XML области"""
        xmlActions = xpath.Evaluate('child::caption/action',xmlArea)
        if xmlActions and xmlActions[0].firstChild:
            return xmlActions[0].firstChild.nodeValue
        else:
            return False

    def delActionNodeArea(self, xmlArea):
        """Удаляет свойство action XML области"""
        xmlActions = xpath.Evaluate('child::caption/action',xmlArea)
        if xmlActions and xmlActions[0].firstChild:
            parentNode = xmlActions[0].parentNode
            parentNode.removeChild(xmlActions[0])
            return True
        else:
            return False

    def delActionNodeField(self, xmlField):
        """Удаляет свойство action XML поля"""
        xmlActions = xpath.Evaluate('child::action',xmlField)
        if xmlActions and xmlActions[0].firstChild:
            parentNode = xmlActions[0].parentNode
            parentNode.removeChild(xmlActions[0])
            return True
        else:
            return False

    # Создает распределенные списки
    def postParserListSeplist(self, xmlArea):
        """Создает распределенные списки из элементов области"""
        # Потомки
        childNodes = self.getFieldsArea(xmlArea)
        # содержит списки нод полей с одинаковыми именами в одной области
        fieldsSeplist = {}
        for node in childNodes:
            if node.tagName == "area":
                self.postParserListSeplist(node)
            else:
                fieldName = False
                xmlFieldNameNodes = xpath.Evaluate('child::name',node)
                if xmlFieldNameNodes and xmlFieldNameNodes[0].firstChild:
                    fieldName = xmlFieldNameNodes[0].firstChild.nodeValue
                if fieldName:
                    if  fieldsSeplist.has_key(fieldName):
                        fieldsSeplist[fieldName].append(node)
                    else:
                        fieldsSeplist[fieldName] = []
                        fieldsSeplist[fieldName].append(node)
        for listNodes in fieldsSeplist.values():
            if len(listNodes) > 1:
                for node in listNodes:
                    node.setAttribute("type", "seplist")

    def insertBRtoBody(self, xmlArea):
        """Добавляет необходимые переводы строк
        """
        # Потомки
        childNodes = self.getFieldsArea(xmlArea)
        # нода BR
        fieldXMLBr = self.createField("br",[],"",[],False, False)
        # разделитель поля
        fieldSplit = False
        # Предыдущая нода
        lastNode = False
        # Cледующая нода
        nextNode = False
        lenChildNodes = len(childNodes)
        for i in range(lenChildNodes):
            node = childNodes[i]
            lastTmpNode = node
            # Нода area
            if node.tagName == "area":
                if self.getActionArea(node) == "append" or\
                    self.getActionArea(node) == "join":
                    self.delActionNodeArea(node)
                    if lastNode and lastNode.hasAttribute("type") and\
                        lastNode.getAttribute("type") == "br" or\
                        lastNode and lastNode.hasAttribute("type") and\
                        lastNode.getAttribute("type") == "comment":
                        indNext = i + 1
                        if indNext == lenChildNodes:
                            xmlArea.appendChild(fieldXMLBr.cloneNode(True))
                        else:
                            nextNode = childNodes[indNext]
                            lastTmpNode = xmlArea.insertBefore(\
                                                    fieldXMLBr.cloneNode(True),
                                                    nextNode)
                    else:
                        xmlArea.insertBefore(fieldXMLBr.cloneNode(True),
                                             node)
                self.insertBRtoBody(node)
            # Нода field
            else:
                if self.getActionField(node) == "append" or\
                self.getActionField(node) == "join":
                    self.delActionNodeField(node)
                    if lastNode and lastNode.hasAttribute("type") and\
                        lastNode.getAttribute("type") == "br" or\
                        lastNode and lastNode.hasAttribute("type") and\
                        lastNode.getAttribute("type") == "comment":
                        indNext = i + 1
                        if indNext == lenChildNodes:
                            xmlArea.appendChild(fieldXMLBr.cloneNode(True))
                        else:
                            nextNode = childNodes[indNext]
                            lastTmpNode = xmlArea.insertBefore(\
                                                    fieldXMLBr.cloneNode(True),
                                                    nextNode)
                    else:
                        xmlArea.insertBefore(fieldXMLBr.cloneNode(True),
                                             node)
            lastNode = lastTmpNode



    def postParserList(self):
        """Находит подходящие XML области и делаем из них поля-массивы"""
        xmlAreas = xpath.Evaluate('descendant::area', self.body)
        for xmlArea in xmlAreas:
            flagListXml = True
            fieldValues = []
            xmlFields = xpath.Evaluate('child::field',xmlArea)
            if not xmlFields:
                flagListXml = False
            lenXmlFields = len(xmlFields)
            lenBrArea = 0
            for xmlField in xmlFields:
                xmlNames = xpath.Evaluate('child::name',xmlField)
                xmlVals = xpath.Evaluate('child::value',xmlField)
                if xmlField.hasAttribute("type") and\
                    xmlField.getAttribute("type") == "br":
                    lenBrArea += 1
                    continue
                if not xmlNames and not xmlVals:
                    flagListXml = False
                    break
                if xmlNames and xmlNames[0].firstChild and\
                    xmlNames[0].firstChild.nodeValue:
                    flagListXml = False
                    break
                if not (xmlVals and xmlVals[0].firstChild and\
                xmlVals[0].firstChild.nodeValue):
                    flagListXml = False
                    break
                else:
                   fieldValues.append(xmlVals[0].firstChild.nodeValue)

            if lenXmlFields == lenBrArea:
                flagListXml = False
            if flagListXml:
                nameNode = xpath.Evaluate('child::caption/name',xmlArea)[0]
                fieldName = ""
                if nameNode.firstChild:
                    fieldName = nameNode.firstChild.nodeValue
                listArea = []
                self.xmlToText([xmlArea],listArea)
                fieldQuote = "".join(listArea)
                fieldXMLBr = False
                if fieldQuote and fieldQuote[-1] == "\n":
                    fieldQuote = fieldQuote[:-1]
                    fieldXMLBr = self.createField("br",[],"",[],False, False)
                fieldXML = self.createField("list",
                                        [fieldQuote],
                                        fieldName, fieldValues,
                                        False, False)
                areaAction = self.getActionArea(xmlArea)
                if areaAction:
                    self.setActionField(fieldXML, areaAction)
                parentNode = xmlArea.parentNode
                parentNode.insertBefore(fieldXML,xmlArea)
                if fieldXMLBr:
                    parentNode.insertBefore(fieldXMLBr,xmlArea)
                parentNode.removeChild(xmlArea)


class blocText:
    """Разбиваем текст на блоки"""

    def splitTxtToBloc(self, text ,openTxtBloc,closeTxtBloc,
                       commentTxtBloc, sepField):
        """Делит текст на блоки (без заголовков)

        openTxtBloc  - регулярное выражение для начала блока
        closeTxtBloc - регулярное выражение для конца блока
        commentTxtBloc  - регулярное выражение - комментарий
        возвращает блоки текста
        """
        blocs = []
        level = 0
        # Нахождение нескольких блоков в строке
        # разделители линий, разделителями могут быть ("","\n")
        sepsLines = []
        # линии
        txtLines = []
        # Исходные строки
        txtLinesSrc = text.splitlines()
        for line in txtLinesSrc:
            lineBR = ""
            lineTmpA = line
            closeBl = False
            txtLinesTmp = []
            commentSpl = commentTxtBloc.split(line)
            flagCommentLine = False
            if commentSpl[0].strip():
                closeBl = True
                if len(commentSpl) > 1:
                    commentBl = commentTxtBloc.search(line)
                    textLine =commentSpl[0]
                    commentLine = line[commentBl.start(0):]
                    lineTmpA = textLine
                    flagCommentLine = True

            while (closeBl):
                closeBl = sepField.search(lineTmpA)
                if closeBl:
                    lineTmpB = lineTmpA[closeBl.end(0):]
                    txtLinesTmp.append(lineTmpA[:closeBl.end(0)])
                    lineTmpA = lineTmpB
            if lineTmpA.strip():
                txtLinesTmp.append(lineTmpA)
            # Если есть значение и комментарий в строке
            if flagCommentLine:
                for l in txtLinesTmp:
                    txtLines.append(l)
                    sepsLines.append("")
                if not txtLinesTmp:
                    txtLines.append(textLine)
                    sepsLines.append("")
                txtLines.append(commentLine)
                sepsLines.append("\n")
            # Если есть несколько блоков в строке
            elif len(txtLinesTmp)>1 and txtLinesTmp[1].strip():
                lenTmpLines = len(txtLinesTmp)
                for l in range(lenTmpLines):
                    txtLines.append(txtLinesTmp[l])
                    if l == lenTmpLines-1:
                        sepsLines.append("\n")
                    else:
                        sepsLines.append("")
            # Cтрока не преобразована
            else:
                txtLines.append(line)
                sepsLines.append("\n")

        # разбивание на блоки
        z = 0
        bl = ""
        for i in txtLines:
            if commentTxtBloc.split(i)[0].strip() and openTxtBloc.search(i):
                level += len(openTxtBloc.split(i)) - 1
            if commentTxtBloc.split(i)[0].strip() and closeTxtBloc.search(i):
                level -= len(closeTxtBloc.split(i)) - 1
            bl += i + sepsLines[z]
            if level == 0:
                if bl:
                    blocs.append(bl)
                bl = ""
            z += 1
        # cоздание блоков с элементами не входящими в блоки
        realBlocs = []
        z = 0
        bl = ""
        for i in blocs:
            txtLines = i.splitlines()
            if len(txtLines) > 0:
                line = txtLines[0]
            else:
                line = i
            if commentTxtBloc.split(i)[0].strip() and openTxtBloc.search(line):
                if bl:
                    realBlocs.append(bl)
                    bl = ""
                realBlocs.append(i)
            else:
                bl += i
            z += 1
        if bl:
            realBlocs.append(bl)
            bl = ""
        if level == 0:
            if text and text[-1] != "\n":
                tmpBlocs = realBlocs.pop()
                tmpBlocs = tmpBlocs[:-1]
                realBlocs.append(tmpBlocs)
            return realBlocs
        else:
            return []

    def findArea(self, text, reTextHeader, reTextArea, numGroupArea=0):
        """ Делит текст на области (с заголовками)

        reTextHeader  - регулярное выражение для заголовка области
        reTextArea - регулярное выражение для всей области
        numGroupArea - номер групы результата поиска по регулярному выражению
        по всей области
        возвращает два списка: первый - заголовки, второй - тела областей без
        заголоков
        """
        # Заголовки областей
        headersArea = []
        # Тексты областей без заголовков
        textBodyArea = []
        r = reTextArea.search(text)
        if not r:
            headersArea.append("")
            textBodyArea.append(text)
            return (headersArea, textBodyArea)

        txtWr = text
        while r:
            textArea = r.group(numGroupArea)
            txtSpl = txtWr.split(textArea)
            area =  txtSpl[0]
            txtWr = txtSpl[1]
            if area:
                headersArea.append("")
                textBodyArea.append(area)
            res = reTextHeader.search(textArea)
            header = textArea[:res.end()]
            body = textArea[res.end():]

            headersArea.append(header)
            textBodyArea.append(body)

            if txtWr:
                r = reTextArea.search(txtWr)
            else:
                r = False
        if txtWr:
            headersArea.append("")
            textBodyArea.append(txtWr)
        return (headersArea, textBodyArea)


    def findBloc(self, text, captionTxtBloc, bodyTxtBloc):
        """ Делит текст на блоки (с заголовками)

        captionTxtBloc  - регулярное выражение для заголовка блока
        bodyTxtBloc - регулярное выражение для тела блока
        возвращает два списка: первый - заголовки, второй - тела блоков
        """
        # Заголовки блоков
        headersTxt = []
        # Тексты блоков
        blocsTxt = []
        r = captionTxtBloc.search(text)
        if r:
            headersTxt.append(r.group(0))
            txtSpl = text.partition(r.group(0))
            blocTxt =  txtSpl[0]
            txtWr = txtSpl[2]
            rb = bodyTxtBloc.search(blocTxt)
            if not blocTxt:
                blocsTxt.append(blocTxt)
            if rb:
                blocsTxt.append(rb.group(0))
            while (r):
                r = captionTxtBloc.search(txtWr)
                if r:
                    headersTxt.append(r.group(0))
                    txtSpl = txtWr.partition(r.group(0))
                    blocTxt =  txtSpl[0]
                    txtWr = txtSpl[2]
                    rb = bodyTxtBloc.search(blocTxt)
                    if rb:
                        blocsTxt.append(rb.group(0))
                else:
                    blocsTxt.append(txtWr)
        if headersTxt and blocsTxt:
            if len(headersTxt)>len(blocsTxt):
                blocsTxt.insert(0,"")
            elif len(headersTxt)<len(blocsTxt):
                headersTxt.insert(0,"")
            if len(headersTxt)!=len(blocsTxt):
                return False
            return (headersTxt, blocsTxt)
        else:
            return False


class _file(_error):
    """Класс для работы с файлами

    """
    def __init__(self):
        # Имя файла конфигурационного файла
        self.nameFileConfig = ""
        # Содержимое конфигурационного файла
        self.textConfig = ""
        # Имя файла шаблона
        self.nameFileTemplate = ""
        # Содержимое шаблона
        self.textTemplate = ""
        # Дескриптор файла шаблона
        self.F_TEMPL = False
        # Дескриптор файла конфигурационного файла
        self.F_CONF = False
        # тип запускаемого шаблона
        self.executeType = None
        # список скриптов на запуск
        self.queueExecute = []

    def saveConfFile(self):
        """Записать конфигурацию"""
        if not self.textConfig:
            self.textConfig = self.textTemplate
        if self.F_CONF:
            self.F_CONF.truncate(0)
            self.F_CONF.seek(0)
            try:
                self.F_CONF.write(self.textConfig)
            except:
                self.setError(_("unable to open the file:")
                            + self.nameFileConfig)
                return False
            self.F_CONF.flush()
            return True
        elif self.executeType == "exec":
            processor = self.textConfig.partition("\n")[0]
            if processor.startswith("#!"):
                self.queueExecute.append((processor[2:],self.textConfig,
                                self.nameFileTemplate))
            else:
                self.setError(_("unable to execute '%s'")
                            + self.textConfig)
                return False

    def openTemplFile(self, nameFileTemplate):
        """Открыть файл шаблона"""
        F_TEMPL = False
        try:
            F_TEMPL = open(nameFileTemplate, "r")
        except:
            self.setError(_("unable to open the file:")
                            + nameFileTemplate)
            return False
        return F_TEMPL

    def closeTemplFile(self):
        if self.F_TEMPL:
            self.F_TEMPL.close()
            self.F_TEMPL = False

    def __closeOldFile(self):
        if self.F_CONF:
            self.F_CONF.close()
            self.F_CONF = False

    def __openConfFile(self, nameFileConfig):
        """Отктрыть конфигурационный файл"""
        F_CONF = False
        try:
            if os.path.islink(nameFileConfig):
                # если ссылка то удаляем её
                os.unlink(nameFileConfig)
            F_CONF = open (nameFileConfig, "r+")
        except:
            try:
                if os.path.isdir(nameFileConfig):
                    self.printWARNING(_("unable to open the directory as file:")
                            + nameFileConfig)
                    return False
                F_CONF = open(nameFileConfig, "w+")
            except:
                self.setError(_("unable to open the file:")
                            + nameFileConfig)
                return False
        return F_CONF


    def openFiles(self, nameFileTemplate, nameFileConfig, typeFormat=None,
                    newBuffer=None):
        """Открывает шаблон и конфигурационный файл"""
        self.textConfig = ""
        self.textTemplate = ""
        self.closeFiles()
        self.F_TEMPL = False
        self.F_CONF = False
        self.nameFileConfig = os.path.abspath(nameFileConfig)
        self.nameFileTemplate = os.path.abspath(nameFileTemplate)
        self.F_TEMPL = self.openTemplFile(self.nameFileTemplate)
        if not self.executeType and typeFormat != "diff":
            self.F_CONF = self.__openConfFile(self.nameFileConfig)
        if self.F_TEMPL and self.F_CONF:
            self.textTemplate = self.F_TEMPL.read()
            if self.configMode == T_NEWCFG:
                origConfigName = re.sub(r'/._cfg\d{4}_([^/]+)$','/\\1',
                            self.nameFileConfig)
                if newBuffer is None:
                    self.textConfig = readFile(origConfigName)
                else:
                    self.textConfig = newBuffer
            else:
                self.textConfig = self.F_CONF.read()

    def __del__(self):
        self.closeFiles()

    def closeFiles(self):
        """Закрытие файлов"""
        self.closeTemplFile()
        self.__closeOldFile()


class utfBin:
    """Класс для преобразования в utf-8

    преобразование бинарного или смеси бинарного и utf-8 кода в utf-8 и
    обратное преобразование 
    методы класса encode и decode
    """
    def _retUTF(self, char):
        byte = ord(char)
        if byte<=127:
            return ('_ch_',1)
        elif byte<=191:
            return ('_nb_',1)
        elif byte<=223:
            return ('_fb_',2)
        elif byte<=239:
            return ('_fb_',3)
        elif byte<=247:
            return ('_fb_',4)
        else:
            return ('_er_',1)

    def _sumbUtf(self, symbols, lenTail):
        if not symbols:
            return (False,0)
        lenSymb = len(symbols)
        if lenSymb >= 4:
            l = 4
        elif lenSymb >= 3:
            l = 3
        elif lenSymb >= 2:
            l = 2
        else:
            if symbols[0] == '_ch_':
                return (True,1)
            else:
                return (False,1)
        result = False
        for i in range(l):
            if i == 0 and symbols[i] != '_fb_':
                break
            elif i > 0 and symbols[i] != '_nb_':
                break 
        if lenTail>1 and lenTail != i:
            return (False,1)
        if i > 0:
            result = True
        return (result, i)


    def _intToChar(self, x):
        he = hex(x)[2:]
        exec("ret = '\\x%s'" %he)
        return ret

    def _hexToChar(self, he):
        exec("ret = '\\x%s'" %he)
        return ret

    def encode(self, text):
        """Кодирует смешанный формат в UTF-8"""
        ind = 0
        l = 0
        utf = []
        lenUtf = []
        indErr = []
        i = 0
        for ch in text:
            r, l = self._retUTF(ch)
            utf.append(r)
            lenUtf.append(l)
            i+=1
        while 1:
            if utf[ind] == '_fb_':
                res, l = self._sumbUtf(utf[ind:],lenUtf[ind])
                if res is False:
                    indErr.append(ind)
                if l>0:
                    ind +=l
                    if ind >= len(utf):
                        break
            else:
                if utf[ind] != '_ch_':
                    indErr.append(ind)
                ind +=1
                if ind >= len(utf):
                    break
        if indErr:
            lenIndErr = len(indErr)
            block = []
            blocks = []
            if lenIndErr > 1:
                i = 1
                while 1:
                    if i == 1:
                        block.append(indErr[i-1])
                    if indErr[i] - indErr[i-1] == 1:
                        block.append(indErr[i])
                    else:
                        if block:
                            blocks.append(block)
                        block = []
                        block.append(indErr[i])
                    i +=1
                    if i >= lenIndErr:
                        break
            else:
                block.append(indErr[0])
            if block:
                blocks.append(block)
            listErr = []
            for block in blocks:
                string = ""
                for elem in block:
                    string += hex(ord(text[elem]))[-2:]
                listErr.append((block[0],"__hex__?%s?__hex__" %string,elem))
            textOut = text
            deltaInd = 0
            for erEl in listErr:
                startInd = erEl[0] + deltaInd
                endInd = erEl[2] + 1 + deltaInd
                textOut = textOut[:startInd] + erEl[1] + textOut[endInd:]
                deltaInd += len(erEl[1])-(erEl[2]-erEl[0]+1)
                #if i == 1:
                    #break
                #i += 1
            return textOut

    def decode(self, text):
        """Декодирует UTF-8 в смешанный формат"""
        varStart = "__hex__\?"
        varEnd = "\?__hex__"
        # -1 Это экранирование '?' которое тоже считается
        deltVarStart = len(varStart)-1
        deltVarEnd = len(varEnd)-1
        reVar = re.compile(("%s[a-f0-9]+%s")%(varStart,varEnd),re.M)
        resS = reVar.search(text)
        textTemplateTmp = text
        while resS:
            mark = textTemplateTmp[resS.start():resS.end()]
            hexString = mark[deltVarStart:-deltVarEnd]
            i = 0
            stringInsert = ""
            hexCode = ""
            for ch in hexString:
                if i>=1:
                    hexCode += ch
                    stringInsert += self._hexToChar(hexCode)
                    hexCode = ""
                    i = 0
                else:
                    hexCode += ch
                    i += 1
            textTemplateTmp = textTemplateTmp.replace(mark, stringInsert)
            resS = reVar.search(textTemplateTmp)
        return textTemplateTmp

class templateFormat:
    """Методы получения классов и объектов форматов шаблонов"""
    # Импортированные классы поддерживаемых форматов шаблонов
    importFormats = {}

    def getClassObj(self, nameClassTemplate):
        """Создает класс шаблона по имени"""
        if nameClassTemplate in self.importFormats:
            classFormat = self.importFormats[nameClassTemplate]
        else:
            try:
                classFormat = getattr(__import__("calculate.lib.format.%s"%
                                                nameClassTemplate,
                                                globals(), locals(),
                                                [nameClassTemplate]),
                                      nameClassTemplate)
            except (ImportError, AttributeError):
                #Создаем объект из self.newObjProt с помощью
                # метаклассов
                if nameClassTemplate in self.newObjProt:
                    # Прототип класса
                    nameProt = self.newObjProt[nameClassTemplate]
                    if nameProt in self.importFormats:
                        classProt = self.importFormats[nameProt]
                    else:
                        try:
                            classProt = getattr(
                                __import__("calculate.lib.format.%s"%nameProt,
                                                    globals(), locals(),
                                                    [nameProt]),
                                                nameProt)
                        except (ImportError, AttributeError):
                            return False
                        self.importFormats[nameProt] = classProt
                    classFormat = self.createNewClass(nameClassTemplate,
                                                      (classProt,))
                else:
                    return False
            self.importFormats[nameClassTemplate] = classFormat
        return classFormat

    def getFormatObj(self, formatTemplate, textTemplate):
        """Создание объекта формата шаблона.

        Объект создается на основании формата шаблона и текста шаблона"""
        classFormat = self.getClassObj(formatTemplate)
        if classFormat:
            return classFormat(textTemplate)
        else:
            return False

class _shareTemplate:
    """Общие аттрибуты для классов шаблонов"""
    # Метка начала переменной
    varStart = "#-"
    # Метка конца переменной
    varEnd = "-#"
    _deltVarStart = len(varStart)
    _deltVarEnd = len(varEnd)

    def getDataUser(self, groupsInfo=False):
        """Получить информацию о пользователе"""
        userName = self.objVar.Get("ur_login")
        if not userName:
            userName = "root"
        import pwd
        try:
            pwdObj = pwd.getpwnam(userName)
            uid = pwdObj.pw_uid
            gid = pwdObj.pw_gid
            homeDir = pwdObj.pw_dir
        except:
            raise TemplatesError(_("User %s not found")%str(userName))
        if groupsInfo:
            import grp
            try:
                groupName = grp.getgrgid(gid).gr_name
            except:
                raise TemplatesError(_("Group ID %s not found")%str(gid))
            groupsNames = map(lambda x: x.gr_name,\
                filter(lambda x: userName in x.gr_mem,  grp.getgrall()))
            groupsNames = [groupName] + groupsNames
            return uid, gid, homeDir, groupsNames
        return uid, gid, homeDir

class templateFunction(_error, _warning, _shareTemplate, _shareTermsFunction):
    """Класс для функций шаблонов"""
    # Словарь установленных программ {"имя программы":[версии]}
    installProg = {}

    # Cписок просканированных категорий установленных программ
    installCategory = []

    # Флаг сканирования всех установленных программ
    flagAllPkgScan = False

    # Список названий функций шаблона
    namesTemplateFunction = []

    # Словарь {название функции шаблона: функция шаблона, ...}
    templateFunction = {}

    # Регулярное выражение для сложения
    sNum = re.compile("\-[^\-\+]+|[^\-\+]+")

    # Регулярное выражение для умножениея и деления
    sMD = re.compile("[^\-\+\*\/]+")

    # директория установленных программ
    basePkgDir = "/var/db/pkg"

    # кэш для проверки наличия пакета в портежах
    cachePortdir = {}

    # стек глобальных переменных
    stackGlobalVars = []

    # регулярное выражение для поиска версии
    reFindVer = re.compile("(?<=-)(?:\d+)(?:(?:\.\d+)*)"
                           "(?:[a-z]?)(?:(?:_(?:pre|p|beta|alpha|rc)\d*)*)"
                           "(?:-r\d+)?$")

    reEmptyLoad = re.compile("^\s*$|^\s*;|^\s*#")

    # Имя обрабатываемого шаблона
    nameTemplate = ""

    # Текст функции шаблона
    functText = ""

    # regular for discard sort number and version
    reData = re.compile(r"^(?:\d+-)?(.+?)(?:-(?:|always|\d+|\d(?:\d|\.|pre|_"
                         "|-always|alpha|beta|pre|rc|[a-z][^a-z])*[a-z]?)(?:"
                         "-r\d+)?)?$",re.S)

    currentBelong = ""
    alreadyInformed = []

    def __init__(self, objVar):
        # Если не определен словарь функций шаблона
        # import services api
        from cl_api import packagesAPI, APIError
        self.packagesAPI = packagesAPI
        self.APIError = APIError
        if not self.templateFunction:
            # префикс функций шаблона
            pref = "func"
            # cписок [(название функции, функция), ...]
            dictFunc = filter(lambda x: x[0].startswith(pref) and\
                              hasattr(x[1],"__call__"),
                              self.__class__.__dict__.items())
            # удаляем у названия функции префикс и переводим остаток названия
            # в нижний регистр
            dictFunc = map(lambda x: (x[0][len(pref):].lower(), x[1]), dictFunc)
            # Формируем словарь функций шаблона
            self.templateFunction.update(dictFunc)
            # Формируем список функций шаблона
            for nameFunction in self.templateFunction.keys():
                self.namesTemplateFunction.append(nameFunction)
        # Объект хранения переменных
        self.objVar = objVar
        self._reFunc = re.compile(("%s%s%s")\
            %(self.varStart,self._reFunctionText,self.varEnd),re.M)
        # Аттрибуты для функции шаблона ini()
        # Первоначальный словарь переменных для ini()
        self.prevDictIni = {}
        # Текущий словарь переменных для ini()
        self.currDictIni = {}
        # Время модификации конфигурационного файла для ini() 
        self.timeIni = -1
        self.recalculateBaseDir()

        # Словарь времен модификации env файлов
        self.timeConfigsIni = {}
        # Словарь хранения переменых полученных функцией env() из env файлов
        self.valuesVarEnv = {}
        # Словарь хранения опций для функции info()
        self.optionsInfo = {}
        # файл параметров сервисов
        envFile = self.objVar.Get("cl_env_server_path")
        # объект конвертирования из старого remote env файла
        self.convObj = False
        if os.access(envFile, os.R_OK):
            self.convObj = False
        elif os.access("/var/calculate/remote/calculate.env", os.R_OK):
            from convertenv import convertEnv
            self.convObj = convertEnv()

    def recalculateBaseDir(self):
        """Recalculate basedir and homedir"""
        # Директория другой системы
        self._chrootDir = self.objVar.Get("cl_chroot_path")
        if self._chrootDir != '/':
            # Изменение директории к базе пакетов
            self.basePkgDir = pathJoin(self._chrootDir, self.basePkgDir)
            self.basePkgDir = os.path.normpath(self.basePkgDir)
        # Базовая директория переноса шаблонов "/mnt/calculate" или "/" и.т.д
        self._baseDir=pathJoin(self._chrootDir,self.objVar.Get("cl_root_path"))
        self._baseDir = os.path.normpath(self._baseDir)
        self.uid, self.gid, self.homeDir, self.groups =\
            self.getDataUser(groupsInfo=True)
        # Домашняя директория, плюс базовая директория
        self.homeDir = pathJoin(self._baseDir, self.homeDir)
        # path to configuration file for ini() function
        # if action is desktop configuration, then path in user directory
        # else config file place in /etc/calculate
        if self.objVar.Get('cl_action') == "desktop":
            self.pathConfigIni = os.path.join(self.homeDir, ".calculate")
            self.modeConfigIni = 0640
        else:
            self.pathConfigIni = pathJoin(self._chrootDir,'/etc/calculate')
            self.modeConfigIni = 0644
        self.fileConfigIni = os.path.join(self.pathConfigIni,"ini.env")

    def equalTerm(self, term, localVars):
        """Метод для вычисления выражения"""
        terms = self.sNum.findall(term)
        if terms:
            strNumers = []
            for n in terms:
                strNum = n.strip()
                if "*" in strNum or "/" in strNum:
                    strNum = self.multAndDiv(strNum,localVars)
                try:
                    num = int(strNum)
                except:
                    minus = False
                    if strNum[:1] == "-":
                        minus = True
                        strNum = strNum[1:]
                    if localVars.has_key(strNum):
                        try:
                            num = int(localVars[strNum])
                        except:
                            self.raiseErrTemplate(
                                _("error: variable %s is not integer")%
                                    str(strNum))
                    elif self.objVar.exists(strNum):
                        try:
                            num = int(self.objVar.Get(strNum))
                        except:
                            self.raiseErrTemplate(
                                _("error: variable %s is not integer")%
                                    str(strNum))
                    else:
                        self.raiseErrTemplate(
                                _("error: local variable %s not defined")%
                                    str(strNum))
                    if minus:
                        num = -num
                strNumers.append(num)
            return sum(strNumers)
        self.raiseErrTemplate(_("error: template term %s, incorrect data")\
                                 %str(term))

    def multAndDiv(self, term, localVars):
        """Метод для умножения и деления"""
        termTmp = term
        varsLocal = self.sMD.findall(term)
        for var in varsLocal:
            flagVarTxt = True
            try:
                int(var)
            except:
                flagVarTxt = False
            if flagVarTxt:
                continue
            varReplace = str(self.equalTerm(var, localVars))
            termTmp = termTmp.replace(var,varReplace)
        ret = eval(termTmp)
        return ret

    def funcSum(self, funArgv, resS, localVars, textTemplateTmp,nameTemp):
        """Функция шаблона, вычисляет функцию sum()"""
        terms = funArgv.replace(" ","").split(",")
        # Название локальной переменной
        nameLocVar = terms[0]
        if not localVars.has_key(nameLocVar):
            localVars[nameLocVar] = 0
        if len(terms) == 2:
            if terms[1].strip():
                localVars[nameLocVar] = self.equalTerm(terms[1], localVars)
                replace = str(localVars[nameLocVar])
            else:
                replace = ""
            textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
                textTemplateTmp[resS.end():]
        elif len(terms) == 3:
            if terms[1].strip():
                replaceInt = self.equalTerm(terms[1], localVars)
                replace = str(replaceInt)
            else:
                replace = ""
            localVars[nameLocVar] =  self.equalTerm(terms[2], localVars)
            textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
                textTemplateTmp[resS.end():]
        else:
            self.raiseErrTemplate()
        return textTemplateTmp

    def funcExists(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
        """Функция шаблона exists(),
        проверяет существование файла, если существует выдает '1'
        если второй параметр root, то проверка осуществляется от корня.
        """
        terms = map(lambda x: x.strip(), funArgv.split(","))
        if len(terms) > 2:
            self.raiseErrTemplate()
        fileName = terms[0]
        flagNotRootFS = True
        if len(terms) == 2:
            if terms[1] == "root":
                flagNotRootFS = False
            else:
                self.raiseErrTemplate(
                    _("The second argument of the function is not 'root'"))
        if fileName[0] == "~":
            # Получаем директорию пользователя
            fileName = os.path.join(self.homeDir,
                                    fileName.partition("/")[2],"")[:-1]
        elif fileName[0] != "/":
            self.raiseErrTemplate(_("wrong path '%s'")%fileName)
        else:
            if flagNotRootFS:
                fileName = pathJoin(self._baseDir, fileName)
        replace = ""
        if os.path.exists(fileName):
            replace = "1"
        textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
                textTemplateTmp[resS.end():]
        return textTemplateTmp

    def funcLoad(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
        """Функция шаблона load(),

        если файл существует читает из файла локальную переменную
        если один параметр - выводит значение локальной переменной
        """
        terms = funArgv.split(",")
        if terms:
            lenTerms = len(terms)
            if not terms[0].strip() or\
                (lenTerms==2 and not terms[1].strip()) or\
                (lenTerms==3 and not terms[2].strip()) or\
                lenTerms>3:
                self.raiseErrTemplate()
        else:
            self.raiseErrTemplate()
        flagNotRootFS = True
        if lenTerms == 3:
            if terms[2] =="root":
                flagNotRootFS = False
            else:
                self.raiseErrTemplate(
                    _("The third argument of the function is not 'root'"))
        if lenTerms >= 2:
            if not terms[0] in ["ver","num","char","key","empty"]:
                self.raiseErrTemplate(
                    _("the first argument of the function is neither 'ver'"
                      " or 'num' or 'char' or 'empty'"))
        if lenTerms == 1:
            fileName = terms[0].strip()
        else:
            fileName = terms[1].strip()
        # Если домашняя директория
        if fileName[0] == "~":
            # Получаем директорию пользователя
            fileName = os.path.join(self.homeDir,
                                    fileName.partition("/")[2],"")[:-1]
        elif fileName[0] != "/":
            self.raiseErrTemplate(_("wrong path '%s'")%fileName)
        else:
            if flagNotRootFS:
                fileName = pathJoin(self._baseDir,fileName)
        replace = ""
        if os.path.exists(fileName):
            FD = open(fileName)
            replace = FD.read().strip()
            FD.close()
        if replace and lenTerms >= 2 and terms[0] == "empty":
           replace ="\n".join(filter(lambda x: not self.reEmptyLoad.search(x),
                              replace.split("\n")))
        if not replace and lenTerms >= 2 and terms[0] in ["ver","num"]:
            replace = "0"
        textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
                textTemplateTmp[resS.end():]
        return textTemplateTmp

    def sharePkg(self,pkgs,force=False):
        """
        Update packages from pkgs list
        """
        for pkgname,category,ver,slot in pkgs:
            fullname = "%s/%s"%(category,pkgname)
            if not fullname in self.installProg or \
                type(self.installProg[fullname]) != dict:
                self.installProg[fullname] = self.installProg[pkgname] = {}
            if force or not slot in self.installProg[fullname]:
                self.installProg[fullname][slot] = ver
        return self.installProg

    def getInstallPkgGentoo(self,category=""):
        pkgs = []
        filterFunc = "SLOT".__eq__
        def getFilesDir(pkgs, dirname, names):
            for nameFile in filter(filterFunc,names):
                absNameFile = os.path.join(dirname,nameFile)
                category,spl,pkgname = dirname.rpartition('/')
                dbpkg,spl,category = category.rpartition('/')
                slot = open(absNameFile,'r').read().strip()
                pkgname,spl,rev = pkgname.rpartition("-")
                if rev.startswith('r'):
                    pkgname, spl, ver = pkgname.rpartition("-")
                    ver = "%s-%s"%(ver,rev)
                else:
                    ver = rev
                pkgs.append((pkgname,category,ver,slot))
            return True
        os.path.walk(os.path.join(self.basePkgDir,category),
                    getFilesDir, pkgs)
        return self.sharePkg(pkgs)

    def pkg(self,nameProg,slot=None):
        if len(self.installProg) > 0:
            if type(self.installProg.values()[0]) != dict:
                self.installProg.clear()
                self.getInstallPkgGentoo()
        if nameProg in self.installProg:
            versions = self.installProg[nameProg]
            if slot:
                return versions.get(slot,"")
            if len(versions) == 1:
                return versions.values()[0]
            else:
                return versions[max(versions.keys(),key=getTupleVersion)]
        else:
            return ""

    def funcPkg(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
        """Функция шаблона pkg(), выдает номер версии программы"""
        # Название программы
        nameProg = funArgv.replace(" ","")
        if not nameProg:
            fileName = os.path.split(self.nameTemplate)[1]
            if fileName == '.calculate_directory':
                parentDir = os.path.dirname(self.nameTemplate)
                parentDir, pkgName = os.path.split(parentDir)
            else:
                parentDir, pkgName = os.path.split(self.nameTemplate)
            category = os.path.split(parentDir)[1]
            # reg for discard version and sort number
            pkgName = self.reData.search(pkgName).group(1)
            category = self.reData.search(category).group(1)
            nameProg = "%s/%s"%(category,pkgName)
        # Замена функции в тексте шаблона
        replace = ""
        if "/" in nameProg:
            category, spl, nameProg = nameProg.partition("/")
            nameProg, spl, slot = nameProg.partition(":")
            if not category in self.installCategory:
                self.getInstallPkgGentoo(category=category)
                self.installCategory.append(category)
            replace = self.pkg(nameProg, slot=slot or None)
        else:
            if not self.flagAllPkgScan:
                self.getInstallPkgGentoo()
                templateFunction.flagAllPkgScan = True
            nameProg,spl,slot = nameProg.partition(":")
            replace = self.pkg(nameProg, 
                               slot=slot)
        textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
                textTemplateTmp[resS.end():]
        return textTemplateTmp

    def funcRnd(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
        """Функция шаблона rnd(), выдает строку случайных символов

        первый аргумент:
            'num' - числа,
            'pas' - цифры и буквы
            'uuid' - цифры и строчные буквы a-f
        второй аргумент:
            количество символов
        """
        terms = funArgv.replace(" ","").split(",")
        if  not terms[0].strip() or\
            (len(terms)==2 and not terms[1].strip()) or\
            len(terms)!=2:
            self.raiseErrTemplate()
        fArgvNames = {'num':string.digits,
                      'pas':string.ascii_letters + string.digits,
                      'uuid':string.ascii_lowercase[:6] + string.digits}
        if not terms[0] in fArgvNames:
            self.raiseErrTemplate(
                _("the first argument of the function must "
                  "be 'num', 'pas' or 'uuid'"))
        try:
            lenStr = int(terms[1])
        except:
            self.raiseErrTemplate(
                _("the second argument of the function is not a number"))
        choiceStr = fArgvNames[terms[0]]
        replace = ''.join([random.choice(choiceStr) for i in xrange(lenStr)])
        textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
                textTemplateTmp[resS.end():]
        return textTemplateTmp

    def funcCase(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
        """Функция шаблона case(), выдает переменную в определенном регистре

        первый аргумент:
            'upper' - верхний регистр,
            'lower' - нижний регистр,
            'capitalize' - первая буква в верхнем регистре
        второй аргумент:
            название переменной
        """
        terms = funArgv.replace(" ","").split(",")
        if  not terms[0].strip() or\
            (len(terms)==2 and not terms[1].strip()) or len(terms)!=2:
            self.raiseErrTemplate()
        fArgvNames = ['upper','lower','capitalize']
        if not terms[0] in fArgvNames:
            self.raiseErrTemplate(_("the first argument of the function"
                                    " is neither 'upper' or 'lower' or"
                                    " 'capitalize'"))
        try:
            strValue = self.objVar.Get(terms[1])
            if not strValue:
                strValue = ""
            else:
                strValue = str(strValue)
        except:
            raise TemplatesError(
                _("error in template %s")%self.nameTemplate + "\n" +
                _("error: variable %s not found")%str(terms[1]))
        replace = ""
        strValue = _toUNICODE(strValue)
        if terms[0] == 'upper':
            replace = strValue.upper()
        elif terms[0] == 'lower':
            replace = strValue.lower()
        elif terms[0] == 'capitalize':
            replace = strValue.capitalize()
        if replace:
            replace = replace.encode("UTF-8")
        textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
                textTemplateTmp[resS.end():]
        return textTemplateTmp

    def funcIn(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
        """
        Function in for check value in variable
        """
        terms = funArgv.replace(" ","").split(",")
        # Название локальной переменной
        nameLocVar = terms[0]
        flagFoundVar = False
        try:
            value =  self.objVar.Get(nameLocVar)
            flagFoundVar = True
        except:
            pass
        if flagFoundVar:
            if value in terms[1:]:
                replace = "1"
            else:
                replace = ""
        else:
            self.raiseErrTemplate(_("error: variable %s does not exist")\
                                     %str(nameLocVar))
        textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
                textTemplateTmp[resS.end():]
        return textTemplateTmp

    def funcPush(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
        """локальная функция записывает значение переменной 

        в стек глобальных переменных
        """
        terms = funArgv.replace(" ","").split(",")
        # Название локальной переменной
        nameLocVar = terms[0]
        flagFoundVar = False
        if nameLocVar in localVars.keys():
                flagFoundVar = True
                value = localVars[nameLocVar]
        else:
            try:
                value =  self.objVar.Get(nameLocVar)
                flagFoundVar = True
            except:
                pass
        if flagFoundVar:
            # Если переменная существует
            if len(terms) == 1:
                self.stackGlobalVars.append(str(value))
            else:
                self.raiseErrTemplate(_("error: variable %s exists")\
                                         %str(nameLocVar))
        else:
            # Если переменная не существует
            if len(terms) == 1:
                self.raiseErrTemplate(_("error: variable %s does not exist")\
                                         %str(nameLocVar))
            elif len(terms) == 2:
                value = terms[1].strip()
                self.stackGlobalVars.append(str(value))
                localVars[nameLocVar] = value
            else:
                self.raiseErrTemplate()
        replace = ""
        textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
                textTemplateTmp[resS.end():]
        return textTemplateTmp

    def funcPop(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
        """локальная функция получает значение

        из стека глобальных переменных и присваивает локальной переменной 

        """
        terms = funArgv.replace(" ","").split(",")
        # Название локальной переменной
        nameLocVar = terms[0]
        if len(terms) == 1:
            if self.stackGlobalVars:
                localVars[nameLocVar] = self.stackGlobalVars.pop()
            else:
                self.raiseErrTemplate(
                    _("error: global variables stack empty"))
        else:
            self.raiseErrTemplate()
        replace = ""
        textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
                textTemplateTmp[resS.end():]
        return textTemplateTmp

    def funcPrint(self,funArgv, resS, localVars, textTemplateTmp, nameTemp):
        """
        Вывод успешного сообщения
        """
        self.printSUCCESS(_(funArgv))
        textTemplateTmp = textTemplateTmp[:resS.start()] + \
                textTemplateTmp[resS.end():]
        return textTemplateTmp

    def funcWarning(self,funArgv, resS, localVars, textTemplateTmp, nameTemp):
        """
        Вывод сообщения с предупреждением
        """
        self.printWARNING(_(funArgv))
        textTemplateTmp = textTemplateTmp[:resS.start()] + \
                textTemplateTmp[resS.end():]
        return textTemplateTmp

    def funcError(self,funArgv, resS, localVars, textTemplateTmp, nameTemp):
        """
        Вывод сообщения с ошибкой
        """
        self.printERROR(_(funArgv))
        textTemplateTmp = textTemplateTmp[:resS.start()] + \
                textTemplateTmp[resS.end():]
        return textTemplateTmp

    def funcExit(self,funArgv, resS, localVars, textTemplateTmp, nameTemp):
        """
        Good exit
        """
        # TODO: need remove
        return textTemplateTmp
        self.printSUCCESS(_(funArgv))
        raise TemplatesInterrupt(_("Execution of templates was stopped"),
                                 TemplatesInterrupt.EXIT)

    def funcBreak(self,funArgv, resS, localVars, textTemplateTmp, nameTemp):
        """
        Bad exit
        """
        # TODO: need remove
        return textTemplateTmp
        self.printERROR(_(funArgv))
        raise TemplatesInterrupt(_("Execution of templates was "
                                   "interrupted with an error"),
                                 TemplatesInterrupt.ABORT)

    def getElogTimestamp(self):
        # Получаем время модификации конфигурационного файла
        curTime = self.getTimeFile(self.fileConfigIni)
        nameLocVar = "update.timestamp"
        if self.timeIni != curTime:
            # читаем переменные из файла
            self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
            self.currDictIni= {}
            self.currDictIni.update(self.prevDictIni)
            self.timeIni = self.getTimeFile(self.fileConfigIni)
        if nameLocVar in self.currDictIni.keys():
            if self.currDictIni[nameLocVar] is None:
                return 0
            else:
                val = self.currDictIni[nameLocVar].encode("UTF-8")
                if val.isdigit():
                    return int(val)
        return 0

    elogFile = '/var/log/emerge.log'

    @classmethod
    def getLastElog(cls):
        # get last timestamp
        lastStr = ""
        for l in readLinesFile(cls.elogFile):
            lastStr  = l
        return lastStr.partition(':')[0]

    def funcElog(self,funArgv, resS, localVars, textTemplateTmp, nameTemp):
        """Function for work with emerge.log"""
        funArgv = funArgv.strip()
        rePkg = re.compile(r'completed emerge \(\d+ of \d+\) (\S+)\s',re.S)
        replace = ""
        if funArgv:
            lastTimestamp = self.getElogTimestamp()
            skip = True
            for line in reversed(list(readLinesFile(self.elogFile))):
                timestamp,op,info = line.partition(':')
                if timestamp.isdigit() and lastTimestamp and \
                    int(timestamp) < lastTimestamp:
                        break
                match = rePkg.search(info)
                if match and match.group(1).startswith(funArgv):
                    pkgInfo = reVerSplitToPV(match.group(1))
                    if "{CATEGORY}/{PN}".format(**pkgInfo) == funArgv:
                        replace = pkgInfo['PVR']
                        break
        else:
            replace = self.getLastElog()
        textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
                textTemplateTmp[resS.end():]
        return textTemplateTmp

    def funcConfirm(self,funArgv, resS, localVars, textTemplateTmp, nameTemp):
        # TODO: need remove
        return textTemplateTmp
        res = self.askConfirm(_(funArgv))
        textTemplateTmp = textTemplateTmp[:resS.start()] + res + \
                textTemplateTmp[resS.end():]
        return textTemplateTmp

    def loadVarsIni(self, iniFileName):
        """ Читает файл fileName
        создает и заполняет переменные на основе этого файла
        Используеться совместно c funcIni
        """
        localVarsIni = {}
        # получить объект ini файла
        config = iniParser(iniFileName)
        # получаем все секции из конфигурационного файла
        allsect = config.getAllSectionNames()
        if not allsect:
            if self.getError():
                # Очистка ошибки
                _error.error = []
            return localVarsIni
        # Заполняем переменные для funcIni
        for sect in allsect:
            sectVars = config.getAreaVars(sect)
            for name in sectVars.keys():
                nameVar = "%s.%s"%(sect,name) 
                valueVar = sectVars[name]
                localVarsIni[nameVar] = valueVar
        return localVarsIni

    def getTimeFile(self, fileName):
        # Получаем время модификации файла
        nameEnvFile = os.path.split(fileName)[1]
        if nameEnvFile in self.timeConfigsIni:
            return self.timeConfigsIni[nameEnvFile]
        return 0

    def funcIni(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
        """локальная функция записывает и считывает значение переменной 

        из ini файла ~./calculate/ini.env
        """
        # Создаем директорию
        if not os.path.exists(self.pathConfigIni):
            os.makedirs(self.pathConfigIni)
            os.chown(self.pathConfigIni, self.uid, self.gid)
        termsRaw = funArgv.split(",")
        flagFirst = True
        terms = []
        for term in termsRaw:
            if flagFirst:
                terms.append(term.replace(" ",""))
                flagFirst = False
            else:
                val = term.strip()
                # Флаг (не найдены кавычки)
                flagNotFoundQuote = True
                for el in ('"',"'"):
                    if val.startswith(el) and val.endswith(el):
                        terms.append(val[1:-1])
                        flagNotFoundQuote = False
                        break
                if flagNotFoundQuote:
                    if not val:
                        terms.append(None)
                    else:
                        terms.append(val)
        # Название локальной переменной
        nameLocVar = terms[0]
        namesVar = nameLocVar.split(".")
        if len(namesVar) == 1:
            nameLocVar = "main.%s"%nameLocVar
        elif len(namesVar)>2:
            self.raiseErrTemplate()
        replace = ""
        # Получаем время модификации конфигурационного файла
        curTime = self.getTimeFile(self.fileConfigIni)
        if len(terms) == 1:
            if self.timeIni != curTime:
                # читаем переменные из файла
                self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
                self.currDictIni= {}
                self.currDictIni.update(self.prevDictIni)
                self.timeIni = self.getTimeFile(self.fileConfigIni)
            if nameLocVar in self.currDictIni.keys():
                if self.currDictIni[nameLocVar] is None:
                    replace = ""
                else:
                    replace = self.currDictIni[nameLocVar].encode("UTF-8")
        elif len(terms) == 2:
            if self.timeIni != curTime:
                # читаем переменные из файла
                self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
                self.currDictIni= {}
                self.currDictIni.update(self.prevDictIni)
                self.timeIni = self.getTimeFile(self.fileConfigIni)
            # Значение локальной переменной
            valueLocVar = terms[1]
            self.currDictIni[nameLocVar] = valueLocVar
        elif len(terms) == 3:
            if not terms[2] in ['url','purl','unicode']:
                self.raiseErrTemplate(
                    _("the third argument of the function is neither "
                      "'url' or 'purl' or 'unicode'"))
            if terms[1]:
                self.raiseErrTemplate()
            if self.timeIni != curTime:
                # читаем переменные из файла
                self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
                self.currDictIni= {}
                self.currDictIni.update(self.prevDictIni)
                self.timeIni = self.getTimeFile(self.fileConfigIni)
            if nameLocVar in self.currDictIni.keys():
                unicodeValue = self.currDictIni[nameLocVar]
                if unicodeValue is None:
                    unicodeValue = ""
                if terms[2] in ('url', 'purl'):
                    replace = unicodeValue.encode("UTF-8").\
                              __repr__()[1:-1].replace('\\x','%').\
                              replace(' ','%20')
                    if terms[2] == 'purl':
                        replace = replace.replace('/','%2f')
                elif terms[2] == 'unicode':
                    replace = unicodeValue.__repr__()[2:-1]
        else:
            self.raiseErrTemplate()
        textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
                textTemplateTmp[resS.end():]
        return (textTemplateTmp)

    def funcReplace(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
        """локальная функция заменяет в значении переменной old на new

        replace(old, new, name_var_template)

        одинарные и двойные кавычки должны быть обязательно использованы
        в первых двух аргументах old и new
        "test\ntest" - преобразование строки (строка с переводом)
        'test\ntest' - без преобразования (одна строка)
        """
        def getStrArgv(terms):
            """Определяет в двойных или одинарных кавычках параметры

            Результат [(тип, аргумент),...] [("double", arg1).]
            """
            listArgv = []
            for term in terms:
                if term.startswith('"') and term.endswith('"'):
                    replTerms = [(r"\'", "'"), (r'\"', '"'), (r'\n', '\n'),
                                 (r'\r', '\r'), (r'\t', '\t'), (r"\\", "\\")]
                    textArgv = term[1:-1]
                    for replTerm in replTerms:
                        textArgv = textArgv.replace(*replTerm)
                    listArgv.append(textArgv)
                elif term.startswith("'") and term.endswith("'"):
                    listArgv.append(term[1:-1])
                else:
                    self.raiseErrTemplate()
            return listArgv

        terms = map(lambda x: x.strip(), funArgv.split(","))
        if len(terms) != 3:
            self.raiseErrTemplate()
        listArgv = getStrArgv(terms[:2])
        old = listArgv[0]
        new = listArgv[1]
        nameVar = terms[2]
        # Получаем значение переменной
        if nameVar in localVars:
            value = str(localVars[nameVar])
        else:
            try:
                value = str(self.objVar.Get(nameVar))
            except:
                self.raiseErrTemplate(_("template variable '%s' not found")\
                                         %str(nameVar))
        replace = value.replace(old,new)
        textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
                textTemplateTmp[resS.end():]
        return textTemplateTmp

    def funcEnv(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
        """Функция шаблона env(), выдает значение переменной из env файлов
        """
        terms = funArgv.replace(" ","").split(",")
        if len(terms) != 1:
            self.raiseErrTemplate()
        nameVar = terms[0]
        replace = ''
        if nameVar in self.valuesVarEnv:
            replace = self.valuesVarEnv[nameVar]
        else:
            # Получаем значение из env файлов
            value = self.objVar.getIniVar(nameVar)
            if value is False:
                self.raiseErrTemplate(self.getError())
            self.valuesVarEnv[nameVar] = value
            replace = value
        textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
                textTemplateTmp[resS.end():]
        return textTemplateTmp

    def funcServer(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
        """Функция шаблона info(), выдает значение опций сервиса

        из /var/calculate/remote/calculate.env
        """
        terms = funArgv.replace(" ","").split(",")
        if len(terms)==0 or len(terms)>2:
            self.raiseErrTemplate()
        nameLocalVar = ""
        if len(terms)==2:
            if not terms[1]:
                self.raiseErrTemplate()
            nameLocalVar = terms[1]
        textLine = terms[0]
        vals = textLine.split(".")
        if len(vals)!= 2:
            self.raiseErrTemplate()
        if filter(lambda x: not x.strip(), vals):
            self.raiseErrTemplate()
        service, option = vals
        if not service or not option:
            self.raiseErrTemplate()
        if not self.optionsInfo:
            # файл /var/calculate/remote/server.env
            envFile = self.objVar.Get("cl_env_server_path")
            # получаем словарь всех информационных переменных
            if self.convObj:
                optInfo = self.convObj.convert()
            else:
                optInfo = self.objVar.getRemoteInfo(envFile)
            if optInfo is False:
                self.raiseErrTemplate()
            if optInfo:
                self.optionsInfo = optInfo
        replace = ''
        if service in self.optionsInfo and option in self.optionsInfo[service]:
            value = self.optionsInfo[service][option]
            if nameLocalVar:
                localVars[nameLocalVar] = value
            else:
                replace = value
        elif nameLocalVar:
            localVars[nameLocalVar] = ""
        textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
                textTemplateTmp[resS.end():]
        return textTemplateTmp

    def funcGroups(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
        """Функция шаблона groups(),
        проверяет нахождение пользователя в группах, если находится выдает '1'
        """
        terms = map(lambda x: x.strip(), funArgv.split(","))
        groupNames = set(terms)
        userGroups = set(self.groups)
        replace = ""
        if groupNames & userGroups:
            replace = "1"
        textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
                textTemplateTmp[resS.end():]
        return textTemplateTmp

    def funcBelong(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
        self.printWARNING(_("Function '{funcname}' used by {template} "
                            "is deprecated and will be removed in the future"
                            ).format(funcname="belong",template=nameTemp))
        replace = ""
        return textTemplateTmp[:resS.start()] + replace +\
                textTemplateTmp[resS.end():]

    def checkCorrectPkgName(self,package):
        """
        Check pkg name (in /var/db/pkg,/usr/portage,/var/lib/layman/calculate
        and other overlays)
        """
        category,spl,pkgname = package.partition('/')
        pkgname, spl, slot = pkgname.partition(":")
        # check installed package in system
        if not category in self.installCategory:
            self.getInstallPkgGentoo(category=category)
            self.installCategory.append(category)
        if self.pkg("%s/%s"%(category,pkgname), slot=slot or None):
            return True
        # check package in portage and calculate,overlay
        def queuePortdir():
            yield "/usr/portage"
            calculate = "/var/lib/layman/calculate"
            yield calculate
            for portdir in filter(lambda x:x!=calculate,
                           self.objVar.Get('cl_portdir_overlay')):
                yield portdir

        for portdir in queuePortdir():
            if not portdir in self.cachePortdir:
                lPortdir = len(portdir)+1
                self.cachePortdir[portdir] = list(set(
                    map(lambda x:x[lPortdir:].rpartition('/')[0],
                    glob.glob("%s/*/*/*.ebuild"%portdir))))
            if package in self.cachePortdir[portdir]:
                return True
            else:
                if portdir == "/usr/portage" and \
                    len(self.cachePortdir[portdir]) < 30:
                    #raise TemplatesError(_("Ebuild files are not found in portage"))
                    return True
        if not "portage/update" in self.cachePortdir:
            updateFiles = sorted(listDirectory('/usr/portage/profiles/updates'),
                          key=lambda x:tuple(reversed(x.split('Q-'))),reverse=True)
            if updateFiles:
                self.cachePortdir["portage/update"] = \
                    map(lambda x:x.split(' ')[1],
                    filter(lambda x:x.startswith('move '),
                    readLinesFile(os.path.join('/usr/portage/profiles/updates',
                                            updateFiles[0]))))
        if "portage/update" in self.cachePortdir and \
            package in self.cachePortdir["portage/update"]:
            self.printWARNING(_("Package {frompkg} was renamed").format(frompkg=package))
            return True
        return False

    def funcMerge(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
        """
        Belong function use value in first arg and compare it 
        for all values in cl_merge_pkg.
        If cl_merge_pkg empty or first arg <=cl_belogn_pkg
        then "1" else ""
        """
        terms = funArgv.replace(" ","").split(",")
        if len(terms) != 1:
            self.raiseErrTemplate()
        funcPkg = terms[0]
        if not funcPkg:
            fileName = os.path.split(self.nameTemplate)[1]
            if fileName == '.calculate_directory':
                parentDir = os.path.dirname(self.nameTemplate)
                parentDir, pkgName = os.path.split(parentDir)
            else:
                parentDir, pkgName = os.path.split(self.nameTemplate)
            category = os.path.split(parentDir)[1]
            # reg for discard version and sort number
            pkgName = self.reData.search(pkgName).group(1)
            category = self.reData.search(category).group(1)
            funcPkg = "%s/%s"%(category,pkgName)
        try:
            if not self.checkCorrectPkgName(funcPkg):
                message = _("Package {pkgName} specified in the merge() into "
                    "{templName} template is not found").format(
                   pkgName=funcPkg,templName=self.nameTemplate)
                hashMessage = hashlib.md5(message).digest()
                if not hashMessage in self.alreadyInformed:
                    self.printWARNING(message)
                    self.alreadyInformed.append(hashMessage)
                return textTemplateTmp[:resS.start()] + \
                        textTemplateTmp[resS.end():]
        except TemplatesError as e:
            self.printWARNING(str(e))
        self.currentBelong = funcPkg
        if self.objVar.Get('cl_action') == 'patch':
            if funcPkg == "%s/%s"%(self.objVar.Get('core.cl_core_pkg_category'),
                                   self.objVar.Get('core.cl_core_pkg_name')):
                replace = self.objVar.Get('core.cl_core_pkg_version')
            else:
                replace = ""
        else:
            pkg = self.objVar.Get("cl_merge_pkg")
            replace = ""
            if pkg:
                if funcPkg in pkg:
                    replace = "1"
            else:
                replace = "1"
        textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
                textTemplateTmp[resS.end():]
        return textTemplateTmp

    def funcList(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
        """Функция шаблона list().
        Если первый аргумент является именем локальной или глобальной
        переменной и значение переменной является списком, выдает 
        элемент списка по второму аргументу индексу.
        Первый элемент имеет индекс 0
        """
        terms = funArgv.replace(" ","").split(",")
        # У функции должно быть два аргумента
        if len(terms) != 2:
            self.raiseErrTemplate()
        # Название локальной или глобальной переменной
        nameLocVar = terms[0]
        strIndex = terms[1]
        try:
            intIndex = int(strIndex)
        except:
            self.raiseErrTemplate(_("'%s' is not a number")%strIndex)
        flagFoundVar = False
        if nameLocVar in localVars.keys():
                flagFoundVar = True
                value = localVars[nameLocVar]
        else:
            try:
                value =  self.objVar.Get(nameLocVar)
                flagFoundVar = True
            except:
                pass
        if not flagFoundVar:
            # Если переменная не существует
            self.raiseErrTemplate(_("error: variable %s does not exist")\
                                         %str(nameLocVar))
        if not type(value) in (list,tuple):
            # Значение переменной не список или кортеж
            self.raiseErrTemplate(_("value of %s is not a list or a tuple")\
                                         %str(nameLocVar))
        try:
            if len(value) > intIndex:
                replace = str(value[intIndex])
            else:
                replace = ""
        except:
            self.raiseErrTemplate(_("wrong %s")%strIndex)
        textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
                textTemplateTmp[resS.end():]
        return textTemplateTmp

    def funcDisk(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
        """Функция шаблона disk().
        Первый аргумент ищется в значении переменной os_disk_install
        (значение os_install_disk_mount - 
        список точек монтирования при установке)
        второй аргумент используется для поиска в переменной
        os_disk_второй_аргумент (значение os_disk_второй_аргумент - список)
        В os_install_disk_mount ищется первый аргумент, находим его индекс
        результат - элемент cписка из os_disk_второй_аргумент с этим индексом
        """
        terms = funArgv.replace(" ","").split(",")
        # У функции должно быть два аргумента
        if len(terms) != 2:
            self.raiseErrTemplate()
        # Название глобальной переменной
        mountPoint = terms[0]
        lastElementVar = terms[1]
        if not mountPoint or mountPoint[:1] !="/":
            self.raiseErrTemplate(_("wrong %s")%lastElementVar)
        nameVar = "install.os_install_disk_mount"
        try:
            valueVar =  self.objVar.Get(nameVar)
        except:
            # Если переменная не существует
            self.raiseErrTemplate(
                _("error: variable %s does not exist")%nameVar)
        nameElementVar = "install.os_install_disk_%s"%lastElementVar
        try:
            valueElementVar =  self.objVar.Get(nameElementVar)
        except:
            # Если переменная не существует
            nameElementVar = "install.os_disk_%s"%lastElementVar
            try:
                valueElementVar =  self.objVar.Get(nameElementVar)
            except:
                self.raiseErrTemplate(_("wrong %s")%lastElementVar+"\n"+
                                      _("error: variable %s does not exist")\
                                             %nameElementVar)
        if not type(valueVar) in (list,tuple):
            # Значение переменной не список или кортеж
            self.raiseErrTemplate(_("value of %s is not a list or a tuple")\
                                         %nameVar)
        if not type(valueElementVar) in (list,tuple):
            # Значение переменной не список или кортеж
            self.raiseErrTemplate(_("value of %s is not a list or a tuple")\
                                         %nameElementVar)
        if len(valueVar) != len(valueElementVar):
            self.raiseErrTemplate(
                _("%(name)s does not match %(nameElement)s in size")\
                  %{'name':nameVar, 'nameElement':nameElementVar})
        index = None
        for num, mPoint in enumerate(valueVar):
            if mountPoint == mPoint:
                index = num
                break
        if index is None:
            for num, mPoint in enumerate(valueVar):
                if "/" == mPoint:
                    index = num
                    break
        if index is None:
            self.raiseErrTemplate(_("mount point '/' or '/%s' not found "
                 " in the value of variable os_disk_install")
                 %mountPoint)
        replace = valueElementVar[index]
        textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
                textTemplateTmp[resS.end():]
        return textTemplateTmp

    def funcModule(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
        """Функция шаблона module(), выдает значение аттрибута api.

        аргумент:
            путь_к_атрибуту - путь к аттрибуту

        возможные пути:
            имя_пакета.var.имя_переменной - получаем значение переменной
            имя_пакета.имя_метода_api - выполнение метода, получение результата
            all.имя_метода_api - выполнение метода для всех пакетов с api
        """
        terms = funArgv.replace(" ","").split(",")
        if len(terms)!=1:
            self.raiseErrTemplate()
        pathObj = terms[0]
        if not '.' in pathObj:
            self.raiseErrTemplate()
        pkgApiObj = self.packagesAPI()
        try:
            value = eval('pkgApiObj.%s'%pathObj)
        except self.APIError, e:
            self.raiseErrTemplate(str(e))
        except Exception, e:
            value = ""
        if value is True:
            replace = '1'
        elif value in (False, None):
            replace = ''
        else:
            replace = str(value)
        textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
                textTemplateTmp[resS.end():]
        return textTemplateTmp

    def raiseErrTemplate(self,message=""):
        """Возвращает ошибки при обработке функций шаблона"""
        if message:
            message = "%s\n"%message
        else:
            message = ""
        raise TemplatesError(
            _("error in template %s")%self.nameTemplate + "\n" + \
            _("error, template term '%s'")%str(self.functText) + \
            message)

    def applyFuncTemplate(self, textTemplate, nameTemplate):
        """Применяет функции к тексту шаблона"""
        # Локальные переменные
        localVars = {}
        # Имя обрабатываемого шаблона
        self.nameTemplate = nameTemplate
        # Регулярное выражение для поиска функции в шаблоне
        reFunc = self._reFunc
        resS = reFunc.search(textTemplate)
        textTemplateTmp = textTemplate
        flagIniFunc = False
        while resS:
            mark = textTemplateTmp[resS.start():resS.end()]
            self.functText = mark[self._deltVarStart:-self._deltVarEnd]
            funcName, spl, funcEnd  = self.functText.partition("(")
            if funcName in self.namesTemplateFunction:
                # аргументы функции - '(' аргументы ')'
                funArgv = funcEnd.rpartition(")")[0]
                # вызов функции шаблона
                textTemplateTmp = self.templateFunction[funcName](self, funArgv,
                                                                resS, localVars,
                                                                textTemplateTmp,
                                                                nameTemplate)
                resS = reFunc.search(textTemplateTmp)
                if funcName == "ini":
                    flagIniFunc = True
            else:
                self.raiseErrTemplate(
                    _("function of templates '%s' not found")\
                    %str(self.functText))
        if flagIniFunc:
            # Очистка файла в случае его ошибочного чтения
            if not self.prevDictIni and os.path.exists(self.fileConfigIni):
                FD = open(self.fileConfigIni, "r+")
                FD.truncate(0)
                FD.seek(0)
                FD.close()
            # Если конф. файл модифицирован шаблоном
            curTime = self.getTimeFile(self.fileConfigIni)
            if curTime != self.timeIni:
                # Считаем переменные из конф. файла
                self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
                self.currDictIni.update(self.prevDictIni)
                self.timeIni = curTime
            # Если словари переменных не совпадают
            if self.prevDictIni != self.currDictIni:
                # Запишем переменные в конфигурационный файл
                # Создание объекта парсера
                config = iniParser(self.fileConfigIni)
                # set specified mode for ini file
                config.setMode(self.modeConfigIni)
                # секции будущего конфигурационного файла
                sects = list(set(map(lambda x: x.split(".")[0],\
                                     self.currDictIni.keys())))
                # запись переменных в файл
                for sect in sects:
                    dictVar = {}
                    for varName in self.currDictIni.keys():
                        if varName.startswith("%s."%sect):
                            nameVar = varName.rpartition(".")[2]
                            valueVar = self.currDictIni[varName]
                            if valueVar is None:
                                config.delVar(sect,nameVar)
                            else:
                                dictVar[nameVar] = valueVar
                    if dictVar:
                        # Запись переменных в секцию
                        config.setVar(sect, dictVar)
                # читаем переменные из файла
                self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
                self.currDictIni.update(self.prevDictIni)
                self.timeConfigsIni[self.fileConfigIni] = float(time.time())
                self.timeIni = self.getTimeFile(self.fileConfigIni)
            # Меняем владельца в случае необходимости
            if os.path.exists(self.fileConfigIni):
                uid, gid = getModeFile(self.fileConfigIni, "owner")
                if not self.uid in (uid,PORTAGEUID) or \
                    not self.gid in (gid,PORTAGEGID):
                    os.chown(self.fileConfigIni, self.uid, self.gid)
        return textTemplateTmp

class ChangedFiles:
    """
    Object which contains modified files and package
    """
    FILE_MODIFIED,FILE_REMOVED,DIR_CREATED,DIR_REMOVED,DIR_EXISTS = 0,1,2,3,4
    
    def __init__(self):
        self.data = {}
        self.pkgs = set()

    def _createEntry(self,fn):
        if not fn in self.data:
            self.data[fn] = []

    def addObj(self,filename,action,pkg):
        self._createEntry(filename)
        self.data[filename].append((pkg,action))
        self.pkgs.add(pkg)

    def getPkgs(self):
        return self.pkgs

    def getPkgFiles(self,pkg):
        return map(lambda x:(x[0],x[1][0][1]),
            filter(lambda x:x[1],
            map(lambda x:(x[0],filter(lambda x:x[0] == pkg,x[1])),self.data.items())))

# modes work with configuration file
# T_ORIGIN - work with original config file
# T_CFG - work with last ._cfg file
# T_NEWCFG - new content has difference with (create new ._cfg file)
T_ORIGIN, T_CFG, T_NEWCFG = 0,1,2

class Template(_file,_terms,_warning,xmlShare,templateFormat,_shareTemplate):
    """Класс для работы с шаблонами

    На вход 2 параметра: объект хранения переменных, имя сервиса - не
    обязательный параметр

    """
    # Название файла шаблона директории
    templDirNameFile = ".calculate_directory"
    titleEnd = "For modify this file, create %(conf_path)s.clt template."
    protectPaths = []
    allContents = {}
    if "CONFIG_PROTECT" in os.environ:
        protectPaths = ["/etc"] + filter(lambda x: x.strip(),
                                      os.environ["CONFIG_PROTECT"].split(" "))
        protectPaths = map(lambda x: os.path.normpath(x), protectPaths)

    def __init__(self, objVar, servDir=False, dirsFilter=[], filesFilter=[],
                 cltObj=True, cltFilter=True, printWarning=True,
                 printSUCCESS=lambda x:x,printWARNING=lambda x:x,
                 printERROR=lambda x:x,askConfirm=lambda x:x,
                 userProfile=False,dispatchConf=None):
        # совместимость с вызовами из модулей предыдущих версий
        if userProfile and objVar:
            objVar.Set('cl_protect_use_set','off',force=True)

        self.protectPaths = objVar.Get('cl_config_protect')
        self.dispatchConf = dispatchConf
        self.changedFiles = ChangedFiles()
        self.printSUCCESS = printSUCCESS
        self.printERROR = printERROR
        if printERROR:
            self.setError = self.printERROR
        self.printWARNING = printWARNING
        self.askConfirm = askConfirm
        self.stop = 0
        self.cltObj = None
        self.functObj = None
        # Предупреждения
        #self.warning = []
        # Печатать ли предупреждения о корневых шаблонах без cl_name==pkg
        self.printWarning = printWarning
        # Необрабатываемые директории
        self.dirsFilter = dirsFilter
        # Необрабатываемые файлы
        self.filesFilter = filesFilter
        _file.__init__(self)
        # Словарь для создания объектов новых классов по образцу
        self.newObjProt = {'proftpd':'apache'}
        # Заголовок title
        self.__titleHead = "--------------------------------------\
----------------------------------------"
        self._titleBody = ""
        self._titleList = ("Modified", "Processed template files" + ":")
        self._reVar = re.compile(("%s(?:[a-z0-9_]+\.)?[a-zA-Z0-9_-]+%s")%(self.varStart,
                                                         self.varEnd),re.M)
        # Условия
        self._reTermBloc = re.compile(
"#\?(?P<rTerm>(?:[a-z0-9_]+\.)?[a-zA-Z0-9\-_]+)\
(?P<func>\((%s+|)\))?\
(?P<lTerm>[\>\<\=\!\&\|]+\
[\>\<\=\!\|\&\(\)%s]*)#\
\n*(?P<body>.+?)\n*#(?P=rTerm)#(?P<end>[ ,\t]*\n?)"\
%(self._reFunctionArgvText, self._reFunctionArgvInSquareBrackets),
re.M|re.S)
        # Объект с переменными
        self.objVar = objVar
        self.recalculateBaseDir()
        # Последняя часть директории шаблона (имя сервиса: samba, mail)
        self._servDir = servDir 
        if self._servDir:
            if self._servDir[0] != "/":
                self._servDir = "/" + self._servDir
            if self._servDir[-1] != "/":
                self._servDir += "/"
            self._servDir = os.path.split(self._servDir)[0]
        # Созданные директории
        self.createdDirs = []
        # Примененные файлы
        self.filesApply = []
        # номер обрабатываемого файла
        self.numberProcessTempl = 0
        # имя текущей программы
        _nameProgram = self.objVar.Get("cl_name").capitalize()
        # версия текущей программы
        _versionProgram = self.objVar.Get("cl_ver")
        # имя и версия текущей программы
        self.programVersion = "%s %s"%(_nameProgram, _versionProgram)
        # Словарь директорий с количеством файлов шаблонов
        self.dictTemplates = {}
        # Общее количество шаблонов
        self.allTemplates = 0
        # Объект функций шаблона
        self.functObj = templateFunction(self.objVar)
        self.functObj.printSUCCESS = self.printSUCCESS
        self.functObj.printWARNING = self.printWARNING
        self.functObj.printERROR = self.printERROR
        if self.printERROR:
            self.functObj.setError = self.printERROR
        self.functObj.askConfirm = self.askConfirm
        # Метод применения функций к шаблонам
        self.applyFuncTemplate = self.functObj.applyFuncTemplate
        # Объект для определения типа файла шаблона
        self.typeFileObj = typeFile()
        # Глобальный словарь обработанных шаблонов файлов
        # {путь к конф. файлу:[имена шаблонов] ...}
        self.dictProcessedTemplates = {}
        if cltObj is True:
            # Объект templateClt
            self.cltObj = templateClt(self.objVar,printSUCCESS=self.printSUCCESS,
                                                  printERROR=self.printERROR,
                                                  printWARNING=self.printWARNING,
                                                  askConfirm=self.askConfirm)
        elif cltObj:
            # Объект templateClt
            self.cltObj = cltObj
        else:
            # Объект templateClt
            self.cltObj = False
        # Фильтровать ли шаблоны clt по конфигурационным файлам обычных шаблонов
        self.cltFilter = cltFilter
        # autoupdate файлы
        self.autoUpdateFiles = []
        self.autoUpdateDirs = []

        self.protectedFiles = self.objVar.Get('main.cl_env_path') + \
            [self.functObj.fileConfigIni]
        # список выполненных файлов
        self.executedFiles = []

    def recalculateBaseDir(self):
        """Recalculate basedir and homedir"""
        # Базовая директория переноса шаблонов "/mnt/calculate" или "/" и.т.д
        self._baseDir = pathJoin(self.objVar.Get("cl_chroot_path"),
                                 self.objVar.Get("cl_root_path"))
        self._baseDir = os.path.normpath(self._baseDir)
        self.uid, self.gid, self.homeDir = self.getDataUser()
        # Домашняя директория, плюс базовая директория
        self.homeDir = pathJoin(self._baseDir, self.homeDir)
        if self.cltObj:
            self.cltObj.recalculateBaseDir()
        if self.functObj:
            self.functObj.recalculateBaseDir()
                
    def _addFile(self,filesApl,pkg=None):
        """
        Add files to ChangedFiles
        """
        for fn in filesApl:
            if os.path.exists(fn):
                self.changedFiles.addObj(fn,ChangedFiles.FILE_MODIFIED,
                                         pkg or self.functObj.currentBelong)
            else:
                self.changedFiles.addObj(fn,ChangedFiles.FILE_REMOVED,
                                         pkg or self.functObj.currentBelong)
    
    def executeTemplate(self, code, execPath):
        """Execute template"""
        p = process(execPath,lang=self.objVar.Get('os_locale_locale'),
                    envdict=os.environ)
        if "/bin/bash" in code.partition('\n')[0]:
            p.write("""function translate() {
gettext -d cl_template "$*"
}
""")
        p.write(code)
        p.pipe.stdin.close()
        for line in p.readByLine():
            self.printSUCCESS(line.strip())
        p.pipe.wait()
        if p.success():
            self.executedFiles.append((code,execPath))
            if p.readerr():
                for line in p.readerr().split('\n'):
                    self.printWARNING(line.strip())
            return True
        else:
            if p.readerr():
                for line in p.readerr().split('\n'):
                    self.printERROR(line.strip())
            return False

    def __octToInt(self, strOct):
        """Преобразование восьмеричного в целое (ввод строка, вывод число)"""
        if strOct:
            try:
                res = string.atoi(strOct, 8)
            except ValueError:
                self.setError(_("Invalid oct value: ") + str(strOct))
                return False
            return res
        else:
            self.setError(_("Empty oct value"))
            return False

    def getTemplateType(self):
        """выдать тип шаблона (text, bin)"""
        return self.getFileType(self.nameFileTemplate)

    def getFileType(self, fileName):
        """выдать тип файла (text, bin)"""
        isBin = self.typeFileObj.isBinary(fileName)
        typeTemplate = "bin"
        if isBin is True:
            typeTemplate = "bin"
        elif isBin is False:
            typeTemplate = "text"
        else:
            self.setError(_("ERROR") + ": getFileType()")
            self.setError(isBin)
            return False
        return typeTemplate

    def createDir(self, dirName, mode=False, uid=False, gid=False):
        """Создает директорию"""
        if os.access(dirName, os.F_OK):
            return True
        else:
            dMode = False
            prevDir, tmpSubdir = os.path.split(dirName)
            createDirs = []
            while not os.access(prevDir, os.F_OK) and prevDir:
                createDirs.append(prevDir)
                prevDir = os.path.split(prevDir)[0]
            try:
                dUid,dGid = getModeFile(prevDir,"owner")
            except OSError:
                self.setError(_("No access to the directory: ") + prevDir)
                return False
            if not mode is False:
                dMode = mode
            if not uid is False:
                dUid = uid
            if not gid is False:
                dGid = gid
            createDirs.reverse()
            for nameDir in createDirs:
                try:
                    if dMode:
                        os.mkdir(nameDir, dMode)
                        os.chmod(nameDir, dMode)
                    else:
                        os.mkdir(nameDir)
                    os.chown(nameDir, dUid, dGid)
                except:
                    self.setError(_("Failed to create the directory: ")
                       + nameDir)
                    return False
            try:
                if dMode:
                    os.mkdir(dirName, dMode)
                    os.chmod(dirName, dMode)
                else:
                    os.mkdir(dirName)
                os.chown(dirName, dUid, dGid)
                createDirs.append(dirName)
            except:
                self.setError(_("Failed to create the directory: ")
                   + dirName)
                return False  
            return createDirs

    def applyVarsTemplate(self, textTemplate, nameTemplate):
        """ Заменяет переменные на их значения
        """
        resS = self._reVar.search(textTemplate)
        textTemplateTmp = textTemplate
        while resS:
            mark = textTemplateTmp[resS.start():resS.end()]
            varName = mark[self._deltVarStart:-self._deltVarEnd]
            varValue = ""
            try:
                varValue = self.objVar.Get(varName)
                if not varValue:
                    varValue = ""
                else:
                    varValue = str(varValue)
            except DataVarsError, e:
                raise TemplatesError(_("error in template %s")%nameTemplate
                    + "\n" + str(e))
            textTemplateTmp = textTemplateTmp.replace(mark, varValue)
            resS = self._reVar.search(textTemplateTmp)
        return textTemplateTmp

    def applyTermsTemplate(self,textTemplate,nameTemplate):
        """ Применяет условия, к условным блокам текста
        """
        def function(text):
            """Функция обработки функций в заголовке"""
            return self.applyFuncTemplate(text, nameTemplate)

        textTerm = ""
        resS = self._reTermBloc.search(textTemplate)
        textTemplateTmp = textTemplate
        while resS:
            mark = resS.group(0)
            body = resS.group("body")
            end = resS.group("end")
            parent = resS.group("func")
            if not parent:
                parent = ""
            term = resS.group("rTerm") + parent +\
                resS.group("lTerm")
            if self._equalTerm(term, _("invalid template content: ")+\
                                                nameTemplate, function):
                textTemplateTmp = textTemplateTmp.replace(mark, body+end)
            else:
                textTemplateTmp = textTemplateTmp.replace(mark, "")
            resS = self._reTermBloc.search(textTemplateTmp)
        return textTemplateTmp

    def getNeedTemplate(self, fileTemplate):
        """Применяем правила к названию файла"""
        dirP,fileP = os.path.split(fileTemplate)
        if fileP:
            spFile = fileP.split("?")
            realFileName = spFile[0]
            if len(spFile)>1:
                flagTrue = False
                for term in spFile[1:]:
                    if self._equalTerm(term, _("invalid template name: ")+\
                                                fileTemplate):
                        flagTrue = True
                        break
                if flagTrue:
                    return True
                else:
                    return False
            else:
                return True
        else:
            self.setError(_("invalid template name: ")+ str(fileTemplate))
            return False

    def getTitle(self, comment, commentList, configPath=""):
        """Выдает заголовок шаблона ( версия и.т.д)"""
        if configPath and self.protectPaths:
            flagFoundPath = False
            for protectPath in self.protectPaths:
                if self._baseDir != "/":
                    lenBaseDir = len(self._baseDir)
                    if len(configPath)>lenBaseDir and\
                        configPath[:lenBaseDir] == self._baseDir:
                        configPath = configPath[lenBaseDir:]
                if configPath.startswith(protectPath + "/"):
                    flagFoundPath = True
                    break
            if flagFoundPath:
                origConfigPath = PkgContents.reCfg.sub("/",configPath)
                commentList = commentList +\
                              [self.titleEnd%{'conf_path':origConfigPath}]
        if comment:
            commentFirst = comment
            commentInsert = comment
            commentLast = comment
            flagList = False
            # В случае открывающего и закрывающего комментария
            if type(comment) == types.TupleType and len(comment) == 2:
                commentFirst = comment[0]
                commentInsert = ""
                commentLast = comment[1]
                flagList = True
            if flagList:
                self._titleBody = commentFirst + "\n"
            else:
                self._titleBody = commentFirst + self.__titleHead + "\n"
            z = 0
            flagFirst = True
            for com in list(self._titleList) + [""]*(len(commentList)):
                if com:
                    if flagFirst:
                        self._titleBody += commentInsert + " " + com + " "+\
                                       self.programVersion + "\n"
                        flagFirst = False
                    else:
                        self._titleBody += commentInsert + " " + com + "\n"
                else:
                    self._titleBody += commentInsert + " " +\
                                       commentList[z] + "\n"
                    z += 1
            if flagList:
                self._titleBody +=  commentLast +"\n"
            else:
                self._titleBody += commentLast + self.__titleHead + "\n"
            return self._titleBody
        else:
            return ""

    def changeMergePackage(self,package):
        return True

    def numberAllTemplates(self, number):
        """Количество шаблонов

        Вызов происходит перед наложением шаблонов
        в момент вызова в number находится количество обрабатываемых файлов
        Наследуемая функция
        Используется для отображения прогресса при наложениии шаблонов
        """
        return True

    def numberProcessTemplates(self, number):
        """Номер текущего обрабатываемого шаблона

        Вызов происходит при наложении шаблона
        в момент вызова в number находится номер обрабатываемого шаблона
        Наследуемая функция
        Используется для отображения прогресса при наложениии шаблонов
        """
        return True

    def templateModify(self):
        """
        Files which created by apping templates
        """
        return True

    def fixNameFileConfig(self,origfilename):
        """Support ._cfg0000 files for postinst"""
        #if self.objVar.Get('cl_ebuild_phase') != 'postinst':
        #    return origfilename
        directory,filename = os.path.split(origfilename)
        i = 0
        for i in range(0,9999):
            if not os.path.exists(os.path.join(directory,
                                  "._cfg%04d_%s"%(i,filename))):
                if i:
                    filename = os.path.join(directory,
                                  "._cfg%04d_%s"%(i-1,filename))
                    if not os.path.exists(origfilename):
                        return origfilename
                    #origstat = os.stat(origfilename)[stat.ST_CTIME]
                    #newstat = os.stat(filename)[stat.ST_CTIME]
                    self.configMode = T_CFG
                    return filename
                return origfilename
        return origfilename

    def getHeaderText(self, text):
        textLines = text.splitlines()
        paramLine = ""
        if textLines:
            textLine = textLines[0]
            rePar = re.compile(\
                "\s*#\s*calculate\s+\\\\?|\s*#\s*calculate\\\\?$",re.I)
            reP = rePar.search(textLine)
            if reP:
                reL = False
                reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*",re.M)
                reLs = reLns.search(text)
                if reLs:
                    reL = reLs
                    paramLine = text[reP.end():reLs.end()]
                    paramLine = paramLine.replace("\\"," ")
                else:
                    reLn = re.compile("\n")
                    reL = reLn.search(text)
                    paramLine = textLine[reP.end():]
        return paramLine

    def getTemplateDirs(self, dirsTemplates):
        """Check template variable cl_name in first directories and files"""
        skipDirs = []
        skipTemplates = []
        for dirsTemplate in dirsTemplates:
            filesAndDirs = map(lambda x: os.path.join(dirsTemplate,x),
                               os.listdir(dirsTemplate))
            for dirFile in filesAndDirs:
                if os.path.isdir(dirFile):
                    flagDir = True
                    templatePath = os.path.join(dirFile,self.templDirNameFile)
                    if not os.path.isfile(templatePath):
                        skipDirs.append(dirFile)
                        continue
                else:
                    flagDir = False
                    templatePath = dirFile
                if os.path.isfile(templatePath):
                    if self.getFileType(templatePath) == "bin":
                        skipTemplates.append(dirFile)
                    else:
                        textTemplate = open(templatePath).read()
                        if textTemplate:
                            headerLine = self.getHeaderText(textTemplate)
                            if headerLine:
                                if not "cl_name==" in headerLine and \
                                    not "ac_" in headerLine:
                                    if flagDir:
                                        skipDirs.append(dirFile)
                                    else:
                                        skipTemplates.append(dirFile)
                            else:
                                if flagDir:
                                    skipDirs.append(dirFile)
                                else:
                                    skipTemplates.append(dirFile)
                        else:
                            skipTemplates.append(dirFile)
        if skipDirs or skipTemplates:
            # print warning
            from cl_print import color_print
            self.printWARNING(_("No conditions for checking the value of "
                                "an action variable"))
            skipDirTemplates = []
            for skipDir in skipDirs:
                skipTempl = os.path.join(skipDir,self.templDirNameFile)
                if os.path.isfile(skipTempl):
                    skipDirTemplates.append(skipTempl)
            if skipTemplates or skipDirTemplates:
                self.printWARNING(_("Skipped templates:"))
            for skipTemplate in skipTemplates + skipDirTemplates:
                self.printWARNING(" "*6 + skipTemplate)
            if skipDirs:
                self.printWARNING(_("Skipped directories:"))
            for skipDir in skipDirs:
                self.printWARNING(" "*6 + skipDir)
            self.printWARNING("")
            self.printWARNING(_("Headers of directory templates and headers "
                         "of files on the first level should include "
                         "an action variable"))
            self.printWARNING(_("Example:"))
            self.printWARNING("# Calculate ac_install_merge==on")
        return skipDirs + skipTemplates

    def applyTemplates(self,progress=True,rerun=True):
        """Применяет шаблоны к конфигурационным файлам"""

        def createDictTemplates(path, prefix, dictTemplates):
            """Создает словарь {"директория":"кол-во шаблонов" ...}

            и считает общее количество шаблонов
            """
            # Количество шаблонов
            self.allTemplates += 1
            dirTemplate = os.path.split(path)[0]
            while(True):
                if dirTemplate in dictTemplates.keys():
                    dictTemplates[dirTemplate] += 1
                else:
                    dictTemplates[dirTemplate] = 1
                if dirTemplate == prefix:
                    break
                dirTemplate = os.path.split(dirTemplate)[0]
            return dictTemplates

        self.clearErrors()
        self.clearWarnings()
        if not self.objVar.defined("cl_template_path_use"):
            self.setError(_("undefined variable: ") + "cl_template_path_use")
            return False
        dirsTemplates = self.objVar.Get("cl_template_path_use")
        # Созданные директории
        self.createdDirs = []
        # Примененные файлы
        self.filesApply = []
        # Номер применяемого шаблона
        self.numberProcessTempl = 0
        # Словарь директорий с количеством файлов шаблонов
        self.dictTemplates = {}
        # Количество шаблонов
        self.allTemplates = 0
        # Установка по умолчанию аттрибутов для функциии шаблонов ini()
        # Время доступа к конфигурационному файлу функции шаблона ini()
        self.functObj.timeIni = -1
        # Первоначальный словарь переменных для ini()
        self.functObj.prevDictIni = {}
        # Текущий словарь переменных для ini()
        self.functObj.currDictIni = {}
        self.functObj.currentBelong = ""
        # Словарь времен модификации env файлов для ini()
        self.functObj.timeConfigsIni = {}
        if self._servDir:
            tmpDirsTemplates = []
            for dirP in dirsTemplates:
                dirTempl = dirP + self._servDir
                if os.access(dirTempl, os.F_OK):
                    # Если директория существует
                    tmpDirsTemplates.append(dirTempl)
            dirsTemplates = tmpDirsTemplates
        scanObj = scanDirectory()
        scanObj.processingFile = lambda x,y: createDictTemplates(x, y,\
                                                             self.dictTemplates)
        # Считаем количество шаблонов
        dirsTemplatesExists = filter(lambda x: os.path.exists(x), dirsTemplates)
        if not dirsTemplatesExists and not self.cltObj:
            self.setError(_("No such templates directory") +\
                    ": %s"%", ".join(map(lambda x: "'%s'"%x ,dirsTemplates)))
            return (self.createdDirs, self.filesApply)
        # check cl_name in first template dirs and files
        skipTemplates = self.getTemplateDirs(dirsTemplatesExists)
        #if not os.environ.get("EBUILD_PHASE","") and progress:
        #    for dirTemplate in dirsTemplatesExists:
        #        scanObj.scanningDirectory(dirTemplate)
        # Считаем количество шаблонов clt
        if self.cltObj:
            # Считаем количество шаблонов clt
            self.cltObj.countsNumberTemplates()
            # не считать количество файлов в объекте self.cltObj
            self.cltObj.checkNumberTemplate = False
            # начальный номер clt шаблона
            self.cltObj.numberProcessTempl = self.allTemplates
            # метод показывающий номер clt шаблона
            self.cltObj.numberProcessTemplates = self.numberProcessTemplates
            # метод показывающий номер clt шаблона
            self.cltObj.templateModify = self.templateModify
            # общее количество шаблонов
            self.allTemplates += self.cltObj.allTemplates
            self.cltObj.allTemplates = self.allTemplates
        self.numberAllTemplates(self.allTemplates)
        # Обрабатываем шаблоны
        for dirTemplate in dirsTemplatesExists:
            if self.scanningTemplates(dirTemplate,
                                      skipTemplates=skipTemplates) is False:
                break
        if self.cltObj and not self.stop:
            # Созданные директории
            self.cltObj.createdDirs = self.createdDirs
            # Примененные файлы
            self.cltObj.filesApply = self.filesApply
            # Словарь директорий с количеством файлов шаблонов
            self.cltObj.dictTemplates = self.dictTemplates
            # Количество шаблонов
            self.cltObj.allTemplates = self.allTemplates
            # Установка по умолчанию аттрибутов для функциии шаблонов ini()
            # Время доступа к конфигурационному файлу функции шаблона ini()
            self.cltObj.functObj = self.functObj
            self.cltObj.protectedFiles = self.protectedFiles
            # Метод применения функций к шаблонам
            self.cltObj.applyFuncTemplate = self.functObj.applyFuncTemplate
            # Словарь примененных файлов шаблонов
            self.cltObj.dictProcessedTemplates = self.dictProcessedTemplates
            self.cltObj.changedFiles = self.changedFiles
            self.cltObj.autoUpdateFiles = self.autoUpdateFiles
            self.cltObj.autoUpdateDirs = self.autoUpdateDirs

            if self.cltFilter:
                # Шаблоны + .clt которые будут  применены
                self.cltObj.filterApplyTemplates = {}
                if self.objVar.Get('cl_merge_set') == "on":
                    for pkg in self.objVar.Get('cl_merge_pkg'):
                        if not pkg:
                            continue
                        category = isPkgInstalled(pkg)
                        if category:
                            pkgContents = PkgContents("{CATEGORY}/{PF}".format(
                                        **category[0]))
                            for filename in pkgContents.content.keys():
                                if not filename in self.cltObj.filterApplyTemplates:
                                   self.cltObj.filterApplyTemplates[filename] = []
                                self.cltObj.filterApplyTemplates[filename].append(pkg)
                for filename,pkgs in self.changedFiles.data.items():
                    filename = PkgContents.reCfg.sub("/",filename)
                    if not filename in self.cltObj.filterApplyTemplates:
                       self.cltObj.filterApplyTemplates[filename] = []
                    pkgs = filter(lambda x:not x in \
                                  self.cltObj.filterApplyTemplates[filename],
                           map(lambda x:x[0],pkgs))
                    self.cltObj.filterApplyTemplates[filename].extend(pkgs)
            self.cltObj.applyTemplates()
            self.stop = self.stop or self.cltObj.stop
        if not self.stop and ((self.objVar.Get('cl_merge_pkg') or \
            self.objVar.Get('cl_action') in ("sync","domain","undomain")) and \
            self.objVar.Get('cl_merge_pkg_new')):
            self.objVar.Set('cl_root_path',
                            self.objVar.Get('cl_root_path_next'),force=True)
            self.recalculateBaseDir()
            self.objVar.Set('cl_merge_pkg_pass',list(
                set(self.objVar.Get('cl_merge_pkg_pass'))|
                set(self.objVar.Get('cl_merge_pkg'))|
                set(self.objVar.Get('cl_merge_pkg_new'))),force=True)
            self.objVar.Set('cl_merge_pkg',
                            self.objVar.Get('cl_merge_pkg_new'),force=True)
            self.objVar.Set('cl_merge_pkg_new',[],force=True)
            createdDirs = self.createdDirs
            filesApply = self.filesApply
            self.changeMergePackage(self.objVar.Get('cl_merge_pkg'))
            self.applyTemplates(rerun=False)
            createdDirs.extend(self.createdDirs)
            filesApply.extend(self.filesApply)
            self.filesApply = filesApply
            self.createdDirs = createdDirs
        if rerun and self.stop != TemplatesInterrupt.ABORT:
            if self.cltObj:
                self.queueExecute.extend(self.cltObj.queueExecute)
            for processor,text,nameTemplate in self.queueExecute:
                if not self.executeTemplate(text,processor):
                    self.setError(_("Failed to execute") + ": " +\
                                  nameTemplate)
                    return False
            self.queueExecute = []
            self.filesApply = list(set(self.filesApply))
            if self.objVar.Get('cl_protect_use_set') == 'on':
                self.updateProtectedFiles()
            if self.objVar.Get('cl_verbose_set') == 'on' and \
                self.filesApply:
                self.verboseOutput(self.filesApply)
        return (self.createdDirs, self.filesApply)

    def verboseOutput(self,filesApply):
        """
        Verbose output applied templates
        """
        self.printWARNING(_("Calculate Utilities have changed files")+":")
        reGrey = re.compile(r"\._cfg\d{4}_")
        rootPath = self.objVar.Get('cl_root_path')
        for fn in sorted(list(set(filesApply))):
            if rootPath != '/' and self.objVar.Get('cl_action') == 'patch' and \
                fn.startswith(rootPath):
                fn = fn[len(rootPath)+1:]
            if reGrey.search(fn):
                self.printSUCCESS("&nbsp;"*5 + \
                    "<font color=\"dark gray\">%s</font>"%fn)
            else:
                self.printSUCCESS("&nbsp;"*5 + fn)

    def updateProtectedFiles(self):
        """
        Update ._cfg0000 files
        """
        if self.objVar.Get('cl_ebuild_phase') == 'compile':
            return
        chrootPath = self.objVar.Get('cl_chroot_path')
        cfgs = getCfgFiles(self.objVar.Get('cl_config_protect'),
                           prefix=chrootPath)
        autoUpdateDict = {}
        for pkg in list(set(list(self.changedFiles.getPkgs())+
                            self.objVar.Get('cl_merge_pkg'))):
            category = isPkgInstalled(pkg,prefix=chrootPath)
            if category:
                pkgContents = PkgContents("{CATEGORY}/{PF}".format(
                           **category[0]),prefix=chrootPath)
                for filename,action in self.changedFiles.getPkgFiles(pkg):
                    if filename in self.protectedFiles:
                        pkgContents.removeObject(filename)
                        continue
                    if action in (ChangedFiles.FILE_MODIFIED,
                                  ChangedFiles.DIR_CREATED,
                                  ChangedFiles.DIR_EXISTS):
                        pkgContents.addObject(filename)
                    elif action in (ChangedFiles.FILE_REMOVED,
                                    ChangedFiles.DIR_REMOVED):
                        pkgContents.removeObject(filename)
                files = set(map(lambda x:pathJoin(chrootPath,x),
                                     pkgContents.content.keys()))
                if (self.objVar.Get('cl_dispatch_conf') != 'usenew' and
                    self.objVar.Get('cl_autoupdate_set') != "on"):
                    notUpdate = files - set(self.autoUpdateFiles)
                    files &= set(self.autoUpdateFiles)
                    for filename in list(notUpdate&set(cfgs.keys())):
                        if hashlib.md5(readFile(filename)).hexdigest() == \
                           hashlib.md5(readFile(
                            cfgs[filename][0][1])).hexdigest():
                            files.add(filename)

                for filename in list(files&set(cfgs.keys())):
                    # get ctime from orig filename
                    #if os.path.exists(filename):
                    #    ctime = os.stat(filename).st_ctime
                    #else:
                    #    ctime = 0
                    # if orig filename older that .cfg
                    cfgs[filename].sort(reverse=True)
                    #if ctime < cfgs[filename][0][0]:
                    try:
                        open(filename,'w').write(
                            readFile(cfgs[filename][0][1]))
                    except Exception as e:
                        self.printERROR(str(e))
                        self.printWARNING(
                            _("Failed to copy {ffrom} to {fto}").format(
                             ffrom=cfgs[filename][0][1],fto=filename))
                        continue
                    autoUpdateDict[cfgs[filename][0][1]] = filename
                    for mtime,fn in cfgs[filename]:
                        try:
                            os.unlink(fn)
                        except Exception as e:
                            self.printWARNING(_("Failed to remove %s")%fn)
                pkgContents.writeContents()
        self.filesApply = map(lambda x:autoUpdateDict.get(x,x),self.filesApply)
        if filter(lambda x:"._cfg" in x, self.filesApply):
            self.printWARNING(_("Some config files need updating. "
                                "Perform run dispatch-conf."))
            if self.dispatchConf and \
                self.objVar.Get('cl_dispatch_conf') == 'dispatch' and \
                self.objVar.Get('cl_ebuild_phase') == '':
                self.dispatchConf(self.filesApply)

    def scanningTemplates(self, scanDir, prefix=None, flagDir=False,
                          optDir={}, skipTemplates=[]):
        """Сканирование и обработка шаблонов в директории scanDir"""
        ret = True
        if not prefix:
            prefix = os.path.realpath(scanDir)
        if not flagDir:
            # проверка корневой директории
            retDir = self.processingDirectory(scanDir, scanDir, optDir)
            if retDir is None:
                return None
            elif retDir is False:
                return False
            pathDir, objHead =  retDir
            optDir["path"] = pathDir
            if not objHead is True:
                if objHead.typeAppend == "skip":
                    # Установка опции пропуска директории
                    optDir["skip"] = True
                if ("autoupdate" in objHead.params or
                    self.objVar.Get('cl_autoupdate_set') == 'on'):
                    optDir["autoupdate"] = True
        if flagDir or stat.S_ISDIR(os.lstat(scanDir)[stat.ST_MODE]):
            for fileOrDir in sorted(os.listdir(scanDir)):
                absPath = os.path.join(scanDir,fileOrDir)
                if skipTemplates and absPath in skipTemplates:
                        continue
                stInfo = os.lstat(absPath)
                statInfo = stInfo[stat.ST_MODE]
                prevModule = self.objVar.defaultModule
                prevBelong = self.functObj.currentBelong
                try:
                    if stat.S_ISREG(statInfo):
                        if not self.processingFile(absPath, prefix, optDir):
                            ret = False
                            continue
                    elif stat.S_ISDIR(statInfo):
                        # Обработка директории
                        retDir = self.processingDirectory(absPath, prefix,
                                                          optDir)
                        if retDir is None:
                            continue
                        elif retDir is False:
                            ret = False
                            break
                        # Опции следующей директории
                        optNextDir = {}
                        pathDir, objHead =  retDir
                        optNextDir["path"] = pathDir
                        if not objHead is True:
                            if objHead.typeAppend == "skip":
                                # Установка опции пропуска директории
                                optNextDir["skip"] = True
                            if ("autoupdate" in objHead.params or
                                self.objVar.Get('cl_autoupdate_set') == 'on'):
                                optNextDir["autoupdate"] = True
                        ret = self.scanningTemplates(absPath, prefix, True,
                                                     optNextDir)
                        if ret is False:
                            break
                except TemplatesInterrupt as e:
                    if e.isInterrupt():
                        self.stop = e.status()
                        return False
                    else:
                        self.clearErrors()
                        self.printWARNING(str(e))
                finally:
                    self.objVar.defaultModule = prevModule
                    self.functObj.currentBelong = prevBelong
        return ret


    def processingFile(self, path, prefix, optFile):
        """Обработка в случае шаблона файла"""
        self.numberProcessTempl += 1
        self.numberProcessTemplates(self.numberProcessTempl)
        # Пропуск шаблонов директорий
        if self.templDirNameFile == os.path.split(path)[1]:
            return True
        # Проверка на переменные в названии файла
        if not self.getNeedTemplate(path):
            if self.getError():
                return False
            return True
        if self.getError():
            return False
        nameFileConfig = path.partition(prefix)[2]
        # файл в системе без условий
        nameFileConfig = "/".join(map(lambda x:x.split("?")[0],\
                        nameFileConfig.split("/")))
        # Записываем в переменную обрабатываемый файл
        self.objVar.Set("cl_pass_file",nameFileConfig)
        filesApl = self.joinTemplate(path, nameFileConfig, optFile)
        if self.getError():
            return False
        if filesApl:
            # Настоящее имя конфигурационного файла
            nameFileConfig = filesApl[0]
            # Пишем время модификации *.env файлов
            if nameFileConfig.endswith(".env"):
                nameEnvFile = os.path.basename(nameFileConfig)
                self.functObj.timeConfigsIni[nameEnvFile] = float(time.time())
            self.filesApply += filesApl
        if filesApl:
            self._addFile(filesApl)
        return True

    def processingDirectory(self, path, prefix, opt):
        """Обработка в случае директории если возвращаем None то пропуск дир."""
        # Файл шаблона директории
        dirInfoFile = os.path.join(path, self.templDirNameFile)
        newDir = pathJoin(self._baseDir, path.partition(prefix)[2])
        newDir = "/".join(map(lambda x:x.split("?")[0], newDir.split("/")))
        # Применяем шаблон
        pathDir, objHeadDir, createdDirs =\
                                self.getApplyHeadDir(newDir, dirInfoFile, opt)
        if createdDirs:
            self.createdDirs += createdDirs
        if os.path.isfile(pathDir):
            self.printWARNING(_("{dirpath} is a file").format(dirpath=pathDir))
            self.printWARNING(_("templates in {tempath} are skipped"
                ).format(tempath=path))
            return None
        if objHeadDir:
            return pathDir, objHeadDir
        else:
            if self.getError():
                return False
            # Добавление количества файлов в пропущенной директории
            if path in self.dictTemplates.keys():
                self.numberProcessTempl += self.dictTemplates[path]
            return None

    def getApplyHeadDir(self, newDir, templateDirFile, optDir):
        """Применяет шаблон к директории (права, владелец, и.т. д)"""

        def function(text):
            """Функция обработки функций в заголовке"""
            return self.applyFuncTemplate(text, templateDirFile)

        def chownConfDir(nameDirConfig, uid, gid, nameFileTemplate):
            """Изменение владельца конфигурационной директории"""
            try:
                os.chown(nameDirConfig, uid, gid)
            except Exception as e:
                if hasattr(e,'errno') and e.errno == 13 and \
                    "var/calculate/remote" in nameDirConfig:
                    return True
                import pwd, grp
                try:
                    userName = pwd.getpwuid(uid).pw_name
                except:
                    userName = str(uid)
                try:
                    groupName = grp.getgrgid(gid).gr_name
                except:
                    groupName = str(gid)
                owner = userName + ":" + groupName
                self.setError(_("Failed to apply template file %s")\
                                %nameFileTemplate)
                self.setError(_("error") + " " +\
                              "'chown %s %s'"%(owner, nameDirConfig))
                return False
            return True

        applyDir = newDir

        # Родительская директория
        if optDir.get("path"):
            path = optDir["path"]
        else:
            if applyDir == self._baseDir:
                path = os.path.dirname(self._baseDir)
            else:
                path = os.path.split(applyDir)[1]
                path = pathJoin(self._baseDir, path)
        if not os.path.exists(templateDirFile):
            if applyDir != self._baseDir:
                applyDir = os.path.join(path, os.path.split(applyDir)[1])
            # Фильтрация шаблонов по названию директории
            realPath = os.path.join("/",applyDir.partition(self._baseDir)[2])
            if realPath in self.dirsFilter:
                return ("", False, [])
            # Создаем директорию если необходимо
            crDirs = self.createDir(applyDir, False, self.uid, self.gid)
            if not crDirs:
                return ("", False, [])
            if "autoupdate" in optDir:
                self.autoUpdateDirs.append(applyDir)
            if crDirs is True:
                return (applyDir, True, [])
            else:
                return (applyDir, True, crDirs)
        try:
            FD = open(templateDirFile)
            textTemplate = FD.readline().rstrip()
            buf = textTemplate
            while buf and textTemplate.endswith('\\'):
                buf = FD.readline()
                textTemplate = "%s %s"%(textTemplate[:-1],buf.rstrip())
            FD.close()
        except:
            self.setError(_("Failed to open the template") + ": " +\
                               templateDirFile)
            return ("", False, [])

        headerLine = self.getHeaderText(textTemplate)
        if headerLine:
            moduleParam = filter(lambda x:x.startswith('env='),
                          headerLine.split())
            if moduleParam:
                self.objVar.defaultModule = moduleParam[0].partition('=')[2]
                try:
                    varModule = importlib.import_module(
                        "calculate.%s.variables"%self.objVar.defaultModule)
                except (ImportError, AttributeError),e:
                    return ("", False, [])
        # Заменяем переменные на их значения
        textTemplate = self.applyVarsTemplate(textTemplate, templateDirFile)

        # Заменяем функции на их значения
        textTemplate = self.applyFuncTemplate(textTemplate, templateDirFile)
        # Обработка заголовка
        objHead = dirHeader(templateDirFile,textTemplate,self.objVar,function)
        # Директория с профилями не будет применена
        if not objHead.headerTerm:
            if objHead.getError():
                self.setError(_("Incorrect template") + ": " +\
                              templateDirFile)
            return ("", False, [])

        # add packeges for reconfigure
        if "merge" in objHead.params:
            mergePkgs = objHead.params['merge'].split(',')
            for wrongPkg in (x for x in mergePkgs \
                             if not self.functObj.checkCorrectPkgName(x)):
                self.printWARNING(
                    _("Wrong package '%s' for 'merge' in the template")%
                              wrongPkg + ": " + templateDirFile)
            for pkg in mergePkgs:
                if not pkg in self.objVar.Get('cl_merge_pkg_new') and \
                   not pkg in self.objVar.Get('cl_merge_pkg_pass') and \
                   not pkg in self.objVar.Get('cl_merge_pkg'):
                    self.objVar.Get('cl_merge_pkg_new').append(pkg)

        # Пропускаем директорию
        if objHead.typeAppend == "skip":
            applyDir = path
            return (applyDir, objHead, [])

        # Изменяем название родительской директории
        if "path" in  objHead.params:
            path = objHead.params['path']
            if path and path[0] == "~":
                # Получаем путь с заменой ~ на директорию пользователя
                path = os.path.join(self.homeDir,
                                    path.partition("/")[2],"")[:-1]
            elif not path or path and path[0] != "/":
                self.setError(_("Wrong value 'path' in the template") + ": " +\
                                templateDirFile)
                return ("", False, [])
            else:
                path = pathJoin(self._baseDir, path)

        # Изменяем название директории
        if  "name" in  objHead.params:
            nameDir = objHead.params['name']
            if "/" in nameDir or nameDir == ".." or nameDir == ".":
                self.setError(_("Wrong value 'name' in the template") + ": " +\
                            templateDirFile)
                return ("", False, [])
            # Новый путь к директории
            applyDir = pathJoin(path, nameDir)
        else:
            applyDir = pathJoin(path, os.path.split(applyDir)[1])

        # Фильтрация шаблонов по названию директории
        realPath = os.path.join("/",applyDir.partition(self._baseDir)[2])
        if realPath in self.dirsFilter:
            return ("", False, [])
        # Удаляем директорию
        if objHead.typeAppend == "remove":
            if os.path.isdir(applyDir):
                self.changedFiles.addObj(applyDir,ChangedFiles.DIR_REMOVED,
                                         self.functObj.currentBelong)
                # удаляем директорию
                try:
                    removeDir(applyDir)
                except:
                     self.setError(_("Failed to delete the directory: ") +\
                                   applyDir)
            return ("", False, [])

        # Очищаем директорию
        if objHead.typeAppend == "clear":
            if os.path.isdir(applyDir):
                for rmPath in os.listdir(applyDir):
                    removePath = pathJoin(applyDir, rmPath)
                    if os.path.isdir(removePath):
                        # удаляем директорию
                        try:
                            removeDir(removePath)
                        except:
                            self.setError(
                                _("Failed to delete the directory: ") +\
                                          removePath)
                    else:
                        try:
                            os.unlink(removePath)
                        except:
                            self.setError(
                                _("Failed to delete: ") + removePath)
            return ("", False, [])

        # Созданные директории
        createdDirs = []
        # chmod - изменяем права
        if "chmod" in objHead.params:
            mode = self.__octToInt(objHead.params['chmod'])
            if mode:
                if not os.path.exists(applyDir):
                    crDirs = self.createDir(applyDir, mode, self.uid, self.gid)
                    if not crDirs:
                        return ("", False, [])
                    if not crDirs is True:
                        createdDirs += crDirs
                else:
                    os.chmod(applyDir, mode)
            else:
                self.setError(_("Wrong value 'chmod' in the template") + ": " +\
                               templateDirFile)
                return ("", False, [])
        # chown - изменяем владельца и группу
        if "chown" in objHead.params:
            owner = objHead.params['chown']
            if owner:
                if  ":" in owner:
                    strUid, strGid = owner.split(":")
                    import pwd
                    uid = self.getUidFromPasswd(strUid)
                    try:
                        uid = pwd.getpwnam(strUid).pw_uid
                    except:
                        self.setError(_("No such user on the system: ")
                                + strUid)
                        self.setError(_("Wrong value 'chown' in the template")+\
                        ": " + templateDirFile)
                        return ("", False, [])
                    gid = self.getGidFromGroup(strGid)
                    try:
                        import grp
                        gid = grp.getgrnam(strGid).gr_gid
                    except:
                        self.setError(_("Group not found on the system: ")
                                        +strGid)
                        self.setError(
                            _("Wrong value 'chown' in the template") +\
                                      ": "+ templateDirFile)
                        return ("", False, [])

                    if not os.path.exists(applyDir):
                        crDirs = self.createDir(applyDir, False, uid, gid)
                        if not crDirs:
                            return ("", False, [])
                        if not crDirs is True:
                            createdDirs += crDirs
                    else:
                        if not chownConfDir(applyDir, uid, gid,
                                            templateDirFile):
                            return ("", False, [])
                else:
                    self.setError(_("Wrong value 'chown' in the template")
                                + ": " + templateDirFile)
                    return ("", False, [])
            else:
                self.setError(_("Wrong value 'chown' in the template") +
                        ": " + templateDirFile)
                return ("", False, [])
        else:
            # Устанавливаем владельцем директории, пользователя по умолчанию
            # (переменная шаблона ur_login)
            if os.path.exists(applyDir):
                self.changedFiles.addObj(applyDir,ChangedFiles.DIR_EXISTS,
                                         self.functObj.currentBelong)
                tUid, tGid = getModeFile(applyDir, mode="owner")
                if (self.uid, self.gid) != (tUid, tGid):
                    if not chownConfDir(applyDir, self.uid, self.gid,
                                        templateDirFile):
                        return ("", False, [])
            else:
                self.changedFiles.addObj(applyDir,ChangedFiles.DIR_CREATED,
                                         self.functObj.currentBelong)
                crDirs = self.createDir(applyDir, False, self.uid, self.gid)
                if not crDirs:
                    return ("", False, [])
                if not crDirs is True:
                    createdDirs += crDirs
        if not objHead:
            applyDir = ""
        if applyDir:
            if ("autoupdate" in optDir or "autoupdate" in objHead.params ) and \
                    not self.objVar.Get('cl_merge_pkg_pass'):
                self.autoUpdateDirs.append(applyDir)
        return (applyDir, objHead, createdDirs)

    def getUidFromPasswd(self,strUid):
        """Get uid by username from chroot passwd file"""
        passwdFile = os.path.join(self._baseDir,'etc/passwd')
        if os.path.exists(passwdFile):
            mapUid = dict(
                     filter(lambda x:x and len(x)>1 and x[0] and x[1],
                     map(lambda x:x.split(':')[0:3:2],
                     filter(lambda x:not x.startswith('#'),
                     open(passwdFile,'r')))))
            if strUid in mapUid:
                return int(mapUid[strUid])
        return None

    def getGidFromGroup(self,strGid):
        """Get gid by groupname from chroot group file"""
        groupFile = os.path.join(self._baseDir,'etc/group')
        if os.path.exists(groupFile):
            mapGid = dict(
                     filter(lambda x:x and len(x)>1 and x[0] and x[1],
                     map(lambda x:x.split(':')[0:3:2],
                     filter(lambda x:not x.startswith('#'),
                     open(groupFile,'r')))))
            if strGid in mapGid:
                return int(mapGid[strGid])
        return None

    def checkOnNewConfigName(self,pathFile):
        """
        Check on need update and return pathFile
        """
        # if file in PROTECT_MASK or not in PROTECT
        chrootPath = self.objVar.Get('cl_chroot_path')
        if not filter(pathFile.startswith,
            map(lambda x:pathJoin(chrootPath,x),
            self.objVar.Get('cl_config_protect'))) or \
            filter(pathFile.startswith,
            map(lambda x:pathJoin(chrootPath,x),
            self.objVar.Get('cl_config_protect_mask'))):
            return pathFile
        # if file was already modified by templates
        if pathFile in self.changedFiles.data.keys():
            return pathFile
        # if using already created ._cfg file
        if self.configMode != T_ORIGIN:
            return pathFile
        # not current package file
        pkg = self.functObj.currentBelong
        if not pkg:
            if not self.allContents:
                fillContents(self.allContents,
                    self.objVar.Get('cl_config_protect'),
                    prefix=self.objVar.Get('cl_chroot_path'))
            origName = pathFile if chrootPath == '/' \
                                else pathFile[len(chrootPath):]
            if origName in self.allContents:
                pkg = self.allContents[origName]
            else:
                return pathFile
        pkg = isPkgInstalled(pkg,sortByVersion=True,prefix=chrootPath)
        if not pkg:
            return pathFile
        if checkContents("{CATEGORY}/{PF}".format(**pkg[-1]),
               pathFile,
               prefix=chrootPath,
               reservedFile='/var/lib/calculate/-CONTENTS-{PN}'.format(**pkg[-1]) \
                   if self.objVar.Get('cl_ebuild_phase') == 'postinst' \
                   else None):
                return pathFile
        real_filename = os.path.basename(pathFile)
        real_dirname = os.path.dirname(pathFile)
        self.configMode = T_NEWCFG
        return os.path.join(real_dirname,"._cfg0000_%s"%real_filename)

    def getApplyHeadTemplate(self, nameFileTemplate, nameFileConfig,
                               templateFileType, optFile):
        """Применяет заголовок к шаблону (права, владелец, и.т. д)"""
        def function(text):
            """Функция обработки функций в заголовке"""
            return self.applyFuncTemplate(text,nameFileTemplate)

        def preReturn(pathProg):
            """Действия перед выходом из метода"""
            if pathProg:
                os.chdir(pathProg)

        def chownConfFile(nameFileConfig, uid, gid, nameFileTemplate,
                          checkExists=True):
            """Изменение владельца конфигурационного файла"""
            try:
                if checkExists and not os.path.exists(nameFileConfig):
                    # Создание файла
                    FD  = open(nameFileConfig, "w")
                    FD.close()
                os.chown(nameFileConfig, uid, gid)
            except Exception as e:
                if hasattr(e,'errno') and e.errno == 13 and \
                    "var/calculate/remote" in nameFileConfig:
                    return True
                import pwd, grp
                try:
                    userName = pwd.getpwuid(uid).pw_name
                except:
                    userName = str(uid)
                try:
                    groupName = grp.getgrgid(gid).gr_name
                except:
                    groupName = str(gid)
                owner = userName + ":" + groupName
                self.setError(_("Failed to apply template file %s")\
                                %nameFileTemplate)
                self.setError(_("error") + " " +\
                              "'chown %s %s'"%(owner, nameFileConfig))
                return False
            return True

        def chmodConfFile(nameFileConfig, mode, nameFileTemplate,
                          checkExists=True):
            """Изменения режима доступа конфигурационного файла"""
            try:
                if checkExists and not os.path.exists(pathOldFile):
                    # Создание файла
                    FD  = open(nameFileConfig, "w")
                    FD.close()
                os.chmod(nameFileConfig, mode)
            except Exception as e:
                if hasattr(e,'errno') and e.errno == 13 and \
                    "var/calculate/remote" in nameFileConfig:
                    return True
                self.setError(_("Failed to apply template file %s")\
                                %nameFileTemplate)
                self.setError(\
                    _("error") + " " +\
                    "'chmod %s %s'"%(str(oct(mode)), nameFileConfig))
                return False
            return True

        self.closeFiles()
        pathProg = ""
        self.executeType = None
        # Файлы в системе к которым были применены шаблоны
        applyFiles = [nameFileConfig]
        # В случае бинарного типа файла читаем шаблон
        if templateFileType == "bin":
            self.nameFileTemplate = os.path.abspath(nameFileTemplate)
            self.F_TEMPL = self.openTemplFile(self.nameFileTemplate)
            if not self.F_TEMPL:
                self.setError(_("Failed to open the template") + ": " +\
                                   self.nameFileTemplate)
                return False
            self.textTemplate = self.F_TEMPL.read()
            self.closeTemplFile()
        objHeadNew = fileHeader(nameFileTemplate, self.textTemplate, False,
                                templateFileType ,objVar=self.objVar,
                                function=function,templateObj=self)
        # файл шаблона не будет применен
        if not objHeadNew.headerTerm:
            if objHeadNew.getError():
                self.setError(_("Incorrect template") + ": " +\
                                nameFileTemplate)
            return ([], False)

        # add packeges for reconfigure
        if "merge" in objHeadNew.params:
            mergePkgs = objHeadNew.params['merge'].split(',')
            for wrongPkg in (x for x in mergePkgs \
                             if not self.functObj.checkCorrectPkgName(x)):
                self.printWARNING(
                    _("Wrong package '%s' for 'merge' in the template")%
                              wrongPkg + ": " + nameFileTemplate)
            for pkg in mergePkgs:
                if not pkg in self.objVar.Get('cl_merge_pkg_new') and \
                   not pkg in self.objVar.Get('cl_merge_pkg_pass') and \
                   not pkg in self.objVar.Get('cl_merge_pkg'):
                    self.objVar.Get('cl_merge_pkg_new').append(pkg)

        # Родительская директория
        path = optFile["path"]
        # Изменяем название родительской директории
        if "path" in  objHeadNew.params:
            path = objHeadNew.params['path']
            if path and path[0] == "~":
                # Получаем путь с заменой ~ на директорию пользователя
                path = os.path.join(self.homeDir,path.partition("/")[2],"")[:-1]
            elif not path or path and path[0] != "/":
                self.setError(_("Wrong value 'path' in the template") + ": " +\
                                  nameFileTemplate)
                return ([], False)
            else:
                path = pathJoin(self._baseDir, path)

        # Путь к оригинальному файлу - pathOldFile
        # Изменяем путь к оригинальному файлу
        if objHeadNew.params.has_key("name"):
            nameFile = objHeadNew.params['name']
            if "/" in nameFile or nameFile == ".." or nameFile == ".":
                self.setError(_("Wrong value 'name' in the template") + ": " +\
                              nameFileTemplate)
                return ([], False)
            # Новый путь к оригинальному файлу
            pathOldFile = pathJoin(path,nameFile)
        else:
            pathOldFile = pathJoin(path,os.path.split(nameFileConfig)[1])
        pathOrigFile = pathOldFile
        if self.objVar.Get('cl_protect_use_set') == 'on':
            pathOldFile = self.fixNameFileConfig(pathOldFile)
            pathOldFile = self.checkOnNewConfigName(pathOldFile)
        # буффер для использование в link=
        newBuffer = None
        applyFiles = [pathOldFile]
        # Фильтрация шаблонов по названию файла
        realPath = os.path.join("/",pathOldFile.partition(self._baseDir)[2])
        if realPath in self.filesFilter:
            return ([], False)
        typeAppendTemplate = objHeadNew.typeAppend
        
        # Параметр exec
        if "exec" in  objHeadNew.params or "run" in objHeadNew.params:
            if "exec" in objHeadNew.params:
                paramName = "exec"
            else:
                paramName = "run"
            self.executeType = paramName
            execPath = objHeadNew.params[paramName]
            if not os.access(execPath,os.X_OK):
                self.setError(_("Wrong value '%s' in the template")%paramName \
                    + ": " + nameFileTemplate)
                self.setError(_("Failed to execute %s") %execPath)
                return ([], False)
            if typeAppendTemplate == "join":
                self.setError(_("Wrong value 'append=join' in the template") +
                             ": " +\
                                  nameFileTemplate)
                return ([], False)

        # Очищаем оригинальный файл
        if typeAppendTemplate == "clear":
            try:
                open(pathOldFile, "w").truncate(0)
                newBuffer = ""
            except:
                self.setError(_("Template error") + ": " +\
                                  nameFileTemplate)
                self.setError(_("Failed to clear the file") + ": " +\
                               pathOldFile)
            return (applyFiles, False)
        # Удаляем оригинальный файл
        if typeAppendTemplate == "remove":
            if objHeadNew.params.has_key("force"):
                pathOldFile = pathOrigFile
            if os.path.islink(pathOldFile):
                # удаляем ссылку
                try:
                    os.unlink(pathOldFile)
                    return (applyFiles, False)
                except:
                    self.setError(_("Template error") + ": " +\
                                  nameFileTemplate)
                    self.setError(_("Failed to delete the link") + ": " +\
                               pathOldFile)
                    return ([], False)
            if os.path.isfile(pathOldFile) and self.configMode == T_ORIGIN:
                # удаляем файл
                try:
                    os.remove(pathOldFile)
                    return (applyFiles, False)
                except:
                    self.setError(_("Template error") + ": " +\
                                  nameFileTemplate)
                    self.setError(_("Failed to delete the file") + ": " +\
                               pathOldFile)
                    return ([], False)
            return ([], False)
        # Пропускаем обработку шаблона
        elif typeAppendTemplate == "skip":
             return ([], False)

        # Создаем директорию для файла если ее нет
        if not os.path.exists(path):
            if not self.createDir(path):
                return ([], False)
        # В случае force
        if objHeadNew.params.has_key("force"):
            if os.path.islink(pathOldFile):
                # удаляем ссылку
                try:
                    newBuffer = ""
                    os.unlink(pathOldFile)
                except:
                    self.setError(_("Template error") + ": " +\
                                  nameFileTemplate)
                    self.setError(_("Failed to delete the link") + ": " +\
                               pathOldFile)
                    return ([], False)
            if os.path.isfile(pathOldFile):
                # удаляем файл
                try:
                    newBuffer = ""
                    os.remove(pathOldFile)
                except:
                    self.setError(_("Template error") + ": " +\
                                  nameFileTemplate)
                    self.setError(_("Failed to delete the file") + ": " +\
                                    pathOldFile)
                    return ([], False)

        flagSymlink = False
        flagForce = False
        # Если есть параметр mirror
        if objHeadNew.params.has_key("mirror"):
            if objHeadNew.params.has_key("link"):
                templateFile = objHeadNew.params['link']
                templateFile = pathJoin(self._baseDir, templateFile)
                if not os.path.exists(templateFile):
                    if os.path.exists(pathOldFile):
                        try:
                            newBuffer = ""
                            os.remove(pathOldFile)
                        except:
                            self.setError(_("Template error") + ": " +\
                                          nameFileTemplate)
                            self.setError(_("Failed to delete the file") + ": " +\
                                          pathOldFile)
                    return ([], False)
            elif not os.path.exists(pathOldFile):
                return ([], False)
        # Если есть указатель на файл шаблона (link)
        if objHeadNew.params.has_key("link") and\
            not objHeadNew.params.has_key("symbolic"):
            templateFile = objHeadNew.params['link']
            templateFile = pathJoin(self._baseDir, templateFile)
            foundTemplateFile = os.path.exists(templateFile)
            if foundTemplateFile:
                try:
                    F_CONF = self.openTemplFile(templateFile)
                    buff = F_CONF.read()
                    F_CONF.close()
                    fMode, fUid, fGid = getModeFile(templateFile)
                except:
                    self.setError(_("Template error") + ": " +\
                                  nameFileTemplate)
                    self.setError(_("Failed to open the file") + ": " +\
                                          templateFile)
                    return ([], False)
            if os.path.exists(pathOldFile):
                try:
                    newBuffer = ""
                    os.remove(pathOldFile)
                except:
                    self.setError(_("Template error") + ": " +\
                                    nameFileTemplate)
                    self.setError(_("Failed to delete the file") + ": " +\
                                    pathOldFile)
                    return ([], False)
            if foundTemplateFile:
                try:
                    FD  = open(pathOldFile, "w+")
                    newBuffer = buff
                    FD.write(buff)
                    FD.close()
                except:
                    self.setError(_("Template error") + ": " +\
                                  nameFileTemplate)
                    self.setError(_("Failed to create the file") + " '%s'"\
                                  %pathOldFile)
                    return ([], False)
                oMode = getModeFile(pathOldFile, mode="mode")
                # Если права не совпадают, меняем права
                if fMode != oMode:
                    if not chmodConfFile(pathOldFile, fMode, nameFileTemplate,
                                         checkExists=False):
                        return ([], False)

        # Если символическая ссылка
        if objHeadNew.params.has_key("symbolic"):
            prevOldFile = pathOldFile
            pathOldFile = objHeadNew.params['link']
            flagSymlink = True
            if not pathOldFile:
                raise TemplatesError(
                    _("Missed source link in template '%s'")
                        %str(nameFileTemplate))
            if not "/" == pathOldFile[0]:
                pathLink = os.path.split(os.path.abspath(prevOldFile))[0]
                pathProg = os.getcwd()
                try:
                    os.chdir(pathLink)
                except:
                    self.setError(_("Template error") + ": " +\
                                    nameFileTemplate)
                    self.setError(
                        _("Failed to change the current directory to")+\
                                    " " + pathLink)
                    return ([], False)

        # chmod - изменяем права
        if objHeadNew.params.has_key("chmod"):
            mode = self.__octToInt(objHeadNew.params['chmod'])
            if mode:
                if not chmodConfFile(pathOldFile, mode, nameFileTemplate):
                    preReturn(pathProg)
                    return ([], False)
            else:
                self.setError(_("Wrong value 'chmod' in the template") + ": " +\
                               nameFileTemplate)
                preReturn(pathProg)
                return ([], False)
        # chown - изменяем владельца и группу
        if objHeadNew.params.has_key("chown"):
            owner = objHeadNew.params['chown']
            if owner:
                if  ":" in owner:
                    strUid, strGid = owner.split(":")
                    if strUid.isdigit():
                        uid = int(strUid)
                    else:
                        uid = self.getUidFromPasswd(strUid)
                        import pwd
                        try:
                            if uid is None:
                                uid = pwd.getpwnam(strUid).pw_uid
                        except:
                            self.setError(_("No such user on the system: ") +
                                          strUid)
                            self.setError(
                                _("Wrong value 'chown' in the template") +
                                          ": "+ nameFileTemplate)
                            preReturn(pathProg)
                            return ([], False)
                    if strGid.isdigit():
                        gid = int(strGid)
                    else:
                        gid = self.getGidFromGroup(strGid)
                        try:
                            if gid is None:
                                import grp
                                gid = grp.getgrnam(strGid).gr_gid
                        except:
                            self.setError(_("Group not found on the system: ") +
                                          strGid)
                            self.setError(
                                _("Wrong value 'chown' in the template") +
                                          ": "+ nameFileTemplate)
                            preReturn(pathProg)
                            return ([], False)
                    # Изменяем владельца файла
                    if not chownConfFile(pathOldFile,uid,gid,nameFileTemplate):
                        preReturn(pathProg)
                        return ([], False)
                else:
                    self.setError(_("Wrong value 'chown' in the template") +
                                  ": " + nameFileTemplate)
                    preReturn(pathProg)
                    return ([], False)
            else:
                self.setError(_("Wrong value 'chown' in the template") 
                    + ": " + nameFileTemplate)
                preReturn(pathProg)
                return ([], False)
        if not flagSymlink:
            self.openFiles(nameFileTemplate, pathOldFile,objHeadNew.fileType,
                            newBuffer)
            if self.getError():
                return ([], False)
        if not objHeadNew.params.has_key("chown"):
            # Устанавливаем владельцем конфигурационного файла,
            # пользователя по умолчанию (переменная шаблона ur_login)
            if os.path.exists(pathOldFile):
                tUid, tGid = getModeFile(pathOldFile, mode="owner")
                if (self.uid, self.gid) != (tUid, tGid):
                    # Изменяем владельца файла
                    if not chownConfFile(pathOldFile, self.uid, self.gid,
                                        nameFileTemplate, checkExists=False):
                        preReturn(pathProg)
                        return ([], False)
        if flagSymlink:
            if os.path.exists(prevOldFile) or os.path.islink(prevOldFile):
                try:
                    if os.path.islink(prevOldFile):
                        # если ссылка то удаляем её
                        os.unlink(prevOldFile)
                    else:
                        # иначе удаляем файл
                        os.remove(prevOldFile)
                except:
                    self.setError(_("Template error") + ": " +\
                                    nameFileTemplate)
                    self.setError(_("Failed to delete the file") + ": " +\
                                    prevOldFile)
                    preReturn(pathProg)
                    return ([], False)
            if not "/" == pathOldFile[0]:
                applyFiles = [prevOldFile]#,os.path.join(pathLink,pathOldFile)]
            else:
                applyFiles = [prevOldFile]#,pathOldFile]
            try:
                os.symlink(pathOldFile, prevOldFile)
            except:
                self.setError(_("Template error") + ": " +\
                                    nameFileTemplate)
                self.setError(_("Failed to create a symbolic link") + " :" +\
                                    "%s -> %s"%(prevOldFile, pathOldFile))
                preReturn(pathProg)
                return ([], False)
            if not objHeadNew.body.strip():
                preReturn(pathProg)
                if "protected" in objHeadNew.params:
                    self.protectedFiles += applyFiles
                return (applyFiles, False)
        else:
            applyFiles = [pathOldFile]
        if pathProg:
            os.chdir(pathProg)
        # Если файлы заменяются не нужно их обрабатывать дальше
        if typeAppendTemplate == "replace" and\
            not objHeadNew.params.has_key("symbolic") and\
            objHeadNew.params.has_key("link"):
                preReturn(pathProg)
                return (applyFiles, False)
        if not pathOldFile in self.dictProcessedTemplates:
            self.dictProcessedTemplates[pathOldFile] = []
        self.dictProcessedTemplates[pathOldFile].append(nameFileTemplate)
        preReturn(pathProg)
        if ( "autoupdate" in optFile or "autoupdate" in objHeadNew.params ) \
                and not self.objVar.Get('cl_merge_pkg_pass'):
            reCfg = re.compile(r"/._cfg\d{4}_",re.S)
            self.autoUpdateFiles += map(lambda x:reCfg.sub('/',x),applyFiles)
        if "protected" in objHeadNew.params:
            self.protectedFiles += applyFiles
        return (applyFiles, objHeadNew)

    def createNewClass(self, name, bases, attrs={}):
        """Создает объект нового класса

        createNewClass(self, name, bases, attrs)
        name - имя класса - str,
        bases - cписок наследуемых классов - (tuple),
        attrs - аттрибуты класса - {dict}
        """
        class newMethod:
            #Объединяем конфигурации
            def join(self, newObj):
                if newObj.__class__.__name__ == self.__class__.__name__:
                    self.docObj.joinDoc(newObj.doc)
                    # Пост обработка
                    if 'postXML' in dir(self):
                        self.postXML()
        attrsNew = {}
        attrsNew["configName"] = name
        if attrs:
            for key in attrs.keys():
               attrsNew[key] = attrs[key]
        newCl = type(name, bases + (newMethod, object,), attrsNew)
        return newCl

    def fileIsUtf(self, fileName):
        """Проверяет файл на кодировку UTF-8"""
        if os.path.isfile(fileName):
            FD = open(os.path.abspath(fileName),'r')
            newTemplate = FD.read(1)+FD.read()
            FD.close()
            try:
                newTemplate.decode("UTF-8")
            except:
                return False
            return True
        return False

    def joinTemplate(self, nameFileTemplate, nameFileConfig, optFile={}):
        """Объединения шаблона и конф. файла

        join(nameFileTemplate, nameFileConfig, ListOptTitle)
        Объединение шаблона nameFileTemplate и конф. файла nameFileConfig,
        ListOptTitle - список строк которые добавятся в заголовок
        optFile = опции для шаблона
        """
        # Выполняем условия для блока текста а так-же заменяем переменные
        self.nameFileTemplate = os.path.abspath(nameFileTemplate)
        self.F_TEMPL = self.openTemplFile(self.nameFileTemplate)
        self.textTemplate = self.F_TEMPL.read()
        self.configMode = T_ORIGIN
        self.closeTemplFile()
        # Флаг копирования шаблона в конфигурационный файл
        flagCopyTemplate = True
        # Тип шаблона бинарный или текстовый
        templateFileType = self.getTemplateType()
        headerLine = self.getHeaderText(self.textTemplate)
        if headerLine:
            moduleParam = filter(lambda x:x.startswith('env='),
                          headerLine.split())
            if moduleParam:
                self.objVar.defaultModule = moduleParam[0].partition('=')[2]
                try:
                    varModule = importlib.import_module(
                        "calculate.%s.variables"%self.objVar.defaultModule)
                except (ImportError, AttributeError),e:
                    return []

        if templateFileType != "bin":
            # Заменяем переменные на их значения
            self.textTemplate = self.applyVarsTemplate(self.textTemplate,
                                                    nameFileTemplate)
            flagCopyTemplate = False
        if not optFile:
            optFile = {"path":os.path.split(nameFileConfig)[0]}
        filesApply, objHeadNew = self.getApplyHeadTemplate(nameFileTemplate,
                                                             nameFileConfig,
                                                             templateFileType,
                                                             optFile)
        if not objHeadNew:
            return filesApply
        if filesApply and not filter(lambda x:"calculate/ini.env" in x,
                              filesApply):
             self.templateModify()
        if templateFileType != "bin":
            # Вычисляем условные блоки
            objHeadNew.body = self.applyTermsTemplate(objHeadNew.body,
                                                        nameFileTemplate)
            # Вычисляем функции
            objHeadNew.body = self.applyFuncTemplate(objHeadNew.body,
                                                       nameFileTemplate)
        # Настоящее имя конфигурационного файла
        nameFileConfig = filesApply[0]
        # Флаг - кодировка с бинарными примесями у файла шаблона включаем при
        # условии текстового файла и кодировки отличной от UTF-8
        flagNotUtf8New = False
         # Флаг - кодировка с бинарными примесями у оригинального файла
        flagNotUtf8Old = False 
        if not flagCopyTemplate:
            # проверяем кодировку шаблона
            if not self.fileIsUtf(nameFileTemplate):
                flagNotUtf8New = True
        if not (objHeadNew.params.has_key("link") and\
            objHeadNew.params.has_key("symbolic")):
            # проверяем кодировку оригинального файла
            if not self.fileIsUtf(nameFileConfig):
                flagNotUtf8Old = True
        self.textTemplate = objHeadNew.body
        # Список примененных шаблонов
        ListOptTitle = []
        if nameFileConfig in self.dictProcessedTemplates:
            ListOptTitle = self.dictProcessedTemplates[nameFileConfig]
        # Титл конфигурационного файла
        title = ""
        if ListOptTitle:
            title = self.getTitle(objHeadNew.comment, ListOptTitle,
                                  configPath=nameFileConfig)
            title = title.encode("UTF-8")

        objHeadOld = False
        if objHeadNew.comment:
            objHeadOld = fileHeader(nameFileConfig, self.textConfig,
                                    objHeadNew.comment)
        elif objHeadNew.fileType and\
            objHeadNew.typeAppend in ("before", "after"):
            configFileType = self.getFileType(nameFileConfig)
            objHeadOld = fileHeader(nameFileConfig, self.textConfig,
                                    fileType=configFileType)
        # Строка вызова скрипта (#!/bin/bash ...)
        execStr = ""
        if objHeadNew.execStr:
            execStr = objHeadNew.execStr
        elif objHeadOld and objHeadOld.execStr:
            execStr = objHeadOld.execStr

        if objHeadNew.fileType:
            formatTemplate = objHeadNew.fileType
            typeAppendTemplate = objHeadNew.typeAppend
            if formatTemplate in ("patch","diff"):
                if typeAppendTemplate != "patch":
                    self.setError(\
                        _("Wrong option append=%(type)s in template %(file)s")\
                          %{"type":typeAppendTemplate,"file":nameFileTemplate})
                    return False
                # создаем объект формата шаблона
                objTempl = self.getFormatObj(formatTemplate, self.textTemplate)
                if not objTempl:
                    self.setError(\
                        _("Incorrect header parameter format=%s "
                          "in the template")\
                          %formatTemplate + " " + nameFileTemplate)
                    return False
                if objHeadOld and objHeadOld.body:
                    self.textConfig = objHeadOld.body
                # обработка конфигурационного файла
                self.textTemplate = objTempl.processingFile(self.textConfig,
                                    self.objVar.Get('cl_root_path'))
                if objTempl.getError():
                    raise TemplatesError(_("Failed to use patch ") + \
                                    nameFileTemplate)
                elif formatTemplate == 'diff':
                    self.printSUCCESS(_("Appling patch")+ " " + \
                                os.path.basename(nameFileTemplate))
                if execStr:
                    self.textConfig = execStr + title + self.textTemplate
                else:
                    self.textConfig = title + self.textTemplate
                if formatTemplate in ("diff",):
                    return objTempl.patchFiles
                else:
                    self.saveConfFile()
                if  'run' in objHeadNew.params:
                    if not self.executeTemplate(self.textConfig,
                                                objHeadNew.params['run']):
                        self.setError(_("Wrong template") + ": " +\
                                      nameFileTemplate)
                        self.setError(_("Failed to execute") + ": " +\
                                      self.nameFileConfig)
                        return False
                    return False
                return filesApply if not 'exec' in objHeadNew.params else False
            # Создаем объект в случае параметра format в заголовке
            if (typeAppendTemplate == "replace" or\
                typeAppendTemplate == "before" or\
                typeAppendTemplate == "after") and\
                not (formatTemplate == "bin" or\
                formatTemplate == "raw"):
                # Преобразовываем бинарные файлы
                if flagNotUtf8New:
                    objTxtCoder = utfBin()
                    self.textTemplate = objTxtCoder.encode(self.textTemplate)
                # создаем объект формата шаблона
                objTemplNew = self.getFormatObj(formatTemplate,
                                                self.textTemplate)
                if not objTemplNew:
                    self.setError(\
                        _("Incorrect header parameter format=%s "
                          "in the template")\
                          %formatTemplate + " " + nameFileTemplate)
                    return False
                if "xml_" in formatTemplate:
                    if objTemplNew.getError():
                        self.setError(_("Wrong template") + ": " +\
                                      nameFileTemplate)
                        return False
                    # Имя файла внутри xml xfce конфигурационных файлов
                    nameRootNode=nameFileConfig.rpartition("/")[2].split(".")[0]
                    objTemplNew.setNameBodyNode(nameRootNode)
                # Объект Документ
                docObj = objTemplNew.docObj
                # Удаление комментариев из документа
                docObj.removeComment(docObj.getNodeBody())
                # Добавление необходимых переводов строк
                docObj.insertBRtoBody(docObj.getNodeBody())
                # Добавление необходимых разделителей между областями
                docObj.insertBeforeSepAreas(docObj.getNodeBody())
                # Пост обработка
                if 'postXML' in dir(objTemplNew):
                    objTemplNew.postXML()
                # Получение текстового файла из XML документа
                self.textTemplate = objTemplNew.getConfig().encode("UTF-8")
                # Если не UTF-8 производим преобразование
                if flagNotUtf8New:
                    self.textTemplate = objTxtCoder.decode(self.textTemplate)
                # Титл для объединения
                if ListOptTitle:
                    title = self.getTitle(objTemplNew._comment,
                                          ListOptTitle,
                                          configPath=nameFileConfig)
                    title = title.encode("UTF-8")
            # Замена
            if typeAppendTemplate == "replace":
                if "xml_" in formatTemplate:
                    data = self.textTemplate.split("\n")
                    data.insert(1,title)
                    self.textConfig = "\n".join(data)
                else:
                    if objHeadNew.execStr:
                        self.textConfig = objHeadNew.execStr+title+\
                                          self.textTemplate
                    else:
                        self.textConfig = title + self.textTemplate
                
                self.saveConfFile()
                if  'run' in objHeadNew.params:
                    if not self.executeTemplate(self.textConfig,
                                                objHeadNew.params['run']):
                        self.setError(_("Wrong template") + ": " +\
                                      nameFileTemplate)
                        self.setError(_("Failed to execute") + ": " +\
                                      self.nameFileConfig)
                        return False
                    return False
                return filesApply if not 'exec' in objHeadNew.params else False
            # Вверху
            elif typeAppendTemplate == "before":
                if "xml_" in formatTemplate:
                    self.setError(\
                        _("Wrong option append=before in template %s")\
                        %nameFileTemplate)
                    return False
                if objHeadOld and objHeadOld.body:
                    self.textConfig = objHeadOld.body
                if self.textTemplate and self.textTemplate[-1] == "\n":
                    tmpTemplate = self.textTemplate + self.textConfig
                else:
                    tmpTemplate = self.textTemplate + "\n" + self.textConfig
                if execStr:
                    self.textConfig = execStr + title + tmpTemplate
                else:
                    self.textConfig = title + tmpTemplate

                self.saveConfFile()
                if  'run' in objHeadNew.params:
                    if not self.executeTemplate(self.textConfig,
                                                objHeadNew.params['run']):
                        self.setError(_("Wrong template") + ": " +\
                                      nameFileTemplate)
                        self.setError(_("Failed to execute") + ": " +\
                                      self.nameFileConfig)
                        return False
                    return False
                return filesApply if not 'exec' in objHeadNew.params else False
            # Внизу
            elif typeAppendTemplate == "after":
                if "xml_" in formatTemplate:
                    self.setError(\
                        _("Wrong option append=after in template %s")\
                        %nameFileTemplate)
                    return False
                if objHeadOld and objHeadOld.body:
                    self.textConfig = objHeadOld.body
                if self.textTemplate[-1] == "\n":
                    tmpTemplate = self.textConfig + self.textTemplate
                else:
                    tmpTemplate = self.textConfig + "\n" + self.textTemplate
                if execStr:
                    self.textConfig = execStr + title + tmpTemplate
                else:
                    self.textConfig = title + tmpTemplate
                self.saveConfFile()
                if  'run' in objHeadNew.params:
                    if not self.executeTemplate(self.textConfig,
                                                objHeadNew.params['run']):
                        self.setError(_("Wrong template") + ": " +\
                                      nameFileTemplate)
                        self.setError(_("Failed to execute") + ": " +\
                                      self.nameFileConfig)
                        return False
                    return False
                return filesApply if not 'exec' in objHeadNew.params else False
            # Объединение
            elif typeAppendTemplate == "join":
                if flagNotUtf8New:
                    objTxtCoder = utfBin()
                    self.textTemplate = objTxtCoder.encode(self.textTemplate)
                if formatTemplate =="raw":
                    self.setError(\
                        _("Incorrect header parameter append=%s "
                          "in the template")\
                          %typeAppendTemplate + " " + nameFileTemplate)
                    return False
                # создаем объект формата шаблона
                objTemplNew = self.getFormatObj(formatTemplate,
                                                self.textTemplate)
                if not objTemplNew:
                    self.setError(\
                        _("Incorrect header parameter format=%s in "
                          "the template")\
                          %formatTemplate + " " + nameFileTemplate)
                    return False
                if "xml_" in formatTemplate:
                    if objTemplNew.getError():
                        self.setError(_("Wrong template") + ": " +\
                                        nameFileTemplate)
                        return False
                    nameRootNode=nameFileConfig.rpartition("/")[2].split(".")[0]
                    objTemplNew.setNameBodyNode(nameRootNode)
                # Титл для объединения
                if ListOptTitle:
                    title = self.getTitle(objTemplNew._comment,
                                          ListOptTitle,
                                          configPath=nameFileConfig)
                    title = title.encode("UTF-8")

                # В случае пустого конфигурационного файла
                reNoClean = re.compile("[^\s]",re.M)
                if not self.textConfig or\
                    not reNoClean.search(self.textConfig):
                    self.textConfig = ""

                objHeadOld = fileHeader(nameFileConfig, self.textConfig,
                                        objTemplNew._comment)
                if objHeadOld.body:
                    self.textConfig = objHeadOld.body
                else:
                    self.textConfig = ""
                if flagNotUtf8Old:
                    objTxtCoder = utfBin()
                    self.textConfig = objTxtCoder.encode(self.textConfig)
                # создаем объект формата шаблона для конфигурационного файла
                objTemplOld = self.getFormatObj(formatTemplate,
                                                self.textConfig)
                if not objTemplOld:
                    self.setError(_("Error in template %s") %nameFileConfig)
                    return False
                if "xml_" in formatTemplate:
                    if objTemplOld.getError():
                        self.setError(_("Wrong template") + ": " +\
                                        nameFileConfig)
                        return False
                    nameRootNode=nameFileConfig.rpartition("/")[2].split(".")[0]
                    objTemplOld.setNameBodyNode(nameRootNode)

                objTemplOld.join(objTemplNew)
                if "xml_" in formatTemplate:
                    if objTemplOld.getError():
                        self.setError(_("Wrong template") + ": " +\
                                        nameFileTemplate)
                        return False
                    data = objTemplOld.getConfig().encode("UTF-8").split("\n")
                    data.insert(1,title)
                    self.textConfig = "\n".join(data)
                else:
                    if execStr:
                        self.textConfig = execStr + title +\
                            objTemplOld.getConfig().encode("UTF-8")
                    else:
                        self.textConfig = title +\
                                        objTemplOld.getConfig().encode("UTF-8")
                # Декодируем если кодировка не UTF-8
                if flagNotUtf8New or flagNotUtf8Old:
                    self.textTemplate = objTxtCoder.decode(self.textTemplate)
                    self.textConfig = objTxtCoder.decode(self.textConfig)
                self.saveConfFile()
                if  'run' in objHeadNew.params:
                    if not self.executeTemplate(self.textConfig,
                                                objHeadNew.params['run']):
                        self.setError(_("Wrong template") + ": " +\
                                      nameFileTemplate)
                        self.setError(_("Failed to execute") + ": " +\
                                      self.nameFileConfig)
                        return False
                    return False
                return filesApply if not 'exec' in objHeadNew.params else False
            else:
                self.setError(_("Wrong template option (type append)") + ": " +\
                               typeAppendTemplate)
                return False
        else:
            self.setError(_("Template type not found: ") + nameFileTemplate)
            return False
        return filesApply

class scanDirectoryClt:
    """Класс для cканирования директорий с файлами .clt"""

    # Расширение файла шаблона
    extFileTemplate = ".clt"
    lenExtFileTemplate = len(extFileTemplate)
    filterApplyTemplates = []
    reHeader = re.compile(r"\s*#\s*calculate\s*", re.I)

    def __init__(self,objVar=None):
        if objVar:
            self.objVar = objVar

    def processingFile(self, path, prefix):
        """Обработка в случае файла"""
        return True

    def hasBelong(self,filename):
        """
        Change belong function
        """
        f = open(filename,'r')
        s = f.readline()
        if self.reHeader.search(s):
            while s:
                if "belong(" in s or "merge(" in s:
                    return True
                if not s.strip().endswith('\\'):
                    break
                s = f.readline()
        return False


    def scanningTemplates(self, scanDir, prefix=None, flagDir=False,
        objVar=None):
        """Сканирование и обработка шаблонов в директории scanDir"""
        ret = True
        if not objVar:
            objVar = self.objVar
        if not prefix:
            prefix = os.path.realpath(scanDir)
        if flagDir or stat.S_ISDIR(os.lstat(scanDir)[stat.ST_MODE]):
            for fileOrDir in sorted(os.listdir(scanDir)):
                try:
                    absPath = os.path.join(scanDir,fileOrDir)
                    stInfo = os.lstat(absPath)
                    statInfo = stInfo[stat.ST_MODE]
                    if fileOrDir.endswith(self.extFileTemplate) and\
                        stat.S_ISREG(statInfo):
                        if not self.filterApplyTemplates and \
                            self.objVar.Get('cl_merge_set') == 'off' or \
                            self.filterApplyTemplates and \
                            absPath[:-self.lenExtFileTemplate] in\
                            self.filterApplyTemplates.keys() or self.hasBelong(absPath):
                            prevDefault = self.objVar.defaultModule
                            if not self.processingFile(absPath, prefix):
                                return False
                            self.objVar.defaultModule = prevDefault
                    elif stat.S_ISDIR(statInfo):
                        if not self.scanningTemplates(absPath, prefix, True):
                            return False
                except TemplatesInterrupt as e:
                    if e.isInterrupt():
                        self.stop = e.status()
                        return False
                    else:
                        self.clearErrors()
                        self.printWARNING(str(e))
        return True

class templateClt(scanDirectoryClt, Template):
    """Класс для обработки шаблонов c расширением .clt"""

    def __init__(self, objVar,**kwargs):
        self.checkNumberTemplate = True
        Template.__init__(self, objVar, cltObj=False,**kwargs)
        applyPackages = ["calculate-core"]
        self.flagApplyTemplates = False
        if self.objVar.Get("cl_name") in applyPackages:
            self.flagApplyTemplates = True
        # Базовая директория переноса шаблонов "/mnt/calculate" или "/" и.т.д
        self._chrootDir = os.path.normpath(self.objVar.Get("cl_chroot_path"))

    def applyTemplate(self, path):
        """Применение отдельного .clt шаблона"""
        if not self.flagApplyTemplates:
            return True
        return self.processingFile(path, "")

    def processingFile(self, path, prefix):
        """Обработка в случае шаблона файла"""
        self.numberProcessTempl += 1
        self.numberProcessTemplates(self.numberProcessTempl)
        # Пропуск шаблонов директорийscanningTemplates
        if self.templDirNameFile == os.path.split(path)[1]:
            return True
        # Проверка на переменные в названии файла
        if not self.getNeedTemplate(path):
            if self.getError():
                return False
            return True
        if self.getError():
            return False
        if prefix and prefix[-1] == "/":
            prefix = prefix[:-1]
        if prefix and path.startswith(prefix):
            nameFileConfig = path.partition(prefix)[2]
        else:
            nameFileConfig = path
        nameFileConfig = nameFileConfig[:-self.lenExtFileTemplate]
        origFileName = nameFileConfig
        nameFileConfig = pathJoin(self._baseDir, nameFileConfig)
        # файл в системе без условий
        nameFileConfig = "/".join(map(lambda x:x.split("?")[0],\
                        nameFileConfig.split("/")))
        # Записываем в переменную обрабатываемый файл
        self.objVar.Set("cl_pass_file",nameFileConfig)
        filesApl = self.joinTemplate(path, nameFileConfig)
        if self.getError():
            return False
        if filesApl:
            if self.functObj.currentBelong:
                self._addFile(filesApl)
            else:
                if origFileName in self.filterApplyTemplates:
                    for pkg in self.filterApplyTemplates[origFileName]:
                        self._addFile(filesApl,pkg=pkg)
                else:
                    if not self.allContents:
                        fillContents(self.allContents,
                            self.objVar.Get('cl_config_protect'),
                            prefix=self.objVar.Get('cl_chroot_path'))
                    for fn in filesApl:
                        fn_orig = PkgContents.reCfg.sub('/',fn)
                        if self.objVar.Get('cl_chroot_path') != '/':
                            fn_orig = \
                                fn_orig[len(self.objVar.Get('cl_chroot_path')):]
                        if fn_orig in self.allContents:
                            self._addFile([fn],pkg=self.allContents[fn_orig])
            # Настоящее имя конфигурационного файла
            nameFileConfig = filesApl[0]
            # Пишем время модификации *.env файлов
            if nameFileConfig.endswith(".env"):
                nameEnvFile = os.path.basename(nameFileConfig)
                self.functObj.timeConfigsIni[nameEnvFile] = float(time.time())
            self.filesApply += filesApl
            return nameFileConfig
        else:
            return True

    def countsNumberTemplates(self, dirsTemplates=[]):
        """Считаем количество шаблонов"""
        def createDictTemplates(path, prefix, dictTemplates):
            """Создает словарь {"директория":"кол-во шаблонов" ...}

            и считает общее количество шаблонов
            """
            # Количество шаблонов
            self.allTemplates += 1
            dirTemplate = os.path.split(path)[0]
            while(True):
                if dirTemplate in dictTemplates.keys():
                    dictTemplates[dirTemplate] += 1
                else:
                    dictTemplates[dirTemplate] = 1
                if dirTemplate == prefix:
                    break
                dirTemplate = os.path.split(dirTemplate)[0]
            return dictTemplates

        if not dirsTemplates:
            dirsTemplates = self.objVar.Get("cl_template_clt_path")
            dirsTemplates.sort()
        scanObj = scanDirectoryClt(objVar=self.objVar)
        scanObj.processingFile = lambda x,y: createDictTemplates(x, y,\
                                                             self.dictTemplates)
        # Считаем количество шаблонов
        for dirTemplate in dirsTemplates:
            scanObj.scanningTemplates(dirTemplate, "/")

    def applyTemplates(self,cltPath=None):
        """Применяет шаблоны к конфигурационным файлам"""
        if not self.flagApplyTemplates:
            return ([],[])
        if cltPath is None and \
            not self.objVar.defined("cl_template_clt_path"):
            self.setError(_("undefined variable: ") + "cl_template_clt_path")
            return False
        if cltPath is None:
            dirsTemplates = self.objVar.Get("cl_template_clt_path")
        else:
            dirsTemplates = cltPath
        dirsTemplates.sort()
        if self.checkNumberTemplate:
            # Созданные директории
            self.createdDirs = []
            # Примененные файлы
            self.filesApply = []
            # Номер применяемого шаблона
            self.numberProcessTempl = 0
            # Словарь директорий с количеством файлов шаблонов
            self.dictTemplates = {}
            # Количество шаблонов
            self.allTemplates = 0
            # Установка по умолчанию аттрибутов для функциии шаблонов ini()
            # Время доступа к конфигурационному файлу функции шаблона ini()
            self.functObj.timeIni = -1
            # Первоначальный словарь переменных для ini()
            self.functObj.prevDictIni = {}
            # Текущий словарь переменных для ini()
            self.functObj.currDictIni = {}
            # Словарь времен модификации env файлов для ini()
            self.functObj.timeConfigsIni = {}
            # Считаем количество шаблонов
            self.countsNumberTemplates(dirsTemplates=dirsTemplates)
            self.numberAllTemplates(self.allTemplates)
        # default module
        self.defaultModule = "main"
        # Обрабатываем шаблоны
        for dirTemplate in dirsTemplates:
            if self.scanningTemplates(dirTemplate, self._chrootDir) is False:
                break
        return (self.createdDirs, self.filesApply)

class iniParser(_error, templateFormat):
    """Класс для работы с ini файлами

    """
    def __init__(self, iniFile=None,text=None):
        # название ini файла
        self.iniFile = iniFile
        # права создаваемого ini-файла
        self.mode = 0640
        # Cоответствует ли формат файла нужному
        self.checkIni = None
        self.FD = None
        self.readOnly = False
        self.text = text

    def joinText(self, iniObj, xmlNewDoc):
        """Объединяет два документа"""
        newRootNode = xmlNewDoc.documentElement
        newBodyNode = xpath.Evaluate('child::body',newRootNode)[0]
        newImportBodyNode = iniObj.doc.importNode(newBodyNode, True)
        iniObj.docObj.joinBody(iniObj.docObj.body, newImportBodyNode)
        #iniObj.docObj.insertBRtoBody(iniObj.docObj.body)

    def setMode(self, mode):
        """установка прав создаваемого ini-файла"""
        self.mode = mode

    def lockfile(self,fd,fn,timeout=5):
        """
        Блокировка файла с таймаутом
        """
        for i in range(0,timeout):
            try:
                fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
                return True
            except IOError,e:
                if e.errno != errno.EAGAIN:
                    raise e
            time.sleep(1)
        else:
            raise TemplatesError(_("Timeout lock %s")%fn)

    def openIniFile(self):
        if not self.text is None:
            return self.text
        if not os.access(self.iniFile, os.R_OK):
            return ""
        self.FD = open(self.iniFile, "r")
        self.lockfile(self.FD.fileno(),self.iniFile)
        textIni = self.FD.read()
        return textIni

    def openRWIniFile(self):
        if not os.access(self.iniFile, os.R_OK):
            return ""
        try:
            self.FD = open(self.iniFile, "r+")
        except (IOError,OSError),e:
            self.FD = open(self.iniFile, "r")
            self.readOnly = True
        self.lockfile(self.FD.fileno(), self.iniFile)
        textIni = self.FD.read()
        return textIni

    def writeIniFile(self, txtConfig):
        if self.readOnly:
            self.setError(_("Failed to write to file")
                    + ": " + self.iniFile)
            return False
        if not os.path.exists(self.iniFile):
            try:
                # Создание файла
                self.FD  = open(self.iniFile, "w+")
                self.lockfile(self.FD.fileno(), self.iniFile)
                os.chmod(self.iniFile, self.mode)
            except:
                self.setError(_("Failed to create the file") +
                            ": " + self.iniFile)
                return False
        if not self.FD:
            self.setError(_("Failed to write to file")
                    + ": " + self.iniFile)
            return False
        self.FD.truncate(0)
        self.FD.seek(0)
        self.FD.write(txtConfig)
        self.FD.close()
        self.FD = None
        return True

    def setVar(self, strHeader, dictVar):
        """Заменяет или добавляет область и переменные

        Добавляет область в ini-файл или объединяет с существующей
        strHeader - имя области
        dictVar - словарь переменных
        """
        textIni = self.openRWIniFile()
        nameFomat = self.checkIniFile(textIni)
        if not nameFomat:
            return False
        if type(strHeader) in (tuple, list):
            # формат plasma
            classObj = self.getClassObj("plasma")
        else:
            if nameFomat == "plasma":
                self.setError(_("Trying to write a variable of 'samba' "
                                "format to file %s ('plasma' format)")\
                                %self.iniFile)
                return False
            # формат samba
            classObj = self.getClassObj("samba")
        # создаем объект
        # и записываем в него содержимое ini-файла
        objIni = classObj(textIni)
        # создаем текст из строки заголовка и
        # словаря переменных области
        txtConfig = objIni.createTxtConfig(strHeader, dictVar)
        # создаем объект и записываем в него текст
        objIniAdd = classObj(txtConfig)
        # объединяем объекты для получения результирующего текста
        objIni.join(objIniAdd)
        # получаем текст
        txtConfig = objIni.getConfig().encode("UTF-8")
        # записываем его в ini файл
        if not self.writeIniFile(txtConfig):
            return False
        return True

    def isEmptyFile(self, textIni):
        """Если файл пустой или содержит только комментарии - False

        иначе - True
        """
        if textIni.strip():
            if filter(lambda x: x.strip(),
                      map(lambda x:x[0].split(";")[0], 
                          map(lambda x: x.split("#"),
                              textIni.splitlines()))):
                return False
            else:
                return True
        else:
            return True

    def checkIniFile(self, textIni):
        """Проверка на правильность формата файла"""
        if self.checkIni is None:
            # Ошибка
            if textIni == False:
                self.checkIni = False
                return False
            self.checkIni = "samba"
            # В файле есть данные
            if not self.isEmptyFile(textIni):
                try:
                    objIni = self.getClassObj("plasma")(textIni)
                except:
                    self.setError(_("Incorrect file format") + ": " + \
                                    self.iniFile)
                    self.checkIni = False
                    return self.checkIni
                allAreas = objIni.docObj.getAllAreas()
                for xmlArea in allAreas:
                    parentNode = xmlArea.parentNode
                    if parentNode and parentNode.tagName == "area":
                        self.checkIni = "plasma"
                        break
                if self.checkIni == "samba":
                    objIni = self.getClassObj("samba")(textIni)
                    xmlBody = objIni.docObj.getNodeBody()
                    if not xmlBody.firstChild:
                        self.checkIni = False
        return self.checkIni

    def delVar(self, strHeader, nameVar):
        """Удаляем переменную из ini файла"""
        delNameVar = "!%s" %(nameVar)
        dictVar = {delNameVar:"del"}
        res = self.setVar(strHeader, dictVar)
        return res

    def delArea(self, strHeader):
        """Удаляем область из ini файла"""
        if type(strHeader) in (tuple, list):
            # Формат plasma
            delStrHeader = list(strHeader[:])
            delStrHeader[-1] = "!%s"%delStrHeader[-1]
        else:
            # Формат samba
            delStrHeader = "!%s" %(strHeader)
        dictVar = {"del":"del"}
        res = self.setVar(delStrHeader, dictVar)
        return res

    def getVar(self, strHeader, nameVar, checkExistVar=False):
        """Получаем значение переменной из ini-файла"""
        textIni = self.openIniFile()
        if self.FD:
            self.FD.close()
            self.FD = None
        nameFomat = self.checkIniFile(textIni)
        if not nameFomat:
            return False
        formatPlasma = False
        if type(strHeader) in (tuple, list):
            # формат plasma
            classObj = self.getClassObj("plasma")
            formatPlasma = True
        else:
            if nameFomat == "plasma":
                self.setError(_("Trying to fetch a variable of 'samba' "
                                "format from file %s ('plasma' format)")\
                                %self.iniFile)
                return False
            # формат samba
            classObj = self.getClassObj("samba")
        # создаем объект и записываем в него содержимое ini-файла
        objIni = classObj(textIni)
        # получаем ноду body
        xmlBody = objIni.docObj.getNodeBody()
        flagFound, xmlBody = self.getLastNode(objIni, xmlBody, strHeader,
                                              formatPlasma)
        if flagFound and xmlBody:
            if formatPlasma:
                strHeader = strHeader[-1]
            # находим в области переменную
            res = objIni.docObj.getAreaFieldValues(strHeader, nameVar, xmlBody)
        else:
            res = False
        if checkExistVar:
            if res is False:
                return False, ""
            else:
                return True, res
        else:
            if res is False:
                return ""
            else:
                return res


    def getLastNode(self, objIni, xmlBody, strHeader, formatPlasma):
        """Ищет область в XML в которой область с переменными"""
        flagFound = True
        if not strHeader:
            flagFound = False
            return flagFound,xmlBody
        lenStrHeader = len(strHeader)
        if formatPlasma and lenStrHeader>0:
            xmlAreas = [xmlBody]
            for i in xrange(lenStrHeader-1):
                flagFound = False
                for xmlArea in xmlAreas:
                    xmlAreas = objIni.docObj.getArea(strHeader[i], xmlArea)
                    if xmlAreas:
                        flagFound = True
                        break
            if xmlAreas:
                xmlBody = xmlAreas[0]
        return flagFound,xmlBody

    def getAreaVars(self, strHeader):
        """Получаем все переменнные области из ini-файла"""
        textIni = self.openIniFile()
        if self.FD:
            self.FD.close()
            self.FD = None
        nameFomat = self.checkIniFile(textIni)
        if not nameFomat:
            return False
        formatPlasma = False
        if type(strHeader) in (tuple, list):
            # формат plasma
            classObj = self.getClassObj("plasma")
            formatPlasma = True
        else:
            if nameFomat == "plasma":
                self.setError(_("Trying to fetch a variable of 'samba' "
                                "format from file %s ('plasma' format)")\
                                %self.iniFile)
                return False
            # формат samba
            classObj = self.getClassObj("samba")
        # создаем объект типа samba и записываем в него содержимое ini-файла
        objIni = classObj(textIni)
        # получаем ноду body
        xmlBody = objIni.docObj.getNodeBody()
        flagFound, xmlBody = self.getLastNode(objIni, xmlBody, strHeader,
                                              formatPlasma)
        if flagFound and xmlBody:
            if formatPlasma:
                strHeader = strHeader[-1]
            # если находим область то выдаем словарем все переменные иначе False
            res = objIni.docObj.getAreaFields(strHeader, xmlBody, allVars=True)
        else:
            res = False
        if res is False:
            return {}
        else:
            return res

    def getAllSectionNames(self):
        """Получаем все имена секций определенных в ini файле

        Если формат ini файла plasma то имя секции -
        имена нескольких секций через запятую
        """
        textIni = self.openIniFile()
        if self.FD:
            self.FD.close()
            self.FD = None
        nameFomat = self.checkIniFile(textIni)
        if not nameFomat:
            return False
        if nameFomat == "samba":
            # создаем объект типа samba и записываем в него содержимое ini-файла
            objIni = self.getClassObj("samba")(textIni)
        elif nameFomat == "plasma":
            # создаем объект типа plasma и записываем в него содержимое
            # ini-файла
            objIni = self.getClassObj("plasma")(textIni)
        else:
            return []
        xmlNodes = objIni.docObj.getAllAreas()
        # Имена секций ini файла
        namesSection = []
        if nameFomat == "plasma":
            for xmlNode in xmlNodes:
                nSect = objIni.docObj.getNameArea(xmlNode)
                if nSect:
                    namesSect = [nSect]
                    parentNode =  xmlNode.parentNode
                    while parentNode != objIni.docObj.body:
                        nameSect = objIni.docObj.getNameArea(parentNode)
                        if nameSect:
                            namesSect.append(nameSect)
                            parentNode =  parentNode.parentNode
                        else:
                            return []
                    namesSection.append(",".join(reversed(namesSect)))
        elif nameFomat == "samba":
            # получаем ноду body
            for xmlNode in xmlNodes:
                nSect = objIni.docObj.getNameArea(xmlNode)
                if nSect:
                    namesSection.append(nSect)
        return namesSection

class ProgressTemplate(Template):
    """
    Progress template for wsdl interface
    """
    def __init__(self, setValueCallback, *args, **kwargs):
        Template.__init__(self, *args, **kwargs)
        self.setValueCallback = setValueCallback
        self.value = None
        self.firstValue = True

    def numberAllTemplates(self, number):
        self.maximum = number
        return True

    def numberProcessTemplates(self,number):
        maximum = self.maximum or 1
        value = number * 100 / maximum;
        if value != self.value:
            self.setValueCallback(min(100,max(0,value)))
            self.value = value
        return True

    def templateModify(self):
        if self.firstValue and hasattr(self,"onFirstValue"):
            self.onFirstValue()
            self.firstValue = False
