cross-packer 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +151 -0
  3. package/README.zh-CN.md +151 -0
  4. package/dist/archive/ar.d.ts +12 -0
  5. package/dist/archive/seven-za.d.ts +32 -0
  6. package/dist/archive/tar.d.ts +30 -0
  7. package/dist/archive/zip-reader.d.ts +17 -0
  8. package/dist/asar/dependency/collect.d.ts +2 -0
  9. package/dist/asar/dependency/detector.d.ts +8 -0
  10. package/dist/asar/dependency/hoister.d.ts +27 -0
  11. package/dist/asar/dependency/utils.d.ts +59 -0
  12. package/dist/asar/fileset/matcher.d.ts +12 -0
  13. package/dist/asar/fileset/platform-fileset.d.ts +36 -0
  14. package/dist/asar/fileset/transformer.d.ts +2 -0
  15. package/dist/asar/fileset/unpack-detector.d.ts +10 -0
  16. package/dist/asar/fileset/walker.d.ts +14 -0
  17. package/dist/asar/pack.d.ts +23 -0
  18. package/dist/asar/packer/app-collector.d.ts +2 -0
  19. package/dist/asar/packer/collector.d.ts +18 -0
  20. package/dist/asar/packer/concurrency.d.ts +1 -0
  21. package/dist/asar/packer/integrity.d.ts +8 -0
  22. package/dist/asar/packer/nm-collector.d.ts +7 -0
  23. package/dist/asar/packer/stream-builder.d.ts +18 -0
  24. package/dist/cli.d.ts +2 -0
  25. package/dist/config/index.d.ts +97 -0
  26. package/dist/electron/dist-zip.d.ts +18 -0
  27. package/dist/electron/download.d.ts +21 -0
  28. package/dist/index.d.ts +11 -0
  29. package/dist/packer/common/app-update-yml.d.ts +5 -0
  30. package/dist/packer/common/extra-resources.d.ts +39 -0
  31. package/dist/packer/common/staging.d.ts +3 -0
  32. package/dist/packer/common/template.d.ts +2 -0
  33. package/dist/packer/linux/linux.d.ts +2 -0
  34. package/dist/packer/mac/mac.d.ts +23 -0
  35. package/dist/packer/win/nsis.d.ts +24 -0
  36. package/dist/packer/win/resedit.d.ts +5 -0
  37. package/dist/packer/win/toolchain.d.ts +8 -0
  38. package/dist/packer/win/win.d.ts +12 -0
  39. package/dist/pipeline/pipeline.d.ts +41 -0
  40. package/dist/pipeline/targets.d.ts +28 -0
  41. package/dist/shared/hash.d.ts +2 -0
  42. package/dist/shared/logger.d.ts +39 -0
  43. package/dist/shared/platform.d.ts +26 -0
  44. package/dist/shared/types.d.ts +68 -0
  45. package/dist/update/blockmap.d.ts +13 -0
  46. package/dist/update/metadata.d.ts +20 -0
  47. package/dist/update/version.d.ts +7 -0
  48. package/package.json +71 -0
  49. package/src/archive/ar.ts +41 -0
  50. package/src/archive/seven-za.ts +160 -0
  51. package/src/archive/tar.ts +142 -0
  52. package/src/archive/zip-reader.ts +61 -0
  53. package/src/asar/dependency/collect.ts +437 -0
  54. package/src/asar/dependency/detector.ts +73 -0
  55. package/src/asar/dependency/hoister.ts +714 -0
  56. package/src/asar/dependency/utils.ts +225 -0
  57. package/src/asar/fileset/matcher.ts +101 -0
  58. package/src/asar/fileset/platform-fileset.ts +416 -0
  59. package/src/asar/fileset/transformer.ts +154 -0
  60. package/src/asar/fileset/unpack-detector.ts +38 -0
  61. package/src/asar/fileset/walker.ts +115 -0
  62. package/src/asar/pack.ts +186 -0
  63. package/src/asar/packer/app-collector.ts +74 -0
  64. package/src/asar/packer/collector.ts +134 -0
  65. package/src/asar/packer/concurrency.ts +24 -0
  66. package/src/asar/packer/integrity.ts +53 -0
  67. package/src/asar/packer/nm-collector.ts +194 -0
  68. package/src/asar/packer/stream-builder.ts +723 -0
  69. package/src/cli.ts +182 -0
  70. package/src/config/index.ts +365 -0
  71. package/src/electron/dist-zip.ts +65 -0
  72. package/src/electron/download.ts +121 -0
  73. package/src/index.ts +14 -0
  74. package/src/packer/common/app-update-yml.ts +21 -0
  75. package/src/packer/common/extra-resources.ts +83 -0
  76. package/src/packer/common/staging.ts +33 -0
  77. package/src/packer/common/template.ts +24 -0
  78. package/src/packer/linux/linux.ts +329 -0
  79. package/src/packer/mac/mac.ts +495 -0
  80. package/src/packer/win/nsis.ts +244 -0
  81. package/src/packer/win/resedit.ts +60 -0
  82. package/src/packer/win/toolchain.ts +63 -0
  83. package/src/packer/win/win.ts +421 -0
  84. package/src/pipeline/pipeline.ts +149 -0
  85. package/src/pipeline/targets.ts +67 -0
  86. package/src/shared/hash.ts +15 -0
  87. package/src/shared/logger.ts +91 -0
  88. package/src/shared/platform.ts +41 -0
  89. package/src/shared/types.ts +82 -0
  90. package/src/update/blockmap.ts +247 -0
  91. package/src/update/metadata.ts +97 -0
  92. package/src/update/version.ts +59 -0
  93. package/templates/linux/app.desktop +11 -0
  94. package/templates/linux/control +9 -0
  95. package/templates/linux/postinst +10 -0
  96. package/templates/linux/postrm +8 -0
  97. package/templates/linux/preinst +49 -0
  98. package/templates/linux/prerm +43 -0
  99. package/templates/mac/Info.plist +18 -0
  100. package/templates/mac/app-update.yml +4 -0
  101. package/templates/win/nsis/README.md +51 -0
  102. package/templates/win/nsis/THIRD-PARTY-NOTICES.md +20 -0
  103. package/templates/win/nsis/assistedInstaller.nsh +154 -0
  104. package/templates/win/nsis/assistedMessages.yml +368 -0
  105. package/templates/win/nsis/common.nsh +147 -0
  106. package/templates/win/nsis/empty-license.txt +1 -0
  107. package/templates/win/nsis/include/FileAssociation.nsh +123 -0
  108. package/templates/win/nsis/include/StdUtils.nsh +496 -0
  109. package/templates/win/nsis/include/StrContains.nsh +48 -0
  110. package/templates/win/nsis/include/UAC.nsh +299 -0
  111. package/templates/win/nsis/include/allowOnlyOneInstallerInstance.nsh +164 -0
  112. package/templates/win/nsis/include/extractAppPackage.nsh +138 -0
  113. package/templates/win/nsis/include/getProcessInfo.nsh +157 -0
  114. package/templates/win/nsis/include/installUtil.nsh +248 -0
  115. package/templates/win/nsis/include/installer.nsh +247 -0
  116. package/templates/win/nsis/include/nsProcess.nsh +28 -0
  117. package/templates/win/nsis/include/webPackage.nsh +64 -0
  118. package/templates/win/nsis/installSection.nsh +110 -0
  119. package/templates/win/nsis/installer.nsi +132 -0
  120. package/templates/win/nsis/messages.yml +240 -0
  121. package/templates/win/nsis/multiUser.nsh +134 -0
  122. package/templates/win/nsis/multiUserUi.nsh +230 -0
  123. package/templates/win/nsis/oneClick.nsh +19 -0
  124. package/templates/win/nsis/portable.nsi +91 -0
  125. package/templates/win/nsis/uninstaller.nsh +263 -0
  126. package/templates/win/nsis-header.nsh +57 -0
@@ -0,0 +1,49 @@
1
+ #!/bin/sh
2
+ # preinst: close running {{productName}} processes before install/upgrade.
3
+ # Matches by /proc/<pid>/comm and cmdline argv[0] basename — deliberately not
4
+ # by /proc/<pid>/exe, which becomes "(deleted)" after dpkg renames the old dir.
5
+ APP_NAME="{{productName}}"
6
+ APP_BASENAME="{{name}}"
7
+ LOG="/tmp/{{name}}-preinst.log"
8
+
9
+ log() { echo "$(date '+%H:%M:%S') preinst: $*" >> "$LOG" 2>/dev/null || true; }
10
+
11
+ log "=== start (called as: $* , uid=$(id -u 2>/dev/null), PATH=$PATH) ==="
12
+
13
+ find_app_pids() {
14
+ for dir in /proc/[0-9]*; do
15
+ [ -d "$dir" ] || continue
16
+ pid=${dir#/proc/}
17
+ [ "$pid" = "$$" ] && continue
18
+ comm=$(cat "$dir/comm" 2>/dev/null) || comm=""
19
+ if [ "$comm" = "$APP_BASENAME" ]; then
20
+ echo "$pid"
21
+ continue
22
+ fi
23
+ cmdline=$(cat "$dir/cmdline" 2>/dev/null) || continue
24
+ [ -n "$cmdline" ] || continue
25
+ argv0=${cmdline%%$'\x00'*}
26
+ base=${argv0##*/}
27
+ if [ "$base" = "$APP_BASENAME" ]; then
28
+ echo "$pid"
29
+ fi
30
+ done
31
+ }
32
+
33
+ kill_all() {
34
+ pids=$(find_app_pids)
35
+ [ -n "$pids" ] || { log "no running process found"; return 0; }
36
+ for pid in $pids; do
37
+ log "killing pid=$pid"
38
+ kill "$pid" 2>/dev/null || true
39
+ done
40
+ # give processes a moment to exit, then force leftovers
41
+ sleep 2
42
+ for pid in $pids; do
43
+ kill -9 "$pid" 2>/dev/null || true
44
+ done
45
+ }
46
+
47
+ kill_all
48
+ log "=== done ==="
49
+ exit 0
@@ -0,0 +1,43 @@
1
+ #!/bin/sh
2
+ # prerm: close running {{productName}} processes before remove/upgrade.
3
+ APP_EXE="/opt/{{installDir}}/{{name}}"
4
+ LOG="/tmp/{{name}}-prerm.log"
5
+
6
+ log() { echo "$(date '+%H:%M:%S') prerm: $*" >> "$LOG" 2>/dev/null || true; }
7
+
8
+ log "=== start (called as: $* , uid=$(id -u 2>/dev/null)) ==="
9
+ log "APP_EXE=$APP_EXE"
10
+
11
+ find_app_pids() {
12
+ for dir in /proc/[0-9]*; do
13
+ [ -d "$dir" ] || continue
14
+ pid=${dir#/proc/}
15
+ [ "$pid" = "$$" ] && continue
16
+ exe=$(readlink "$dir/exe" 2>/dev/null) || exe=""
17
+ case "$exe" in
18
+ *"$APP_EXE"*) echo "$pid"; continue ;;
19
+ esac
20
+ cmdline=$(cat "$dir/cmdline" 2>/dev/null) || continue
21
+ [ -n "$cmdline" ] || continue
22
+ case "$cmdline" in
23
+ *"$APP_EXE"*) echo "$pid" ;;
24
+ esac
25
+ done
26
+ }
27
+
28
+ kill_all() {
29
+ pids=$(find_app_pids)
30
+ [ -n "$pids" ] || { log "no running process found"; return 0; }
31
+ for pid in $pids; do
32
+ log "killing pid=$pid"
33
+ kill "$pid" 2>/dev/null || true
34
+ done
35
+ sleep 2
36
+ for pid in $pids; do
37
+ kill -9 "$pid" 2>/dev/null || true
38
+ done
39
+ }
40
+
41
+ kill_all
42
+ log "=== done ==="
43
+ exit 0
@@ -0,0 +1,18 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>CFBundleInfoDictionaryVersion</key>
6
+ <string>6.0</string>
7
+ <key>CFBundlePackageType</key>
8
+ <string>APPL</string>
9
+ <key>NSHighResolutionCapable</key>
10
+ <true/>
11
+ <key>NSMainNibFile</key>
12
+ <string>MainMenu</string>
13
+ <key>NSRequiresAquaSystemAppearance</key>
14
+ <false/>
15
+ <key>NSSupportsAutomaticGraphicsSwitching</key>
16
+ <true/>
17
+ </dict>
18
+ </plist>
@@ -0,0 +1,4 @@
1
+ provider: generic
2
+ url: {{updateServerUrl}}
3
+ updaterCacheDirName: {{updaterCacheDirName}}
4
+ channel: {{channel}}
@@ -0,0 +1,51 @@
1
+ # NSIS
2
+
3
+ ⚠️ **It is developer documentation.** If your are looking for usage guide, see [user documentation](https://electron.build/nsis).
4
+
5
+ > **Provenance & license**: the templates in this directory originate from
6
+ > [electron-userland/electron-builder](https://github.com/electron-userland/electron-builder)
7
+ > (MIT). See [THIRD-PARTY-NOTICES.md](./THIRD-PARTY-NOTICES.md) for details.
8
+
9
+ NSIS stands for Nullsoft Scriptable Install System. electron-builder utilizes a [customized version](https://github.com/electron-userland/electron-builder-binaries) of it and uses `NsisMultiUser` plugin to handle installation for single user or all users on the computer.
10
+
11
+ ## Some links
12
+ http://www.mathiaswestin.net/2012/09/how-to-make-per-user-installation-with.html
13
+
14
+ https://msdn.microsoft.com/en-us/library/windows/desktop/dd378457(v=vs.85).aspx#FOLDERID_UserProgramFiles
15
+
16
+ https://github.com/Drizin/NsisMultiUser
17
+
18
+ NSIS vs Inno Setup — it is not easy to choose because both are far from ideal, e.g. inno also doesn't have built-in per-user installation implementation — http://stackoverflow.com/questions/34330668/inno-setup-custom-dialog-with-per-user-or-per-machine-installation.
19
+
20
+ http://stackoverflow.com/questions/2565215/checking-if-the-application-is-running-in-nsis-before-uninstalling
21
+
22
+ One-click installer: http://forums.winamp.com/showthread.php?t=300479
23
+
24
+ ## Localization (l10n)
25
+
26
+ For translators, the strings to be displayed are included in [`assistedMessages.yml`](https://github.com/electron-userland/electron-builder/blob/master/packages/app-builder-lib/templates/nsis/assistedMessages.yml) and [`messages.yml`]https://github.com/electron-userland/electron-builder/blob/master/packages/app-builder-lib/templates/nsis/messages.yml).
27
+
28
+ As for other strings in NSIS, head to [electron-userland/electron-builder-binaries](https://github.com/electron-userland/electron-builder-binaries) or the upstream repository on [Sorceforge](https://sourceforge.net/p/nsis/code/HEAD/tree/).
29
+
30
+ ## GUID
31
+ See [docs](https://electron.build/nsis).
32
+
33
+ We use UUID v5 to generate sha-1 name-based UUID.
34
+
35
+ http://stackoverflow.com/questions/3029994/convert-uri-to-guid
36
+ https://alexandrebrisebois.wordpress.com/2013/11/14/create-predictable-guids-for-your-windows-azure-table-storage-entities/
37
+ https://github.com/Squirrel/Squirrel.Windows/pull/658
38
+
39
+ ## Compression
40
+
41
+ NSIS LZMA compression is slower and worse compared to external `7za` compression. Slower because `7za` is multi-threaded, worse because LZMA codec implementation is outdated and BCJ2 filter is not enabled.
42
+ Difference for test app — 4 MB (before: 36.3 after: 32.8).
43
+
44
+ And compression time is also greatly reduced.
45
+
46
+ Since NSIS is awesome, no disadvantages in our approach — [compression is disabled](http://nsis.sourceforge.net/Reference/SetCompress) before `File /oname=app.7z "${APP_ARCHIVE}"` and enabled after (it is the reasons why `SOLID` compression is not used).
47
+ So, opposite to Squirrel.Windows, archive is not twice compressed.
48
+
49
+ So, in your custom NSIS scripts you should not use any compression instructions. Only `SetCompress` if you need to disable compression for already archived file.
50
+
51
+
@@ -0,0 +1,20 @@
1
+ # Third-party notices — NSIS templates
2
+
3
+ The `.nsh` / `.nsi` templates and message YAML files in this directory
4
+ originate from [electron-builder](https://github.com/electron-userland/electron-builder)
5
+ (`packages/app-builder-lib/templates/nsis`), Copyright (c) electron-builder
6
+ contributors, licensed under the [MIT License](https://github.com/electron-userland/electron-builder/blob/master/LICENSE).
7
+
8
+ - Upstream project: https://github.com/electron-userland/electron-builder
9
+ - NSIS binaries downloaded at build time come from
10
+ [electron-userland/electron-builder-binaries](https://github.com/electron-userland/electron-builder-binaries)
11
+ (customized NSIS build + NsisMultiUser plugin, MIT licensed).
12
+ - The `NsisMultiUser` plugin itself is by Drizin — see
13
+ https://github.com/Drizin/NsisMultiUser
14
+ - NSIS (Nullsoft Scriptable Install System) is upstream at
15
+ https://sourceforge.net/p/nsis/code/HEAD/tree/
16
+
17
+ Modifications by cross-packer contributors are released under the MIT license
18
+ (see the repository root LICENSE). Version pinning of the downloaded toolchain
19
+ is configurable via `config.win.nsisVersion` / `config.win.nsisResourcesVersion`
20
+ in `cross-packer.config.mjs`.
@@ -0,0 +1,154 @@
1
+ !include UAC.nsh
2
+
3
+ !ifndef INSTALL_MODE_PER_ALL_USERS
4
+ !include multiUserUi.nsh
5
+ !endif
6
+
7
+ !ifndef BUILD_UNINSTALLER
8
+
9
+ !ifmacrodef customWelcomePage
10
+ !insertmacro customWelcomePage
11
+ !endif
12
+
13
+ !ifmacrodef licensePage
14
+ !insertmacro skipPageIfUpdated
15
+ !insertmacro licensePage
16
+ !endif
17
+
18
+ !ifndef INSTALL_MODE_PER_ALL_USERS
19
+ !insertmacro PAGE_INSTALL_MODE
20
+ !endif
21
+
22
+ !ifdef allowToChangeInstallationDirectory
23
+ !include StrContains.nsh
24
+
25
+ !insertmacro skipPageIfUpdated
26
+ !insertmacro MUI_PAGE_DIRECTORY
27
+
28
+ # pageDirectory leave doesn't work (it seems because $INSTDIR is set after custom leave function)
29
+ # so, we use instfiles pre
30
+ !define MUI_PAGE_CUSTOMFUNCTION_PRE instFilesPre
31
+
32
+ # sanitize the MUI_PAGE_DIRECTORY result to make sure it has a application name sub-folder
33
+ Function instFilesPre
34
+ ${StrContains} $0 "${APP_FILENAME}" $INSTDIR
35
+ ${If} $0 == ""
36
+ StrCpy $INSTDIR "$INSTDIR\${APP_FILENAME}"
37
+ ${endIf}
38
+ FunctionEnd
39
+ !endif
40
+
41
+ # after change installation directory and before install start, you can show custom page here.
42
+ !ifmacrodef customPageAfterChangeDir
43
+ !insertmacro customPageAfterChangeDir
44
+ !endif
45
+
46
+ !insertmacro MUI_PAGE_INSTFILES
47
+ !ifmacrodef customFinishPage
48
+ !insertmacro customFinishPage
49
+ !else
50
+ !ifndef HIDE_RUN_AFTER_FINISH
51
+ Function StartApp
52
+ ${if} ${isUpdated}
53
+ StrCpy $1 "--updated"
54
+ ${else}
55
+ StrCpy $1 ""
56
+ ${endif}
57
+ ${StdUtils.ExecShellAsUser} $0 "$launchLink" "open" "$1"
58
+ FunctionEnd
59
+
60
+ !define MUI_FINISHPAGE_RUN
61
+ !define MUI_FINISHPAGE_RUN_FUNCTION "StartApp"
62
+ !endif
63
+ !insertmacro MUI_PAGE_FINISH
64
+ !endif
65
+ !else
66
+ !ifndef removeDefaultUninstallWelcomePage
67
+ !ifmacrodef customUnWelcomePage
68
+ !insertmacro customUnWelcomePage
69
+ !else
70
+ !insertmacro MUI_UNPAGE_WELCOME
71
+ !endif
72
+
73
+ !endif
74
+ !ifndef INSTALL_MODE_PER_ALL_USERS
75
+ !insertmacro PAGE_INSTALL_MODE
76
+ !endif
77
+ !insertmacro MUI_UNPAGE_INSTFILES
78
+ !ifmacrodef customUninstallPage
79
+ !insertmacro customUninstallPage
80
+ !endif
81
+ !insertmacro MUI_UNPAGE_FINISH
82
+ !endif
83
+
84
+ !macro initMultiUser
85
+ !ifdef INSTALL_MODE_PER_ALL_USERS
86
+ !insertmacro setInstallModePerAllUsers
87
+ !else
88
+ ${If} ${UAC_IsInnerInstance}
89
+ ${AndIfNot} ${UAC_IsAdmin}
90
+ # special return value for outer instance so it knows we did not have admin rights
91
+ SetErrorLevel 0x666666
92
+ Quit
93
+ ${endIf}
94
+
95
+ !ifndef MULTIUSER_INIT_TEXT_ADMINREQUIRED
96
+ !define MULTIUSER_INIT_TEXT_ADMINREQUIRED "$(^Caption) requires administrator privileges."
97
+ !endif
98
+
99
+ !ifndef MULTIUSER_INIT_TEXT_POWERREQUIRED
100
+ !define MULTIUSER_INIT_TEXT_POWERREQUIRED "$(^Caption) requires at least Power User privileges."
101
+ !endif
102
+
103
+ !ifndef MULTIUSER_INIT_TEXT_ALLUSERSNOTPOSSIBLE
104
+ !define MULTIUSER_INIT_TEXT_ALLUSERSNOTPOSSIBLE "Your user account does not have sufficient privileges to install $(^Name) for all users of this computer."
105
+ !endif
106
+
107
+ # checks registry for previous installation path (both for upgrading, reinstall, or uninstall)
108
+ StrCpy $hasPerMachineInstallation "0"
109
+ StrCpy $hasPerUserInstallation "0"
110
+
111
+ # set installation mode to setting from a previous installation
112
+ ReadRegStr $perMachineInstallationFolder HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation
113
+ ${if} $perMachineInstallationFolder != ""
114
+ StrCpy $hasPerMachineInstallation "1"
115
+ ${endif}
116
+
117
+ ReadRegStr $perUserInstallationFolder HKCU "${INSTALL_REGISTRY_KEY}" InstallLocation
118
+ ${if} $perUserInstallationFolder != ""
119
+ StrCpy $hasPerUserInstallation "1"
120
+ ${endif}
121
+
122
+ ${GetParameters} $R0
123
+ ${GetOptions} $R0 "/allusers" $R1
124
+ ${IfNot} ${Errors}
125
+ StrCpy $hasPerMachineInstallation "1"
126
+ StrCpy $hasPerUserInstallation "0"
127
+ ${EndIf}
128
+
129
+ ${GetOptions} $R0 "/currentuser" $R1
130
+ ${IfNot} ${Errors}
131
+ StrCpy $hasPerMachineInstallation "0"
132
+ StrCpy $hasPerUserInstallation "1"
133
+ ${EndIf}
134
+
135
+ ${if} $hasPerUserInstallation == "1"
136
+ ${andif} $hasPerMachineInstallation == "0"
137
+ !insertmacro setInstallModePerUser
138
+ ${elseif} $hasPerUserInstallation == "0"
139
+ ${andif} $hasPerMachineInstallation == "1"
140
+ !insertmacro setInstallModePerAllUsers
141
+ ${else}
142
+ # if there is no installation, or there is both per-user and per-machine
143
+ !ifdef INSTALL_MODE_PER_ALL_USERS
144
+ !insertmacro setInstallModePerAllUsers
145
+ !else
146
+ !ifdef INSTALL_MODE_PER_ALL_USERS_DEFAULT
147
+ !insertmacro setInstallModePerAllUsers
148
+ !else
149
+ !insertmacro setInstallModePerUser
150
+ !endif
151
+ !endif
152
+ ${endif}
153
+ !endif
154
+ !macroend