diff --git a/db/backup/backup_script.bat b/db/backup/backup_script.bat new file mode 100644 index 000000000..16e34c393 --- /dev/null +++ b/db/backup/backup_script.bat @@ -0,0 +1,118 @@ +:: MySQL backup script +:: +:: DESCRIPTION +:: +:: Create a mysqldump gziped file for each database and put them into +:: separate folders. +:: +:: DEPENDENCIES +:: +:: 7zip for Windows (optional) +:: +:: COMMAIL (optional) +:: - http://msdn.microsoft.com/en-us/library/e1y530dz(v=vs.90).aspx +:: +:: REFERENCES +:: - http://dev.mysql.com/doc/refman/5.1/en/mysqldump.html +:: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: ---------------------------------------------------------------------------- +:: START +:: ---------------------------------------------------------------------------- + +@echo off +color 0E +title MySQL backup. + +:: Set some variables +set bkupdir=C:\Users\logau\Downloads\Test\db\backup +::Dir where your SQL executables are (needs to have mysqldump in this foder to work) +set mysqldir="C:\Program Files\MySQL\MySQL Server 8.0\" +set logdir=C:\Users\logau\Downloads\Test\db\logs +:: Database settings +set db=wia_app +set dbuser=gauthier +set dbpass=WIASourcing2021 +::Path of your 7zip +set zip="C:\Program Files\7-Zip\7z.exe" +:: The number of day after which they get deleted +set deleteDay=30 +set endtime=0 + +:GETTIME + +:: get the date and then parse it into variables +for /f "tokens=1,2,3 delims=/ " %%i in ('date /t') do ( + set dd=%%i + set mm=%%j + set yy=%%k +) +:: get the time and then parse it into variables +for /f "tokens=1,2,3 delims=:" %%i in ('time /t') do ( + set hh=%%i + set ii=%%j +) +::on récupère les secondes +set ss=%time:~6,2% +:: If this is the second time through then go to the end of the file +if "%endtime%"=="1" goto END + +:: Create the filename suffix +set fn=_%yy%%mm%%dd%_%hh%%ii%%ss% + +:: Write to the log file +echo Beginning MySQLDump Process > %logdir%\LOG%fn%.txt +echo Start Time = %yy%-%mm%-%dd% %hh%:%ii%:%ss% >> %logdir%\LOG%fn%.txt +echo --------------------------- >> %logdir%\LOG%fn%.txt +echo. >> %logdir%\LOG%fn%.txt + +:: Create the backup sub-directory if it does not exist +if not exist %bkupdir%\%db%\ ( +echo Making Directory %db% +echo Making Directory %db% >> %logdir%\LOG%fn%.txt +mkdir %bkupdir%\%db% +) else ( +echo Directory %db% Exists +echo Directory %db% Exists >> %logdir%\LOG%fn%.txt + +::delete backups older than %deleteDay% days +echo Deleting files older than %deleteDay% days +echo Deleting files older than %deleteDay% days >> %logdir%\LOG%fn%.txt +forfiles /p %logdir%\ /s /m *.* /d -%deleteDay% /C "cmd /c echo deleting : @path" +forfiles /p %logdir%\ /s /m *.* /d -%deleteDay% /C "cmd /c echo deleting : @path >> %logdir%\LOG%fn%.txt" +forfiles /p %logdir%\ /s /m *.* /d -%deleteDay% /C "cmd /c del @path" + +::delete logfiles older than %deleteDay% days +echo Deleting logs older than %deleteDay% days +echo Deleting logs older than %deleteDay% days >> %logdir%\LOG%fn%.txt +forfiles /p %bkupdir%\%db%\ /s /m *.* /d -%deleteDay% /C "cmd /c echo deleting : @path" +forfiles /p %bkupdir%\%db%\ /s /m *.* /d -%deleteDay% /C "cmd /c echo deleting : @path >> %logdir%\LOG%fn%.txt" +forfiles /p %bkupdir%\%db%\ /s /m *.* /d -%deleteDay% /C "cmd /c del @path" +) + +:: Run mysqldump on each database and compress the data by piping through gZip +echo Backing up database %db%%fn%.sql.7z +echo Backing up database %db%%fn%.sql.7z >> %logdir%\LOG%fn%.txt +:: l'option SI de 7zip permet de récupérer le fichier à zipper via l'entrée standard Stdin +%mysqldir%\bin\mysqldump.exe -e --user=%dbuser% --password=%dbpass% -h localhost --databases %db% | %zip% a -si "%bkupdir%\%db%\%db%%fn%.sql.7z">>%logdir%\LOG%fn%.txt + +echo Done. +echo Done. >> %logdir%\LOG%fn%.txt + + +:: Go back and get the end time for the script +set endtime=1 +goto :GETTIME + +:END +:: Write to the log file +echo. >> %logdir%\LOG%fn%.txt +echo --------------------------- >> %logdir%\LOG%fn%.txt +echo MySQLDump Process Finished >> %logdir%\LOG%fn%.txt +echo End Time = %yy%-%mm%-%dd% %hh%:%ii%:%ss% >> %logdir%\LOG%fn%.txt +echo. >> %logdir%\LOG%fn%.txt + +:: Send the log file in an e-mail +:: c:\commail\commail -host=smtp.yourcompany.com -from="server " -to=serveradmins@yourcompany.com -subject="MySQL Backup" -msg=%logdir%\LOG%fn%.txt + +:: ---------------------------------------------------------------------------- +:: END advanced \ No newline at end of file diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/DBArchivingJob.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/DBArchivingJob.java new file mode 100644 index 000000000..45acf2bcb --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/DBArchivingJob.java @@ -0,0 +1,97 @@ +package org.jeecg.modules.business.domain.job; + +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; +import org.jeecg.modules.business.entity.Parcel; +import org.jeecg.modules.business.entity.ParcelTrace; +import org.jeecg.modules.business.entity.PlatformOrder; +import org.jeecg.modules.business.entity.PlatformOrderContent; +import org.jeecg.modules.business.service.IParcelService; +import org.jeecg.modules.business.service.IParcelTraceService; +import org.jeecg.modules.business.service.IPlatformOrderContentService; +import org.jeecg.modules.business.service.IPlatformOrderService; +import org.quartz.Job; +import org.quartz.JobDataMap; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.List; +import java.util.stream.Collectors; + +/** + * A job that archives entries from platform_order, platform_order_content, parcel, parcel_trace + */ +@Slf4j +@Component +public class DBArchivingJob implements Job { + @Autowired + @Setter + private IParcelService parcelService; + @Autowired + @Setter + private IParcelTraceService parcelTraceService; + @Autowired + @Setter + private IPlatformOrderService platformOrderService; + @Autowired + @Setter + private IPlatformOrderContentService platformOrderContentService; + private static final Integer DEFAULT_NUMBER_OF_DAYS = 365; + @Override + public void execute(JobExecutionContext context) throws JobExecutionException { + LocalDateTime endDateTime = LocalDateTime.now(ZoneId.of(ZoneId.SHORT_IDS.get("CTT"))); + LocalDateTime startDateTime = endDateTime.minusDays(DEFAULT_NUMBER_OF_DAYS); + JobDataMap jobDataMap = context.getMergedJobDataMap(); + String parameter = ((String) jobDataMap.get("parameter")); + if (parameter != null) { + try { + JSONObject jsonObject = new JSONObject(parameter); + if (!jsonObject.isNull("startDateTime")) { + String startDateStr = jsonObject.getString("startDateTime"); + startDateTime = LocalDateTime.parse(startDateStr); + } + if (!jsonObject.isNull("endDateTime")) { + String endDateStr = jsonObject.getString("endDateTime"); + endDateTime = LocalDateTime.parse(endDateStr); + } + } + catch (JSONException e) { + log.error("Error while parsing parameter as JSON, falling back to default parameters."); + } + } + if (!endDateTime.isAfter(startDateTime)) { + throw new RuntimeException("EndDateTime must be strictly greater than StartDateTime !"); + } + System.out.println("startdatetime : " + startDateTime + "\nendDateTime : " + endDateTime); + String startDate = startDateTime.toString().substring(0,10); + endDateTime = endDateTime.plusDays(1); + String endDate = endDateTime.toString().substring(0,10); + System.out.println("startdatetime : " + startDateTime + "\nendDateTime : " + endDateTime); + System.out.println("startdate : " + startDate + "\nendDate : " + endDate); + + // step1: sauvegarde des entrées dans des objets + // insertion des objets dans les tables d'archives + // drop les entrées dans l'ancienne table + + List platformOrders = platformOrderService.fetchPlatformOrdersToArchive(startDate, endDate); + List platformOrderIDs = platformOrders.stream().map(PlatformOrder::getId).collect(Collectors.toList()); + List platformOrderContents = platformOrderContentService.fetchPlatformOrderContentsToArchive(platformOrderIDs); + List platformOrderTrackingNumber = platformOrders.stream().map(PlatformOrder::getTrackingNumber).collect(Collectors.toList()); + try { + List parcels = parcelService.fetchParcelsToArchive(platformOrderTrackingNumber); + List parcelIDs = parcels.stream().map(Parcel::getId).collect(Collectors.toList()); + List parcelTraces = parcelTraceService.fetchParcelTracesToArchive(parcelIDs); + System.out.println("Parcel count : " + parcels.size()); + System.out.println("Parcel_trace count : " + parcelTraces.size()); + } catch (Exception ignored) { + + } + System.out.println(platformOrderIDs); + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ParcelMapper.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ParcelMapper.java index 5e2a5d136..c8e4bb730 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ParcelMapper.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ParcelMapper.java @@ -1,6 +1,7 @@ package org.jeecg.modules.business.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; import org.jeecg.modules.business.domain.api.equick.EQuickResponse; import org.jeecg.modules.business.domain.api.jt.JTParcelTrace; import org.jeecg.modules.business.domain.api.yd.YDTraceData; @@ -25,4 +26,5 @@ public interface ParcelMapper extends BaseMapper { void insertOrUpdateEQParcels(List parcels); void insertOrIgnoreYDParcels(List parcels); + List fetchParcelsToArchive(@Param("trackingNumbers") List trackingNumbers); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ParcelTraceMapper.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ParcelTraceMapper.java index 1a34a32bf..ca91a9ead 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ParcelTraceMapper.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ParcelTraceMapper.java @@ -28,4 +28,5 @@ public interface ParcelTraceMapper extends BaseMapper { void insertOrUpdateEQTraces(@Param("traces") List traceDetails); void insertOrIgnoreYDTraces(@Param("traces") List traceDetails); + List fetchParcelTracesToArchive(@Param("parcelIDs") List parcelIDs); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/PlatformOrderContentMapper.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/PlatformOrderContentMapper.java index 45d764a9c..98ff39b02 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/PlatformOrderContentMapper.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/PlatformOrderContentMapper.java @@ -71,4 +71,5 @@ public interface PlatformOrderContentMapper extends BaseMapper findUninvoicedShippedOrderContents(); + List fetchPlatformOrderContentsToArchive(@Param("orderIDs") List orderIDs); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/PlatformOrderMapper.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/PlatformOrderMapper.java index bfd2580b3..d12cc1aa9 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/PlatformOrderMapper.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/PlatformOrderMapper.java @@ -177,4 +177,5 @@ public interface PlatformOrderMapper extends BaseMapper { @Param("shops") List shops, @Param("erpStatuses") List erpStatuses, @Param("warehouses") List warehouses); + List fetchPlatformOrdersToArchive(@Param("startDate") String startDate, @Param("endDate") String endDate); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ParcelMapper.xml b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ParcelMapper.xml index ce8f02d77..c290e098e 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ParcelMapper.xml +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ParcelMapper.xml @@ -67,4 +67,12 @@ ) + \ No newline at end of file diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ParcelTraceMapper.xml b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ParcelTraceMapper.xml index 5f8805d18..0cf9a9277 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ParcelTraceMapper.xml +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ParcelTraceMapper.xml @@ -80,4 +80,12 @@ ) + diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/PlatformOrderContentMapper.xml b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/PlatformOrderContentMapper.xml index 0833bd5e2..b7543deae 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/PlatformOrderContentMapper.xml +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/PlatformOrderContentMapper.xml @@ -241,4 +241,12 @@ + diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/PlatformOrderMapper.xml b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/PlatformOrderMapper.xml index 0541d9b99..8ac078e23 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/PlatformOrderMapper.xml +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/PlatformOrderMapper.xml @@ -488,7 +488,7 @@ AND po.erp_status = 3; + diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IParcelService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IParcelService.java index e40884b9c..bb09b561f 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IParcelService.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IParcelService.java @@ -46,4 +46,5 @@ public interface IParcelService extends IService { void saveEQParcelAndTraces(List parcelTraces); void saveYDParcelAndTraces(List traceData); + List fetchParcelsToArchive(List trackingNumbers); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IParcelTraceService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IParcelTraceService.java index 174451320..dfd0e6112 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IParcelTraceService.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IParcelTraceService.java @@ -14,4 +14,5 @@ import java.util.List; public interface IParcelTraceService extends IService { public List selectByMainId(String mainId); + List fetchParcelTracesToArchive(List parcelIDs); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPlatformOrderContentService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPlatformOrderContentService.java index 1e890505b..2884d870c 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPlatformOrderContentService.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPlatformOrderContentService.java @@ -34,4 +34,5 @@ public interface IPlatformOrderContentService extends IService getAllSKUWeightsDiscountsServiceFees(); List searchOrderContent(List orderIDList); + List fetchPlatformOrderContentsToArchive(List orderIDs); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPlatformOrderService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPlatformOrderService.java index 5928db06d..dbdfc4428 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPlatformOrderService.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPlatformOrderService.java @@ -139,4 +139,13 @@ public interface IPlatformOrderService extends IService { List fetchOrderInShopsReadyForShopifySync(List shopCodes); List fetchUninvoicedShippedOrderIDInShops(String startDate, String endDate, List shops, List warehouses); + + /** + * Fetch all platform orders between 2 dates and of status erp_status 4 or 5 + * this list will then be archived + * @param startDate + * @param endDate + * @return List of PlatformOrder + */ + List fetchPlatformOrdersToArchive(String startDate, String endDate); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/ParcelServiceImpl.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/ParcelServiceImpl.java index 5c729265a..7132f533f 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/ParcelServiceImpl.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/ParcelServiceImpl.java @@ -218,4 +218,7 @@ public class ParcelServiceImpl extends ServiceImpl impleme } log.info("Finished inserting {} parcels and their traces into DB.", parcelTraces.size()); } + public List fetchParcelsToArchive(List trackingNumbers) { + return parcelMapper.fetchParcelsToArchive(trackingNumbers); + } } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/ParcelTraceServiceImpl.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/ParcelTraceServiceImpl.java index 9607939d0..ac7ff5e8f 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/ParcelTraceServiceImpl.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/ParcelTraceServiceImpl.java @@ -25,4 +25,7 @@ public class ParcelTraceServiceImpl extends ServiceImpl selectByMainId(String mainId) { return parcelTraceMapper.selectByMainId(mainId); } + public List fetchParcelTracesToArchive(List parcelIDs) { + return parcelTraceMapper.fetchParcelTracesToArchive(parcelIDs); + } } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/PlatformOrderServiceImpl.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/PlatformOrderServiceImpl.java index 23a9e6dce..fbe201bd6 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/PlatformOrderServiceImpl.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/PlatformOrderServiceImpl.java @@ -366,4 +366,8 @@ public class PlatformOrderServiceImpl extends ServiceImpl fetchUninvoicedShippedOrderIDInShops(String startDate, String endDate, List shops, List warehouses) { return platformOrderMap.fetchUninvoicedShippedOrderIDInShops(startDate, endDate, shops, warehouses); } + @Override + public List fetchPlatformOrdersToArchive(String startDate, String endDate) { + return platformOrderMap.fetchPlatformOrdersToArchive(startDate, endDate); + } } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/purchase/PlatformOrderContentServiceImpl.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/purchase/PlatformOrderContentServiceImpl.java index ffac38ce4..152f57be0 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/purchase/PlatformOrderContentServiceImpl.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/purchase/PlatformOrderContentServiceImpl.java @@ -20,8 +20,11 @@ import java.util.Map; @Service public class PlatformOrderContentServiceImpl extends ServiceImpl implements IPlatformOrderContentService { @Autowired - private PlatformOrderContentMapper platformOrderContentMapper; + private final PlatformOrderContentMapper platformOrderContentMapper; + public PlatformOrderContentServiceImpl(PlatformOrderContentMapper platformOrderContentMapper) { + this.platformOrderContentMapper = platformOrderContentMapper; + } public List getAllSKUWeightsDiscountsServiceFees() { return platformOrderContentMapper.getAllWeightsDiscountsServiceFees(); } @@ -51,5 +54,7 @@ public class PlatformOrderContentServiceImpl extends ServiceImpl fetchPlatformOrderContentsToArchive(List orderIDs) { + return platformOrderContentMapper.fetchPlatformOrderContentsToArchive(orderIDs); + } }