1
0
mirror of https://github.com/mintty/wsltty.git synced 2025-11-09 03:21:55 +00:00

Compare commits

...

21 Commits
3.4.7 ... 3.6.1

Author SHA1 Message Date
mintty
449a310d90 update to wslbridge2 0.9 (to fix #302), drop patches;
update to mintty 3.6.1
2022-10-30 11:30:07 +01:00
mintty
87aa168b41 CI: install build environment 2022-04-01 00:05:05 +02:00
mintty
9de7d8d6f1 CI control file 2022-03-31 21:46:17 +02:00
mintty
c91ec886b5 3.6.0 2022-03-25 19:28:34 +01:00
mintty
4caa2c34eb portable installation (#306) 2022-03-22 15:54:28 +01:00
mintty
73fcc66790 fix previous change 2022-03-01 00:11:44 +01:00
mintty
5cee2c341b installer: support customized install dirs via environment vars (#304) 2022-02-28 09:49:30 +01:00
mintty
ea570a191e (#304) 2022-02-19 23:50:24 +01:00
mintty
2dd099265d mention winget package 2022-02-05 22:52:32 +01:00
mintty
2ddd2cd1ff add 41575379b4
as a patch: add COM instance for new lifted WSL service
2022-02-03 21:00:40 +01:00
mintty
d1fa49985b add wsltty quiet installer (microsoft/winget-pkgs#40573) 2022-01-18 19:37:26 +01:00
mintty
76fad756e1 3.5.1 2021-09-03 22:37:00 +02:00
mintty
600df69bb8 3.5.1 2021-09-03 22:05:59 +02:00
mintty
97dc68d64a ensure wsltty-specific recompile for mintty -V message (#284) 2021-05-11 00:57:26 +02:00
mintty
9469b2b5f5 3.5.0.2 2021-05-01 19:16:58 +02:00
mintty
5b27a3d3c8 update to wslbridge 0.8, matching the updated patch 2021-04-27 21:46:31 +02:00
mintty
ab46c2b1b0 Merge pull request #282 from Biswa96/master
update wslbridge2 patch file, to catch up with wslbridge2 0.8, to fix #281
2021-04-27 21:44:37 +02:00
Biswapriyo Nath
2e56730282 update wslbridge2 patch file 2021-04-27 23:42:59 +05:30
mintty
d67ce45c3e 3.5.0 2021-04-15 18:07:12 +02:00
mintty
6e74ab4d5b filter out "docker" default distributions from configuration (#277) 2021-04-09 10:29:21 +02:00
mintty
ee4e403f4c filter out "docker" distributions from configuration (#277) 2021-04-07 14:30:15 +02:00
11 changed files with 231 additions and 81 deletions

View File

@@ -1,25 +1,16 @@
diff -rup old/src/wslbridge2-backend.cpp new/src/wslbridge2-backend.cpp diff --git a/src/wslbridge2-backend.cpp b/src/wslbridge2-backend.cpp
--- old/src/wslbridge2-backend.cpp 2020-10-18 15:03:06.000000000 +0000 index 8b86cc6..63a19e5 100644
+++ new/src/wslbridge2-backend.cpp 2021-03-18 18:31:35.684184400 +0000 --- a/src/wslbridge2-backend.cpp
@@ -21,6 +21,7 @@ +++ b/src/wslbridge2-backend.cpp
#include <termios.h> @@ -17,6 +17,7 @@
#include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
#include <wordexp.h> #include <wordexp.h>
+#include <limits.h> // PIPE_BUF +#include <limits.h> // PIPE_BUF
#include <string> #include <string>
#include <vector> #include <vector>
@@ -321,6 +322,9 @@ int main(int argc, char *argv[]) @@ -196,6 +197,7 @@ int main(int argc, char *argv[])
/* Use dupped master fd to read OR write */
const int mfd_dp = dup(mfd);
assert(mfd_dp > 0);
+#ifdef debug_to_input
+ FILE * debug = fdopen(mfd_dp, "w"); // for fprintf
+#endif
struct pollfd fds[] = {
{ ioSockets.inputSock, POLLIN, 0 },
@@ -330,6 +334,7 @@ int main(int argc, char *argv[])
ssize_t readRet = 0, writeRet = 0; ssize_t readRet = 0, writeRet = 0;
char data[1024]; /* Buffer to hold raw data from pty */ char data[1024]; /* Buffer to hold raw data from pty */
@@ -27,13 +18,12 @@ diff -rup old/src/wslbridge2-backend.cpp new/src/wslbridge2-backend.cpp
do do
{ {
@@ -340,8 +345,86 @@ int main(int argc, char *argv[]) @@ -206,8 +208,85 @@ int main(int argc, char *argv[])
if (fds[0].revents & POLLIN) if (fds[0].revents & POLLIN)
{ {
readRet = recv(ioSockets.inputSock, data, sizeof data, 0); readRet = recv(ioSockets.inputSock, data, sizeof data, 0);
- if (readRet > 0) - if (readRet > 0)
- writeRet = write(mfd_dp, data, readRet); - writeRet = write(mfd_dp, data, readRet);
+
+ char * s = data; + char * s = data;
+ int len = readRet; + int len = readRet;
+ writeRet = 1; + writeRet = 1;
@@ -116,14 +106,14 @@ diff -rup old/src/wslbridge2-backend.cpp new/src/wslbridge2-backend.cpp
} }
/* Resize window when buffer received in control socket */ /* Resize window when buffer received in control socket */
diff -rup old/src/wslbridge2.cpp new/src/wslbridge2.cpp diff --git a/src/wslbridge2.cpp b/src/wslbridge2.cpp
--- old/src/wslbridge2.cpp 2020-10-18 15:03:06.000000000 +0000 index 300ad57..3ba9096 100644
+++ new/src/wslbridge2.cpp 2021-02-26 17:45:28.437040700 +0000 --- a/src/wslbridge2.cpp
@@ -57,32 +57,85 @@ union IoSockets +++ b/src/wslbridge2.cpp
@@ -43,19 +43,41 @@ union IoSockets
/* global variable */ /* global variable */
static union IoSockets g_ioSockets = { 0, 0, 0 }; static volatile union IoSockets g_ioSockets = { 0 };
+
+#define dont_debug_inband +#define dont_debug_inband
+#define dont_use_controlsocket +#define dont_use_controlsocket
+ +
@@ -136,7 +126,7 @@ diff -rup old/src/wslbridge2.cpp new/src/wslbridge2.cpp
/* Send terminal window size to control socket */ /* Send terminal window size to control socket */
- ioctl(STDIN_FILENO, TIOCGWINSZ, &winp); - ioctl(STDIN_FILENO, TIOCGWINSZ, &winp);
send(g_ioSockets.controlSock, &winp, sizeof winp, 0); send(g_ioSockets.controlSock, (char *)&winp, sizeof winp, 0);
+#else +#else
+ static char wins[2 + sizeof(struct winsize)] = {0, 16}; + static char wins[2 + sizeof(struct winsize)] = {0, 16};
+ static struct winsize * winsp = (struct winsize *)&wins[2]; + static struct winsize * winsp = (struct winsize *)&wins[2];
@@ -159,27 +149,16 @@ diff -rup old/src/wslbridge2.cpp new/src/wslbridge2.cpp
{ {
int ret; int ret;
char data[1024]; char data[1024];
-
- struct pollfd fds = { STDIN_FILENO, POLLIN, 0 };
+ assert(sizeof data <= PIPE_BUF); + assert(sizeof data <= PIPE_BUF);
while (1) while (1)
{ {
+#ifdef use_poll @@ -65,8 +87,33 @@ static void* send_buffer(void *param)
+ // we could poll on a single channel but we don't need to closesocket(g_ioSockets.inputSock);
+ static struct pollfd fds = { STDIN_FILENO, POLLIN, 0 }; break;
ret = poll(&fds, 1, -1); }
- if (!send(g_ioSockets.inputSock, data, ret, 0))
if (fds.revents & POLLIN) - break;
+#else
+ if (1)
+#endif
{
ret = read(STDIN_FILENO, data, sizeof data);
- if (ret > 0)
- ret = send(g_ioSockets.inputSock, data, ret, 0);
- else
+
+ char * s = data; + char * s = data;
+ int len = ret; + int len = ret;
+ while (ret > 0 && len > 0) + while (ret > 0 && len > 0)
@@ -207,33 +186,27 @@ diff -rup old/src/wslbridge2.cpp new/src/wslbridge2.cpp
+ } + }
+ } + }
+ } + }
+ if (ret <= 0)
break;
}
}
@@ -164,6 +217,7 @@ int main(int argc, char *argv[])
if (GetWindowsBuild() < 17763)
fatal("Windows 10 version is older than minimal requirement.\n");
+ setlocale(LC_ALL, "");
#ifdef __CYGWIN__
cygwin_internal(CW_SYNC_WINENV);
#endif
@@ -529,13 +583,6 @@ int main(int argc, char *argv[])
g_ioSockets.controlSock = AcceptLocSock(controlSocket);
} }
- /* Create thread to send window size through control socket */ pthread_exit(&ret);
- struct sigaction act = {}; @@ -480,16 +527,6 @@ int main(int argc, char *argv[])
g_ioSockets.controlSock = win_local_accept(controlSock);
}
- /* Capture window resize signal and send buffer to control socket */
- {
- struct sigaction act;
- memset(&act, 0, sizeof act);
- act.sa_handler = resize_window; - act.sa_handler = resize_window;
- act.sa_flags = SA_RESTART; - act.sa_flags = SA_RESTART;
- ret = sigaction(SIGWINCH, &act, NULL); - ret = sigaction(SIGWINCH, &act, NULL);
- assert(ret == 0); - assert(ret == 0);
- }
- -
/* Create thread to send input buffer to input socket */ /* Create thread to send input buffer to input socket */
pthread_t tidInput; pthread_t tidInput;
ret = pthread_create(&tidInput, nullptr, send_buffer, nullptr); ret = pthread_create(&tidInput, nullptr, send_buffer, nullptr);
@@ -548,6 +595,17 @@ int main(int argc, char *argv[]) @@ -502,6 +539,17 @@ int main(int argc, char *argv[])
termState.enterRawMode(); termState.enterRawMode();

View File

@@ -0,0 +1,62 @@
diff -rup src/sav/GetVmId.cpp src/GetVmId.cpp
--- src/sav/GetVmId.cpp 2021-04-27 13:50:51.000000000 +0000
+++ src/GetVmId.cpp 2022-02-03 19:43:53.684999800 +0000
@@ -46,11 +46,24 @@ void ComInit(void)
EOAC_STATIC_CLOAKING, NULL);
assert(hRes == 0);
- hRes = CoCreateInstance(CLSID_LxssUserSession,
+ // First try with COM server in lifted WSL service
+ hRes = CoCreateInstance(CLSID_WslService,
NULL,
CLSCTX_LOCAL_SERVER,
- IID_ILxssUserSession,
+ IID_IWSLService,
(PVOID *)&wslSession);
+
+
+ // Now try with COM server in system WSL service
+ if (FAILED(hRes))
+ {
+ hRes = CoCreateInstance(CLSID_LxssUserSession,
+ NULL,
+ CLSCTX_LOCAL_SERVER,
+ IID_ILxssUserSession,
+ (PVOID *)&wslSession);
+ }
+
assert(hRes == 0);
}
diff -rup src/sav/LxssUserSession.hpp src/LxssUserSession.hpp
--- src/sav/LxssUserSession.hpp 2021-04-27 13:50:51.000000000 +0000
+++ src/LxssUserSession.hpp 2022-02-03 19:45:22.846298200 +0000
@@ -11,14 +11,26 @@
#ifndef LXSSUSERSESSION_H
#define LXSSUSERSESSION_H
-/* Class identifier */
+// COM IDs for lifted WSL service
+static const GUID CLSID_WslService = {
+ 0xF122531F,
+ 0x326B,
+ 0x4514,
+ { 0x85, 0xAE, 0xDC, 0x99, 0xD3, 0x1D, 0x82, 0x56 } };
+
+static const GUID IID_IWSLService = {
+ 0x50047071,
+ 0x122C,
+ 0x4CAD,
+ { 0x9C, 0x93, 0x94, 0x72, 0x0E, 0xB7, 0x7B, 0x06 } };
+
+// COM IDs for system WSL service
static const GUID CLSID_LxssUserSession = {
0x4F476546,
0xB412,
0x4579,
{ 0xB6, 0x4C, 0x12, 0x3D, 0xF3, 0x31, 0xE3, 0xD6 } };
-/* Interface identifier */
static const GUID IID_ILxssUserSession = {
0x536A6BCF,
0xFE04,

View File

@@ -1,4 +1,4 @@
mintty is copyright 2008-13 Andy Koppe, 2015-18 Thomas Wolff. mintty is copyright 2008-22 Andy Koppe, 2015-22 Thomas Wolff.
Licensed under the terms of the GNU General Public License version 3 or later, Licensed under the terms of the GNU General Public License version 3 or later,
amended with the bundling clause to clarify ambiguous interpretation. amended with the bundling clause to clarify ambiguous interpretation.

View File

@@ -35,11 +35,23 @@ You may need to open the Properties of the installer first, tab “General”
section “Security” (if available) and select “Unblock”, section “Security” (if available) and select “Unblock”,
to enable the “Run anyway” button. to enable the “Run anyway” button.
#### WSLtty Portable installer
For a portable installation, e.g. on a USB stick, choose the
“-install-portable.exe” file for download. Installation will prompt
for a portable installation folder interactively.
For example, choosing `U:\opt` will create and use folder
`U:\opt\wsltty` both as installation directory and configuration directory.
Portable installation does not install any start menu or desktop shortcuts
and no context menu entries. It creates a shortcut in the selected
portable installation folder to start the default WSL distribution.
#### Installation from archive #### #### Installation from archive ####
In case a local anti-virus guard barfs about the wsltty installer, the In case a local anti-virus guard barfs about the wsltty installer, the
release also contains a `.cab` file. Download it, open it, extract its files release also contains a `.cab` file. Download it, open it, extract its files
to some temporary deployment directory, and invoke `install.bat` from there. to some temporary deployment directory, and invoke `install.bat` from there,
or `install-portable.bat` for a portable installation.
#### Installation from source repository #### #### Installation from source repository ####
@@ -62,14 +74,20 @@ the optional second parameter designates the configuration directory.
### Installation with other package management environments ### ### Installation with other package management environments ###
Note that these are 3rd-party contributions and do not necessarily Note: These are 3rd-party packages, not managed by this repository.
provide the latest version.
#### Windows Package Manager ####
To install wsltty from the
[Windows Package Manager Community Repository](https://github.com/microsoft/winget-pkgs),
invoke one of
* `winget install wsltty`
* `winget upgrade wsltty`
#### Chocolatey #### #### Chocolatey ####
If you use the [Chocolatey package manager](https://chocolatey.org/), If you use the [Chocolatey package manager](https://chocolatey.org/),
invoke one of invoke one of
<img height=222 align=right src=https://github.com/mintty/wsltty.appx/raw/master/wsltty.appx.png>
* `choco install wsltty` * `choco install wsltty`
* `choco upgrade wsltty` * `choco upgrade wsltty`
@@ -82,10 +100,6 @@ then, invoke one of
* `scoop install wsltty` * `scoop install wsltty`
* `scoop update wsltty` * `scoop update wsltty`
#### Windows Appx package ####
A Windows Appx package and certificate is available in the [wsltty.appx](https://github.com/mintty/wsltty.appx/) repository.
### Uninstallation ### ### Uninstallation ###
To uninstall wsltty desktop, start menu, and context menu integration: To uninstall wsltty desktop, start menu, and context menu integration:

View File

@@ -1 +1 @@
3.4.7 3.6.1

31
appveyor.yml Normal file
View File

@@ -0,0 +1,31 @@
# This file is part of wsltty project
# Build image; of course wsltty has nothing to do with Visual Studio -
# this is just the name of Appveyor's build environment image
# that also contains cygwin
image: Visual Studio 2022
# Version format
version: "#{build}"
# Do not increment build number after pull requests
pull_requests:
do_not_increment_build_number: true
# Do not start a new build when a new Git tag is created
skip_tags: true
init:
- cmd: |
set PATH=C:\cygwin64;C:\cygwin64\bin;%windir%\System32
setup-x86_64 -q -P unzip -P zoo -P patch -P lcab
winget install Alpine
build_script:
- cmd: |
make
test_script:
- cmd: |
bin\mintty.exe --log mintty.log --exec echo hello mintty
grep echo mintty.log

View File

@@ -291,6 +291,15 @@ config () {
echoc "- root $root" echoc "- root $root"
wdir=%USERPROFILE% wdir=%USERPROFILE%
case "$name" in
docker*) echo skipping docker system
return;;
esac
case "$root" in
*\\Docker*) echo skipping docker system
return;;
esac
if $ok && ! $remove && [ -n "$distro" ] if $ok && ! $remove && [ -n "$distro" ]
then # fix #163: backend missing +x with certain mount options then # fix #163: backend missing +x with certain mount options
echo Setting +x wslbridge2 backends for distro "'$distro'" echo Setting +x wslbridge2 backends for distro "'$distro'"

27
install-portable.bat Executable file
View File

@@ -0,0 +1,27 @@
@echo off
set sel="Select folder to place installation of portable wsltty"
for /f "usebackq delims=" %%f in (`powershell "(new-object -COM Shell.Application).BrowseForFolder(0, '%sel%', 0, 0).self.path"`) do set f=%%f
set instdir=%f%\wsltty
if "%f%"=="" (
echo no installation
exit
) else if not exist "%f%" (
echo invalid installation folder %instdir%
exit
)
call install "%instdir%" "%instdir%" /P
rem create shortcut
cd /D "%instdir%"
set instpath=%instdir:~2%
set target=%%COMSPEC%%
set minttyargs=/C bin\mintty.exe --WSL= --icon=/wsl.ico --configdir=. -~
set bridgeargs= -
set wdir=%instpath%
set icon=%instpath%\wsl.ico
cscript /nologo mkshortcut.vbs "/name:WSL Terminal Portable"

View File

@@ -1,9 +1,9 @@
@echo off @echo off
set refinstalldir=%%LOCALAPPDATA%%\wsltty set refinstalldir=%%LOCALAPPDATA%%\wsltty
set installdir="%LOCALAPPDATA%\wsltty"
set refconfigdir=%%APPDATA%%\wsltty set refconfigdir=%%APPDATA%%\wsltty
set configdir="%APPDATA%\wsltty" if "%installdir%" == "" set installdir="%LOCALAPPDATA%\wsltty"
if "%configdir%" == "" set configdir="%APPDATA%\wsltty"
call dequote installdir call dequote installdir
call dequote configdir call dequote configdir
set oldroot="%installdir%" set oldroot="%installdir%"
@@ -137,11 +137,16 @@ mkdir "%configdir%\themes" 2> nul:
mkdir "%configdir%\sounds" 2> nul: mkdir "%configdir%\sounds" 2> nul:
rem create config file if it does not yet exist rem create config file if it does not yet exist
if not exist "%configdir%\config" echo # To use common configuration in %%APPDATA%%\mintty, simply remove this file>"%configdir%\config" if exist "%configdir%\config" goto appconfig
echo # To use common configuration in %%APPDATA%%\mintty, simply remove this file>"%configdir%\config"
if "%3" == "/P" echo # Do not remove this file for WSLtty Portable>>"%configdir%\config"
:appconfig :appconfig
rem skip configuration for WSLtty Portable
if "%3" == "/P" goto end
rem distro-specific stuff: shortcuts and launch scripts rem distro-specific stuff: shortcuts and launch scripts
cd /D "%installdir%" cd /D "%installdir%"
echo Configuring for WSL distributions echo Configuring for WSL distributions

View File

@@ -10,16 +10,16 @@
# wsltty release # wsltty release
ver=3.4.7 ver=3.6.1
# wsltty appx release - must have 4 parts! # wsltty appx release - must have 4 parts!
verx=3.4.7.0 verx=3.6.1.0
############################## ##############################
# mintty release version # mintty release version
minttyver=3.4.7 minttyver=3.6.1
############################## ##############################
@@ -27,7 +27,7 @@ minttyver=3.4.7
repo=Biswa96/wslbridge2 repo=Biswa96/wslbridge2
# wslbridge2 master release version # wslbridge2 master release version
wslbridgever=0.6 wslbridgever=0.9
# wslbridge2 latest version # wslbridge2 latest version
#archive=master #archive=master
@@ -148,8 +148,13 @@ $(wslbridgedir).zip:
wslbridge-source: $(wslbridgedir).zip wslbridge-source: $(wslbridgedir).zip
unzip -o $(wslbridgedir).zip unzip -o $(wslbridgedir).zip
cp $(wslbridgedir)/LICENSE LICENSE.wslbridge2 cp $(wslbridgedir)/LICENSE LICENSE.wslbridge2
# patch # as a hotfix for #302, we assume the two patches are
cd $(wslbridgedir); patch -p1 < ../0001-notify-size-change-inband.patch # not needed anymore for wslbridge2 v0.9
# patch to fix #220
# test case in mintty: (sleep 0.1; echo -e "\e[31;80t") & wslbridge2
##cd $(wslbridgedir); patch -p1 < ../0001-notify-size-change-inband.patch
# patch to https://github.com/Biswa96/wslbridge2/commit/41575379b416703c49e2687e957440239a4cdfb7
##cd $(wslbridgedir); patch -p0 < ../0002-add-com-for-lifted-wsl.patch
wslbridge-frontend: wslbridge-source wslbridge-frontend: wslbridge-source
echo ------------- Compiling wslbridge2 frontend echo ------------- Compiling wslbridge2 frontend
@@ -185,6 +190,7 @@ appxversion=VERSION_SUFFIX=" wsltty appx $(verx)" WSLTTY_VERSION="$(verx)"
mintty-build: mintty-build:
# ensure rebuild of version-specific check and message # ensure rebuild of version-specific check and message
rm -f mintty-$(minttyver)/bin/*/windialog.o rm -f mintty-$(minttyver)/bin/*/windialog.o
rm -f mintty-$(minttyver)/bin/*/winmain.o
# build mintty # build mintty
cd mintty-$(minttyver)/src; make $(wslbuild) $(wslversion) cd mintty-$(minttyver)/src; make $(wslbuild) $(wslversion)
mkdir -p bin mkdir -p bin
@@ -276,14 +282,35 @@ cop: copcab
mkdir -p rel mkdir -p rel
cp -fl $(CAB)/* rel/ cp -fl $(CAB)/* rel/
installer: cop installer: cop cab normal-installer silent-installer portable-installer
cab:
# build cab archive
lcab -r $(CAB) rel/$(CAB).cab
normal-installer:
# prepare build of installer # prepare build of installer
rm -f rel/$(CAB)-install.exe rm -f rel/$(CAB)-install.exe
sed -e "s,%version%,$(ver)," -e "s,%arch%,$(arch)," makewinx.cfg > rel/wsltty.SED sed -e "s,%version%,$(ver)," -e "s,%arch%,$(arch)," makewinx.cfg > rel/wsltty.SED
# build installer # build installer
cd rel; iexpress /n wsltty.SED cd rel; iexpress /n wsltty.SED
# build cab archive
lcab -r $(CAB) rel/$(CAB).cab silent-installer:
# prepare build of installer
rm -f rel/$(CAB)-install-quiet.exe
cd rel; sed -e "/ShowInstallProgramWindow/ s/0/1/" -e "/HideExtractAnimation/ s/0/1/" -e "/InstallPrompt/ s/=.*/=/" -e "/FinishMessage/ s/=.*/=/" -e "/TargetName/ s/install.exe/install-quiet.exe/" wsltty.SED > wsltty-quiet.SED
# build installer
cd rel; iexpress /n wsltty-quiet.SED
InstallPrompt=Install Mintty terminal for WSL Portable?
FinishMessage=Mintty for WSL Portable installation finished
portable-installer:
# prepare build of installer
rm -f rel/$(CAB)-install-portable.exe
cd rel; sed -e "/InstallPrompt/ s/=.*/=$(InstallPrompt)/" -e "/FinishMessage/ s/=.*/=$(FinishMessage)/" -e "/AppLaunched/ s/install/install-portable/" -e "/TargetName/ s/install.exe/install-portable.exe/" wsltty.SED > wsltty-portable.SED
# build installer
cd rel; iexpress /n wsltty-portable.SED
install: cop installbat install: cop installbat

View File

@@ -60,6 +60,7 @@ FILE24="mintty.ico"
FILE25="mkshortcut.vbs" FILE25="mkshortcut.vbs"
FILE26="dequote.bat" FILE26="dequote.bat"
FILE27="cmd2.bat" FILE27="cmd2.bat"
FILE28="install-portable.bat"
[SourceFiles] [SourceFiles]
SourceFiles0=. SourceFiles0=.
@@ -93,4 +94,5 @@ SourceFiles0=.
%FILE25%= %FILE25%=
%FILE26%= %FILE26%=
%FILE27%= %FILE27%=
%FILE28%=