0028110: Configuration - specify Unicode charset instead of multibyte in project...
[occt.git] / adm / genproj.tcl
index ebae8f2..57848aa 100644 (file)
@@ -108,9 +108,155 @@ proc osutils:findSrcSubPath {theSubPath} {
   return "$::THE_CASROOT/src/$theSubPath"
 }
 
+# Auxiliary tool comparing content of two files line-by-line.
+proc osutils:isEqualContent { theContent1 theContent2 } {
+  set aLen1 [llength $theContent1]
+  set aLen2 [llength $theContent2]
+  if { $aLen1 != $aLen2 } {
+    return false
+  }
+
+  for {set aLineIter 0} {$aLineIter < $aLen1} {incr aLineIter} {
+    set aLine1 [lindex $theContent1 $aLineIter]
+    set aLine2 [lindex $theContent2 $aLineIter]
+    if { $aLine1 != $aLine2 } {
+      return false
+    }
+  }
+  return true
+}
+
+# Auxiliary function for writing new file content only if it has been actually changed
+# (e.g. to preserve file timestamp on no change).
+# Useful for automatically (re)generated files.
+proc osutils:writeTextFile { theFile theContent {theEol lf} } {
+  if {[file exists "${theFile}"]} {
+    set aFileOld [open "${theFile}" rb]
+    fconfigure $aFileOld -translation crlf
+    set aLineListOld [split [read $aFileOld] "\n"]
+    close $aFileOld
+
+    # append empty line for proper comparison (which will be implicitly added by last puts below)
+    set aContent $theContent
+    lappend aContent ""
+    if { [osutils:isEqualContent $aLineListOld $aContent] == true } {
+      return false
+    }
+
+    file delete -force "${theFile}"
+  }
+
+  set anOutFile [open "$theFile" "w"]
+  fconfigure $anOutFile -translation $theEol
+  foreach aLine ${theContent} {
+    puts $anOutFile "${aLine}"
+  }
+  close $anOutFile
+  return true
+}
+
+# Function re-generating header files for specified text resource
+proc genResources { theResource } {
+  global path
+
+  set aResFileList {}
+  set aResourceAbsPath [file normalize "${path}/src/${theResource}"]
+  set aResourceDirectory ""
+  set isResDirectory false
+
+  if {[file isdirectory "${aResourceAbsPath}"]} {
+    if {[file exists "${aResourceAbsPath}/FILES"]} {
+      set aFilesFile [open "${aResourceAbsPath}/FILES" rb]
+      set aResFileList [split [read $aFilesFile] "\n"]
+      close $aFilesFile
+    }
+    set aResFileList [lsearch -inline -all -not -exact $aResFileList ""]
+    set aResourceDirectory "${theResource}"
+    set isResDirectory true
+  } else {
+    set aResourceName [file tail "${theResource}"]
+    lappend aResFileList "res:::${aResourceName}"
+    set aResourceDirectory [file dirname "${theResource}"]
+  }
+
+  foreach aResFileIter ${aResFileList} {
+    if {![regexp {^[^:]+:::(.+)} "${aResFileIter}" dump aResFileIter]} {
+         continue
+       }
+
+    set aResFileName [file tail "${aResFileIter}"]
+    regsub -all {\.} "${aResFileName}" {_} aResFileName
+    set aHeaderFileName "${aResourceDirectory}_${aResFileName}.pxx"
+    if { $isResDirectory == true && [lsearch $aResFileList $aHeaderFileName] == -1 } {
+      continue
+    }
+
+    # generate
+    set aContent {}
+    lappend aContent "// This file has been automatically generated from resource file src/${aResourceDirectory}/${aResFileIter}"
+       lappend aContent ""
+
+    # generate necessary structures
+    set aLineList {}
+    if {[file exists "${path}/src/${aResourceDirectory}/${aResFileIter}"]} {
+      set anInputFile [open "${path}/src/${aResourceDirectory}/${aResFileIter}" rb]
+      fconfigure $anInputFile -translation crlf
+      set aLineList [split [read $anInputFile] "\n"]
+      close $anInputFile
+    }
+
+    # drop empty trailing line
+    set anEndOfFile ""
+    if { [lindex $aLineList end] == "" } {
+      set aLineList [lreplace $aLineList end end]
+      set anEndOfFile "\\n"
+    }
+
+    lappend aContent "static const char ${aResourceDirectory}_${aResFileName}\[\] ="
+    set aNbLines  [llength $aLineList]
+    set aLastLine [expr $aNbLines - 1]
+    for {set aLineIter 0} {$aLineIter < $aNbLines} {incr aLineIter} {
+      set aLine [lindex $aLineList $aLineIter]
+      regsub -all {\"} "${aLine}" {\\"} aLine
+      if { $aLineIter == $aLastLine } {
+        lappend aContent "  \"${aLine}${anEndOfFile}\";"
+      } else {
+        lappend aContent "  \"${aLine}\\n\""
+      }
+    }
+
+    # Save generated content to header file
+    set aHeaderFilePath "${path}/src/${aResourceDirectory}/${aHeaderFileName}"
+    if { [osutils:writeTextFile $aHeaderFilePath $aContent] == true } {
+      puts "Generating header file from resource file: ${path}/src/${aResourceDirectory}/${aResFileIter}"
+    } else {
+         #puts "Header file from resource ${path}/src/${aResourceDirectory}/${aResFileIter} is up-to-date"
+    }
+  }
+}
+
+# Function re-generating header files for all text resources
+proc genAllResources {} {
+  global path
+  set aCasRoot [file normalize $path]
+  if {![file exists "$aCasRoot/adm/RESOURCES"]} {
+    puts "OCCT directory is not defined correctly: $aCasRoot"
+    return
+  }
+
+  set aFileResources [open "$aCasRoot/adm/RESOURCES" rb]
+  set anAdmResources [split [read $aFileResources] "\r\n"]
+  close $aFileResources
+  set anAdmResources [lsearch -inline -all -not -exact $anAdmResources ""]
+
+  foreach line $anAdmResources {
+    genResources "${line}"
+  }
+}
+
 # Wrapper-function to generate VS project files
 proc genproj {theIDE args} {
-  set aSupportedIDEs { "vc7" "vc8" "vc9" "vc10" "vc11" "vc12" "vc14" "cbp" "xcd" }
+  set aSupportedIDEs { "vc7" "vc8" "vc9" "vc10" "vc11" "vc12" "vc14" "vc14-uwp" "cbp" "xcd"}
   set aSupportedPlatforms { "wnt" "lin" "mac" "ios" "qnx" }
   set isHelpRequire false
 
@@ -159,14 +305,15 @@ proc genproj {theIDE args} {
     puts "usage: genproj IDE \[Platform\] \[-static\] \[-h|-help|--help\]
 
     IDE must be one of:
-      vc8   -  Visual Studio 2005
-      vc9   -  Visual Studio 2008
-      vc10  -  Visual Studio 2010
-      vc11  -  Visual Studio 2012
-      vc12  -  Visual Studio 2013
-      vc14  -  Visual Studio 2015
-      cbp   -  CodeBlocks
-      xcd   -  XCode
+      vc8      -  Visual Studio 2005
+      vc9      -  Visual Studio 2008
+      vc10     -  Visual Studio 2010
+      vc11     -  Visual Studio 2012
+      vc12     -  Visual Studio 2013
+      vc14     -  Visual Studio 2015
+      vc14-uwp -  Visual Studio 2015 for Universal Windows Platform project
+      cbp      -  CodeBlocks
+      xcd      -  XCode
 
     Platform (optional, only for CodeBlocks and XCode):
       wnt   -  Windows
@@ -193,6 +340,7 @@ proc genproj {theIDE args} {
   OS:MKPRC "$anAdmPath" "$theIDE" "$aLibType" "$aPlatform" "$aCmpl"
 
   genprojbat "$theIDE" $aPlatform
+  genAllResources
 }
 
 proc genprojbat {theIDE thePlatform} {
@@ -223,7 +371,7 @@ proc genprojbat {theIDE thePlatform} {
     file copy -force -- "$::THE_CASROOT/adm/templates/draw.${aTargetPlatformExt}" "$::path/draw.${aTargetPlatformExt}"
   }
 
-  if {[regexp {(vc)[0-9]*$} $theIDE] == 1} {
+  if {[regexp {(vc)[0-9]*$} $theIDE] == 1 || [regexp {(vc)[0-9]*-uwp$} $theIDE] == 1} {
     file copy -force -- "$::THE_CASROOT/adm/templates/msvc.bat" "$::path/msvc.bat"
   } else {
     switch -exact -- "$theIDE" {
@@ -266,7 +414,7 @@ proc OS:MKPRC { theOutDir theIDE theLibType thePlatform theCmpl } {
 
   # Create output directory
   set aWokStation "$thePlatform"
-  if { [lsearch -exact {vc7 vc8 vc9 vc10 vc11 vc12 vc14} $theIDE] != -1 } {
+  if { [lsearch -exact {vc7 vc8 vc9 vc10 vc11 vc12 vc14 vc14-uwp} $theIDE] != -1 } {
     set aWokStation "msvc"
   }
 
@@ -294,6 +442,14 @@ proc OS:MKPRC { theOutDir theIDE theLibType thePlatform theCmpl } {
     set aModules [osutils:juststation $goaway $aModules]
   }
 
+  # Draw module is turned off due to it is not supported on UWP
+  if { [regexp {(vc)[0-9]*-uwp$} $theIDE] == 1 } {
+    set aDrawIndex [lsearch -exact ${aModules} "Draw"]
+    if { ${aDrawIndex} != -1 } {
+      set aModules [lreplace ${aModules} ${aDrawIndex} ${aDrawIndex}]
+    }
+  }
+
   # generate one solution for all projects if complete OS or VAS is processed
   set anAllSolution "OCCT"
 
@@ -318,12 +474,13 @@ proc OS:MKPRC { theOutDir theIDE theLibType thePlatform theCmpl } {
     "vc7"   -
     "vc8"   -
     "vc9"   -
-    "vc10"   -
-    "vc11"   -
-    "vc12"   -
-    "vc14"  { OS:MKVC  $anOutDir $aModules $anAllSolution $theIDE }
-    "cbp"   { OS:MKCBP $anOutDir $aModules $anAllSolution $thePlatform $theCmpl }
-    "xcd"   {
+    "vc10"  -
+    "vc11"  -
+    "vc12"  -
+    "vc14"  -
+    "vc14-uwp" { OS:MKVC  $anOutDir $aModules $anAllSolution $theIDE }
+    "cbp"      { OS:MKCBP $anOutDir $aModules $anAllSolution $thePlatform $theCmpl }
+    "xcd"      {
       set ::THE_GUIDS_LIST($::aTKNullKey) "000000000000000000000000"
       OS:MKXCD $anOutDir $aModules $anAllSolution $theLibType $thePlatform
     }
@@ -639,16 +796,27 @@ proc osutils:collectinc {theModules theIncPath} {
       }
     }
   }
-  lsort -unique $anUsedToolKits
+  set anUsedToolKits [lsort -unique $anUsedToolKits]
 
   set anUnits {}
   foreach anUsedToolKit $anUsedToolKits {
     set anUnits [concat $anUnits [osutils:tk:units $anUsedToolKit]]
   }
-  lsort -unique $anUnits
+  set anUnits [lsort -unique $anUnits]
+
+  # define copying style
+  set aCopyType "copy"
+  if { [info exists ::env(SHORTCUT_HEADERS)] } {
+    if { [string equal -nocase $::env(SHORTCUT_HEADERS) "hard"]
+      || [string equal -nocase $::env(SHORTCUT_HEADERS) "hardlink"] } {
+      set aCopyType "hardlink"
+    } elseif { [string equal -nocase $::env(SHORTCUT_HEADERS) "true"]
+            || [string equal -nocase $::env(SHORTCUT_HEADERS) "shortcut"] } {
+      set aCopyType "shortcut"
+    }
+  }
 
-  if { [info exists ::env(SHORTCUT_HEADERS)] && 
-       $::env(SHORTCUT_HEADERS) == "true" } {
+  if { $aCopyType == "shortcut" } {
     # template preparation
     if { ![file exists $::THE_CASROOT/adm/templates/header.in] } {
       puts "template file does not exist: $::THE_CASROOT/adm/templates/header.in"
@@ -665,7 +833,7 @@ proc osutils:collectinc {theModules theIncPath} {
       foreach aHeaderFile [concat [glob -nocomplain -dir $aCasRoot/src/$anUnit "*.\[hgl\]xx"] $aHFiles] {
         set aHeaderFileName [file tail $aHeaderFile]
 
-        regsub -all -- {@OCCT_HEADER_FILE@} $aHeaderTmpl "$aFromBuildIncToSrcPath/$anUnit/$aHeaderFileName" aShortCutHeaderFileContent
+        regsub -all -- {@OCCT_HEADER_FILE_CONTENT@} $aHeaderTmpl "#include \"$aFromBuildIncToSrcPath/$anUnit/$aHeaderFileName\"" aShortCutHeaderFileContent
 
         if {[file exists "$theIncPath/$aHeaderFileName"] && [file readable "$theIncPath/$aHeaderFileName"]} {
           set fp [open "$theIncPath/$aHeaderFileName" r]
@@ -683,6 +851,7 @@ proc osutils:collectinc {theModules theIncPath} {
               continue
             }
           }
+          file delete -force "$theIncPath/$aHeaderFileName"
         }
 
         set aShortCutHeaderFile [open "$theIncPath/$aHeaderFileName" "w"]
@@ -690,7 +859,7 @@ proc osutils:collectinc {theModules theIncPath} {
         puts $aShortCutHeaderFile $aShortCutHeaderFileContent
         close $aShortCutHeaderFile
       }
-    }  
+    }
   } else {
     set nbcopied 0
     foreach anUnit $anUnits {
@@ -700,14 +869,20 @@ proc osutils:collectinc {theModules theIncPath} {
 
         # copy file only if target does not exist or is older than original
         set torig [file mtime $aHeaderFile]
-        if { ! [file isfile $anIncPath/$aHeaderFileName] } {
-          set tcopy 0
-        } else {
+        set tcopy 0
+        if { [file isfile $anIncPath/$aHeaderFileName] } {
           set tcopy [file mtime $anIncPath/$aHeaderFileName]
         }
         if { $tcopy < $torig } {
           incr nbcopied
-          file copy -force $aHeaderFile $anIncPath/$aHeaderFileName
+          if { $aCopyType == "hardlink" } {
+            if { $tcopy != 0 } {
+              file delete -force "$theIncPath/$aHeaderFileName"
+            }
+            file link -hard  $anIncPath/$aHeaderFileName $aHeaderFile
+          } else {
+            file copy -force $aHeaderFile $anIncPath/$aHeaderFileName
+          }
         } elseif { $tcopy != $torig } {
           puts "Warning: file $anIncPath/$aHeaderFileName is newer than $aHeaderFile, not changed!"
         }
@@ -742,7 +917,7 @@ proc osutils:vcsolution:header { vcversion } {
     append var \
       "Microsoft Visual Studio Solution File, Format Version 13.00\n" \
       "# Visual Studio 2013\n"
-  } elseif { "$vcversion" == "vc14" } {
+  } elseif { "$vcversion" == "vc14"  || "$vcversion" == "vc14-uwp"} {
     append var \
       "Microsoft Visual Studio Solution File, Format Version 12.00\n" \
       "# Visual Studio 14\n"
@@ -979,19 +1154,40 @@ proc osutils:vcproj:readtemplate {theVcVer isexec} {
   set aVerExt "v${aVerExt}0"
   set aCmpl32 ""
   set aCmpl64 ""
+  set aCharSet "Unicode"
   if { $isexec } {
     set anExt "${anExt}x"
     set what "$what executable"
   }
   if { "$theVcVer" == "vc10" } {
     # SSE2 is enabled by default in vc11+, but not in vc10 for 32-bit target
-    set aCmpl32 "\n      <EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>"
+    set aCmpl32 "<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>"
   }
   set aTmpl [osutils:readtemplate $anExt "MS VC++ project ($what)"]
-  regsub -all -- {__VCVER__}    $aTmpl $theVcVer aTmpl
-  regsub -all -- {__VCVEREXT__} $aTmpl $aVerExt  aTmpl
-  regsub -all -- {__VCMPL32__}  $aTmpl $aCmpl32  aTmpl
-  regsub -all -- {__VCMPL64__}  $aTmpl $aCmpl64  aTmpl
+
+  if { $theVcVer == "vc14-uwp" } {
+    set aVerExt "v140"
+    set UwpWinRt "<CompileAsWinRT>false</CompileAsWinRT>"
+    foreach bitness {32 64} {
+      set indent ""
+      if {"[set aCmpl${bitness}]" != ""} {
+        set indent "\n      "
+      }
+      set aCmpl${bitness} "[set aCmpl${bitness}]${indent}${UwpWinRt}"
+    }
+  }
+
+  foreach bitness {32 64} {
+    set format_template ""
+    if {"[set aCmpl${bitness}]" == ""} {
+      set format_template "\[\\r\\n\\s\]*"
+    }
+    regsub -all -- "${format_template}__VCMPL${bitness}__" $aTmpl "[set aCmpl${bitness}]" aTmpl
+  }
+
+  regsub -all -- {__VCVER__}     $aTmpl $theVcVer aTmpl
+  regsub -all -- {__VCVEREXT__}  $aTmpl $aVerExt  aTmpl
+  regsub -all -- {__VCCHARSET__} $aTmpl $aCharSet aTmpl
   return $aTmpl
 }
 
@@ -1058,7 +1254,7 @@ proc osutils:csfList { theOS theCsfLibsMap theCsfFrmsMap } {
   set aLibsMap(CSF_TclTkLibs) "tk8.6"
   if { "$::HAVE_FREEIMAGE" == "true" } {
     if { "$theOS" == "wnt" } {
-      set aLibsMap(CSF_FreeImagePlus) "FreeImage FreeImagePlus"
+      set aLibsMap(CSF_FreeImagePlus) "FreeImage"
     } else {
       set aLibsMap(CSF_FreeImagePlus) "freeimage"
     }
@@ -1088,7 +1284,9 @@ proc osutils:csfList { theOS theCsfLibsMap theCsfFrmsMap } {
     set aLibsMap(CSF_netapi32)     "netapi32"
     set aLibsMap(CSF_AviLibs)      "ws2_32 vfw32"
     set aLibsMap(CSF_OpenGlLibs)   "opengl32"
-    set aLibsMap(CSF_winspool)     "Winspool"
+    if { "$::HAVE_GLES2" == "true" } {
+      set aLibsMap(CSF_OpenGlLibs) "libEGL libGLESv2"
+    }
     set aLibsMap(CSF_psapi)        "Psapi"
     set aLibsMap(CSF_d3d9)         "d3d9"
 
@@ -1121,6 +1319,10 @@ proc osutils:csfList { theOS theCsfLibsMap theCsfFrmsMap } {
         set aLibsMap(CSF_XwLibs)     "X11 Xext Xmu Xi"
         set aLibsMap(CSF_MotifLibs)  "X11"
       }
+
+      if { "$::HAVE_GLES2" == "true" } {
+        set aLibsMap(CSF_OpenGlLibs) "EGL GLESv2"
+      }
     }
   }
 }
@@ -1429,7 +1631,14 @@ proc osutils:vcproj { theVcVer theOutDir theToolKit theGuidsMap {theProjTmpl {}
   }
   regsub -all -- {__PROJECT_GUID__} $theProjTmpl $aGuidsMap($theToolKit) theProjTmpl
 
+  set theProjTmpl [osutils:uwp:proj ${theVcVer} ${theProjTmpl}]
+
   set aUsedLibs [list]
+
+  if { "$theVcVer" == "vc14-uwp" } {
+    lappend aUsedLibs "WindowsApp.lib"
+  }
+
   foreach tkx [osutils:commonUsedTK  $theToolKit] {
     lappend aUsedLibs "${tkx}.lib"
   }
@@ -2136,6 +2345,9 @@ proc osutils:cbp { theCmpl theOutDir theProjName thePlatform theSrcFiles theLibs
     }
   }
   puts $aFile "\t\t\t\t\t<Add option=\"\$(CSF_OPT_LNK${aWokArch})\" />"
+  if { "$aWokStation" == "lin" } {
+    puts $aFile "\t\t\t\t\t<Add option=\"-Wl,-rpath-link=../../../${aWokStation}/cbp/lib\" />"
+  }
   puts $aFile "\t\t\t\t</Linker>"
 
   puts $aFile "\t\t\t</Target>"
@@ -2183,6 +2395,9 @@ proc osutils:cbp { theCmpl theOutDir theProjName thePlatform theSrcFiles theLibs
     }
   }
   puts $aFile "\t\t\t\t\t<Add option=\"\$(CSF_OPT_LNK${aWokArch}D)\" />"
+  if { "$aWokStation" == "lin" } {
+    puts $aFile "\t\t\t\t\t<Add option=\"-Wl,-rpath-link=../../../${aWokStation}/cbp/libd\" />"
+  }
   puts $aFile "\t\t\t\t</Linker>"
 
   puts $aFile "\t\t\t</Target>"
@@ -2527,6 +2742,9 @@ proc osutils:xcdtk { theOutDir theToolKit theGuidsMap theIsStatic thePlatform {t
   set anExecPrefix "\t\t\t\tEXECUTABLE_PREFIX = lib;"
   set aWrapperExtension "\t\t\t\tWRAPPER_EXTENSION = dylib;"
   set aTKDefines [list "OCC_CONVERT_SIGNALS"]
+  if { $theIsStatic == 1 } {
+    lappend aTKDefines "OCCT_NO_PLUGINS"
+  }
 
   if { "$theTargetType" == "executable" } {
     set aPBXBuildPhase "CopyFiles"
@@ -3047,3 +3265,61 @@ proc osutils:xcdx { theOutDir theExecutable theGuidsMap } {
   puts $aPlistFile $aPlistTmpl
   close $aPlistFile
 }
+
+# Returns available Windows SDKs versions
+proc osutils:sdk { theSdkMajorVer {isQuietMode false} {theSdkDirectories {}} } {
+  if { ![llength ${theSdkDirectories}] } {
+    foreach anEnvVar { "ProgramFiles" "ProgramFiles\(x86\)" "ProgramW6432" } {
+      if {[ info exists ::env(${anEnvVar}) ]} {
+        lappend theSdkDirectories "$::env(${anEnvVar})/Windows Kits/${theSdkMajorVer}/Include"
+      }
+    }
+  }
+
+  set sdk_versions {}
+  foreach sdk_dir ${theSdkDirectories} {
+    if { [file isdirectory ${sdk_dir}] } {
+      lappend sdk_versions [glob -tails -directory "${sdk_dir}" -type d *]
+    }
+  }
+
+  if {![llength ${sdk_versions}] && !${isQuietMode}} {
+    error "Error : Could not find Windows SDK ${theSdkMajorVer}"
+  }
+
+  return [join [lsort -unique ${sdk_versions}] " "]
+}
+
+# Generate global properties to Visual Studio project file for UWP solution
+proc osutils:uwp:proj { theVcVer theProjTmpl } {
+
+  set uwp_properties ""
+  set uwp_generate_metadata ""
+  set uwp_app_container ""
+
+  set format_template ""
+
+  if { ${theVcVer} == "vc14-uwp" } {
+    set sdk_versions [osutils:sdk 10]
+    set sdk_max_ver [lindex ${sdk_versions} end]
+
+    set uwp_properties "<DefaultLanguage>en-US</DefaultLanguage>\n   \
+<ApplicationType>Windows Store</ApplicationType>\n   \
+<ApplicationTypeRevision>10.0</ApplicationTypeRevision>\n   \
+<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>\n   \
+<AppContainerApplication>true</AppContainerApplication>\n   \
+<WindowsTargetPlatformVersion>${sdk_max_ver}</WindowsTargetPlatformVersion>\n   \
+<WindowsTargetPlatformMinVersion>${sdk_max_ver}</WindowsTargetPlatformMinVersion>"
+
+    set uwp_generate_metadata        "<GenerateWindowsMetadata>false</GenerateWindowsMetadata>"
+
+    regsub -all -- {[\r\n\s]*<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>} ${theProjTmpl} "" theProjTmpl
+  } else {
+    set format_template "\[\\r\\n\\s\]*"
+  }
+
+  regsub -all -- "${format_template}__UWP_PROPERTIES__"        ${theProjTmpl} "${uwp_properties}" theProjTmpl
+  regsub -all -- "${format_template}__UWP_GENERATE_METADATA__" ${theProjTmpl} "${uwp_generate_metadata}" theProjTmpl
+
+  return ${theProjTmpl}
+}