From f0ac1d59798b9eaad8824e9734312a13aa1c26cb Mon Sep 17 00:00:00 2001 From: GuentherJulian <69513769+GuentherJulian@users.noreply.github.com> Date: Thu, 10 Mar 2022 11:09:53 +0100 Subject: [PATCH 1/8] Adjust documentation (#1491) * fixed some types and links and corrected some parts of the documentation * adjust angular client guide * fixed typo * fixed requested changes --- documentation/Guide-to-the-Reader.asciidoc | 3 +- documentation/Home.asciidoc | 14 +- documentation/cobigen-usecases.asciidoc | 12 +- .../howto_angular-client-generation.asciidoc | 205 +++++++++++------- .../howto_ionic-client-generation.asciidoc | 18 +- .../images/howtos/angular4-gen/ng4gen_1.png | Bin 52357 -> 70473 bytes .../images/howtos/angular4-gen/ng4gen_5.png | Bin 45046 -> 23257 bytes .../images/howtos/angular4-gen/ng4gen_6.png | Bin 8887 -> 14046 bytes 8 files changed, 154 insertions(+), 98 deletions(-) diff --git a/documentation/Guide-to-the-Reader.asciidoc b/documentation/Guide-to-the-Reader.asciidoc index 91374ddff1..f608c05a5e 100644 --- a/documentation/Guide-to-the-Reader.asciidoc +++ b/documentation/Guide-to-the-Reader.asciidoc @@ -2,9 +2,10 @@ Dependent on the intention you are reading this document, you might be most interested in the following chapters: -* If this is *your first contact with CobiGen*, you will be interested in the link:home[general purpose] of CobiGen, in the link:mgmt_license-agreement[licensing of CobiGen], as well as in the link:mgmt_shared-service[Shared Service] provided for CobiGen. Additionally, there are some link:cobigen-usecases[general use cases], which are currently implemented and maintained to be used out of the box. +* If this is *your first contact with CobiGen*, you will be interested in the link:home[general purpose] of CobiGen. Additionally, there are some link:cobigen-usecases[general use cases], which are currently implemented and maintained to be used out of the box. * As a **user of the CobiGen Eclipse integration**, you should focus on the link:cobigen-eclipse_installation[Installation] and link:cobigen-eclipse_usage[Usage] chapters to get a good introduction about how to use CobiGen in eclipse. + * As a **user of the Maven integration**, you should focus on the link:cobigen-maven_configuration[Maven configuration] chapter, which guides you through the integration of CobiGen into your build configuration. * If you like to *adapt the configuration of CobiGen*, you have to step deeper into the link:cobigen-core_configuration[configuration guide] as well as into the plug-in configuration extensions for the link:cobigen-javaplugin[Java Plug-in], link:cobigen-xmlplugin[XML-Plugin], link:cobigen-propertyplugin[Java Property Plug-in], as well as for the link:cobigen-textmerger[Text-Merger Plug-in]. diff --git a/documentation/Home.asciidoc b/documentation/Home.asciidoc index d58c0cfdfe..b751868f18 100644 --- a/documentation/Home.asciidoc +++ b/documentation/Home.asciidoc @@ -6,7 +6,7 @@ toc::[] == Overview -CobiGen is a *generic incremental generator* for end to end code generation tasks, mostly used in Java projects. +CobiGen is a *generic incremental generator* for end-to-end code generation tasks, mostly used in Java projects. Due to a template-based approach, CobiGen *generates any set of text-based documents and document fragments*. **Input (currently):** @@ -28,11 +28,11 @@ CobiGen is build as an extensible framework for incremental code generation. It == Features and Characteristics -* Generate fresh files across all the layers of a application - ready to run. -* Add on to existing files merging code into it. E.g. generate new methods into existing java classes or adding nodes to an XML file. Merging of contents into existing files will be done using structural merge mechanisms. +* Generate fresh files across all the layers of an application - ready to run. +* Add on to existing files merging code into it. E.g. generate new methods into existing Java classes or adding nodes to an XML file. Merging of contents into existing files will be done using structural merge mechanisms. * Structural merge mechanisms are currently implemented for Java, XML, Java Property Syntax, JSON, Basic `HTML`, Text Append, TypeScript. * Conflicts can be resolved individually but automatically by former configuration for each template. -* CobiGen provides an link:cobigen-eclipse_usage[Eclipse integration] as well as a link:cobigen-maven_configuration[Maven Integration]. +* CobiGen provides an link:cobigen-eclipse_usage[Eclipse integration] as well as a link:cobigen-maven_configuration[Maven integration]. * CobiGen comes with an extensive documentation for link:cobigen-eclipse_installation[users] and link:cobigen-core_configuration[developers]. * Templates can be fully tailored to project needs - this is considered as a simple task. @@ -41,10 +41,10 @@ CobiGen is build as an extensible framework for incremental code generation. It General applications: * Generation of a **Java CRUD application based on link:https://github.com/devonfw/[devonfw] architecture** including all software-layers on the server plus code for JS-clients (Angular). You can find details link:cobigen-usecases[here]. -* Generation of a *Java `CRUD` application according to the Register Factory architecture*. Persistence entities are the input for generation. +* Generation of a *Java CRUD application according to the Register Factory architecture*. Persistence entities are the input for generation. * Generation of *builder classes for generating test data* for JUnit-Tests. Input are the persistence entities. -* Generation of a **`EXT JS` 6** client with full `CRUD` operations connected a devon4j server. -* Generation of a **`Angular` 6** client with full `CRUD` operations connected a devon4j server. +* Generation of an **Angular 13** client with full `CRUD` operations connected to a devon4j server based on link:https://github.com/devonfw/devon4ng-application-template[devon4ng application template]. +* Generation of an **Ionic** client with full `CRUD` operations connected to a devon4j server based on link:https://github.com/devonfw/devon4ng-ionic-application-template[devon4ng Ionic template]. Project-specific applications in the past: diff --git a/documentation/cobigen-usecases.asciidoc b/documentation/cobigen-usecases.asciidoc index 8610959b49..bda7e58f5a 100644 --- a/documentation/cobigen-usecases.asciidoc +++ b/documentation/cobigen-usecases.asciidoc @@ -3,7 +3,7 @@ toc::[] = General use cases -In addition to the link:Home#selection-of-current-and-past-cobigen-applications[selection of CobiGen applications] introduced before, this chapter provides a more detailed overview about the currently implemented and maintained general use cases. These can be used by any project following a supported reference architecture as e.g. the link:https://github.com/devonfw[devonfw] or link:http://www.bva.bund.de/SharedDocs/Downloads/DE/BIT/RegisterFactory/Whitepaper_Register_Factory.html[Register Factory]. +In addition to the link:Home#selection-of-current-and-past-cobigen-applications[selection of CobiGen applications] introduced before, this chapter provides a more detailed overview about the currently implemented and maintained general use cases. These can be used by any project following a supported reference architecture such as link:https://github.com/devonfw[devonfw] or link:https://www.bva.bund.de/SharedDocs/Downloads/DE/Aufgaben/IT/RegisterFactory/Whitepaper_Register_Factory.html[Register Factory]. == devon4j @@ -11,11 +11,11 @@ With our templates for link:https://github.com/devonfw/devon4j[devon4j], you can === CRUD server application for devon4j -For the server, the required files for all architectural layers (Data access, logic, and service layer) can be created based on your Entity class. After the generation, you have CRUD functionality for the entity from bottom to top which can be accessed via a RESTful web service. Details are provided in the link:https://github.com/devonfw/devon/wiki/tutorial-devon-generator[devonfw wiki]. +For the server, the required files for all architectural layers (data access, logic, and service layer) can be created based on your Entity class. After the generation, you have CRUD functionality for the entity from bottom to top which can be accessed via a RESTful web service. Details are provided in the link:https://github.com/devonfw/devon4j/wiki/architecture[devon4j wiki] or in our link:https://github.com/devonfw/jump-the-queue/wiki/devon4j-components#the-component-structure-using-cobigen['Jump the queue' reference application]. === CRUD client application for devon4ng -Based on the REST services on the server, you can also generate an link:https://angularjs.org/[Angular] client based on link:https://github.com/devonfw/devon4ng[devon4ng]. With the help of link:https://nodejs.org/[Node.js], you have a working client application for displaying your entities within minutes! +Based on the REST services on the server, you can generate an link:https://angularjs.org/[Angular] client or even an link:https://ionicframework.com/[Ionic] mobile client based on link:https://github.com/devonfw/devon4ng[devon4ng]. With the help of link:https://nodejs.org/[Node.js], you have a working client application for displaying your entities within minutes! === Test data Builder for devon4j @@ -65,7 +65,7 @@ The Builder classes generated by CobiGen try to tackle this inconvenience by pro public class PersonBuilder { private void fillMandatoryFields() { - firstname("lasdjfaöskdlfja"); + firstname("Heinz"); address(new AddressBuilder().createNew()); }; private void fillMandatoryFields_custom() {...}; @@ -88,7 +88,7 @@ Finally, the builder API provides different methods to create new objects. * `createNew()` just creates a new object from the builder specification and returns it. * `persist(EntityManager)` will create a new object from the builder specification and persists it to the database. -* `persistAndDuplicate(EntityManager, int)` will create the given amount of objects form the builder specification and persists all of these. After the initial generation of each builder, you might want to adapt the method body as you will most probably not be able to persist more than one object with the same field assignments to the database due to `unique` constraints. Thus, please see the generated comment in the method to adapt `unique` fields accordingly before persisting to the database. +* `persistAndDuplicate(EntityManager, int)` will create the given amount of objects from the builder specification and persists all of these. After the initial generation of each builder, you might want to adapt the method body as you will most probably not be able to persist more than one object with the same field assignments to the database due to `unique` constraints. Thus, please see the generated comment in the method to adapt `unique` fields accordingly before persisting to the database. ==== Custom Builder for Business Needs @@ -113,7 +113,7 @@ Generates a CRUD application with persistence entities as inputs. This includes === Test data Builder -Analogous to xref:testdata-builder-for-devon4j[Test data Builder for devon4J] +Analogous to xref:test-data-builder-for-devon4j[Test data Builder for devon4J] === Test documentation diff --git a/documentation/howto_angular-client-generation.asciidoc b/documentation/howto_angular-client-generation.asciidoc index 52de1f4fe5..40d1b53ff6 100644 --- a/documentation/howto_angular-client-generation.asciidoc +++ b/documentation/howto_angular-client-generation.asciidoc @@ -1,9 +1,9 @@ :toc: macro toc::[] -= Angular 8 Client Generation += Angular Client Generation -The generation can create a full Angular 8 client using the devon4ng-application-template package located at `workspaces/examples` folder of the distribution. For more details about this package, please refer link:https://github.com/devonfw/devon4ng-application-template[here]. +The generation can create a full Angular client (Angular 13, as of March 2022) using the devon4ng-application-template package located at `workspaces/examples` folder of the distribution. For more details about this package, please refer link:https://github.com/devonfw/devon4ng-application-template[here]. Take into account that the TypeScript merging for CobiGen needs Node 6 or higher to be installed at your machine. @@ -17,7 +17,7 @@ Install yarn globally: npm install -g yarn ``` -== Angular 8 workspace +== Angular workspace The output location of the generation can be defined editing the `*__cobigen.properties__*` file located at *__crud_angular_client_app/templates__* folder of the *__CobiGen_Templates__* project. @@ -48,7 +48,7 @@ root/ ``` -Once the output path is chosen, copy the files of the link:https://github.com/devonfw/devon4ng-application-template[`DEVON4NG-APPLICATION-TEMPLATE`] repository into this output path. +Once the output path is chosen, copy the files of the link:https://github.com/devonfw/devon4ng-application-template[devon4ng-application-template] repository into this output path. == Install Node dependencies @@ -79,41 +79,58 @@ image::images/howtos/angular4-gen/ng4gen_3.png[CobiGen Client Generation Wizard == Routing -Due to the nature of the TypeScript merger, currently it is not possible to merge the array of path objects of the routings at `app.routing.ts` file properly, so the modification should be done by hand on this file. However, the import related to the new component generated is added. +Due to the nature of the TypeScript merger, currently it is not possible to merge the array of path objects of the routings at `app-routing.module.ts` file properly, so the modification should be done by hand on this file. However, the import related to the new component generated is added. -This would be the generated `app-routing.module` file: +This would be the generated `app-routing.module.ts` file: [source, ts] ---- -import { Routes, RouterModule } from '@angular/router'; -import { LoginComponent } from './login/login.component'; -import { AuthGuard } from './shared/security/auth-guard.service'; -import { InitialPageComponent } from './initial-page/initial-page.component'; -import { HomeComponent } from './home/home.component'; -import { SampleDataGridComponent } from './sampledata/sampledata-grid/sampledata-grid.component'; -//Routing array -const appRoutes: Routes = [{ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { AuthGuard } from './core/security/auth-guard.service'; +import { NavBarComponent } from './layout/nav-bar/nav-bar.component'; + +const routes: Routes = [ + { + path: '', + redirectTo: '/login', + pathMatch: 'full', + }, + { path: 'login', - component: LoginComponent -}, { + loadChildren: () => + import('./auth/auth.module').then(m => m.AuthDataModule), + }, + { path: 'home', - component: HomeComponent, - canActivate: [AuthGuard], - children: [{ - path: '', - redirectTo: '/home/initialPage', - pathMatch: 'full', - canActivate: [AuthGuard] - }, { - path: 'initialPage', - component: InitialPageComponent, - canActivate: [AuthGuard] - }] -}, { + component: NavBarComponent, + canActivateChild: [AuthGuard], + children: [ + { + path: 'initial', + loadChildren: () => + import('./home/initial-page/initial-page.module').then( + m => m.InitialPageModule, + ), + }, + { + path: 'sampleData', + loadChildren: () => + import('./sampledata/sampledata.module').then( + m => m.SampleDataModule, + ), + }, + ], + }, + { path: '**', redirectTo: '/login', - pathMatch: 'full' -}]; -export const routing = RouterModule.forRoot(appRoutes); + }, +]; +@NgModule({ + imports: [RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' })], + exports: [RouterModule], +}) +export class AppRoutingModule {} ---- Adding the following to the children object of `home` will add a new side menu entry to the component generated: @@ -121,57 +138,95 @@ Adding the following to the children object of `home` will add a new side menu e [source, ts] ---- { - path: 'sampleData', - component: SampleDataGridComponent, - canActivate: [AuthGuard], -} + path: 'employee', + loadChildren: () => + import('./employee/employee.module').then( + m => m.EmployeeModule, + ) +} ---- [source, ts] ---- -import { Routes, RouterModule } from '@angular/router'; -import { LoginComponent } from './login/login.component'; -import { AuthGuard } from './shared/security/auth-guard.service'; -import { InitialPageComponent } from './initial-page/initial-page.component'; -import { HomeComponent } from './home/home.component'; -import { SampleDataGridComponent } from './sampledata/sampledata-grid/sampledata-grid.component'; -//Routing array -const appRoutes: Routes = [{ - path: 'login', - component: LoginComponent -}, { - path: 'home', - component: HomeComponent, - canActivate: [AuthGuard], - children: [{ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { AuthGuard } from './core/security/auth-guard.service'; +import { NavBarComponent } from './layout/nav-bar/nav-bar.component'; + + +const routes: Routes = [{ path: '', - redirectTo: '/home/initialPage', - pathMatch: 'full', - canActivate: [AuthGuard] - }, { - path: 'initialPage', - component: InitialPageComponent, - canActivate: [AuthGuard] - }, { - path: 'sampleData', - component: SampleDataGridComponent, - canActivate: [AuthGuard], - }] -}, { - path: '**', - redirectTo: '/login', - pathMatch: 'full' -}]; -export const routing = RouterModule.forRoot(appRoutes); + redirectTo: '/login', + pathMatch: 'full' + }, + { + path: 'login', + loadChildren: () => + import('./auth/auth.module').then(m => m.AuthDataModule) + }, + { + path: 'home', + component: NavBarComponent, + canActivateChild: [ + AuthGuard + ], + children: [{ + path: 'initial', + loadChildren: () => + import('./home/initial-page/initial-page.module').then( + m => m.InitialPageModule, + ) + }, + { + path: 'sampleData', + loadChildren: () => + import('./sampledata/sampledata.module').then( + m => m.SampleDataModule, + ) + }, + { + path: 'employee', + loadChildren: () => + import('./employee/employee.module').then( + m => m.EmployeeModule, + ) + } + ] + }, + { + path: '**', + redirectTo: '/login' + } +]; + +@NgModule({ + imports: [ + RouterModule.forRoot(routes) + ], + exports: [ + RouterModule + ] +}) +export class AppRoutingModule { + +} ---- image::images/howtos/angular4-gen/ng4gen_6.png[`APP SideMenu`,width="450"link="images/howtos/angular4-gen/ng4gen_6.png"] == `JWT` Authentication -If you are using a backend server with `JWT` Authentication (there is a sample in `workspaces/folder` called `*sampleJwt*`) you have to specify the Angular application to use this kind of authentication. +If you are using a backend server with `JWT` authentication, you need to specify this type of authentication to be used by your Angular application (default when generating from the devon4ng template). + +.link:https://github.com/devonfw/devon4ng-application-template/blob/develop/src/environments/environment.ts[environment.ts] +``` +export const environment = { + ..., + security: 'jwt', +}; +``` -By default the variable is set to CSRF but you can change it to `JWT` by going to the link:https://github.com/devonfw/devon4ng-application-template/blob/develop/src/environments/environment.ts#L10[Enviroment.ts] and setting `security: 'jwt'`. +An alternative would be to set `security: 'csrf'`. For more details, see the link:https://github.com/devonfw/devon4j/wiki/guide-csrf[devon4j CSRF guide]. == Running @@ -179,20 +234,20 @@ First of all, run your devon4j java server by right clicking on the `SpringBootA image::images/howtos/angular4-gen/ng4gen_4.png[Starting `SpringBoot`,width="450"link="images/howtos/angular4-gen/ng4gen_4.png"] -Once the the server is running, open a Devon console at the output directory defined previously and run: +Once the the server is running, open a devonfw console at the output directory defined previously and run: ``` ng serve --open ``` -This will run the Angular 8 application at: +This will run the Angular application at: [source, URL] ---- http://localhost:4200 ---- -image::images/howtos/angular4-gen/ng4gen_5.png[Running Angular 8 app,width="450"link="images/howtos/angular4-gen/ng4gen_5.png"] +image::images/howtos/angular4-gen/ng4gen_5.png[Running Angular app,width="450"link="images/howtos/angular4-gen/ng4gen_5.png"] -Once finished, the browser will open automatically at the previously stated localhost URL showing the Angular 8 application. You can use the credentials set at the devon4j java server to login. +Once finished, the browser will open automatically at the previously stated localhost URL showing the Angular application. You can use the credentials set at the devon4j java server to login. diff --git a/documentation/howto_ionic-client-generation.asciidoc b/documentation/howto_ionic-client-generation.asciidoc index 1c1e9312d8..d23199b846 100644 --- a/documentation/howto_ionic-client-generation.asciidoc +++ b/documentation/howto_ionic-client-generation.asciidoc @@ -10,29 +10,29 @@ NOTE: This is a short introduction to the Ionic generation. For a deeper tutoria == Prerequisites -Before starting, make sure you already have in your computer: +Before starting, make sure you have the following things already installed on your machine: -- link:https://ionicframework.com/docs/installation/cli[Ionic]: by following the steps defined on that page. -It includes installing: -** link:https://nodejs.org/en/[NodeJS]: We have to use "NPM" for downloading packages. +- link:https://ionicframework.com/docs/installation/cli[Ionic]: follow the steps described on the Ionic page. +It includes the installation of: +** link:https://nodejs.org/en/[Node.js]: We have to use the `npm` package manager for downloading packages. ** Ionic CLI. - link:https://capacitor.ionicframework.com/docs/getting-started/[Capacitor]: Necessary to access to native device features. If _CobiGen_Templates_ are not already downloaded, follow the next steps: -- Right click on any file of your workspace _CobiGen > Update Templates_ and now you are able to start the generation. +- Right click on any file in your Eclipse workspace. Select _CobiGen -> Update Templates..._ from the context menu and now you are able to start the generation. -- If you want to adapt them, click _Adapt Templates_ and you should have the _CobiGen_Templates_ as a new project in Eclipse's workspace. +- If you want to adapt the templates, select _CobiGen -> Adapt Templates..._ from the menu and you should have the _CobiGen_Templates_ as a new project in your Eclipse's workspace. After following those steps correctly, you should have the latest version of the templates ready to use. == Generation -We are going to generate the CRUD into a **sample application** that we have developed for -testing this functionality. It is present on your `workspaces/examples` folder (devon4ng-ionic-application-template). If you do not see it, you can clone or download it from link:https://github.com/devonfw/devon4ng-ionic-application-template[here]. +We are going to generate the CRUD functions into a **sample application**. +First, clone or download the link:https://github.com/devonfw/devon4ng-ionic-application-template[devon4ng Ionic template] in your workspace. -After having that sample app, please create an link:https://github.com/devonfw/devon4ng/wiki/tutorial-newapp[devon4j project] and then start implementing the ETO: You will find an example link:https://github.com/devonfw/devon4j/blob/develop/samples/core/src/main/java/io/devonfw/gastronomy/restaurant/tablemanagement/logic/api/to/TableEto.java[here]. +After that, please create a link:https://github.com/devonfw/devon4ng/wiki/tutorial-newapp[devon4j project] and then start implementing the ETO: you can find an example link:https://github.com/devonfw/devon4j/blob/develop/samples/core/src/main/java/io/devonfw/gastronomy/restaurant/tablemanagement/logic/api/to/TableEto.java[here]. As you can see, `TableEto` contains 3 attributes: 2 of them are `Long` and the third one `TableState` is an enum that you will find link:https://github.com/devonfw/devon4j/blob/develop/samples/core/src/main/java/io/devonfw/gastronomy/restaurant/tablemanagement/common/api/datatype/TableState.java[here]. diff --git a/documentation/images/howtos/angular4-gen/ng4gen_1.png b/documentation/images/howtos/angular4-gen/ng4gen_1.png index 06ed8e1b9683cee36fb80068e1e2ecc36f7ea0eb..b0e0b283664cdde0f61c7a7e18bbf9005808bf41 100644 GIT binary patch literal 70473 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

grZJTo6_rUpC0xgXV4WaA5F6O5L;i5(J`{ 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 literal 52357 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 HHv;|}`U4z^ diff --git a/documentation/images/howtos/angular4-gen/ng4gen_5.png b/documentation/images/howtos/angular4-gen/ng4gen_5.png index d7e23f66485bff98bf04162cdf12ea22a483510e..c7fa36cfab2c7478bd4c1e10e9aa28387a69ff94 100644 GIT binary patch literal 23257 zcmcG#2~<;Cw>20QQAETmS5ZNtUIkGBl^z1IyDHK|K}DpAsE9P7Z$g(SAY4?4ih^{B zs1Q*g^gRRw$pwTcU4Q@y1c(p<2~7fN>)`#~dtbd*HLB_#^)qmsad0PR?|t^3d#<_W zO1NTkQDMv8Eg%p`!Q#?+TM%di76e-Ndb2F>mlTS&0&rOuXnXN2sIW_Q8n}^hKVy9c z1S-bJi(EGX_i}!h90Eb09YJgV){Wi=BSD~BJ{ITCTtm9BM{1KME~QLyBOmh4Du0S7 zM@1tF?rw?knE2~y_(PA_=TA3YxRj@S)3xZ4$Nty08jf$GpB^rNoZa6N{wU?_r9AK< z_`{C769*JKG0w^OJxzaL(t2g;p>1N zf{Ns$HP)`T?PXwV*T%xlz!*WGht9u2el@5)h+Mz+hmb!xGHch_Cv>^B>%h(?rL}9( zvH!1MFf#%bHAAb`CI|%b9vfNfVa&oF~Fl*1=h2CCA=INu@lWz49is>ovuX+bzLe9veP zfpjr6OP`6BPaTyW?#l#&Kz>y9CS9wz^v@4#c3ne9e(ARcOo6mKDlfBNz80qhHc* zm-d$vFU}hyU090IAP~~>EGIvz8?V&Ut56fPn3C`)>fK&~sivWu^Zv}Zapd6lifqZr z(@EKHO}h#sZ_#ctJvdg@apMU#Gb>&deI-60Kf_6LRKhU|l(AaK#!au9vhjYR zbF0&bP6VTxE7EuhtV06B<4|)2Du#5@EY3-YAht3;RiJ&MMDga&#TQ6dOY1`=Et%lo zKXk!7q~#l^)U$J{`08GHH(_3yre#9MX8nDCJ0~4~46uF@mqOSM!gr3P;LL*8%zB^(Mcb=W)^CFb2X>sz)sdgYP|dt!gED2Hvy2D?~h zEWLS`5Yu~@sz};vT{FvVZI$f7kf=nnem|5|n4u=0TwlcOiOBN8wex&wyeqyp@uun# zkZRsB!oD1?ZeeH!13tk0y|UoG&^E&ILqqTC9{xOrY+K!LeB6+ol+$j>Fr}bs^LsT$ zCH0arl6@e`b7IJy>?^8SS{w4;3;N;=FXB!fIE$GsDPIm_em)dD{Ha$`IKn=)Pl+dX z+6{Gy%9A*}yDtSj6n@`GKH)zwrSW`Jp*Q0>wXMKW?Xhdb`)-vqoAY&aZ`L!4;^dDB zljDIids6tU%cc{uGku!F3>|N{C$X-AH2=Ee{Mh95$=+$}-CuYKfwMeJpiO?2v_>pc zDwtW!cz~Pa5j>uzuudMPPGq9T`r*c?SYmyk=)Q19vZo(cf!9NM4*8PdPB(@|kMRYr zNw(szj6lJ)S3|Flk`sMl!}0HOw}pzl{ZL*XhV1v^Lf}IvL~?KC9|>)LyWhJt~2OPy-!sc%De%qE(?s(duv zg1kH9bIp05f7IxqmQg25rFhr0p01+Eflx;>cR&?WlGPg)&IrPk7e(cX7i#ogys)qz zb}#k`=pnez1PC?KcULiwoP3ecmkEF2xi-paC|d)OY;!)4O$m>skjohw$N59{4+5>F zv&Iqz8|GrKir$TmB7Thmr(~(Vr(CS4%V96_d|Tb~oKh3Ig&%n$QUIG0ylWHrHPf(8 zdx>~S)^L6xxRYqOHD>jrc{K<@X)CWHM z0d4JAhV#z2%%-?~VY!bq=%IQG647~~CS$6P#n)A(7W)zcnVMPPP-)kS)oa$NtKs0u zE+PV+H>?8YR&lC?@Gw-cgT<$)9IgjHhg}&}!V~4QX~q;>k@Uexy2M#ma<>Lr@IF`U zLj3w6F<@&p`~HZrxb*zLUZ>+`>;h)4)wuq*7Ia@o)q!2=dR%K`tWj)0wK2(X?n|Pb z?;B@7Q$%W3P^>^8SR1gzom0ICX}2m>Jd-G#9Jss`gBDHy$7u5j)QDvKn*uTm9ARE# z@#SVA0XD>3%KBtXyfKG_2`F{_Y;RnD89Yq5EYR?YnZ!w1U};`SH_sWJOOCRb79oYW zBywc+YZd#0*VR%ql8QqjADirmDhy!weqPLY=>_+R9E$P~A~GmgoR+|lg4)?{;Ueu3 zQ_I~~SNJXBE1pD(Z}Io3kgOHK0Z)N@UiV5lYdvVR;sElA-{MP^aPsJp*wNFM4Y%?y z>^tiWuk;36KZ~pBlrU6WeWcCz&Kn1(s^8C}YtDYSH()=0fz2kAMHPzQ=@ma0uvfbS zH4%Qo5FeT)T49piGFi+%Mo7%vM#T=BUuHl3Dt1g?*~Z$s45QA^!OydgCE~KbIZ9<) z(Vz0~3s;6WT@?o2$ARtm?*d9~@|@gAp}FE_6E5ohEV=_2nNNFiW55mHLFf z@>-sx9?zvco-x>Jh5Ztu)Tz~a%_DMje5GE)S1g(}ldJmqt1yZzBzl9CynY6 z35bgkM=7@#OwT7k0|`XS;5=e(c%B$O9{Tq<@s?vC>UroiH^Sl>a9(rzb7Gj%mE6@r z1uX5F6)0Zry-jAzJ{vXi0jn!Ize5=FTM|bCIoGNe1Lq5aMNY~3416yUpc$#Jwqj`_ zngLQmt7(HnxM20?R*iKiseDzIK;OKTGzSZqnG-J~Ip2|ugM-ZA%mL&~|VM4sV zE^?|B-sT|^!cH;dEn1xBECV;4b-$`;bTndyobZg+(#M4~10Vrq_{@_q!sG|e8<^Um1e{94bHwbH*wK~>I zBR9o)r~xndzpR%iuwL*uP;oL)S3VOcYfc;Rc-&BtwBMh;|a zCq{5{iG|;Dbmb&FoD_0r8To2be9HY!9{YzlM?LI@$DORZ8fnd^OpA4vVAj$+Thoz* z&pi#c)rNyE|LWQ6CRZEr*8seD%qWYuDu%0}47U3oy6|;rlXl zsSbiz(1V~ode+Vc!Umq+D&wr6cagdWT)K0#<*3!$Z!NxaE&5hv@d?GRhoD{*qOs)g=Z&O z;pBa#!OYNbk!AF`LaDlVpSpNih@pbpGbO*}Nnlyzy(6m}a#njEyoZ>>%So~v7Oec{ zN^Ij_bd}x*I81FKrQsSHFQ^Veoi9XtRe-x3UGstN9zQ9E74(+!yso{n$ybNndnb3r z^K4G51%?>)#%NjTo$E+LL%O(@^@jIq$o^F93wlmixOcNPEv~yk`E^F{<;kO}?=>rx zrk#ZG!QxjT${{_ie|J&lb|D^!2@Jn-#<>JB;J!M^^W9zaa|8@^O%&5-S9KAXeDPE`!LmO4G zCh`X*Vx~?fg}|;DUwvQOWjj>J#4KX+`bkVeXDWGqq@-X%5K5M8c(~W94mA8ZqCry7 zsaUn|9Oo5XR|fNV-3L9t%VVBTA1SZz{X!2~S%Da%5G*YjvW4HXA%dqM)LOc(aj&Ji zOFSQ!p%c)lODSj`ySpe_wp?5_Q`!xxbj8q(zX@kWoNr@YUd=C8HAmx;HLwxpVWuRz z`kbabd7qwyb|INOw%jR0R#^W>lTu^OaYZaVT?gLEG6e1l26d4$qJYgv_jKl0;igZ~ z%-wYp_Y0xLf1OL0scbmD_j~fGj{H=riv_injmyAv!TwB?xh;jk<@*j4p-tO< zEcgpKOJ&kFYisEsin7cI4!BHm?jatuCx4K>$6ZcDsIm9-uB$Wah;fgAJ|I*x^q2II zxpUyLTVhdI6)KT3{f*}&1$ob^Hrd67xdbU#I)m*3&zib-YIYL-^g+!yJO1eepA$S| zojQgbQt|gZkrHj`@pfvae1q23Q|^9~JlrWOryU#mwnZXhMldN0$K0mJJ;9eL?oO#`FbL^P^4@3Fj~IRXKG#3e8AM+; zWQf>!_uTZ7ETFj^TUfEdP9K%cA+LC^BE<-Tih&hB%ni73eljhG2n&Aq<39>O1Y?j zWrvX2CScs;tpObtp*k=aVN{1xmCH|f4Irrw;U-=!THVO0ysFBs-x zxex(isFeh+nCF{{WbPvw{Ro0sEy;CCCGVg2&gS;r3|9jU6SSh;ky_BSc|vxMFur~l zEBF}png81R4wQlYR_NX=D)WolN=18Msg0Vfzn5(b2?DNTL12i+ zCskjD>^FX|$U&TNe4~aI3<334A}IGk2m4>e2j4@Vb1=mbB0{kaweQ*FZ<1T;?88YOta6Jh}J3@Mba;HAY zb0632c0eLSu<7TQPH<$>+5Bf=@wpTFi_MwS!&UAxAq3pP&?x=Mw&0`G z_(jvOaXC=q;n|bi^$#5z0oZy7sAE-I*1+djA-ZZ4AgVQ9zdgQ@?&2?QHrxMyA*EGq ziR|6lSU)ZZby$*yIUPr;NhZIGc*Jd;hRQ3+i$n=IgoZZNBTkV=HZ=BCy;hO_hyFEu z4&)t64_y1$c1TtLsBsm5^x@Bz&QcVAI&}&zmGBdwQG!ut!%4rDhE;}637gzG-x9!ZtJRRzV%!f|2Xi{%P77$~c)4vL)~*!Zc_9p565w8$yMn zd{8S6lBm594K|!pW(N?6yPL6lC(b^97M<2m0Y0Yy15@30h@Ld{$b}~dEY4>`J_UAY zymX0(oxN*hfJLoubkM5jhMp-@e0g>ItV@Sd=S}6c*77M8!=i{In3=6jJ&=qlc*_)AJtLt$(0;ib4BP_N1v) zhe8{BRl>P;@~ZY1i69`%SqY+_pJIN>aSQfN$6I;O5ywCVrEwJrQAp#?Ke#oC848&k zD!if&vr?KoI7^0XJd9j_q&kkS8yTd(C1S5?DL4mU1v#(-c0{EaGjZ=JEYhXYgX0ae zMRvQdhdbqh|11Yz>?^s(*-8)=8On53)rpC*t=T?y>b$Mkx#B;Cn?SQ(*EzEr-YP_D zxbfasL~TF5k<1xFIoYR>CdcIPd8VElnv_nr9gZe%*Xx|W6pnsyL>bb2F|d=Dg|1$8TodyfSGWIL(x7lXIC%Yk zw#nECTdhgfLdBnwL|F+(u+3oE0Lejwht#p0aA9Rz_ZRyb5GYqWn2{=Og_oAJOnBMf z;@u2@^KFNuH`p8e>NlI4i)Vf(cv}K^=PhX|oe~<@Ekziy`HxyB^XPe(h47w+TflpM zGv93}+0NM|Ybw@;38UWjECg|`<%kI$;D@Y=C4n*;b6>UFrh(PH>hi6~MH-c1*|14> z^x|-wg^GJWP97VHVX~_W>4Q+VlhQ!p0RXb6YL^nx)h%jzola9RGfKC6mQDa5qO<91(E>)D^PEY;{c2SwqY(e9CTfiw20 z4btJK+ab#q?;swpG?K;`AK6kOBIa%3N7h!by|v7FodJ)xnZ2nFDW58*-j`U$xJO1F zT%ORMLa6Y`>4J51wd2)XR&opDF2AK%cxlFRap^XJDDG*^9#;IzrHHlO?HWA5A=hPu z|KxVsQK(tNQnEdW;?cHDz8iB(c?;SH<;#2zwrQT6Hy3wn1-4&aXu1;3(dh&e4TXw` zbnT8bRg7#0N@xTKV8><1pY`Ri23sFL?AK1llzCQ*qbwZ@JK`q&IaUZ7K|@;c$SQ2C z|1<5@EtesmZ91oY9iX7PKLL<72=W-%vaUdS>2nG-98s;Ul0s_IEsr9)tW?THzVF#S z)90(DrGwZ+7qkhH2u?!G{mp6qoM)7iXTHnl7@sQ=9TL7cZ4~$AiW-|pwXbxUk@K*M z!SnS1R4lFV@p>w`IM}8H(|Yc^Xg>~x1mYeYvb4Gu+!bAZuNMHBuJljdv zFjrdn%cj8hz|3jg3SdxfKfrNV(Y>GLvFdt50XmS}=#dZRa`&%Bxn{}B!n9Pd758V3SnMO+Sl-a+ST@lL-wHIG zs`xGMcIb|KS@@jPt=MyE=7`STb##-q2;@_`(%Fv+(NmgtH>1F<8d(4DPP-r^jZAKd zb}UcWhkvV!yPT9AUIPXckx1{Vh26b3#F)Auj^0?Cysg2dnNu(1Ll!75lZ=XzB=JB& z4X_P{z?RLf(?f}$QLG2cs%Ef4Rd+Eyg%Ko)y-{WkB%XM%1 zL#xvDP$9L11qbU1@vpu} zlJJ|)z&hj~d0TKG9_Px$7OUTAO=V4XL1U%z8KYbsxvXg51Ze|eK_d!EyHl8T6Lfks zoxVrfFxB5x4hHcP{$XmF`p7s;Y6JIlZd6+MCwUOZIgs)ls2drA0)>uxJVlihwunZHHj?bm=8)VS;4 zl~(&l7?XAX3FoC7VPZ2FYSY50!aQknXk)_<8h>NaaQWy;j&rm9>q8AT8$td1S60Re zc7yT&nwJ6{h@+LQYd!XPr=&!yDey&Qw-f+YteLL}L!$Hr$Ad0&WQt;PC`7KQfvL-- zr^NYy&d{h_)dp#=NV8a6CGDACr`5I*)<9b1ZHM@77Aw-V{y?s;vbQ9lcYH&weD7q{ zaQK#sq4Zja8|6Q=pOLFf(Q#gTidDdIf(# zWE?GQft@?E5X*nfI~r-2NGi59PJ~9NDu2T z(*mT9d!HaU!?oyjPQ)BTiPQdTc^cTgTM!PP8hRJDn{@vA7-+aMhXS>PhM1bKn~iZp z4jp-f*opvT=a^=an=b6qU4xHtf*s&sXB9|29)QuM=m!N_0Teb3`ZH;=CTwS9Jo z^9QU=Z*v$dzwY4y7Fzl77o*JHG93*{$kk71w#0HYTR z#eYZj@;FFUtgYwvWdLT^E%+h5ljf9qip}(aLzxCl4exI0LimaprqXW(QjH$pZglu` zm%MMX#>?7`WJQf^yJxV|i5p?2Uw4TyC2jM__6hXLk$b<}oHtl0+hEabxp`OA<|mZE z7#R5cEa~_;6@g&3;#^u!!z-ulrI(j=M$iS7L(-Ev$S3te<;Gxuam{~mmR{{|v1_{r zAl=E>)}QZ7j?VtE4SV1oPnh*4?uV@qn62_AjmVZ>Nayc!7d<*lw6|WqtwKp#>^-q9 zJz^udDzV**#VMwx2_2}?j|_?b0R>O)1aYbNO2^^TANqm5)Dl+`9Bn>DY1W_$**Eee z)k55{>(T-q`uI*r{6f}RPlm=@p(1m)-{%6F>>h*_Dja~^fN;NAlq)tyIR=Us&*J}r zhMQ`$V(^Rc@l&EC=I$-9uT8-tO5}MV8_!;dcBe>Ig$Iz>cooQF~yI=d$uR@?F;!UqZbXD1!+Y}mgRPxBT^?9vFl(Wk9d6x_F$h4$d_`%5T&y} z&MiSB?X2|e_YO92PIiuFRz(_<|y4PobuoK+qZQpHLfJw1^^Qm`Jr6;x6gs^ z?By0aXuHZLZ!B^Y3$PKnWYo8lk-b0UjJV-091iwc*fNP)i}=~WEYnerJoIhAWGU}< zo@7Y;bUS@WOffh6Jurz}80sY^jME()p${t&ZHYAD(_)uKh=a}+RG!8QAMp>~oJmv| zV(opnQJ@O3#V6@mBDH(Jx7z^uj~7l#kaN%bYBnve>y?H5cudyz#+ErB-~1mqYWd({ z6_e1k88)+}$x8=7AfDoZuu0Hd&tYHD-tDXDN}$x!oa!}RYM_8U5H#ZP_B$S#x+QCT zmjK@EFS@o1q#edcjaodkqcLZD9whB9PT zjZ6j74C_Glk5r%!Bg&Tq8cnnDiq79nBBgn&J+!sBT)ex^vt2)5;mjOU@myHjkT~^k zUJl*3m-trvL`V*crSEC@E``?OUoQkJ)5-}%p(FnqmkNCra}KMw4W96unSU=~iPNBc z4j1cLUsGRTda;rs2#%;l`|caW6>I|e)u#-vC}K!c%PYNR1(8vRBn+nWWTaU;Krl~? zZcxKGSM&QcOK91%D@Mna1&4z2?X6g{56gd{#XQua|9`dg82o>u(9_pZjwr zg$LHrL$tPG5xXJgY63sa>?_T8LSfItmuUy{nUNn1WWJy0l)3f*VnF}E!Iht+TZru) zufgV`;kYVX28~boq8)U($dd9xH&m*xhuoIk6WeZt3_nxWzXm|u1b6U3{YH+ui^C$-V3IpPIn2sAU+=A`*L{aq0D@4!*@aT|6oZ}y@CK@+)U zkpKNxXly-r45_AuO-~)WTVe*ND#uC;R$?)4?wcQEy$*#z4i_bMq?+qHl}Ps<$iINN z=Hl3lx*z9wh6BNTqEDNN>nb#`$qOiSEDTh&FG2=3Kdk|StaHlHZ*uqe*@NjHqE}3W zLik&<-bIYBMuA`AgON?8UeXor*sXs$v~cl}p3w}eAclFxSN+-(Th8w;rXUc-3r8Om zU)`^eBuJ;r(bJDBn7i!Huv0^e^y|!5FM086(|G(d@g=W?IzQ-|(xeT?VGv)K_#%QD z9ET~c$eyS2mVE_?AZIObKP!ed+SEfODnD5Vd@rDu=j%p(;{jStq^AqeWTcJc_b2!? zkk9CH{ju!3Iks4Pe@c6;$vawd5bENooe?Q)S6hTGqV<@vj07P^;vjd zv9^~VQqTOGm2FLbllw3I?K($Q;`jZr^bU{%E)~7j20cWKEF_{=ZtZHgzp-(>3>Yp7 zJ{plNB{TAy?AB+YbUwxdiXWeqzQ&EX5ogQ*qU1FjCRQQNFDwal8S_I1aM>?>ho$O`+(IeTLMpqqFzdIvM{+2Xynh7eQRvWqF>yA zDjY@V_Mg;b#bnEpR)Q1L>BeR7n4jPLfb2T+qzu`2==727D-r_S@!f%|xbrB!4&$v! znY3Rcxk6Mc@q$exj8&q4_E!eq;(1-2HQ`cnVx!7C?tyI!g~h_{JG|pf?nCtZc&rLn z;m-toWfEHv)M#P}Sevp$(&c6S@8L@p6Wkw8WH6>Vxvf}KY|NuJG&JbJ6h{OVT?v4| zMZ34J)G0POpOkS-e`U0@kG#1fl{;7dRRh*9N!%a}-0$n-&jwUszW%1q{P^zZ< zTeaJLHEzbW7)V}c{hHrSdjZaEVYdB@lgi87MQ zx|2^{iy&u5q(7}<+{Y6}`!|nn7(c9`L4K#L$<& z_lpM6?!tM15bw>w=hXOq(Exe7PbbpkBWGp+!qTGDC>}IjnTTe-{H{5!kz^|LmTtHG1kBlu90>rHk8w6xya28PJEsPi3nETi%Hc8jK2d#_l6)3i3i zuFmLy8X>?GxzI~z=dHHEcDu`xi!cuyzIk2LM7EoVY&0GMhvKa~`t-({H?mf~!WBk! zwMJ4kC*xg{on+spdu#k;hVB9F+8dowH`ffPcD>8vn9r>pu=Zm>^m8#1QquL3KHWc3 zsWG|>RP?P|g{ZueKTUGLbiS{{?tui?kG(J2dyg^cAND6Fh_(N(^`UMAx-RNk-^>@< z?jz!Wf5om5Fh1l^90E-d0gbW}4MI}HLjY|K`YFjVl zKvzF%t%1{R==`YCKO&mx|7+)MBF1X8c315@k%&h}l!G1eaZ0gL- z`ProOJr6H8UFC5n7lp}_o(R942O2vOd?C3rb!8w%r<2KFW*^xHPdv=t^u78CxNez( zsis7?=^Obgs1{z=EqoE*Oqw$Ggz;kv=LEYdO)Jq(n|_h0{46BmH>@o$-?2c!$7|>k zM@E}v+hn(4Y?0*VsukO1KC5u%M9sFJ3rr?6tjTVOH)+|?uS38$*-^1W(85i>I?3CN zWwd+{wuSNSxYIq2a~eOR9Q0h%UOC*aALbpk>Wcf7e{Jz1(2cEHGsP5DoY6($qll0^ zdRmQ7?@#O{8v@?>d2nIz4mGH@9FV>vlcT%v<4yj75YOGND3|FZQ#%DXbRk%grlA|65aOLyEky# zjzgV_@0O_0H(!6Za!8-+s;N5msd3Xc$-BZCID>UxU{)%EB)VK#DZslIKFQ zyiN7(T+bNFOEJX{1GN(5!j9DAf7d7Bd7e-|vbHjW`u4$SrT?36dkQz6qrYOcFQt1C zwDP#Zr+_51Eu57Jj_Sd>$p>l6?T*0CVX^3_fbhiGc%E)uegV&lHVn zhN=D9g!};LQT&zBl2?9Fa+FyAsEDWp0yNLd_wr35G54pwr!6s1OP-RwN7xuvFI>d@ zvUg|pIBvz(pljK`dWoJ?A_rE0tK3r~$BnDayX3H9#T<2NyxRybz&TCS*j_~aFhKXP zs4uCHhzczXt5TaEmCl1lfDP3(ogU+U@L#ocJM^ zeDFOk|5Y?T1z!QKNT58O!FhYNH=C3Yvu6P-0E79HweDL;dz$y_pZAWtnA_})==yLx zI5KHW{_ARVA5 z4?j1y$gi=H_=x|3693x_8#5ztwBW}t_yOIP2M7%C(^xnvUh09Zy?Efqk)H5B5$54% z4ri&m4q{g22I8cw!{>#SG^V|7b7aYkAxH0QoelH3h!0A6jLmF$FFvDc{gsgF0Zr zjlj$6dGx`JmDA_P#Y`qga6g(U`{)Hgbqj8(K>!$Qc*X~C<)LG#JLeg=H`7aP&pa5( zmx!V9=w2C^9Gn3=j?KV`Yno3RKs&eZl?lFcTVoxt-hFnw*p_maQ^qbz-mYaRG$fg( zgbEWXl?{+dBu8km=Ehd-n|z^mLFy4)Chn(GIP(Gd?KV)LmLird{#c)jq5SNjr`4g` z>glVCeo?CP8`9X-4eJL6jHB_J7ytgbH>JircPcZ)CetpR_;grAsjYZY)iAughmvE0 zY;P>mFv*-~5sV~8szTZx;pA@ipD4am*163J@xB1wfe_ZyJv8?E3zw`7@*M|5u1D16 zEZa_wMV|kcEhDw$C^AmYCKUHq4Bkm<%P08h{G8wC8aCh)PNoaC-1cRLjSp^YLYiai z%>iG81IZ`3$JxGvMRB^wh&=GimEiz`6!Z#4-kK{Ughc6Vo{B{PM{)t7jA%T$a7%U} zl?-kUx0DS+o@;~M**d>s=?ftY3#U=4{k3Aea63pF;mm==vYhxEzVvvF-&2VY8%q0G zpR@A)qc-|&i;yLE5BH=yfhTXd7h-tptn$>3_2wZiee+)yuwKjQzz|H>*43})~p#3KA9D9i1Pe*S|C3g zuNe0#ax9A%bn0a-deE!h1-^{kuI}IjUzgcr4De3ahEfXYz-;+41ZqeompIKh87R-q zsIV&Ca#jhcI-Ue_mD=?tU9~FLv{KZ~8@u&v{y(pkvchIQR>utRz4 z&u*2=ulpC<5g#i%?3R#TLmNQM5(8vA%O~KJi;^W@N9bGMFodXTSZ@>$m?IQCO=wy! zV0~l-)vS^g8JXhcO3Wutb@i2xEv2VtNaGBQ-2#D!*R|6%HTt*p&Xqeu8&)HNilSCe zp&R3H-REPD@$C@|h8&e2bAyItsC@Q`h`JkRNc#53Wy`BiWiFqF)!>OkJWyk`_ivD9 zuhq6lbfWeMakkur@RWP+8SB`?`m8^I^pBa!6!9_Z?tsK{aah*I;bLKGKvdRZ-q)K| z<|b5pVMb2mNxtA&N4hL*k9W$R-8~DuI7#uo&B>2ED(rro-retLbo$F%y=6sc(=@Ad zBk6#*EE}ksx+?UF!GEt9Km-IRy|9(`EfH#Md?Et9L4FEA2++LjBO1HSleiTwhiCPh zj7NN%*xSCmvoWq~CnVS$65IK0`D**QA{OD7DT54{GHU<3DMKZiY5bG^QNataI~S8$ z8_Wz&Z|jAfeJwJ4HMwZEAis z05wO-uD|hZnpxRPB>GULRN}sLxX$kPhu7>3&F2=E7KT*8gj#rc7C{Hr+5C>rpR7n- zTo4TT97_WDRb|p*AaomsB8Ef7SE$R+Hv6msI*bK~@A=_gY4B0Zq zE`|Mb@V{j;>C+6+a8h-X9ea?N!!6z!%{&#cDVfCZs+b2F#L5{p^?Y5e-WM2yAF4(3 zx0=T{^E<)l)rds`T3Wpt6*L^*96uFLv~+Oy`TJ?5ltPqti?~96uosKGk<6`n1~=Cy zI&##8N~I?~W0<&+=!kbpJTFCTgej@z_3ctsCNq3EkTcu^B${jn2xiE+g5SL>P8T@< zgE5=aLaP0WdJVSzkDym`OOo+kk@pGF2p+CJ=4&l}r;gmV?6qCI+T2!iIAR%^J1U-p zqP9rCb8^6&lnnlAi?vYKUqEYNG>lK}DW#ILWZGIRD$Ai)E1NjAA=N2pVSLTPj@o+O znYyT9Xfm&y+IG*jqkNzLzGQ|MB}><%T&xCj@=AhM)@zl{hF7z%&xjmsVV=TQLyH+y zbfn}}@3aqjH7|tC#7~L$%+pxlT4|9DO*TSQ<8$=QlmIZO_dQc2pb-&)bqKF6I6~b2 zQboEOBGkAr_J==E4HkpIX(^GWiha>l7{qN%3M`1p2dYGg35# z+|i^*A$qmqUJ5F=nLBT1eYvlE8Ww|}+}NfXm7dq6b6kF`n?@cMJXTmsR5X8Xs1PbP zrP9O7N5!ioZDfjirb+c4bw_qA+c0EYT}f*(Tssenz1ON_YMLg;E;vpxv3p77i?b&U zF2Q&-pZCr8zW*kFO+FiMbN*qFy$e+o^!{N`kc+T-XU z(`3m7Gw=XLWwK2cWJvBEkV!sQZ3A(8Ip|BZR&zURn)NJh^8S}S#6mY}PAdSShYwUe&CJ){DQgF?{!! z93NkduMfv5FfyeVzV{EW-i_p*{SG^#N4Lw=vU^}hm=pp)&9l_6wE|9-cjde}bkJx$ znwHgg!v8OIr5ljnlG{=s`ri|Re7Z}|``>Zr!H-hhH0O9B(ysGfCFs&Zo5nJmX(fV| zOO}3}oJ*cKWMo*TcuIAuqB3O``qiu<#9>a9(uzTBV!As?c9Ah7sr{dYTjybT?OIr< z^f8Y-O)DqipEL#DkJ5CZR(wLYB@*@gArOeZjt1<(M4pB6q1hUf;<99i+PR{7J9h=& z@tUtK_J7~2># zF~n*L(byA6&DI?z{xR661v|Ky?Q0=+=7{`un0#H4>HSZULQ?hIN^PR;;a?gTM`JC* zlnB*9r``h=g1@b2hulK$ygBx32JVmlv_8l-C|7cf@E%(^N_7uoX0KI{%|Qy~45}C1 zDW6A1ZSIUPyiy0(mWgV{90i-vTj3gEht}$X5mB|Xx4K|l@pPtqgjEe%< zOK4<1#QgeR@R}y_Q6Ug1K2Y)TpE+4le-V;VlTZNhNJvcX>Ka=){O; zx;&gIiof!%E!;!OlY41q*oN59g{hfbw2NGuhU~fN)e3698Bw2PZ#kor_(K13Q;&J| zQoG&RH?ypLlIPErB>jClHkH%8J(l$Syt?cCOA;C2GWCrg*n3sUPMBU61-e*VBqe)Uyja*$gWi~8=hpX@s->1 zW-*!8Ffp{Y0@QE_JFb}hDn49bGQz+CHK-UE05jR_tO)FD3OIRT=dw;UH&s1puBFHP zH%)8rERDUE)k>7t|LxnSGJ9vCGAgEdh6uW7qEe@tw|JMILvp8Hi$t4FW@8(=%9)`o zu062s0nMlT%1?3ee&4}v!Jqt=MPY;ZM?)q(O}MWob4?Z-!^nRfm$UUaySH68`Gsm0 za=OJD&QuRM)z%F-_ATq!?3Sw?><`+#gvtBPY&YlrLu}*5y*1IY&y$P< zhz1!0w~iviA88vv+MZSLQFz@^n6(&?2`6d(4<{3tY&jSt_>O+q_;%~tp6WYFk_wt_ zCN2k^Qs#}=cs3y5(p=vds(DX}ZCHX2PF~hTQ)Q;o4VV*+g1|TVJVI*O4{E;;+!O5~ zbj^5BUxlhI&{AZT2~|?;Gl@l`PZ&^-i2G7oHB4s_7J>e1ZhM)8pUlKH%nmb2OTlyE zv~YC%g1NVXTW(kK0#8azp+tpQOAC$7cT%#cwZVME(@OXbh!?<<0HcZ0*0{Ek61T?* z1tX-Q`j43pYN+Wz4W7>b$xRz{O07;0hG9=cOiAp9*^CNzp3dZ0-2nUXe?1?p1zlV{ z8I^@X=hA4|PR$=u(oA6OhtGGg8tP_5`9|hmZOeq#m8;i3%g5b)yVOyh1en>}#^m0Q z^vgEa2m-x1zdNtYe#sS@V&%``2R=(rPNI5wLqA(uZH9rWhKd3+qRG_?uv@Q%!QK02 zUF4|ZGo#1gF)C8(`{V$X;i;czo0i@`xS+lVB-W%I?keD zl+gySD<)F?aZEt#8I8w_cCD*}WPMefWIJ6|IMFKQM8%o%vWLCFc&M;Km#vbDw8nG+J04YbHiU@ zyRToAsp_a9ju?r+LIuIE+x@`-e0M;7IRK=#{mymYKC){#)6>WMz(bcKNOLuKMk;<& zrT4#zC%hKR`D+Sbu(>&AlKY{wEXrDZxLOQr5BUhCNSXmTP}$Bv&>e~LW&KqD4kwx$ zg5Udd0hQnZHH>s+hE~4(RG&%g|DGy80~UtX*er-3Xh_~&#eaOj0}z`eX0h?Fj6{!r zQ43%g2WtE~=+lX~iB;&HyOI@d`&3d^Jq_*IDP-E#@Gk~Qx8=@b0HRvW{bR}r%7`HC zVr&8xxgf{)!0O^uuKjsBlT{!KtJa)pDa@#|@{JtJ9i$zPSIJL{?DNJQ)6rzpx-*cS z=dTx-nb%?s4{TNn9-Jx_(G;;>>N|3Hh^x|F;^g^7b(t`;f>yr+GZI0@^;A*@i>Qu((X(fGMay*%DfWv--vjBY#Fxv#59l~BdV1=c&E${bFvSp%6>IZL7(2@ZRv8c`VomzbdSn(=EA_N_@W{Er4~lVaNTcA zIV_&-XeaGw(t7#^VJ-L2g9(delDXho1TuZNyhC2ybtLWXU3vYc(j^JmId%4fEsN6+ z4~*KJ-C};=Tjn40A`+EKX|5_|_CBk&4MUpU6~#WhkI6ZK8jpJH_QR-sAMQxKv_#BM z`&{;8iS&ezIZ`fly398Ub?T_E01L;Wlt%4)B2YJdDxSih=FDTN86;D*tJTaZi;UR^ zoZtU3+|fhG8Q8-5z!!Z1^_%0}RAhnl?$=@Zp2Z5Ckyn*F)c4&VKV@|_t5!ZB}}n6P@pkY4unpQI5dV`>55KZGX%l! z?rXHWK)oJvhwAV{G}jDorFv;|u*MbwP`6X)Yq?d4g*vz|#jWcF8ugCdd~>D?6Y4T+ zkOMfMO;N)Yv2N4c_mef!lbfjvOWZcru#iwD_JgGHX#zg1K@4my(%~3)Xn(mAP02Pj z0v&?dU3Lv{Vq_BiRWxzh%7XxGqZ~9s#UM~`2fDX{xO-j=Qm?UBR|7RSp*JK^Z7Qv8 z`ZM|YSe%hI%zC_@?bXhPJu+o{aPN{_f8#Wm(0E}vHHmBkG8<`VSE@k<-2B{Yu8)^! z2}w#bl}dR(%P0HhZ8GcK(!womXt?EMBfem}b(|Nlm?w&LbSZB~V(?05ZKI~KxMV(d zrhl>Zr5XC`LN!C<=;uAqp1TiH(W=4^L6NucZZz~)$qU9wf?EVtqZ9-6q`c&j`s<+i z&e3@O=$3BiO4@rp)MX~jC7%11q3KO+=z{oTpW&X+HEk)1pwspDIAzK8mNMibm&q1# ztp$=zHAUv0jj^#(S0Wa9*Z6n}hZbH9i5;uk?7crTlujKOIEd^obnl#|887<|La{#G zlchqdK7vxYg>alsx7tSjT5CQ)cMwXz?SkcH6FsJ&;(TZ!{_f$-r$5E7q0s3DxC+FJ z1gq=}a_|f*?p%;e$DHwS#zaYX{vWlRdsI^S+Q*x>%ha)QW;|WJP17k$^HOH!4W^mO zf|SNAGgLCIEK^LpBQR4_j^nNJR;gH%WJZFPfvCu!CF4C6ML{JcBt<|}K*0^~c4j*7 ztXc0`bKcA0zrA4X-`+od``OR$`F@_S=465)Vn%1ZXkuwTdl^nmnMJTL?1p3>`?Y0aK4V)y&{a#v`o z=20KoYAg=$No+HPHW;-&-HU%FKV2HKpGUl_(c45=($R7y)dec4@|?bc}ge{HXI*0z6;etmJx1D@y08Cycyl>j;5B_MY;P1BP^|xD)Gs6+|veaB(_)YGVxYn+;r^HOT9` z&gks}g;mMaw>!7vcHqK0x_+A38Z%nBle{yF!6u_wYpACp7k+5gIa_1s8}5nHgoGEm zvrS5>2UPNIIU;_+hza#uW>3$|kQa}Z7)F(T`w6AICrbXiB2za!jH9s7T?<*ZWR~4y z^J|juUp4(dmb1XGYLhfQh<|$Td}sA1=bt2v$gusl)J8oc=M?KF*8h6GiW~8S`K;m( za^{qrYS6Pk$Oj8ow=DkX-{2$Ux{7Fwum}5l9Q-fjwor4cbSl+LOmYm5QPnsCidB~c znrW`PStK=!SAApVdaT+^=p>Txg(&nqKp5A=M;iDFdIG9Zz?mE5*{T(bjYEk^QLP69 zI#im7okfPfyBIU@cDZO!gNXk8d1Iq!_X2A3S>tEEL87TCZrv|G*S>vaUH6gQR8uzI z##}?%PHar9w0q+@>La;m1h-#tZog*CY*)GTOi@U(q^Xk+P+eF~b}Buz6wYEXfpC@r z*9h)mO5_hy8bdI<0^C9kjjGq1LP*g8O^hZ9^C_5D=;9T+>l2iZK=@LrZ_C91OhAer zU%-|`jtf0zhRnd87xm9@b9xEbzvWK5J_(XF{qeU*0TUU1ChqpzEPlx^T!NZdxN>0F z5s*Q$R{z=Jm4xP-pwhR7khy zNeO+>l2~C`s&~?XlH4KHE_3J?y!!hxraFxeaUZJJ15Tb33-8p>XImAbhYK+aURvQm zP=d}ftCRMS%j!~1mn2W>_)16a?b>}X|B;}dRI3$+C|qhLr_KNe*^P_oUz zF*m?c%16_(I&K%%l6ak!c)`s}Shz~Ux1?Pi&h8e9HvUL2wxCj=Ii4a+yE3gtk4n%R z0pSAoE{%U#9SzsG`+`tVs_1nQmtl&e!eDa>D{x>rl|`B<2+^^zirg0Zth|wBa9a4< ze$Srjci$h~I@tjiZwvH{yS}Y{N7nTVlW*Rvx^VXU1Ln-zu?DSc{D|LGW*lP(GTC{> zl9rv_Z4Y0Qp5u!>7o-~%nfE!W2K34xNk7JM(IJ6MXjR*~;BE6~92xy#j9DCNz1p+` zNzb65Fv$#MnV^4PN7u`6*PDnI6Pd|FkJR6$nJVQ@X>IAr6d#XpwLR{RD~q8gn?uXQ zP6DisY@S9^?k)w>cTsCbr`)5^0{t8>*GBN*8gvZs%k0HL2zB^07`z^ud)HbiBn`|G zunU#btr|+eDJC{&(S0c@yOR^FP(wk;-~=E(N~2CMgfnF1IkOuo5+b%>6AwWpjAHW0 ztbYBgggX#oVb(FiSVva>=v=Gl;t-h76S~yV$7pLReG{MSpLC|E3Na61oR=kaTvl+A z!*I6*-bWWf3kj0_(K>{R;H9fe3L(wpOAXDsol5+sz9FR+i7B-3h#Sb~?o{>H@5n_* ztR%wXHd;PAX^p5fUtb#MF+vN%Ml+``;pSzr_bLS9SArB-o0I`fJo3^i?{e`FA-OIH zS;KZ)J7$Is9P-?lzD|Yig(&6#bw+HBM3`4l&(liGijgb~1ipcG=lDeeyAtO>H!vgm zh{Zm@%eoo2UGYtg0cG0W`#@=j;*`iUL1q)7$j#TX&&=v!RjgMY^$mKlYEaYn7(jN_ zgEl5NhiF{Qa|(#q8FRMqHeAvqw2`K(^^Ely)T8rN)UO$3m^7t}i|`v9vJToX=RjqK zz;>##>NqFUc^ zfo_{&>(9$GmZpeK$f(w% z&TZ;4+2!07WEjo9uB*oR)WYEyfdx0Pf5BPZ&vE)~dYJVuB!eD?v4&8PJe8QCWOHXQ z!7plPbe%#<9cOjV1z_=gnS@-jRnB<*205AA;iN+p3Co+Zrucp@aB}VG=U}oEMo7gb z8>uZZo$SK^@^Y~q(iIN_bzN>QuNU})$kiTH;V$%H+{L&mH6A6g;*h!_TEs)m%$ancL19VbtO2# zIKG&+;l$J3tlbn=5oJx!%;r90+2(wNmVO*kW>qOfVu&CT;xPX6)A#QjDxVAZM#A*$ z9MieD<4pprp#2-SuxQw^(>;OQlZe#*85!PB` z+E`_QUBJWwPHIKe!sGh;T6!2t-ViE`c~~EuT$owhoZx_?syMM@i*{u-ySRZ@Gs9oS z=4$PoBf0lyPMjcQ@RRc7)T*KTK+5^lncCNLpAO^U0$zY6W>j-+CC8DA66)^^DoJX4 zYGYh#$TJ3>d>%kXqS^$A(|H4jHQ7kd1kgil+xBx`M55h;;No-ddG|ufxr87?tt^fI z2qx*I6g+WX%=c-syQSt&Rj~1jb8SB5fws!EeL--M+Qp$Wj2$rHPrB0Olr{QEce& z#z^yAS&=%BLrkmiJ_Nu8lDvD*9SvuzMq#EX!losS|PiJm{kF_hzd!Tehy6`?XR zc!IjA_-k{=&aBgp`k@*xAd=D3lygXx-x99f_)pUtb29dIb??|EypT+ z`T|&RY1lxwvg{^qKPPB&F=IX@2aN~PC#-wHDrtOBt#Z#ZQfpW+Z9$meY^_wm*L1#gflmdHYo8#{ zaY@f*XJ6yGooz!t()=LZ+CeHv&NO*y8_=pM(5+Ng#0A9ire}?@FmZJRTDjm2_A#A_ zg?goKKh+Uxq)A=1RKAJlIT?}s6FuVn-+9r%+J`k$RZH)t&98EZHDRB4l{KHAJoqu% zWJBDb8zrmyWPUw9OHm~I+Ue(oWp``t{brz9?e&4Q`EyqOFLQr?bpjPgHQ}RwuM{>c zT7pjgp207N{HZYbKX&o_%aY~)`L2cmRcZ0ywZ@S*$r}3CGcwDyk@HTjW)}BL^Lb+` zaam%R0NrXq47$$)St2t_tMhO(i!3=_J~T2?me_@lWP)Up^fgR!Q9AQ6xFdO+Jd8Wy zu5@2$eK;Rs>Q3<3disXL8Mrv?$4s+oRw%6k(KO$05<)Ya@0kPA8) z!Ti2LPqO=x>ps4jcz7-1Am`i9z8X|s+5v^csV?2>jo^qw?)3?m3+t~0MhdmK0hT`cWcfMrT}e|k-_ z2pix9E85Z8Pom~PQ?>T=tbsgY%%!P{13Q-e07(ctd*^KTjjgLzhn%i_=-HSy6eKmv zvtLOJW?e`ekG0-UddEL$(pCe3eO%^~IG&KF7979uALCC}VmAMu!Xd?tp-d9uH z2W5!;qR-EC-yj|X8M{lGoGK&OzVE}%Rs=V!vAci`+@7~Qzo+I(!O--(zJ_(4KgWE*$YLF>r^$etV&1=y7sZG?v&$a{i zj*s40ZMyafV}+3|6h5{3yJqY;Uaw+>?C&K%if@Q|R6a7YEh}tl zuV_nE$QWahSF0%Ak}z=sF|W;GpdNL5Y2j?EzeVobv1=7E_124jRF`};d0ake!+qf} z_+A<224lCWZ{#7x(+kSiqw3x~)SiUD;U;XPCE7(?_vd*pQ0IiG78Ymq>6F`bE5w@` z)@AAPM-}xe$jjM|R}{-`k=WZ#7XKiy;dEuu&>+XAH;+BPsuacGER~?>qJ!8dVEsl`O_v_JD1ns|h@O|rI z=6Uz3e!KKgD<}HbMH#g!`)y+R-s2^Z7NeC-i~hY)MJtI3jtwR#$Omi{6b#G({vMK-@w_fyVA)Io(lQKQZ-r>%Tiq8Fp6o2z}uAGVi12+ zRk9B??EUk*zS_BXv!*K~_2)0>+7fw*&X}R#L>yx9YLZU9B_7u^P-_yW+HAA;^SuD| zGL@*$ZJ7&pY1fq~_UcC>{k^V$BLl4N-A32;DE8P}u@~tp)2{xj`%{p62KDt2rto$* zNR_Ww>#M-~6r{%$a0k?`?6$Dz-;2Q42G2tbEfQmp@;9%M9^Eyy)Uv+B#ZC(&+}tN^ zZpYb|8Pg^FsPf(^32}qDNNFLBj)8xM3Bo?hpx9;aWFS zIVJg!hpA*gPu|yH5bp>h>{G0A;0p$;1vWN{o)=-w*k)oQ7``MwVv%FN7El zTfg6mMgDxaVVhM5$(WRxJKr@RY%tN#gw;6DFm9A#2?+|)byItXP}5k_&wU{Tb%Ym} z)J4E*fVqFyKyR-_Az74TW<4z`#Zwxv^{p^E7pIO}{SufFv*{T_EPFM1m!343f17&S z#IH2zDg%kV9cBfOfKZPq{78l=9d)DNz978;jGJzxETcU|#*wpMk}+ScE{S+3Zc-Mt z$u77?5}VWYg&IRFKEl~=a>6Q2v3>{B!FH8<>k~>L+HV#arx$hZepoZ!19tgs1|G|~ z(A??={mMqWKb;T)rH}T~h5{>P_hS3ZBhsjK&zk&}=@b7-U=S zHF{RwPuzK?&5@v+UMFbExMRArb`g z7!Lj=a}HiypZd~!_oZ9!7+~ubW>4vaWy`3=AV#|A*9Oc@ky9xj3pX?*KXo>^UeiCq zxq&wwGVl&vd|^hjGjZu&{`LIh!XKQ&@8;cj^LY>{njHA@74Lps8SvS)a%sp+OQZAr zK0dw`JKvcK4G-pGit8C>V$)%{7A|tGFS$zbTt&LOIb5&2!b|-^>Vzrp4S-(jo$I=1 z36-j;vmPu|`{VFQd|z&C9^iIJU(#h1uvqP)gk%Z3akuNtCGGKZSz1PX)fL-CzWml)5dqB`DWMr22z~1vq z_mIUsZ+`Wo$$RizvBNEB$;x2Y@{i9D$&{5GX!g_;>&={FMyn;|s~@BO49nNJ8Q?kg zM86o{b15p5f<{k>T9(l`=AQnJ(VuhqBt?Y?RUZ1}on)*W#tE>ot3`F8_K_}w2J2A! z@2LvcrQ?tzdRZ4aO2ao?hS$L~p}R6I`^j8ie_0MJ{f)`?L}VUFE@=^$H=BH9xthbf zlXgt&NhhnkS+XbvS?C%7adO0WPdw;b!+st)-N0W?M7l+9WVdkTkqV>QqX*A9fHtcXPz|>YD*kv8s zpowwg$rM`?kR_Lm3}`dIJzY2~qUn+{JE2oL-|AkOl%PtL+-;y!6-Ld@((A1PJAu*N zOB&qokTbGdIJZdJeMgGY-`&vDr93J+w@^Ippp;ix9+(c6;U@vn43h6ta~y9F{z8vTB&58gPF%lf{FAAafK<{i4#)$zoJ%8Fw% zu>_UB9u=u)Q-OlY@89T5J~tV>yoZ2Z*zmw!Apm0>Hhm1Caf-3g#a5ATJ+b~Yi&_aUnvv!CqwTmO8BiUK1t=?PfKvXT*ktn4 zJGd`!P|;AO@KUE`5>k3zyTIgCt-qcGDIu;pS@N8@3@HIRXs1+0Vv#4q&}Ny=U-6co zn}uw*)0Qw=u`l_+sTdVLLqw}y(qo+!t~j@6c2GZ-NngGZAMu2o0QMSq zynx$P_QSr@=a%ldI%zgv6keeV+Kfj(8Zm}3{rqv5kO>F-dJ!!?9c(bik-ts4BDK-)KIjsDC;|T) zXD`_c$jfelP*w?+nq89@k zvYaMovZqUw%wAQie%QP!z~f^Ca%$NAbhS|Io^jMqF&a`)u~udfGAXfi6iasf0r)@3 z`Y^1nd*Dp%f7cEVEsMnTD4GA0ovQ>MfXk~@{{7NQ@`>>NMlQ_E_u#=iUb?rKW!rN< zKQv3qF@izx@zjooSxDc;_TXY);S-P$&Ub8*afv8v=lJIK>W1t}d3A3^M1O$g(7Dr1 zgQJ#P1T9igqm_*OmAhvWvIP^8J*BmpV6~>ts6FdVLPjuRAA`5ig#1Z+zi)-ecmn$N z%~w83h=YyXBVG%IF9V*3eLwtCsL>BltG7$P;ZuemL*jmj;&MZzu=}FS%kab39Rqui zN)M^gd4M5vSDDA`D}UmBiYVH?;Q`{7^u>9@V=hO3^aJo5aVXaVbQ+h)Oa44WYjN&2 zc44rPus-E=td!d%cWreGx-MjMETTzz_R2OpCOf~wtpMH9HHE(dXw@2m=Wen zAVX~(%im;UpO#qa-Gtgt;BQfhOn*Yzn>cFu(7pT&o4@+tZg$7kblqlUY;?xZ_S+%e z!;3L04`$9e`${q9NjS6ah&t_0RB~SnYRsX|Z0iexArq_jT%2G3xntC$t4R>6^T=o&6zdK-*qI9uF@ZS*wTw zD+&7Dy!MUnIGbj3`(y3G;*=FuH{X|UYHXt2A-6U*zg0$ueRrh^k5fZ!GEABA1AMy^ z3}FCFA+{I0KxgI&wMYBZw_x-vizous%AjZohYV%))#+xxSO|RDr#l84Dd(HfYp)d# zZ;z?_^r-q(2&21P)yv4IOzM`ny1CN4985p1`n#OjA_bnU*L^Pe#PSm-d#=YS~qfOr)GTzajuuCp9 zXn@$VjPqw^N`#XlLBw%6i|xBLi}w7EFg-A7$N^ioQayexkQkUg4r3 zqvKG-xe(+GWqe+@v;=WJ6~5^7JX=}l_u0*2g)|3sn>=Ip|4!WREMejalvaV)(0cuO z51qUT=rD$q)BZ^HqsmZM4U#&1N@G>`;5P+ z)7Rg)NhO|T3SS|W-`dul&=$&xO|@BluIXhMPE1lmKRIy9+sVp1GX_%ct1T(}+VcSE z=({eDO7)tudjLiqmqc4uc0w!73^HmCR6uHI&SPuZudvkYKiPseKqYbHXT?8d zkkZaB=ck4BwPXq>J=+(%kwWLJkK^}4!Jb3-7OAZ0W!48fZMbe%ORw|DL^gesEIA|9D+dLmwtetFQwu>d9RqXXPUp#{CzJiNQ)j8$k-fbOYlj2< zp~?-B9x|u%K@h*yAIxVH6LaUuP-m{5cxmi@q=?Y@d4V;Q=)F9QeGUO@r}{KeR#hwb zC!PH&raK#oWX0}3u>B5zCHvf1f?o4A8_%N}uU24;$_NJ(tqmM=K<=fQ&(I!U9X&EM zNkbMUswVYvM!U@HT4!I(pDjVIPhnjOjc3hoibvaLxvvNo?RWIhD_{t{lm^8vr<>X5 zlV=d0D%EXFatvK}mvFzXm9^RRa=D#3Q;)PlBp!NL%1!X8S~EkGpltyp6@-$`4sx7x z47eXPV}jq?JjCw^94Rw@tr%!B)m3HhD_l6%Ybd=VDr82oa(b$;=v3Cefo_4U!*}f_ zzVppc-g>Ma=*%8G)rm#TdK^*l%h8CPJ{tksmOcdI{3I6?wLacNg%5&#s(tV2W z4>SDNsAX?%PS5O+LuTMyi4Fb)*-Dv*-q>RcyzQ z&zE64lcQ#{_vLb-Hxm%ckwM303(utgdtTAx@bAb#WcOd z7GW~KTxaHVWV|>dgZF$d+fVxXi*i=FmfgjE`vNhb<3*k`FbcrF&1vq-4JeSo_zE9f zPyR)lgYJLQi^v}^*A_mwg(@ePclwaR55Bw!#a+FPq2F=1ZrVg>p3Gae&+WugWepe= z)|VEPo>-ns1=McVoMp+eWrc{((<_EBWX1)2{=Pa4eWFttG4*q7`4G^Oa)R=W&yH?! zdCWXKPF8%3P>~J3bob>a_Z=h?8g_RId!{PkAoHiIL5rTp=gh?ILIVc=eer<}D) z?qx%d+upCw?SeD7rCHEPSI`-ase`ypk#lYvZ&Z+CL$v>&P6GB2zq#d*u=R>Jd!wm? zu>A+UPdt;TnDtm-g{{seZ)0~p>|?U&tmnfolH#YiCU(9u%DsSCi9;Nx)3cuL*@Nox zv&N`1rQFwow*8hAZ<`0vnI*f7nF3lUi~1jfXgUr5H#EeCDc;9sXex1r+-uUY{|nv?dQd;+g_ws zgE}f)>C^6_Xg%`IQ*a2d*ls2JXNF{C@K*<31cKV9hgRRiW<+3qBBgU+0lP~MJKd4b z+Fl~P_&<^1%-`9_&Z_AMVh3~W%v6lhb^UC7_Yl|PB%OTasCL6}ws^R3cyA=T z4rE*arhOPX(&YqX+A|$z-4w9BrenFhzeDG@V|*4$gDm^V@zh=i9RD+bYWwV@5_JQ?-=_W*`Dcz&LlgKz&vX{xA~ih>P& zJo~5&zapHFgm?@V#JJl3XdXL2x~~#-O@yvYjLzR}KqeVe_=mWKB4}AQc^y(U(?o&{ zM3pYm60{^K0YH`F+JHI#(~~c9>SU#s9gK@d?uQVZq_<}%;!$K6b-IC; zvMs0hr%l68zGSXCXt>2s{rc>E>7x6jLpI%EYKy(^HQT;9!(|gy^S0q{JomK4`wZxZ zYIz5+brs4Vy#43eSdaWpF^$m~V)`$}%UK%LF4Eq&QT#GoRHplWVs3l2IHgY5pABee zKjY^)sk=Jwv0w7gj)E4^&dJZ)AXvjwmhKQJ>)Kp3IdgqmPzP#W$DKG@w~mx}Hq@%0 zD@`+BnMP(qQhkEE&L}eg{|KpEi@5b8OMm0W>Bj5WwP$9+{$^daOPApjhF=!6Zr!2M z?jjYmPKT+~vKZ&{Vpjr;V^Eb1li+gQPu$1Dk}jui_(DVcCKOfo0+9vRsZ z?;LXlUk#a>Ih?*@#xOIH`@Z`0etGDuK)P%ID#ydRQbuXhac2=a!0(Bj`RXxn1SuQgg%{L6bA`@jw`;gmT z{JM0x^b9S(wvk{UdP#+t$M4LyN&7=1R>+|m3=YQS8~|R5H4Wdd(-}ta^ZE@IPf{nK zidD>*y3Ha+QMwmVYkW{k^E#JI z?WprP2=b3~J?hI;9%aa=uv$_PPQdy(>P#g*L`tObzMNS%%yqw(m(-=yd&6IN)s#D& zd9BZZYV`8#Ajz-vz8Qvki1s;ylKjaG0fVhUEchd zSPqNiOMt!QeZ&Nj(z#mH@4lom9>%8FZjk0wX#+r6SH#6hv0nQY!1;GmH(|wmV~7lg zeK5*wW5=bceyNet3ana!r&^|`eq|IYx#F-N<}V#*oD$_d*<`$ZW!mD6oRxZ3HG;kr zzxS;-UH6)H3&;3-6baN3Mf&@YGW=G2`|=%H%TV?eWTG2yCla9!M|Ty0m&}9i0|!1( z*Zt%}3xVnG-Mop~cMiG^W>;~C`5Yedd6rk+moM?d9t4sHa~vOfATrs=AENQHov_H=lP-D zxtdjG+4QWeo6fgwv7g0Gqq(%of-kW=JOQ z)B)Te?U~W0&CUhKws~9i9@`ww$~U6VH&!h31O4D;CaD)l87&#<=Hy|=#~!iXuO=UJ zftgj{nKkcBeNMA->bi2ojy%5Dt{FA0$*~tZeo^a*lee=tvb1)#6-wp*XBXedwk5IT ze>fDrV%ofqGRPkG7#Lv0LP&p5s+Ex0)U1%9UKe7$+bqru>)faPfeQEQW!a)LEs8pL zPc?exWL4FUNH%eBko=HtZI3+~gbNqEc;LHvO6L9SpPfH^p<{qZklq6ix#Jl5WDolK z9{3L4zGik>0FgS#-^-NUYnY|94dNJjr1jPl8g?J{I5SauxTS;ArjVkf)dQ5cb;dzk z&@piCy?mmMs2KHo8)TGByqkYx*?U9(M?4Z=d>fgbqm3J`lkBQ=O8VUv#D5T>XO%xG zNM;|ku~4CzC!YvpX5tgV{Vk$B(4!7h0}?!aD}`MMejXHlRzD zP0K5lL|wI=3~|8CALz$$;_-nGTgOCWiz%B`f7;mjaK&>HQdY$`GYq}$^N>?n`0!0^ z%Q%YPqo0Lb`q~>Qg>y{c2wXJ`CG~cwvZS0BrrXWM7?Wo~_2$)(TbcUd`RrO7)vVGpEF(eDhpIkB-YymK9f1QPFR0?3%d)}Z%gz@CRIW8!Oni@) zV>*p-RNGD7C&`a;c>C5;bjIv;D^=5L4%|W4NA%!q&A{><{F!D}ivM4=Shmu4Rqj7O ztUkXQQ+T31Wahb*v z=qjaFYW^b2%OUc{od>v~8^zT>Fy+nPyc^6p$}FL(rvnEXWKvB28MG4J+jCleUL^+IKG>CY^ny!Gt?X z1axwp<}bulSa2GzjW+Kuj~>d6l+hVEOQY1Mp< zXSdY%1tgYNv~~Mui9U5vw+Imps>z%TGp4#D>|6YItEzaO2aR{dKS6*ZB2Y@Bs91=6 zDNcpW(I+Iz?QWrIFbQOP&B;Q7dwJ!oTjW8sO#?$QNZCB9$o`JufjOsWQh3>a%2PWE zRu{y79iT_6!i;*?TXdLO~Zob)iac4TKUP)PcP>m{)l zf~i`lFDLzIAKr_}V*ze3q2fU&GRz;xy_kKFS-l`)4@y|r7~C&g)P9n0a<`o|d-~pA z3hy;e)RKp4z{Au_b6sP|U6&FlAEJf3#hj+ByNL~?X4ew-C3DN=v*HQQQezv~EI$(X zA>WqmVA7%9)wcNrZRS2QFUl+I?AXeCVWag-d%C0UPKP0Pe;0cu5$*HE13?=F<#}Ql z`F!W9Mj>_)8qX*N8&bj_a(?T{{7Y$Z_-@NY%o$FO!Q%)i~YT* zf&C0&maal~UwZNWw0Eu@s+rulnC8q%iImOZrurd`lecZ&1;7N=fi6)KPXf}e{hx8u&aCM2HdtjLp*z(~L6AdPdB z6%UlRGxVBQ9fzC#?6OFCxtq<#%eP35sCfUGt(#r!02nCdf{l5t?Pzx=)x{SDoG3O| zTWpf?<=*Z8X?rO37erOG?j8uD{iOfVVi;zAI;)trMLAGgO~L;$vp5ZOH>>_#~5jBl@RYNapKm}!Xx zHo_meUY%+`9{Ks!!`5z{*23V%Fzms%IZSzqqr$zL>e7Zpx(E{9n@CyUjtCrZ@5~Gap1Pv;oifKSXSVQ3r2L_as{F6!@H-tUgZx zQT=O+!!VpLOB&{)&*6+)-dRPKhMfa{`+s~7?}GBEo?qcQ`BLcDGm(9_ZNfL^j=(9; zo&RxHo7Jk{kN;DxjS_0vi;+e~p|i4@<~>!3KAh){35=}U*za%lZgHDo`XrLvH~q}% z&xo{ob})O#00})B0z)##lP>SC7wZGO4)W3c426fx9`|Bo>@u(`qx$_Iuh~vibe8YI zsCQpFN-1RIEc9dHwrHVk?XrDh>W)Wfkc^{I8QP2hn||BhN^5vvBVJJF*w4q1-ca3t z?OU3&w@5ITiH?R{GO}io8}+pr=TA_( z$tJ89gT&wB62Z%JU5_m+xvh@1smO@L`dusC0HX!KoScM?dM>aH`QnjX%R&Bypq!Pm z+-2^5N7;^GKkWs3QCXAwA-%VBV?OQP32|5QFL^BPhOsLJ+8QnL#Z|fdjNUzvLEksX zs_;MJv3j3%vnY%#v#OD~h=@AwYB|lcC?EM{he&iT}dq1M`wx54}o@lq1UT zZo`xz@dml=Oo@;11hBc0>QzU&9`9r&>}n{*a~t6aTa0 zI-e$BRfg}rjI6nscG2E;B-ly5;d$%m1OYEEpMhAlsCcf#2?)5IK4fOmpi7F_N3K>y z^&BSF3VBOJ?I6gBXoA(7sqYz$ZvFWv6X>e%% zsc0=WU(=vn9=&v^KXudO2Fx~a+meLOE6pn9o2=<$1GEktlpK~O5DYZBXQ9rjj>O_A z+q)(Fpr*TyZ2NHDy^J2Mlgc=5jqt_d*7B{c0zb&B7?~f?qj)Kh|ydj9>Hn!?8 zPe!GVex?qUSW@@8%N%y*c1-EH-r!$Myxeq6T8GrXfvQ8|P7ft^Lj7VKxOw)a(U{C9 zO?M|1^M!U5wM6>U+V;j9=6I)SryeKrFT|KIuAP5a*CM%BzZ2!hY8nztJfNU=+tx=& z?R{%H_+>4oni(YG*jYH{L3fwlIZu1b$LUmTsA6-xcAclL>B@9g%L;GJubqY+jL&J5 z8a66N`~vkpFJuS=+Hl_2BYfB-n_BO);>nTLwr!{vTDcEV+2|__nNr58E}O*Y*&baQ=t8~S zA$HCr@&(jhKr8DNN2OoWRiUl#d=k2xR}x{)z>j<4-Mxi&SH6+M{6T6d)QRr)*a8!! z;>0DrFPBN3Kug1rh!#d*oA3xGDrd|p{n=>6Jk+Pr^g~k6ThWhtAl>liqbBbzC<9-M zyUMYaEWJk5e;^ug#XS_I11eb-MaliZ-wW5XwB`ixgNF~fS%+URhha91gr>zdLOwJ^ z-nMRNJk!Lz!HT~QZ(bSPujc;XwT9oqXv|2V-EG!;viM{#$Q@^aaO!dt=OD>N&P15w za7nb=UKND*wijEG@m^~8Kl&;6;?c{25ld#qO1|FpCr1mpn_JCq!jA8i_Dq4uBl}Q8 zUgpk3ZW9k#TFSnvF9{R`5-sVDy)+^ZS9j>S#%x$?gda~>2ac#Puf0!Y<(aqBAr?@V zn<_o~W*4Mqtpx4&zor!8b@IOWOnpgN(mDfi``R~wF^nthGzThvc2Lw?`gX{~5xqVB876mx^u1^DRlC z)vcY`RU+^{-am_*X)<5h&D<@%uzGEywb}M(WgIaRF-1POBipFxJSOS52Q1L8XnqN{ z&DetuB`aco7zFR0UY}lnb=Y97Gu?cw0ji*eS6Vz*(0145WW88Bu+@x3nu0_KMj0h0 z=s;4!uexT>?Ddj_-f)3vt`Ez~=e8-lUuCNkptk?AM)oXp0@imZ9eXjz@l%jgiTcz3 zt&7+wn8Vy54i!q#%l!|A=qcbHvllPUmExHiNY&Dr`ro?BWyGq;*LCkVuKUqNu5yGC zi4*nX`Ug#c3Gcu9Hfi>~%+iwn%okiNso zb-QiSj1PmTeaE+F_g62DxaN1JdU&H_kfknDh=@IrhUV@`*g&%>)eo~z7+ViA{+>Mp z;Li4OBy7g*9PGlxc5A*#gz$!~4|HBIdv+!ram(6!gAUy}(e8K}DKbVOLuhigT1{=A z^*j$^#s2ARc<$iRXkY2NEr`7uaC}^jnUYU)gewci7)rXJ>t<5pb!QeDmYo`}W3i5Vr1x2mbb0{zByYx%PHmc>yy#1fW zQ4lI-{aF{elBW)F$OF+keDPNE+djL8yoWb9z_Yv3W(d0@a`D6jHF+-re#-yMS^tH5 zt>r33LH~DAW);<7nPFmza6gNnSDE)o@0&iC&tg@JS@37C7QK3zSHRzIp?mYj0RHJs zy&$`!4T;gGCo7g1A&okAl?f*qTq8H(EY$8bs>VwVzi}5w7Yg*Ng(a z4^3XjQHw>($a-IoLpq)vKw9$Y%N}yZ%VZwaw>$!eDwXW^-2I9e_`>>`OFJ7sx#x5- zH<~?Wp()=Dg{Sn1Uaj8yHXwn-3@?8~xe6G^5JNMP=Um#p!`$@NJ8yoSEiGZ(PLKG_fXP;uKxMJn zgx+jApJ;yA+|A8%F^B*vN;+r|uc-%ZB}_7p9y492__%;Bkk!r|^F_z;6^t*D@32~e zFBFBsWaxED(;H5t*7(FXN}-#M3sNP{Oig2dDhCb6O+l@OWBRVkUMs*vnKNLb&#y+0 zOH#68poIl-Z)}=BrevgDeu(L1vDaa>d%Ou;FF?EX+PymME8pSr^sX~t zX=B5@j6la2oWGz3P52sdP_ZX)s{2X1zfdX@DC?L7^fl)6cl23~@b3oj>XwdgNJVWu z(oVmibWGryg7@)~OR9DwyOrn(;J<7BBO+!dfn56RZoWpyVPIVXaxo^$Dyn1%A*^HM z0Fmo-4t2H(U9UX|$Yz?LT^)+^zc`dFaV-*v%A!drNN#bmtFbs8o9cZF`L40mg4>EI z5C9CtF%^9Lfu}lCVd@nLw=moeatqCc!VNDqB~6)K1Dt~PRac(aOg97VH-H|Ukdji~ zg(s-_@t=sqbzPL_`9~r5UFODtm(NxfdRm16bn6ola#ED~0P+UhVlIUDZF%@N19d}n z@qmfYq2H{OkF^c2WSO+3zHrU3^3f^b?`yrilpB|w6dfh!ieWrkJ6m^d_IVAV+}C$q z4HSViJEx~!5OyOUQ7Pks>rz%jy+o+`BOAT$##Pg|iU!mVSe-e-3*EX_9@2f?uMk;5&lI#}mExgDOsm>lK8DeZ#wh zJ1}Zc?2&4uk!(~l-3?3ZCUL=08j@kG9yJT!EydHQS z)+lWOf1Jm3Wu4_z8wv04Z(`3A8;Gae-n^9R#d54ow9G1kyDQ`~!fH`Ose^u?@2YUT zoHuQJE*!I+0k95v27=4$ApARba09W+((_WOa$ zK#+i?O$y-BY7;-zF7udXFNm=Ldjf=QCSARv_hrlEZiMpKzy}{UB0ebF>2#^hdG8yW z=hOrphDMi^x9U+$NnOXKi210g9^y)LG`M?KwfL<^JL+4;F?+qz@K5<$gw|vDMCe8u zH7EOtv{`IuPTnnYgGL5sm7lXGi{*c9Q9}7*Sc7X`hFQfbmEVA^)r7;xkq`;n|6zX; z^aioYs{w~M_RF8_?^T*n0^3l-cKYqr<->D)D1(NjI_Vm6bwC5&&Qv=B6*8H|G#oC% z?`NNZIgi7kN!l-L&vLOB^pKh`MQ%WZ{C3^y&nryU!r4oU7k)RCR=Jm$nlaw#We*_E z#GEG1T2R=QdJJ!R9bSumCd=8Hux{;ZD?4<)WGy{FF`Yp5MGs^mx!G{rf7xpsv36|A zCIt93d&r8v>bfd$riBvWYI1<9y@Rh+%A4i~OHcJCKCbDV~py(n+r$`<-gkS8^++T)O^FpgUGD{eDU);*Nai5@hCE zK!9HnlY2?1nf<~3%KjZm6 z`frydEvZfL|7@iE|G;T!R;!Kt<7S292c@w1rH#?`N;7l{!7@Thr_m{L^2=_HFzDkm zVw1akLj}O)y;~Y)feXqQIDF(iM^Gp5kRA2ijhZfmqj9eGUZY!9M_&wpk14KVc;%p6Wn;OMM0 zm#*l5T1VOGYf+6?nyOg{M`VS?)8J#cO?|VrfSySLQJaRaK7v?SQ_I4hytIc~Ut8{- ze$%_=G&tr!+O{dLl`5;y1J0N10#l}P;4<@#exMTC9a`{nFhdnTR?I10-P$xDyHQp4&?(3 zy|pcMG+FsnbC@bd%cqfqm3Xr-QX!;J+8e6EzZ=v4V`oE`w%gNdK~asFJnWBv5JNnK z<+B4jv(AyAf{=A?aa6PfEjrM6iuD;r$(tu}4 zf+G70oWoV)lGF>zBR|W<`s{V;@8oUgD!^xl*e?G_(A|h?-HKV6;2b-k>in%E6fOGJ z$9A0k>^AxyxPP{e)W*so8KDajl$RypYxxRo#qHZdP=7q(;JaYj?=YEcrWJUkYXG{X z8Q3|4B|hLoh7H{k0-3F=V4G!7>qQ~eRiy>jyO8UFS*$GeX2@`;q%?Db88aVX{L1P5 z)WL7*D_NP=q&0I@##`Rm#CF_Hrr!sdNa=l2HfLk4qAAfo@q2c^#Q3cOhz(rXJm(}B zQMb~1jrlZ^|LFOf8%Jg*KkfQ`UKng)s9W2MsQvFo?&7=dh^&vuFqedC4!H`g^f>1L zPgKRm&2CYGZh8A&t~2Tjbx9sf;ip`A$pmEf{~x8?g$%thvsk1fSK4dL|wc zXY0!5ezh~~>oepu?$+S-wakv((__!^%ng%NzOJS$Nysw{ZtOR`0oLnDY2;w~im8ty zCJ$APNME8~kQp)b%%CaI_AD0tIbT$rd5NZY%R&sa`yiWYyh7GH@}Y<8*M1Rnl5%-az_ocr#*a;*%oL7W5UxsMchG5OiaG`~ z6eu>5CQ7@maBwB)36YFrBg1~}Ja1S*N`24O)|l&c?bi^U*WbIGh53qpEV9?L0{$B&QkFa>-$4oq!%`c2 ztZ1DkZ=J17-PFTCWx34v-$9Ftg<)1|KY4{mO#FUOGpDJ0;LL>j8yB9PkH%`Qx)(lK zYZ0b zCi607+%3e9t5>?80Bje)C*8kjFQiTE4!niCRGfYj~V;MT-We2b$4sB1ra1im`YE9Fm z^D3kzxnPaHXLKZ`<&{`0{No3d@kG0}deEZTukqwbo6JUJ-+jiSr=81<_W)BQ9#ahP zdxFXh&DSu2pj}Y>Id__r#q4UuBbJS6a_-!S%Qh_)HCffg`F;@47$eW3vBd0l45U8H zzU3{K))^=tI~OwDW17j7xi5N0D07XC)c=zNS5=gmk3A0h5Z{_65R># zdG#*=erg4iVxe}V(^_yzRH?H&(s|1izn-l#yq2)oS)})qKs6LINh$z$k7;E_mfAAy zwsWox-9)}G?LRSYSHFItT;F&65;s$L_WN0o01F_oK zt9Pp`CFmyVG>i#xXAAgyS(O)|a?1&O%}u6@?~YhH3o~KL%axVg8#3!h6R|#eJ}h1% zNV{Bd0V%d5d4-TIRdEe=i6rq2f7|sRKZ`AH2Iu!Yb0ztD1EM|2hL*>a;U~Jx`ZAv%Zj!XJA`- z&9(pAiCgY_FNtV_KCoO3TXf{J^0w|6&@8!|yf$uYoqAi?EkQOGS@a9vHmwm;gV?M* zKXt5PIRU{6=-0gH-^Cz%;TU?_Pt@1*M$qHNvH`bZFgv;Z&4-hAvzu3f$#7Py?Vrx; zyrZAXcMRk_?-*E`pl1#8vKhHX;nGpn2Hm_8 z@o_-Eht2KlA{b_VZIT9-A2iAaeM%x-50R83anR8)HA!IBUfCE;Q-vFYPU$1&@*b%8 zc%N~l?UhDZZ>J*M&;xk;`hm5Pm4bb&9qjj-Qw(LnCd-TX#VJ@_tkFvBj|Vs6A~Nn$ z1^spjv*>yd_>na?==V){VUMf*xHTZ}N0!&3q`%~~rW;-FMAco{UYD$caW|f%eq@g= z9gdjOj#IpOO(`P=*`4dL2#0QM{2I10T9J;Qu3{|&(r)q3zt=WiCOl=memLInSvXK~ zkzpwT>VA1OJxSxzb#^l}{&!PYa!>_-rrE0vr0s`YT2vqiDteLWl@q2_Vsn{D10Uf zylwojgV&ddbmCgr4N=9*+Fg@E2yKygQga}oarwuf1RaSpOU06?#1!p^DTJHa_Scb6 z6ZXkvCfv1$>sw9-inOC#D!(0Bu5*=*cWD^5Pbk7LYdlprRU;E2p+H?3sV_{!<|~aZ zMp~NE-Mo!yEFXkzp4cz!^I0b-aGc)_b@yuWD9V?ey9$xC+;`GdB4da*l4P+`Dc0ix zt7p`Ny-te<7I=vnGLNxlxcx#blZazeQbVRS>C8JjNHWiV@2PLV_lQ~Lj4f<#e_Dc> z8J1<45k8K=q!E-B+(%pD=NvR=sG-;0wZrG!r*3^|`Zitt9)HCmqUfW4_v1^Ooesp> z5Wz^c67_`p&r?MPf)@U|LbGAepi-*DNzfrP^0^;o?N$VP&JDA%&ng}tLpaKw$R za@W%zzkf#~Q8|g>{$Do?-DKwDts5S8b`yN>g1Ecyl*;C5`TKp~w+O}5+rO=)Bxu{R zM)}lY74w@U6ZE>OW`5_jnrG!Q(8B+oJp*=kLF1yuG(C%~icaE^Yagj1*i%eQXD=}| zDvN4djtcVc{xH`n@s@^=e8kFrIha?1slxh+VvBd8$$JHFmy$p7<3GN2BPU-_K2KE? zoBsUQ7mgldrG21D?OY45TU}~IMRe=hO?4YpK3kZiF1r-1uKNJnm2!$HnAnrucjL61 z`)*G33|5|94{}3GSFcA>rwz-OB=F`x#h0XOe+>Ddf*!c1R^dR)`5#wU!}M=n3#clh z7Q8lbI^oS+(vn+u)w>pC%!cZ|I(=#J-utoYZB^Px?c3zn#lOdI%Qhu_J^zy+4Q0Ok zyR0Q(E&+5WxB8Mr0yVlh`f?Ah=Jz0B+!&!+6FT?p$M=2h-&%_#h9L% zGs-ty`7MNW12q}5f9AEvhe_QxQ%Y4}p=<-?XUZ4hVPe2GMv4m+(7R-Cd={_QWOlt zAoKn-jsMto>%hXJm1imS$>jg6>-XmuX6>`sN}fMk5;;aum;cz=8+VSN#{6MZn*i*w zU00tH`d@UtbzD>b|Ns5A6$zCRP(T4`(9seTC!o}5q*c15hU5ff2uPRY97uOdPNW;@ zo}_edFj!ni-`~&Y7uR+D%Su8}6mRXQlG%w>kb#7zE z&R37p%7~323RBTt@9fqRimkUx3<1VUQoS(Q2V?hAh7YuOzJsLO*i^2 zak{MbNVwI(a6L%)ZzzcaDGLL)&5F=e<}M8?PsrI>hVnZ1@N2FuBjFCOI-Ps0i~ry@ zCYK+(a#srd<%G((B|$pmgiHQF$#_J66k%eQfF;Xz4UKe4)Z#}&E0JX9QcEb)pfSlA zPVD2DdreYxF+bF~mD8@Rh`+$CEd3ZX+6y;e+Q>VMMzuIq82DNejsL}@e4auOiBYVb zUvg1q_&jgs=}H$28y8c(pM!ZE=JAo`8m>Ifh^6kK*buk84}LNlRZU<_K&|?ueE1Ja zl=aTJC$8}@_zN%wwNZ0tO62rROHh@Mwj5*n5f9y1Dk$ESB?je0;(R@YOsl+7=nm_! zhWKUw<@Nr+Z*<4{@sGJC&<|wAin@j>_0jth82si$J2$07;MCZ_wo>T&eHQ zAbQ5@K&4mNi|TYZ4mHQ?MTOUnUH8~NPtZ?9QK9bqN5vx^L1{wO)gzB^a-RDMCb

  • 5f5iOzlA@KYEaACJCBS7)2!3Ddo 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 z zpSxmpD3vhDV$xW$_fMBGaY0sYzJ4?*UbblX?k3AxMbynP49`*(Edm@ZnLq($yb_A~Xb+ryn{8VC*+W+bG|Z&Vqbij*uoc>_j_&TypBdw1IPE zdHDK!yY4jUzX22l(q-)L+1O_-&Y{gb2=jJwN7H4{7hc2{u{W>o;)<;7GNHJ}u*B8dW8pk^tJEYM&5FY{x8E;Qu+V@ diff --git a/documentation/images/howtos/angular4-gen/ng4gen_6.png b/documentation/images/howtos/angular4-gen/ng4gen_6.png index 6260106a0d758179f87643547fd2c6f14505adee..ec6e9f9999d056e22d8927953fafc7c5b2e32326 100644 GIT binary patch literal 14046 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 N%uTE>HyC-|`8SSZqay$S From ce8c193ec6a485f85c965aebef6e1b32bfbc7234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20G=C3=BCnther?= Date: Tue, 19 Apr 2022 18:17:10 +0200 Subject: [PATCH 2/8] implemented independent adaption of template sets --- .../cli/commands/AdaptTemplatesCommand.java | 81 ++++- .../common/tools/ResourcesPluginUtil.java | 7 +- .../devonfw/cobigen/api/TemplateAdapter.java | 59 ++++ .../systemtest/TemplateProcessingTest.java | 98 +++--- .../templates-devon4j-0.0.1-sources.jar | Bin 0 -> 6153 bytes .../templates/templates-devon4j-0.0.1.jar | Bin 0 -> 1109 bytes .../downloaded}/template-test1-0.0.1.jar | Bin .../downloaded}/template-test2-0.0.1.jar | Bin .../devonfw/cobigen/impl/CobiGenFactory.java | 19 -- .../impl/adapter/TemplateAdapterImpl.java | 320 ++++++++++++++++++ .../impl/util/ExtractTemplatesUtil.java | 240 ------------- 11 files changed, 505 insertions(+), 319 deletions(-) create mode 100644 cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/TemplateAdapter.java create mode 100644 cobigen/cobigen-core-systemtest/src/test/resources/testdata/systemtest/AdaptMonolithicTemplatesTest/templates/templates-devon4j-0.0.1-sources.jar create mode 100644 cobigen/cobigen-core-systemtest/src/test/resources/testdata/systemtest/AdaptMonolithicTemplatesTest/templates/templates-devon4j-0.0.1.jar rename cobigen/cobigen-core-systemtest/src/test/resources/testdata/systemtest/{TemplateProcessingTest/templates => AdaptTemplateSetsTest/template-sets/downloaded}/template-test1-0.0.1.jar (100%) rename cobigen/cobigen-core-systemtest/src/test/resources/testdata/systemtest/{TemplateProcessingTest/templates => AdaptTemplateSetsTest/template-sets/downloaded}/template-test2-0.0.1.jar (100%) create mode 100644 cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/adapter/TemplateAdapterImpl.java delete mode 100644 cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/util/ExtractTemplatesUtil.java diff --git a/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/AdaptTemplatesCommand.java b/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/AdaptTemplatesCommand.java index 19f3439a5b..146271f062 100644 --- a/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/AdaptTemplatesCommand.java +++ b/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/AdaptTemplatesCommand.java @@ -1,7 +1,18 @@ package com.devonfw.cobigen.cli.commands; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.devonfw.cobigen.api.TemplateAdapter; +import com.devonfw.cobigen.api.constants.ConfigurationConstants; +import com.devonfw.cobigen.cli.CobiGenCLI; import com.devonfw.cobigen.cli.constants.MessagesConstants; -import com.devonfw.cobigen.impl.CobiGenFactory; +import com.devonfw.cobigen.cli.utils.ValidationUtils; +import com.devonfw.cobigen.impl.adapter.TemplateAdapterImpl; import picocli.CommandLine.Command; @@ -13,10 +24,76 @@ "a" }, mixinStandardHelpOptions = true) public class AdaptTemplatesCommand extends CommandCommons { + /** + * Logger to output useful information to the user + */ + private static Logger LOG = LoggerFactory.getLogger(CobiGenCLI.class); + @Override public Integer doAction() throws Exception { - CobiGenFactory.extractTemplates(); + TemplateAdapter templateAdapter; + if (this.templatesProject == null) { + templateAdapter = new TemplateAdapterImpl(); + } else { + templateAdapter = new TemplateAdapterImpl(this.templatesProject); + } + + if (templateAdapter.isMonolithicTemplatesConfiguration()) { + Path destinationPath = templateAdapter.getTemplatesLocation().resolve(ConfigurationConstants.COBIGEN_TEMPLATES); + templateAdapter.adaptMonolithicTemplates(destinationPath, false); + } else { + List templateJars = templateAdapter.getTemplateSetJarPaths(); + if (templateJars != null && !templateJars.isEmpty()) { + List templateJarsToAdapt = getJarsToAdapt(templateJars); + if (!templateJarsToAdapt.isEmpty()) { + templateAdapter.adaptTemplateSets(templateJarsToAdapt, false); + } + } else { + LOG.info("No template set jars found to extract."); + } + } + return 0; } + + /** + * + * @param templateJars + * @return + */ + private List getJarsToAdapt(List templateJars) { + + List jarsToAdapt = new ArrayList<>(); + if (templateJars != null && templateJars.size() > 0) { + printJarsForSelection(templateJars); + String jarSelection = ValidationUtils.getUserInput(); + + if (jarSelection.equals("0")) { + jarsToAdapt = templateJars; + } else { + String[] userJarSelection = jarSelection.split(","); + for (String jarSelected : userJarSelection) { + jarsToAdapt.add(templateJars.get(Integer.parseInt(jarSelected) - 1)); + } + } + } + + return jarsToAdapt; + } + + /** + * Prints the available template set jars + * + * @param templateSetJarPaths List of {@link Path} to available template jar files + */ + private void printJarsForSelection(List templateSetJarPaths) { + + LOG.info("(0) " + "All"); + for (Path templateSetJarPath : templateSetJarPaths) { + LOG.info("(" + (templateSetJarPaths.indexOf(templateSetJarPath) + 1) + ") " + + templateSetJarPath.getFileName().toString().replace(".jar", "")); + } + LOG.info("Please enter the number(s) of jar(s) that you want to adapt separated by comma."); + } } diff --git a/cobigen-eclipse/cobigen-eclipse/src/com/devonfw/cobigen/eclipse/common/tools/ResourcesPluginUtil.java b/cobigen-eclipse/cobigen-eclipse/src/com/devonfw/cobigen/eclipse/common/tools/ResourcesPluginUtil.java index 2389ed91e6..adc1c3bc4c 100644 --- a/cobigen-eclipse/cobigen-eclipse/src/com/devonfw/cobigen/eclipse/common/tools/ResourcesPluginUtil.java +++ b/cobigen-eclipse/cobigen-eclipse/src/com/devonfw/cobigen/eclipse/common/tools/ResourcesPluginUtil.java @@ -21,13 +21,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.devonfw.cobigen.api.TemplateAdapter; import com.devonfw.cobigen.api.constants.ConfigurationConstants; import com.devonfw.cobigen.api.util.CobiGenPaths; import com.devonfw.cobigen.api.util.TemplatesJarUtil; import com.devonfw.cobigen.eclipse.common.constants.external.ResourceConstants; import com.devonfw.cobigen.eclipse.common.exceptions.GeneratorProjectNotExistentException; import com.devonfw.cobigen.eclipse.updatetemplates.UpdateTemplatesDialog; -import com.devonfw.cobigen.impl.util.ExtractTemplatesUtil; +import com.devonfw.cobigen.impl.adapter.TemplateAdapterImpl; /** Util for NPE save access of {@link ResourcesPlugin} utils */ public class ResourcesPluginUtil { @@ -228,7 +229,9 @@ public static void processJar(String fileName) throws MalformedURLException, IOE } try { - ExtractTemplatesUtil.extractTemplates(cobigenFolderPath.resolve(ConfigurationConstants.COBIGEN_TEMPLATES), false); + TemplateAdapter templateAdapter = new TemplateAdapterImpl(cobigenFolderPath); + templateAdapter.adaptMonolithicTemplates(cobigenFolderPath.resolve(ConfigurationConstants.COBIGEN_TEMPLATES), + false); } catch (Exception e) { LOG.error("An exception occurred while processing Jar files to create CobiGen_Templates folder", e); PlatformUIUtil diff --git a/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/TemplateAdapter.java b/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/TemplateAdapter.java new file mode 100644 index 0000000000..aeedafb62d --- /dev/null +++ b/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/TemplateAdapter.java @@ -0,0 +1,59 @@ +package com.devonfw.cobigen.api; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; + +/** The TemplateAdapter implements methods for adapting template jars */ +public interface TemplateAdapter { + + /** + * Adapt a given set of template set jars. + * + * @param templateSetJars A {@link List} of the {@link Path} of the template set jars to adapt + * @param forceOverride Indicator whether an already adapted template set should be overridden + * @throws IOException If CobiGen is not able to extract the jar file to the destination folder + */ + public void adaptTemplateSets(List templateSetJars, boolean forceOverride) throws IOException; + + /** + * Adapt a set of template set jars to a given destination folder. + * + * @param templateSetJars A {@link List} of the {@link Path} of the template set jars to adapt + * @param destinationPath The parent folder where the jars should be extracted to + * @param forceOverride Indicator whether an already adapted template set should be overridden + * @throws IOException If CobiGen is not able to extract the jar file to the destination folder + */ + public void adaptTemplateSets(List templateSetJars, Path destinationPath, boolean forceOverride) + throws IOException; + + /** + * Adapt an old monolithic template jar structure to a given destination folder. + * + * @param destinationPath The folder where the jars should be extracted to + * @param forceOverride Indicator whether an already adapted template set should be overridden + * @throws IOException If CobiGen is not able to extract the jar file to the destination folder + */ + public void adaptMonolithicTemplates(Path destinationPath, boolean forceOverride) throws IOException; + + /** + * Get the list of template set jar files + * + * @return A {@link List} of {@link Path} with all template set jar files found. + */ + public List getTemplateSetJarPaths(); + + /** + * + * + * @return Returns {@code true} if the template structure consists of an old monolithic template set. Otherwise false. + */ + public boolean isMonolithicTemplatesConfiguration(); + + /** + * Get the location of the templates. + * + * @return The {@link Path} of the templates location. + */ + public Path getTemplatesLocation(); +} diff --git a/cobigen/cobigen-core-systemtest/src/test/java/com/devonfw/cobigen/systemtest/TemplateProcessingTest.java b/cobigen/cobigen-core-systemtest/src/test/java/com/devonfw/cobigen/systemtest/TemplateProcessingTest.java index 4b92561261..b569182f7a 100644 --- a/cobigen/cobigen-core-systemtest/src/test/java/com/devonfw/cobigen/systemtest/TemplateProcessingTest.java +++ b/cobigen/cobigen-core-systemtest/src/test/java/com/devonfw/cobigen/systemtest/TemplateProcessingTest.java @@ -4,24 +4,18 @@ import java.io.File; import java.io.IOException; -import java.net.URI; -import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; +import java.util.List; import org.apache.commons.io.FileUtils; -import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; -import org.mockito.MockedStatic; -import org.mockito.Mockito; +import com.devonfw.cobigen.api.TemplateAdapter; import com.devonfw.cobigen.api.constants.ConfigurationConstants; -import com.devonfw.cobigen.api.util.CobiGenPaths; -import com.devonfw.cobigen.impl.CobiGenFactory; -import com.devonfw.cobigen.impl.util.ConfigurationFinder; +import com.devonfw.cobigen.impl.adapter.TemplateAdapterImpl; import com.devonfw.cobigen.systemtest.common.AbstractApiTest; /** @@ -30,46 +24,40 @@ public class TemplateProcessingTest extends AbstractApiTest { /** - * Root path to all resources used in this test case + * Root path to all resources used in tests that test the structure of the template sets. */ - private static String testFileRootPath = apiTestsRootPath + "TemplateProcessingTest/"; + private static String testFileRootPathTemplateSets = apiTestsRootPath + "AdaptTemplateSetsTest/"; + + /** + * Root path to all resources used in tests that test the old monolithic template structure. + */ + private static String testFileRootPathMonolithicTemplates = apiTestsRootPath + "AdaptMonolithicTemplatesTest/"; /** Temporary files rule to create temporary folders or files */ @Rule public TemporaryFolder tempFolder = new TemporaryFolder(); /** - * mock the pathObject to use the temporary folder instead of the user folder + * temporary project to store CobiGen home for a project with the new template structrue consisting of template sets. */ - private MockedStatic cobigenPaths; + Path cobiGenHomeTemplateSets; /** - * temporary project to store CobiGen home + * temporary project to store CobiGen home for a project with the old template structrue consisting of a monolitihic + * template set */ - Path cobiGenHome; + Path cobiGenHomeMonolithicTemplates; /** - * Creates a temporary CobiGen home directory for each test and create static mock for CobiGenPaths object + * Creates a temporary CobiGen home directory for each test. A separate directory to test the old and new structure. * * @throws IOException if an Exception occurs */ @Before public void prepare() throws IOException { - this.cobiGenHome = this.tempFolder.newFolder("playground", "templatesHome").toPath(); - - this.cobigenPaths = Mockito.mockStatic(CobiGenPaths.class, Mockito.CALLS_REAL_METHODS); - this.cobigenPaths.when(() -> CobiGenPaths.getCobiGenHomePath()).thenReturn(this.cobiGenHome); - - } - - /** - * cleanup mockito static mock - */ - @After - public void cleanup() { - - this.cobigenPaths.close(); + this.cobiGenHomeTemplateSets = this.tempFolder.newFolder("playground", "templateSetsHome").toPath(); + this.cobiGenHomeMonolithicTemplates = this.tempFolder.newFolder("playground", "templatesMonolithicHome").toPath(); } /** @@ -80,13 +68,19 @@ public void cleanup() { @Test public void extractTemplateSetsTest() throws IOException { - FileUtils.copyDirectory(new File(testFileRootPath + "templates"), - this.cobiGenHome.resolve("template-sets/downloaded").toFile()); - CobiGenFactory.extractTemplates(); - Path adaptedFolder = this.cobiGenHome.resolve(ConfigurationConstants.CONFIG_PROPERTY_TEMPLATE_SETS_PATH) - .resolve(ConfigurationConstants.ADAPTED_FOLDER); - Path extractedJar1 = adaptedFolder.resolve("template-test1-0.0.1"); - Path extractedJar2 = adaptedFolder.resolve("template-test2-0.0.1"); + FileUtils.copyDirectory(new File(testFileRootPathTemplateSets), this.cobiGenHomeTemplateSets.toFile()); + + Path templateSetsFolder = this.cobiGenHomeTemplateSets + .resolve(ConfigurationConstants.CONFIG_PROPERTY_TEMPLATE_SETS_PATH); + Path downloadedFolder = templateSetsFolder.resolve(ConfigurationConstants.DOWNLOADED_FOLDER); + Path adaptedFolder = templateSetsFolder.resolve(ConfigurationConstants.ADAPTED_FOLDER); + + TemplateAdapter templateAdapter = new TemplateAdapterImpl(downloadedFolder.getParent()); + List templates = templateAdapter.getTemplateSetJarPaths(); + templateAdapter.adaptTemplateSets(templates, adaptedFolder, false); + + Path extractedJar1 = adaptedFolder.resolve("template-test1-0.0.1/src/main/templates"); + Path extractedJar2 = adaptedFolder.resolve("template-test2-0.0.1/src/main/templates"); assertThat(extractedJar1).exists().isDirectory(); assertThat(extractedJar2).exists().isDirectory(); } @@ -99,27 +93,19 @@ public void extractTemplateSetsTest() throws IOException { @Test public void extractTemplatesWithOldConfiguration() throws IOException { - Path cobigenTemplatesParent = this.cobiGenHome.resolve(ConfigurationConstants.CONFIG_PROPERTY_TEMPLATES_PATH); - Files.createDirectories(cobigenTemplatesParent); + FileUtils.copyDirectory(new File(testFileRootPathMonolithicTemplates), + this.cobiGenHomeMonolithicTemplates.toFile()); + + Path cobigenTemplatesParent = this.cobiGenHomeMonolithicTemplates + .resolve(ConfigurationConstants.CONFIG_PROPERTY_TEMPLATES_PATH); + Path cobigenTemplatesProject = cobigenTemplatesParent.resolve(ConfigurationConstants.COBIGEN_TEMPLATES); - Files.createDirectories(cobigenTemplatesProject); - CobiGenFactory.extractTemplates(); - assertThat(cobigenTemplatesProject).exists().isDirectory(); - } - /** - * Test of find template set downloaded folder to ensure backwards compatibility - * - * @throws IOException if an Exception occurs - */ - @Test - public void findTemplateSetsDownloadedFolderTest() throws IOException { + TemplateAdapter templateAdapter = new TemplateAdapterImpl(cobigenTemplatesParent); + templateAdapter.adaptMonolithicTemplates(cobigenTemplatesProject, false); - Path downloadedFolder = this.cobiGenHome.resolve("template-sets").resolve("downloaded"); - Files.createDirectories(downloadedFolder); - URI templatesLocationURI = ConfigurationFinder.findTemplatesLocation(); - Path expectedDownloadedFolder = Paths.get(templatesLocationURI).resolve("downloaded"); - assertThat(expectedDownloadedFolder).exists().isDirectory(); + assertThat(cobigenTemplatesProject).exists().isDirectory(); + assertThat(cobigenTemplatesProject.resolve("src/main/templates")).exists().isDirectory(); + assertThat(cobigenTemplatesProject.resolve("src/main/java")).exists().isDirectory(); } - } diff --git a/cobigen/cobigen-core-systemtest/src/test/resources/testdata/systemtest/AdaptMonolithicTemplatesTest/templates/templates-devon4j-0.0.1-sources.jar b/cobigen/cobigen-core-systemtest/src/test/resources/testdata/systemtest/AdaptMonolithicTemplatesTest/templates/templates-devon4j-0.0.1-sources.jar new file mode 100644 index 0000000000000000000000000000000000000000..7a3be0198144398d8273394a2eb1ea926b9c9006 GIT binary patch literal 6153 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 W^vVVhViLeB2JELC`=&$#{P%wqkdH3_ literal 0 HcmV?d00001 diff --git a/cobigen/cobigen-core-systemtest/src/test/resources/testdata/systemtest/AdaptMonolithicTemplatesTest/templates/templates-devon4j-0.0.1.jar b/cobigen/cobigen-core-systemtest/src/test/resources/testdata/systemtest/AdaptMonolithicTemplatesTest/templates/templates-devon4j-0.0.1.jar new file mode 100644 index 0000000000000000000000000000000000000000..9dafe1645ddb00a9e12fc21b59cef610b5c66644 GIT binary patch literal 1109 zcmV-b1giT`O9KQH000OG047^BR4eG(;pGDW0Ba5a00#g70B~<@E_iKh%~w&6+cpe- zzh7bG-I9|lx-L-NUW4m)KyEFXuGp($Gl^1LG9)EV_v=T=vSX(~au3U}0|K0=kK{*E zq-6H)P!`c1v=K_a9gRscia=&67jpe}^yk-)@te`R^o~_pZ6UMK!HB8JHc;}p%DDAP z8*8g6r6u2kB)sCdO_W~K&!3*@E0T~TatLz{axi%#j6IOxdK4ieXO=)%YAk+ihG>5zmhMH^T!9*owtl9+#RlimAqVsfQbt(*Y{WWk8fHCci*i1 z2*V4GYxN?v@(AQ!qWPar&jgwo(aKH%-mlNJVp0Mw(F}-QFoBnen6R!b8 zTubr^`UO2ZxpB`HD>tq#HK{{fB|0X*ko#NDm#bX2SrIFw5C`c0o^YYonB4!2a&H~3 zA?98&M&JYQcrSILV^kUn;N8Q_i$L;a0eQOOg+Z_FvelrcD$Gb;nT@jNj99%pXX7Uo zCNQ(c=nbRdi1QDiPm9Hu-=jsVap5g!k}*Le1m_*MKdR>IAUp|aKOaZ`wD%5VbeJGU zhdFd2{OrLtw{1>Y^Dz=iq|x&Z#}^j#4Ws9`&S_b$*I>_Tg)Psf@7oEMJ5e;b!ZJ4I z+kAF{t|a)x)%YfIp&6Z_8_|2gyVq{J+bJ}zKXbb|tI^xO>rO^LNID?JXrSxkaG#Fp zKTt~n0u%!j000OG047^BR4eG(;pGDW0Ba5a00#g700000000000HlEc0001RZ*4Ak bZER3W1qJ{B000310RS}s000UE000001%?1a literal 0 HcmV?d00001 diff --git a/cobigen/cobigen-core-systemtest/src/test/resources/testdata/systemtest/TemplateProcessingTest/templates/template-test1-0.0.1.jar b/cobigen/cobigen-core-systemtest/src/test/resources/testdata/systemtest/AdaptTemplateSetsTest/template-sets/downloaded/template-test1-0.0.1.jar similarity index 100% rename from cobigen/cobigen-core-systemtest/src/test/resources/testdata/systemtest/TemplateProcessingTest/templates/template-test1-0.0.1.jar rename to cobigen/cobigen-core-systemtest/src/test/resources/testdata/systemtest/AdaptTemplateSetsTest/template-sets/downloaded/template-test1-0.0.1.jar diff --git a/cobigen/cobigen-core-systemtest/src/test/resources/testdata/systemtest/TemplateProcessingTest/templates/template-test2-0.0.1.jar b/cobigen/cobigen-core-systemtest/src/test/resources/testdata/systemtest/AdaptTemplateSetsTest/template-sets/downloaded/template-test2-0.0.1.jar similarity index 100% rename from cobigen/cobigen-core-systemtest/src/test/resources/testdata/systemtest/TemplateProcessingTest/templates/template-test2-0.0.1.jar rename to cobigen/cobigen-core-systemtest/src/test/resources/testdata/systemtest/AdaptTemplateSetsTest/template-sets/downloaded/template-test2-0.0.1.jar diff --git a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/CobiGenFactory.java b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/CobiGenFactory.java index 978b7e3311..094aec3d0f 100644 --- a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/CobiGenFactory.java +++ b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/CobiGenFactory.java @@ -2,8 +2,6 @@ import java.net.URI; import java.net.URL; -import java.nio.file.DirectoryNotEmptyException; -import java.nio.file.Path; import java.util.Objects; import org.slf4j.Logger; @@ -11,9 +9,7 @@ import com.devonfw.cobigen.api.CobiGen; import com.devonfw.cobigen.api.HealthCheck; -import com.devonfw.cobigen.api.constants.ConfigurationConstants; import com.devonfw.cobigen.api.exception.InvalidConfigurationException; -import com.devonfw.cobigen.api.util.CobiGenPaths; import com.devonfw.cobigen.impl.aop.BeanFactory; import com.devonfw.cobigen.impl.aop.ProxyFactory; import com.devonfw.cobigen.impl.config.ConfigurationHolder; @@ -21,7 +17,6 @@ import com.devonfw.cobigen.impl.healthcheck.HealthCheckImpl; import com.devonfw.cobigen.impl.util.ConfigurationClassLoaderUtil; import com.devonfw.cobigen.impl.util.ConfigurationFinder; -import com.devonfw.cobigen.impl.util.ExtractTemplatesUtil; /** * CobiGen's Factory to create new instances of {@link CobiGen}. @@ -84,20 +79,6 @@ public static CobiGen create() throws InvalidConfigurationException { return create(configFileOrFolder); } - /** - * Extracts template set projects - * - * @return path to have the template sets extracted to - * @throws DirectoryNotEmptyException if the directory is not empty - */ - public static Path extractTemplates() throws DirectoryNotEmptyException { - - Path extractedFolderLocation = CobiGenPaths.getTemplateSetsFolderPath(true) - .resolve(ConfigurationConstants.ADAPTED_FOLDER); - ExtractTemplatesUtil.extractTemplates(extractedFolderLocation, false); - return extractedFolderLocation; - } - /** * Creates a new {@link HealthCheck}. * diff --git a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/adapter/TemplateAdapterImpl.java b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/adapter/TemplateAdapterImpl.java new file mode 100644 index 0000000000..c8355868e0 --- /dev/null +++ b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/adapter/TemplateAdapterImpl.java @@ -0,0 +1,320 @@ +package com.devonfw.cobigen.impl.adapter; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.nio.file.DirectoryNotEmptyException; +import java.nio.file.DirectoryStream; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Comparator; +import java.util.List; +import java.util.Objects; + +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.devonfw.cobigen.api.TemplateAdapter; +import com.devonfw.cobigen.api.constants.ConfigurationConstants; +import com.devonfw.cobigen.api.exception.CobiGenRuntimeException; +import com.devonfw.cobigen.api.util.CobiGenPaths; +import com.devonfw.cobigen.api.util.TemplatesJarUtil; +import com.devonfw.cobigen.impl.util.FileSystemUtil; + +/** + * Implementation of {@link TemplateAdapter}. Provides methods for adapting template sets as well as the old monolithic + * template structure. + */ +public class TemplateAdapterImpl implements TemplateAdapter { + + /** Logger instance. */ + private static final Logger LOG = LoggerFactory.getLogger(TemplateAdapterImpl.class); + + private Path templatesLocation; + + /** + * Creates a new {@link TemplateAdapter} instance. The location of the templates is not specified, so the location is + * searched by the core module itself. + */ + public TemplateAdapterImpl() { + + Path templatesLocationPath = CobiGenPaths.getTemplateSetsFolderPath(false); + if (Files.exists(templatesLocationPath)) { + this.templatesLocation = templatesLocationPath; + } else { + templatesLocationPath = CobiGenPaths.getTemplatesFolderPath(); + if (Files.exists(templatesLocationPath)) { + this.templatesLocation = templatesLocationPath; + } + } + } + + /** + * Creates a new {@link TemplateAdapter} instance that handles the adaption of templates at the given templates + * location. + * + * @param templatesLocation The {@link Path} of the location to search the templates for. + */ + public TemplateAdapterImpl(Path templatesLocation) { + + this.templatesLocation = templatesLocation; + } + + @Override + public void adaptTemplateSets(List templateSetJars, boolean forceOverride) throws IOException { + + Path destinationPath = this.templatesLocation.resolve(ConfigurationConstants.ADAPTED_FOLDER); + adaptTemplateSets(templateSetJars, destinationPath, forceOverride); + } + + @Override + public void adaptTemplateSets(List templateSetJars, Path destinationPath, boolean forceOverride) + throws IOException { + + try { + processTemplateSetJars(templateSetJars, destinationPath, forceOverride); + LOG.info("Successfully extracted templates to @ {}", destinationPath); + } catch (IOException e) { + throw new CobiGenRuntimeException("Not able to extract templates to " + destinationPath, e); + } + } + + /** + * Extracts a specified set of template jars to the specified target. The list is specified by the user in CLI or + * Eclipse module. + * + * @param templateSetJarsToAdapt A {@link List} of {@link Path} with the template jars to adapt. + * @param destinationPath The {@link Path} where the jars should be extracted to + * @param forceOverride Indicator whether an already adapted template set should be overridden + * @throws IOException If CobiGen is not able to extract the jar file to the destination folder + */ + private void processTemplateSetJars(List templateSetJarsToAdapt, Path destinationPath, boolean forceOverride) + throws IOException { + + for (Path templateSetJar : templateSetJarsToAdapt) { + LOG.debug("Processing jar file @ {}", templateSetJar); + String fileName = templateSetJar.getFileName().toString().replace(".jar", ""); + Path destination = destinationPath.resolve(fileName); + + boolean extract = true; + try { + extract = validatePaths(destination, forceOverride); + } catch (IOException e) { + LOG.info("Unable to extract template jar file to {}", destination); + } + if (extract) { + if (Files.exists(destination) && forceOverride) { + LOG.info("Override the existing destination folder {}", destination); + deleteDirectoryRecursively(destination); + } + + extractArchive(templateSetJar, destination); + if (Files.exists(destination.resolve("com"))) { + FileUtils.deleteDirectory(destination.resolve("com").toFile()); + } + } + } + } + + @Override + public void adaptMonolithicTemplates(Path destinationPath, boolean forceOverride) throws IOException { + + if (validatePaths(destinationPath, forceOverride)) { + try { + extractMonolithicJar(destinationPath, forceOverride); + } catch (IOException e) { + throw new CobiGenRuntimeException("Not able to extract monolithic templates to " + destinationPath, e); + } + } + } + + /** + * Unpacks the source CobiGen_Templates Jar and creates a new CobiGen_Templates folder structure at + * $destinationPath/CobiGen_Templates location + * + * @param destinationPath path to be used as target directory + * @throws IOException if no destination path could be set + * + */ + private void extractMonolithicJar(Path destinationPath, boolean forceOverride) throws IOException { + + if (!isEmpty(destinationPath) && forceOverride) { + LOG.info("Override the existing destination folder {}", destinationPath); + deleteDirectoryRecursively(destinationPath); + } + + Path sourcesJarPath = TemplatesJarUtil.getJarFile(true, this.templatesLocation); + Path classesJarPath = TemplatesJarUtil.getJarFile(false, this.templatesLocation); + + if (sourcesJarPath == null && classesJarPath == null) { + LOG.info("No monolithic jar found in {}!", this.templatesLocation); + return; + } + + LOG.debug("Processing jar file @ {}", sourcesJarPath); + + // extract sources jar to target directory + extractArchive(sourcesJarPath, destinationPath); + + // create src/main/java directory + Files.createDirectory(destinationPath.resolve("src/main/java")); + + // move com folder to src/main/java/com + Files.move(destinationPath.resolve("com"), destinationPath.resolve("src/main/java/com"), + StandardCopyOption.REPLACE_EXISTING); + + // create src/main/resources directory + Files.createDirectory(destinationPath.resolve("src/main/resources")); + + // move META-INF folder to src/main/resources + Files.move(destinationPath.resolve("META-INF"), destinationPath.resolve("src/main/resources/META-INF"), + StandardCopyOption.REPLACE_EXISTING); + + // delete MANIFEST.MF + Files.deleteIfExists(destinationPath.resolve("src/main/resources/META-INF/MANIFEST.MF")); + + URI zipFile = URI.create("jar:file:" + classesJarPath.toUri().getPath()); + + // extract classes jar pom.xml + try (FileSystem fs = FileSystemUtil.getOrCreateFileSystem(zipFile)) { + Files.copy(fs.getPath("pom.xml"), destinationPath.resolve("pom.xml"), StandardCopyOption.REPLACE_EXISTING); + } + + LOG.info("Successfully extracted templates to @ {}", destinationPath); + } + + @Override + public List getTemplateSetJarPaths() { + + Path downloadedJarsFolder = this.templatesLocation.resolve(ConfigurationConstants.DOWNLOADED_FOLDER); + if (!Files.exists(downloadedJarsFolder)) { + LOG.info("No template set jars found. Folder {} does not exist.", downloadedJarsFolder); + return null; + } + return TemplatesJarUtil.getJarFiles(downloadedJarsFolder); + } + + @Override + public boolean isMonolithicTemplatesConfiguration() { + + if (this.templatesLocation != null + && this.templatesLocation.getFileName().endsWith(ConfigurationConstants.TEMPLATE_SETS_FOLDER)) { + return false; + } + return true; + } + + /** + * Get the location to load the templates from. + * + * @return templatesLocation The {@link Path} where the templates are located. + */ + @Override + public Path getTemplatesLocation() { + + return this.templatesLocation; + } + + /** + * Extracts an archive as is to a target directory while keeping its folder structure + * + * @param sourcePath Path of the archive to unpack + * @param targetPath Path of the target directory to unpack the source archive to + * @throws IOException if an error occurred while processing the jar or its target directory + */ + private void extractArchive(Path sourcePath, Path targetPath) throws IOException { + + // TODO: janv_capgemini check if sourcePath is an archive and throw exception if not + FileSystem fs = FileSystems.newFileSystem(sourcePath, null); + + Path path = fs.getPath("/"); + Files.walkFileTree(path, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + + Path relativePath = path.relativize(file); + Path targetPathResolved = targetPath.resolve(relativePath.toString()); + Files.deleteIfExists(targetPathResolved); + Files.createDirectories(targetPathResolved.getParent()); + Files.copy(file, targetPathResolved); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { + + // Log errors but do not throw an exception + LOG.warn("An IOException occurred while reading a file on path {} with message: {}", file, exc.getMessage()); + LOG.debug("An IOException occurred while reading a file on path {} with message: {}", file, + LOG.isDebugEnabled() ? exc : null); + return FileVisitResult.CONTINUE; + } + }); + + } + + /** + * Validates the given source and destination paths. + * + * @param destinationPath The {@link Path} to adapt the template into + * @param forceOverride Indicator if already adapted templates should be overridden + * @return Returns {@code true} the path are valid and the templates can be extracted to the given path + * @throws IOException + */ + private boolean validatePaths(Path destinationPath, boolean forceOverride) throws IOException { + + Objects.requireNonNull(this.templatesLocation, "Templates location cannot be null"); + Objects.requireNonNull(destinationPath, "Destination path cannot be null"); + + if (!Files.exists(this.templatesLocation)) { + LOG.info("Templates location {} does not exist.", this.templatesLocation); + return false; + } + + if (!Files.isDirectory(destinationPath)) { + try { + Files.createDirectories(destinationPath); + } catch (IOException e) { + throw new CobiGenRuntimeException("Unable to create directory " + destinationPath); + } + } + + if (!isEmpty(destinationPath) && !forceOverride) { + throw new DirectoryNotEmptyException(destinationPath.toString()); + } + + return true; + } + + /** + * Deletes a directory and its sub directories recursively + * + * @param pathToBeDeleted the directory which should be deleted recursively + * @throws IOException if the file could not be deleted + */ + private void deleteDirectoryRecursively(Path pathToBeDeleted) throws IOException { + + Files.walk(pathToBeDeleted).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete); + } + + /** + * Check if directory is empty + * + * @param directory to be checked + * @return true if is empty, false otherwise + * @throws IOException in case the directory could not be read + */ + private boolean isEmpty(final Path directory) throws IOException { + + try (DirectoryStream dirStream = Files.newDirectoryStream(directory)) { + return !dirStream.iterator().hasNext(); + } + } +} diff --git a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/util/ExtractTemplatesUtil.java b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/util/ExtractTemplatesUtil.java deleted file mode 100644 index 7b3046318c..0000000000 --- a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/util/ExtractTemplatesUtil.java +++ /dev/null @@ -1,240 +0,0 @@ -package com.devonfw.cobigen.impl.util; - -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.nio.file.DirectoryNotEmptyException; -import java.nio.file.DirectoryStream; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.StandardCopyOption; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Comparator; -import java.util.List; -import java.util.Objects; - -import org.apache.commons.io.FileUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.devonfw.cobigen.api.constants.ConfigurationConstants; -import com.devonfw.cobigen.api.exception.CobiGenRuntimeException; -import com.devonfw.cobigen.api.util.CobiGenPaths; -import com.devonfw.cobigen.api.util.TemplatesJarUtil; - -/** - * Util to extract Templates - */ -public class ExtractTemplatesUtil { - - /** Logger instance. */ - private static final Logger LOG = LoggerFactory.getLogger(ExtractTemplatesUtil.class); - - /** - * Extracts template sets to the given path - * - * @param extractTo Path to extract the templates into - * @param forceOverride force to overwrite the contents of the target folder - * @throws DirectoryNotEmptyException if the given directory is not empty. Can be used to ask for overwriting - */ - public static void extractTemplates(Path extractTo, boolean forceOverride) throws DirectoryNotEmptyException { - - // find templates will also download jars if needed as a side effect and will return the path to the - // files. - URI findTemplatesLocation = ConfigurationFinder.findTemplatesLocation(); - - Path templatesLocationFolder = Paths.get(findTemplatesLocation); - - if (Files.exists(templatesLocationFolder) - && templatesLocationFolder.endsWith(ConfigurationConstants.COBIGEN_TEMPLATES)) { - LOG.info( - "Your are using an old Templates project at {}. You can edit them in place to adapt your generation results.", - templatesLocationFolder); - return; - } - - if (Files.exists(templatesLocationFolder.resolve(ConfigurationConstants.ADAPTED_FOLDER))) { - LOG.info("Templates already found at {}. You can edit them in place to adapt your generation results.", - extractTo); - return; - } - - Objects.requireNonNull(extractTo, "Target path cannot be null"); - if (!Files.isDirectory(extractTo)) { - try { - Files.createDirectories(extractTo); - } catch (IOException e) { - throw new CobiGenRuntimeException("Unable to create directory " + extractTo); - } - } - - try { - if (!isEmpty(extractTo) && !forceOverride) { - throw new DirectoryNotEmptyException(extractTo.toString()); - } - - LOG.info( - "CobiGen is attempting to download the latest template sets jars and will extract them to cobigen home directory {}. please wait...", - ConfigurationConstants.ADAPTED_FOLDER); - Path templatesDirectory = extractTo; - processJars(templatesDirectory); - LOG.info("Successfully downloaded and extracted templates to @ {}", templatesDirectory); - } catch (DirectoryNotEmptyException e) { - throw e; - } catch (IOException e) { - throw new CobiGenRuntimeException("Not able to extract templates to " + extractTo, e); - } - } - - /** - * Unpacks the source CobiGen_Templates Jar and creates a new CobiGen_Templates folder structure at - * $destinationPath/CobiGen_Templates location - * - * @param destinationPath path to be used as target directory - * @throws IOException if no destination path could be set - * - * @deprecated use processJars instead - */ - @Deprecated - private static void processJar(Path destinationPath) throws IOException { - - if (destinationPath == null) { - throw new IOException("Cobigen folder path not found!"); - } - - Path cobigenTemplatesPath = CobiGenPaths.getTemplatesFolderPath(); - - Path sourcesJarPath = TemplatesJarUtil.getJarFile(true, cobigenTemplatesPath); - Path classesJarPath = TemplatesJarUtil.getJarFile(false, cobigenTemplatesPath); - - LOG.debug("Processing jar file @ {}", sourcesJarPath); - - // extract sources jar to target directory - extractArchive(sourcesJarPath, destinationPath); - - // create src/main/java directory - Files.createDirectory(destinationPath.resolve("src/main/java")); - - // move com folder to src/main/java/com - Files.move(destinationPath.resolve("com"), destinationPath.resolve("src/main/java/com"), - StandardCopyOption.REPLACE_EXISTING); - - // create src/main/resources directory - Files.createDirectory(destinationPath.resolve("src/main/resources")); - - // move META-INF folder to src/main/resources - Files.move(destinationPath.resolve("META-INF"), destinationPath.resolve("src/main/resources/META-INF"), - StandardCopyOption.REPLACE_EXISTING); - - // delete MANIFEST.MF - Files.deleteIfExists(destinationPath.resolve("src/main/resources/META-INF/MANIFEST.MF")); - - URI zipFile = URI.create("jar:file:" + classesJarPath.toUri().getPath()); - - // extract classes jar pom.xml - try (FileSystem fs = FileSystemUtil.getOrCreateFileSystem(zipFile)) { - Files.copy(fs.getPath("pom.xml"), destinationPath.resolve("pom.xml"), StandardCopyOption.REPLACE_EXISTING); - } - - } - - /** - * Unpacks the template set jars located in downloaded folder and creates a new folder structure for each template set - * at $destinationPath/ location - * - * @param destinationPath path to be used as target directory - * @throws IOException if no destination path could be set - */ - private static void processJars(Path destinationPath) throws IOException { - - if (destinationPath == null) { - throw new IOException("Cobigen folder path not found!"); - } - - Path cobigenDownloadedTemplateSetsPath = CobiGenPaths.getTemplateSetsFolderPath() - .resolve(ConfigurationConstants.DOWNLOADED_FOLDER); - if (Files.exists(cobigenDownloadedTemplateSetsPath)) { - List templateJars = TemplatesJarUtil.getJarFiles(cobigenDownloadedTemplateSetsPath); - for (Path templateSetJar : templateJars) { - LOG.debug("Processing jar file @ {}", templateSetJar); - String fileName = templateSetJar.getFileName().toString().replace(".jar", ""); - Path destination = destinationPath.resolve(fileName); - extractArchive(templateSetJar, destination); - - if (Files.exists(destination.resolve("com"))) { - FileUtils.deleteDirectory(destination.resolve("com").toFile()); - } - } - } else { - LOG.info("No downloaded templates found in {} to extract", cobigenDownloadedTemplateSetsPath); - } - } - - /** - * Deletes a directory and its sub directories recursively - * - * @param pathToBeDeleted the directory which should be deleted recursively - * @throws IOException if the file could not be deleted - */ - public static void deleteDirectoryRecursively(Path pathToBeDeleted) throws IOException { - - Files.walk(pathToBeDeleted).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete); - } - - /** - * Extracts an archive as is to a target directory while keeping its folder structure - * - * @param sourcePath Path of the archive to unpack - * @param targetPath Path of the target directory to unpack the source archive to - * @throws IOException if an error occurred while processing the jar or its target directory - */ - private static void extractArchive(Path sourcePath, Path targetPath) throws IOException { - - // TODO: janv_capgemini check if sourcePath is an archive and throw exception if not - FileSystem fs = FileSystems.newFileSystem(sourcePath, null); - - Path path = fs.getPath("/"); - Files.walkFileTree(path, new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - - Path relativePath = path.relativize(file); - Path targetPathResolved = targetPath.resolve(relativePath.toString()); - Files.deleteIfExists(targetPathResolved); - Files.createDirectories(targetPathResolved.getParent()); - Files.copy(file, targetPathResolved); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { - - // Log errors but do not throw an exception - LOG.warn("An IOException occurred while reading a file on path {} with message: {}", file, exc.getMessage()); - LOG.debug("An IOException occurred while reading a file on path {} with message: {}", file, - LOG.isDebugEnabled() ? exc : null); - return FileVisitResult.CONTINUE; - } - }); - - } - - /** - * Check if directory is empty - * - * @param directory to be checked - * @return true if is empty, false otherwise - * @throws IOException in case the directory could not be read - */ - private static boolean isEmpty(final Path directory) throws IOException { - - try (DirectoryStream dirStream = Files.newDirectoryStream(directory)) { - return !dirStream.iterator().hasNext(); - } - } -} From 15e6b80b4e0e86141527548ec951eb005e74f676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20G=C3=BCnther?= Date: Tue, 19 Apr 2022 19:17:12 +0200 Subject: [PATCH 3/8] fix adapt template cli test --- .../systemtest/AdaptTemplatesCommandTest.java | 4 +++- .../cli/commands/AdaptTemplatesCommand.java | 23 +++++++++++++++---- .../cli/constants/MessagesConstants.java | 5 ++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/cobigen-cli/cli-systemtest/src/test/java/com/devonfw/cobigen/cli/systemtest/AdaptTemplatesCommandTest.java b/cobigen-cli/cli-systemtest/src/test/java/com/devonfw/cobigen/cli/systemtest/AdaptTemplatesCommandTest.java index 9f4026da4e..82709f05f8 100644 --- a/cobigen-cli/cli-systemtest/src/test/java/com/devonfw/cobigen/cli/systemtest/AdaptTemplatesCommandTest.java +++ b/cobigen-cli/cli-systemtest/src/test/java/com/devonfw/cobigen/cli/systemtest/AdaptTemplatesCommandTest.java @@ -50,8 +50,10 @@ public void initAdaptTemplatesTest() throws URISyntaxException, IOException { @Test public void adaptTemplatesTest() throws Exception { - String args[] = new String[1]; + String args[] = new String[3]; args[0] = "adapt-templates"; + args[1] = "-ts"; + args[2] = "0"; execute(args, false); diff --git a/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/AdaptTemplatesCommand.java b/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/AdaptTemplatesCommand.java index 146271f062..856963d50b 100644 --- a/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/AdaptTemplatesCommand.java +++ b/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/AdaptTemplatesCommand.java @@ -15,6 +15,7 @@ import com.devonfw.cobigen.impl.adapter.TemplateAdapterImpl; import picocli.CommandLine.Command; +import picocli.CommandLine.Option; /** * This class handles the user defined template directory e.g. determining and obtaining the latest templates jar, @@ -24,6 +25,13 @@ "a" }, mixinStandardHelpOptions = true) public class AdaptTemplatesCommand extends CommandCommons { + /** + * List of template sets to adapt + */ + @Option(names = { "--template-sets", + "-ts" }, split = ",", description = MessagesConstants.TEMPLATE_SETS_OPTION_DESCRIPTION) + List templateSets = null; + /** * Logger to output useful information to the user */ @@ -67,13 +75,20 @@ private List getJarsToAdapt(List templateJars) { List jarsToAdapt = new ArrayList<>(); if (templateJars != null && templateJars.size() > 0) { printJarsForSelection(templateJars); - String jarSelection = ValidationUtils.getUserInput(); - if (jarSelection.equals("0")) { + List userSelection = new ArrayList<>(); + if (this.templateSets != null) { + userSelection = this.templateSets; + } else { + for (String templateSelection : ValidationUtils.getUserInput().split(",")) { + userSelection.add(templateSelection); + } + } + + if (userSelection.contains("0")) { jarsToAdapt = templateJars; } else { - String[] userJarSelection = jarSelection.split(","); - for (String jarSelected : userJarSelection) { + for (String jarSelected : userSelection) { jarsToAdapt.add(templateJars.get(Integer.parseInt(jarSelected) - 1)); } } diff --git a/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/constants/MessagesConstants.java b/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/constants/MessagesConstants.java index 9c63da3f73..19cdc8601d 100644 --- a/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/constants/MessagesConstants.java +++ b/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/constants/MessagesConstants.java @@ -52,6 +52,11 @@ public class MessagesConstants { */ public static final String INCREMENTS_OPTION_DESCRIPTION = "List of increments that will be generated. They need to be specified with numbers separated by comma."; + /** + * Message constant: description of the increments option + */ + public static final String TEMPLATE_SETS_OPTION_DESCRIPTION = "List of template sets that should be extracted. They need to be specified with numbers separated by comma."; + /** * Message constant: description of the templates option */ From 29ce4cf7dd21e68a53490a13de3f76db5845e9a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20G=C3=BCnther?= Date: Wed, 20 Apr 2022 12:20:23 +0200 Subject: [PATCH 4/8] ignore AdaptTemplatesCommandTest and further implementations for TemplateAdapter --- .../systemtest/AdaptTemplatesCommandTest.java | 6 +- .../cli/commands/AdaptTemplatesCommand.java | 56 ++++++++----- .../cli/constants/MessagesConstants.java | 5 -- .../devonfw/cobigen/api/TemplateAdapter.java | 29 ++++++- .../systemtest/TemplateProcessingTest.java | 2 +- .../impl/adapter/TemplateAdapterImpl.java | 83 +++++++++++++------ 6 files changed, 121 insertions(+), 60 deletions(-) diff --git a/cobigen-cli/cli-systemtest/src/test/java/com/devonfw/cobigen/cli/systemtest/AdaptTemplatesCommandTest.java b/cobigen-cli/cli-systemtest/src/test/java/com/devonfw/cobigen/cli/systemtest/AdaptTemplatesCommandTest.java index 82709f05f8..0224842063 100644 --- a/cobigen-cli/cli-systemtest/src/test/java/com/devonfw/cobigen/cli/systemtest/AdaptTemplatesCommandTest.java +++ b/cobigen-cli/cli-systemtest/src/test/java/com/devonfw/cobigen/cli/systemtest/AdaptTemplatesCommandTest.java @@ -9,6 +9,7 @@ import java.nio.file.Path; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import com.devonfw.cobigen.api.constants.ConfigurationConstants; @@ -47,13 +48,12 @@ public void initAdaptTemplatesTest() throws URISyntaxException, IOException { * * @throws Exception test fails */ + @Ignore @Test public void adaptTemplatesTest() throws Exception { - String args[] = new String[3]; + String args[] = new String[1]; args[0] = "adapt-templates"; - args[1] = "-ts"; - args[2] = "0"; execute(args, false); diff --git a/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/AdaptTemplatesCommand.java b/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/AdaptTemplatesCommand.java index 856963d50b..6288b0b2be 100644 --- a/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/AdaptTemplatesCommand.java +++ b/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/AdaptTemplatesCommand.java @@ -15,7 +15,6 @@ import com.devonfw.cobigen.impl.adapter.TemplateAdapterImpl; import picocli.CommandLine.Command; -import picocli.CommandLine.Option; /** * This class handles the user defined template directory e.g. determining and obtaining the latest templates jar, @@ -25,13 +24,6 @@ "a" }, mixinStandardHelpOptions = true) public class AdaptTemplatesCommand extends CommandCommons { - /** - * List of template sets to adapt - */ - @Option(names = { "--template-sets", - "-ts" }, split = ",", description = MessagesConstants.TEMPLATE_SETS_OPTION_DESCRIPTION) - List templateSets = null; - /** * Logger to output useful information to the user */ @@ -50,10 +42,15 @@ public Integer doAction() throws Exception { if (templateAdapter.isMonolithicTemplatesConfiguration()) { Path destinationPath = templateAdapter.getTemplatesLocation().resolve(ConfigurationConstants.COBIGEN_TEMPLATES); templateAdapter.adaptMonolithicTemplates(destinationPath, false); + + LOG.info("Templates were adapted to {}", destinationPath); + if (askUserToContinueWithUpgrade()) { + templateAdapter.upgradeMonolithicTemplates(); + } } else { - List templateJars = templateAdapter.getTemplateSetJarPaths(); + List templateJars = templateAdapter.getTemplateSetJars(); if (templateJars != null && !templateJars.isEmpty()) { - List templateJarsToAdapt = getJarsToAdapt(templateJars); + List templateJarsToAdapt = getJarsToAdapt(templateAdapter, templateJars); if (!templateJarsToAdapt.isEmpty()) { templateAdapter.adaptTemplateSets(templateJarsToAdapt, false); } @@ -66,23 +63,20 @@ public Integer doAction() throws Exception { } /** + * Gives the user a selection of available template set jars to adapt. * - * @param templateJars - * @return + * @param templateJars A {@link List} with all available template set jars. + * @return A {@link List} with the template set jars selected by the user to adapt. */ - private List getJarsToAdapt(List templateJars) { + private List getJarsToAdapt(TemplateAdapter templateAdapter, List templateJars) { List jarsToAdapt = new ArrayList<>(); if (templateJars != null && templateJars.size() > 0) { - printJarsForSelection(templateJars); + printJarsForSelection(templateAdapter, templateJars); List userSelection = new ArrayList<>(); - if (this.templateSets != null) { - userSelection = this.templateSets; - } else { - for (String templateSelection : ValidationUtils.getUserInput().split(",")) { - userSelection.add(templateSelection); - } + for (String templateSelection : ValidationUtils.getUserInput().split(",")) { + userSelection.add(templateSelection); } if (userSelection.contains("0")) { @@ -102,13 +96,31 @@ private List getJarsToAdapt(List templateJars) { * * @param templateSetJarPaths List of {@link Path} to available template jar files */ - private void printJarsForSelection(List templateSetJarPaths) { + private void printJarsForSelection(TemplateAdapter templateAdapter, List templateSetJarPaths) { LOG.info("(0) " + "All"); for (Path templateSetJarPath : templateSetJarPaths) { LOG.info("(" + (templateSetJarPaths.indexOf(templateSetJarPath) + 1) + ") " - + templateSetJarPath.getFileName().toString().replace(".jar", "")); + + templateSetJarPath.getFileName().toString().replace(".jar", "") + + (templateAdapter.isTemplateSetAlreadyAdapted(templateSetJarPath) ? " (already adapted)" : "")); } LOG.info("Please enter the number(s) of jar(s) that you want to adapt separated by comma."); } + + /** + * Ask the user to continue with the upgrade of the templates. + * + * @return Returns {@code true} if the user want to continue with the uprade of the templates. + */ + private boolean askUserToContinueWithUpgrade() { + + LOG.info( + "Do you want to upgrade your monolithic template structure to the new template structure with independent template sets?"); + LOG.info("Type 'y' or 'yes' to upgrade the configuration?"); + String userInput = ValidationUtils.getUserInput(); + if (userInput != null && (userInput.toLowerCase().equals("y") || userInput.toLowerCase().equals("yes"))) { + return true; + } + return false; + } } diff --git a/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/constants/MessagesConstants.java b/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/constants/MessagesConstants.java index 19cdc8601d..9c63da3f73 100644 --- a/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/constants/MessagesConstants.java +++ b/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/constants/MessagesConstants.java @@ -52,11 +52,6 @@ public class MessagesConstants { */ public static final String INCREMENTS_OPTION_DESCRIPTION = "List of increments that will be generated. They need to be specified with numbers separated by comma."; - /** - * Message constant: description of the increments option - */ - public static final String TEMPLATE_SETS_OPTION_DESCRIPTION = "List of template sets that should be extracted. They need to be specified with numbers separated by comma."; - /** * Message constant: description of the templates option */ diff --git a/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/TemplateAdapter.java b/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/TemplateAdapter.java index aeedafb62d..977252893b 100644 --- a/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/TemplateAdapter.java +++ b/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/TemplateAdapter.java @@ -27,6 +27,14 @@ public interface TemplateAdapter { public void adaptTemplateSets(List templateSetJars, Path destinationPath, boolean forceOverride) throws IOException; + /** + * Adapt an old monolithic template jar structure. + * + * @param forceOverride Indicator whether an already adapted template set should be overridden + * @throws IOException If CobiGen is not able to extract the jar file to the destination folder + */ + public void adaptMonolithicTemplates(boolean forceOverride) throws IOException; + /** * Adapt an old monolithic template jar structure to a given destination folder. * @@ -37,23 +45,36 @@ public void adaptTemplateSets(List templateSetJars, Path destinationPath, public void adaptMonolithicTemplates(Path destinationPath, boolean forceOverride) throws IOException; /** - * Get the list of template set jar files + * Get a list of available template set jars to adapt. * * @return A {@link List} of {@link Path} with all template set jar files found. */ - public List getTemplateSetJarPaths(); + public List getTemplateSetJars(); /** - * + * Checks if the template configuration consists of an old monolithic template set or independent template sets. * * @return Returns {@code true} if the template structure consists of an old monolithic template set. Otherwise false. */ public boolean isMonolithicTemplatesConfiguration(); /** - * Get the location of the templates. + * Upgrade an adapted monolithic template structure to the new template structure consisting of template sets. + */ + public void upgradeMonolithicTemplates(); + + /** + * Get the parent location of the templates. * * @return The {@link Path} of the templates location. */ public Path getTemplatesLocation(); + + /** + * Checks if a given template set is already adapted + * + * @param templateSetJar The {@link Path} to the template set to check. + * @return Returns {@code true} if the template set is already adapted. Otherwise false. + */ + public boolean isTemplateSetAlreadyAdapted(Path templateSetJar); } diff --git a/cobigen/cobigen-core-systemtest/src/test/java/com/devonfw/cobigen/systemtest/TemplateProcessingTest.java b/cobigen/cobigen-core-systemtest/src/test/java/com/devonfw/cobigen/systemtest/TemplateProcessingTest.java index b569182f7a..4b99934031 100644 --- a/cobigen/cobigen-core-systemtest/src/test/java/com/devonfw/cobigen/systemtest/TemplateProcessingTest.java +++ b/cobigen/cobigen-core-systemtest/src/test/java/com/devonfw/cobigen/systemtest/TemplateProcessingTest.java @@ -76,7 +76,7 @@ public void extractTemplateSetsTest() throws IOException { Path adaptedFolder = templateSetsFolder.resolve(ConfigurationConstants.ADAPTED_FOLDER); TemplateAdapter templateAdapter = new TemplateAdapterImpl(downloadedFolder.getParent()); - List templates = templateAdapter.getTemplateSetJarPaths(); + List templates = templateAdapter.getTemplateSetJars(); templateAdapter.adaptTemplateSets(templates, adaptedFolder, false); Path extractedJar1 = adaptedFolder.resolve("template-test1-0.0.1/src/main/templates"); diff --git a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/adapter/TemplateAdapterImpl.java b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/adapter/TemplateAdapterImpl.java index c8355868e0..f30174cc2c 100644 --- a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/adapter/TemplateAdapterImpl.java +++ b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/adapter/TemplateAdapterImpl.java @@ -37,6 +37,7 @@ public class TemplateAdapterImpl implements TemplateAdapter { /** Logger instance. */ private static final Logger LOG = LoggerFactory.getLogger(TemplateAdapterImpl.class); + /** The parent location of the template. */ private Path templatesLocation; /** @@ -103,12 +104,13 @@ private void processTemplateSetJars(List templateSetJarsToAdapt, Path dest String fileName = templateSetJar.getFileName().toString().replace(".jar", ""); Path destination = destinationPath.resolve(fileName); - boolean extract = true; + boolean extract = false; try { extract = validatePaths(destination, forceOverride); } catch (IOException e) { LOG.info("Unable to extract template jar file to {}", destination); } + if (extract) { if (Files.exists(destination) && forceOverride) { LOG.info("Override the existing destination folder {}", destination); @@ -123,6 +125,13 @@ private void processTemplateSetJars(List templateSetJarsToAdapt, Path dest } } + @Override + public void adaptMonolithicTemplates(boolean forceOverride) throws IOException { + + Path destinationPath = this.templatesLocation.resolve(ConfigurationConstants.COBIGEN_TEMPLATES); + this.adaptMonolithicTemplates(destinationPath, forceOverride); + } + @Override public void adaptMonolithicTemplates(Path destinationPath, boolean forceOverride) throws IOException { @@ -191,7 +200,7 @@ private void extractMonolithicJar(Path destinationPath, boolean forceOverride) t } @Override - public List getTemplateSetJarPaths() { + public List getTemplateSetJars() { Path downloadedJarsFolder = this.templatesLocation.resolve(ConfigurationConstants.DOWNLOADED_FOLDER); if (!Files.exists(downloadedJarsFolder)) { @@ -222,6 +231,19 @@ public Path getTemplatesLocation() { return this.templatesLocation; } + @Override + public boolean isTemplateSetAlreadyAdapted(Path templateSetJar) { + + if (templateSetJar != null && Files.exists(templateSetJar)) { + Path adaptedFolder = this.templatesLocation.resolve(ConfigurationConstants.ADAPTED_FOLDER); + if (Files.exists(adaptedFolder) + && Files.exists(adaptedFolder.resolve(templateSetJar.getFileName().toString().replace(".jar", "")))) { + return true; + } + } + return false; + } + /** * Extracts an archive as is to a target directory while keeping its folder structure * @@ -231,33 +253,35 @@ public Path getTemplatesLocation() { */ private void extractArchive(Path sourcePath, Path targetPath) throws IOException { - // TODO: janv_capgemini check if sourcePath is an archive and throw exception if not - FileSystem fs = FileSystems.newFileSystem(sourcePath, null); - - Path path = fs.getPath("/"); - Files.walkFileTree(path, new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + if (FileSystemUtil.isZipFile(sourcePath.toUri())) { + FileSystem fs = FileSystems.newFileSystem(sourcePath, null); - Path relativePath = path.relativize(file); - Path targetPathResolved = targetPath.resolve(relativePath.toString()); - Files.deleteIfExists(targetPathResolved); - Files.createDirectories(targetPathResolved.getParent()); - Files.copy(file, targetPathResolved); - return FileVisitResult.CONTINUE; - } + Path path = fs.getPath("/"); + Files.walkFileTree(path, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - @Override - public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { + Path relativePath = path.relativize(file); + Path targetPathResolved = targetPath.resolve(relativePath.toString()); + Files.deleteIfExists(targetPathResolved); + Files.createDirectories(targetPathResolved.getParent()); + Files.copy(file, targetPathResolved); + return FileVisitResult.CONTINUE; + } - // Log errors but do not throw an exception - LOG.warn("An IOException occurred while reading a file on path {} with message: {}", file, exc.getMessage()); - LOG.debug("An IOException occurred while reading a file on path {} with message: {}", file, - LOG.isDebugEnabled() ? exc : null); - return FileVisitResult.CONTINUE; - } - }); + @Override + public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { + // Log errors but do not throw an exception + LOG.warn("An IOException occurred while reading a file on path {} with message: {}", file, exc.getMessage()); + LOG.debug("An IOException occurred while reading a file on path {} with message: {}", file, + LOG.isDebugEnabled() ? exc : null); + return FileVisitResult.CONTINUE; + } + }); + } else { + LOG.info("Source path is not a ZIP file {}", sourcePath); + } } /** @@ -317,4 +341,13 @@ private boolean isEmpty(final Path directory) throws IOException { return !dirStream.iterator().hasNext(); } } + + @Override + public void upgradeMonolithicTemplates() { + + if (!isMonolithicTemplatesConfiguration()) { + return; + } + // TODO The upgrade needs to be implemented. Will be done in #1502 + } } From 0003aaf1ee3d7045dd55160a74e83af46e5891c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20G=C3=BCnther?= Date: Wed, 20 Apr 2022 13:44:01 +0200 Subject: [PATCH 5/8] added tests for the template adapter --- .../unittest/adapter/TemplateAdapterTest.java | 84 +++++++++++++++++++ .../templates/template.jar | 0 .../src/main/templates/context.xml | 8 ++ .../downloaded/template-set-1.jar | 0 .../downloaded/template-set-2.jar | 0 5 files changed, 92 insertions(+) create mode 100644 cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/adapter/TemplateAdapterTest.java create mode 100644 cobigen/cobigen-core/src/test/resources/testdata/unittest/TemplateAdapterTest/homeMonolithicTemplates/templates/template.jar create mode 100644 cobigen/cobigen-core/src/test/resources/testdata/unittest/TemplateAdapterTest/homeTemplateSets/template-sets/adapted/template-set-1/src/main/templates/context.xml create mode 100644 cobigen/cobigen-core/src/test/resources/testdata/unittest/TemplateAdapterTest/homeTemplateSets/template-sets/downloaded/template-set-1.jar create mode 100644 cobigen/cobigen-core/src/test/resources/testdata/unittest/TemplateAdapterTest/homeTemplateSets/template-sets/downloaded/template-set-2.jar diff --git a/cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/adapter/TemplateAdapterTest.java b/cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/adapter/TemplateAdapterTest.java new file mode 100644 index 0000000000..7ae88c585b --- /dev/null +++ b/cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/adapter/TemplateAdapterTest.java @@ -0,0 +1,84 @@ +package com.devonfw.cobigen.unittest.adapter; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.nio.file.Path; +import java.util.List; + +import org.junit.Test; + +import com.devonfw.cobigen.api.TemplateAdapter; +import com.devonfw.cobigen.api.constants.ConfigurationConstants; +import com.devonfw.cobigen.impl.adapter.TemplateAdapterImpl; + +/** + * Tests for {@link TemplateAdapterImpl} + */ +public class TemplateAdapterTest { + + /** + * Root Path for tests with the monolithic template structure + */ + private static final Path rootTestPathMonolithicTemplates = new File( + "src/test/resources/testdata/unittest/TemplateAdapterTest/homeMonolithicTemplates/templates").toPath(); + + /** + * Root Path for tests with the template set structure + */ + private static final Path rootTestPathTemplateSets = new File( + "src/test/resources/testdata/unittest/TemplateAdapterTest/homeTemplateSets/template-sets").toPath(); + + /** + * Tests if the {@link TemplateAdapter} recognizes that it is an old monolithic template structure + * + */ + @Test + public void testIsMonolithicTemplatesConfigurationWithOldConfig() { + + TemplateAdapter templateAdapter = new TemplateAdapterImpl(rootTestPathMonolithicTemplates); + assertThat(templateAdapter.isMonolithicTemplatesConfiguration()).isTrue(); + } + + /** + * Tests if the {@link TemplateAdapter} recognizes that it is a new template structure + * + */ + @Test + public void testIsMonolithicTemplatesConfigurationWithNewConfig() { + + TemplateAdapter templateAdapter = new TemplateAdapterImpl(rootTestPathTemplateSets); + assertThat(templateAdapter.isMonolithicTemplatesConfiguration()).isFalse(); + } + + /** + * Tests if the {@link TemplateAdapter} is able to get the list of available template jars + * + */ + @Test + public void testGetTemplateJarsToAdapt() { + + TemplateAdapter templateAdapter = new TemplateAdapterImpl(rootTestPathTemplateSets); + List templateJars = templateAdapter.getTemplateSetJars(); + assertThat(templateJars.size()).isEqualTo(2); + } + + /** + * Tests if the {@link TemplateAdapter} recognizes which template sets are already adapted + * + */ + @Test + public void testIsTemplateSetAlreadyAdapted() { + + TemplateAdapter templateAdapter = new TemplateAdapterImpl(rootTestPathTemplateSets); + + Path templateJarAdapted = rootTestPathTemplateSets.resolve(ConfigurationConstants.DOWNLOADED_FOLDER) + .resolve("template-set-1.jar"); + Path templateJarNotAdapted = rootTestPathTemplateSets.resolve(ConfigurationConstants.DOWNLOADED_FOLDER) + .resolve("template-set-2.jar"); + + assertThat(templateAdapter.isTemplateSetAlreadyAdapted(templateJarAdapted)).isTrue(); + assertThat(templateAdapter.isTemplateSetAlreadyAdapted(templateJarNotAdapted)).isFalse(); + } + +} diff --git a/cobigen/cobigen-core/src/test/resources/testdata/unittest/TemplateAdapterTest/homeMonolithicTemplates/templates/template.jar b/cobigen/cobigen-core/src/test/resources/testdata/unittest/TemplateAdapterTest/homeMonolithicTemplates/templates/template.jar new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cobigen/cobigen-core/src/test/resources/testdata/unittest/TemplateAdapterTest/homeTemplateSets/template-sets/adapted/template-set-1/src/main/templates/context.xml b/cobigen/cobigen-core/src/test/resources/testdata/unittest/TemplateAdapterTest/homeTemplateSets/template-sets/adapted/template-set-1/src/main/templates/context.xml new file mode 100644 index 0000000000..caccd81ab9 --- /dev/null +++ b/cobigen/cobigen-core/src/test/resources/testdata/unittest/TemplateAdapterTest/homeTemplateSets/template-sets/adapted/template-set-1/src/main/templates/context.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/cobigen/cobigen-core/src/test/resources/testdata/unittest/TemplateAdapterTest/homeTemplateSets/template-sets/downloaded/template-set-1.jar b/cobigen/cobigen-core/src/test/resources/testdata/unittest/TemplateAdapterTest/homeTemplateSets/template-sets/downloaded/template-set-1.jar new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cobigen/cobigen-core/src/test/resources/testdata/unittest/TemplateAdapterTest/homeTemplateSets/template-sets/downloaded/template-set-2.jar b/cobigen/cobigen-core/src/test/resources/testdata/unittest/TemplateAdapterTest/homeTemplateSets/template-sets/downloaded/template-set-2.jar new file mode 100644 index 0000000000..e69de29bb2 From 158cd436c80dd2b2e97e0864e4818bf12647afa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20G=C3=BCnther?= Date: Thu, 21 Apr 2022 08:51:30 +0200 Subject: [PATCH 6/8] implemented requested changes --- .../systemtest/TemplateProcessingTest.java | 12 +++--- .../unittest/adapter/TemplateAdapterTest.java | 38 ++++++++++++++++--- .../templates/template.jar | 0 .../src/main/templates/context.xml | 8 ---- .../downloaded/template-set-1.jar | 0 .../downloaded/template-set-2.jar | 0 6 files changed, 40 insertions(+), 18 deletions(-) delete mode 100644 cobigen/cobigen-core/src/test/resources/testdata/unittest/TemplateAdapterTest/homeMonolithicTemplates/templates/template.jar delete mode 100644 cobigen/cobigen-core/src/test/resources/testdata/unittest/TemplateAdapterTest/homeTemplateSets/template-sets/adapted/template-set-1/src/main/templates/context.xml delete mode 100644 cobigen/cobigen-core/src/test/resources/testdata/unittest/TemplateAdapterTest/homeTemplateSets/template-sets/downloaded/template-set-1.jar delete mode 100644 cobigen/cobigen-core/src/test/resources/testdata/unittest/TemplateAdapterTest/homeTemplateSets/template-sets/downloaded/template-set-2.jar diff --git a/cobigen/cobigen-core-systemtest/src/test/java/com/devonfw/cobigen/systemtest/TemplateProcessingTest.java b/cobigen/cobigen-core-systemtest/src/test/java/com/devonfw/cobigen/systemtest/TemplateProcessingTest.java index 4b99934031..dc28c7bba8 100644 --- a/cobigen/cobigen-core-systemtest/src/test/java/com/devonfw/cobigen/systemtest/TemplateProcessingTest.java +++ b/cobigen/cobigen-core-systemtest/src/test/java/com/devonfw/cobigen/systemtest/TemplateProcessingTest.java @@ -38,12 +38,12 @@ public class TemplateProcessingTest extends AbstractApiTest { public TemporaryFolder tempFolder = new TemporaryFolder(); /** - * temporary project to store CobiGen home for a project with the new template structrue consisting of template sets. + * temporary project to store CobiGen home for a project with the new template structure consisting of template sets. */ Path cobiGenHomeTemplateSets; /** - * temporary project to store CobiGen home for a project with the old template structrue consisting of a monolitihic + * temporary project to store CobiGen home for a project with the old template structure consisting of a monolitihic * template set */ Path cobiGenHomeMonolithicTemplates; @@ -79,8 +79,10 @@ public void extractTemplateSetsTest() throws IOException { List templates = templateAdapter.getTemplateSetJars(); templateAdapter.adaptTemplateSets(templates, adaptedFolder, false); - Path extractedJar1 = adaptedFolder.resolve("template-test1-0.0.1/src/main/templates"); - Path extractedJar2 = adaptedFolder.resolve("template-test2-0.0.1/src/main/templates"); + Path extractedJar1 = adaptedFolder.resolve("template-test1-0.0.1") + .resolve(ConfigurationConstants.TEMPLATE_RESOURCE_FOLDER); + Path extractedJar2 = adaptedFolder.resolve("template-test2-0.0.1") + .resolve(ConfigurationConstants.TEMPLATE_RESOURCE_FOLDER); assertThat(extractedJar1).exists().isDirectory(); assertThat(extractedJar2).exists().isDirectory(); } @@ -105,7 +107,7 @@ public void extractTemplatesWithOldConfiguration() throws IOException { templateAdapter.adaptMonolithicTemplates(cobigenTemplatesProject, false); assertThat(cobigenTemplatesProject).exists().isDirectory(); - assertThat(cobigenTemplatesProject.resolve("src/main/templates")).exists().isDirectory(); + assertThat(cobigenTemplatesProject.resolve(ConfigurationConstants.TEMPLATE_RESOURCE_FOLDER)).exists().isDirectory(); assertThat(cobigenTemplatesProject.resolve("src/main/java")).exists().isDirectory(); } } diff --git a/cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/adapter/TemplateAdapterTest.java b/cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/adapter/TemplateAdapterTest.java index 7ae88c585b..c3f2d931ba 100644 --- a/cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/adapter/TemplateAdapterTest.java +++ b/cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/adapter/TemplateAdapterTest.java @@ -2,11 +2,15 @@ import static org.assertj.core.api.Assertions.assertThat; -import java.io.File; +import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.util.List; +import org.junit.BeforeClass; +import org.junit.ClassRule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; import com.devonfw.cobigen.api.TemplateAdapter; import com.devonfw.cobigen.api.constants.ConfigurationConstants; @@ -20,14 +24,38 @@ public class TemplateAdapterTest { /** * Root Path for tests with the monolithic template structure */ - private static final Path rootTestPathMonolithicTemplates = new File( - "src/test/resources/testdata/unittest/TemplateAdapterTest/homeMonolithicTemplates/templates").toPath(); + private static Path rootTestPathMonolithicTemplates; /** * Root Path for tests with the template set structure */ - private static final Path rootTestPathTemplateSets = new File( - "src/test/resources/testdata/unittest/TemplateAdapterTest/homeTemplateSets/template-sets").toPath(); + private static Path rootTestPathTemplateSets; + + /** Temporary files rule to create temporary folders or files */ + @ClassRule + public static TemporaryFolder tempFolder = new TemporaryFolder(); + + /** + * Creates a temporary directory structure for the tests + * + * @throws IOException if an Exception occurs + */ + @BeforeClass + public static void prepare() throws IOException { + + rootTestPathMonolithicTemplates = tempFolder + .newFolder("homeMonolithicTemplates", ConfigurationConstants.TEMPLATES_FOLDER).toPath(); + Files.createFile(rootTestPathMonolithicTemplates.resolve("template.jar")); + + rootTestPathTemplateSets = tempFolder.newFolder("homeTemplateSets", ConfigurationConstants.TEMPLATE_SETS_FOLDER) + .toPath(); + Path downloadedFolder = Files + .createDirectory(rootTestPathTemplateSets.resolve(ConfigurationConstants.DOWNLOADED_FOLDER)); + Files.createFile(downloadedFolder.resolve("template-set-1.jar")); + Files.createFile(downloadedFolder.resolve("template-set-2.jar")); + Path adaptedFolder = Files.createDirectory(rootTestPathTemplateSets.resolve(ConfigurationConstants.ADAPTED_FOLDER)); + Files.createDirectory(adaptedFolder.resolve("template-set-1")); + } /** * Tests if the {@link TemplateAdapter} recognizes that it is an old monolithic template structure diff --git a/cobigen/cobigen-core/src/test/resources/testdata/unittest/TemplateAdapterTest/homeMonolithicTemplates/templates/template.jar b/cobigen/cobigen-core/src/test/resources/testdata/unittest/TemplateAdapterTest/homeMonolithicTemplates/templates/template.jar deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/cobigen/cobigen-core/src/test/resources/testdata/unittest/TemplateAdapterTest/homeTemplateSets/template-sets/adapted/template-set-1/src/main/templates/context.xml b/cobigen/cobigen-core/src/test/resources/testdata/unittest/TemplateAdapterTest/homeTemplateSets/template-sets/adapted/template-set-1/src/main/templates/context.xml deleted file mode 100644 index caccd81ab9..0000000000 --- a/cobigen/cobigen-core/src/test/resources/testdata/unittest/TemplateAdapterTest/homeTemplateSets/template-sets/adapted/template-set-1/src/main/templates/context.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/cobigen/cobigen-core/src/test/resources/testdata/unittest/TemplateAdapterTest/homeTemplateSets/template-sets/downloaded/template-set-1.jar b/cobigen/cobigen-core/src/test/resources/testdata/unittest/TemplateAdapterTest/homeTemplateSets/template-sets/downloaded/template-set-1.jar deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/cobigen/cobigen-core/src/test/resources/testdata/unittest/TemplateAdapterTest/homeTemplateSets/template-sets/downloaded/template-set-2.jar b/cobigen/cobigen-core/src/test/resources/testdata/unittest/TemplateAdapterTest/homeTemplateSets/template-sets/downloaded/template-set-2.jar deleted file mode 100644 index e69de29bb2..0000000000 From 3dd993e1e212b1ea0dc02aeca9d028557814dfdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20G=C3=BCnther?= Date: Mon, 25 Apr 2022 11:59:27 +0200 Subject: [PATCH 7/8] changed TemplateAdapter --- .../cli/commands/AdaptTemplatesCommand.java | 22 +++++------ .../devonfw/cobigen/api/TemplateAdapter.java | 15 ++++++++ ...TemplateSelectionForAdaptionException.java | 37 +++++++++++++++++++ ...UpgradeTemplatesNotificationException.java | 22 +++++++++++ .../systemtest/TemplateProcessingTest.java | 16 ++++++-- .../impl/adapter/TemplateAdapterImpl.java | 16 ++++++++ 6 files changed, 113 insertions(+), 15 deletions(-) create mode 100644 cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/exception/TemplateSelectionForAdaptionException.java create mode 100644 cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/exception/UpgradeTemplatesNotificationException.java diff --git a/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/AdaptTemplatesCommand.java b/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/AdaptTemplatesCommand.java index 6288b0b2be..2f63360f86 100644 --- a/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/AdaptTemplatesCommand.java +++ b/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/AdaptTemplatesCommand.java @@ -8,7 +8,8 @@ import org.slf4j.LoggerFactory; import com.devonfw.cobigen.api.TemplateAdapter; -import com.devonfw.cobigen.api.constants.ConfigurationConstants; +import com.devonfw.cobigen.api.exception.TemplateSelectionForAdaptionException; +import com.devonfw.cobigen.api.exception.UpgradeTemplatesNotificationException; import com.devonfw.cobigen.cli.CobiGenCLI; import com.devonfw.cobigen.cli.constants.MessagesConstants; import com.devonfw.cobigen.cli.utils.ValidationUtils; @@ -39,16 +40,14 @@ public Integer doAction() throws Exception { templateAdapter = new TemplateAdapterImpl(this.templatesProject); } - if (templateAdapter.isMonolithicTemplatesConfiguration()) { - Path destinationPath = templateAdapter.getTemplatesLocation().resolve(ConfigurationConstants.COBIGEN_TEMPLATES); - templateAdapter.adaptMonolithicTemplates(destinationPath, false); - - LOG.info("Templates were adapted to {}", destinationPath); - if (askUserToContinueWithUpgrade()) { + try { + templateAdapter.adaptTemplates(); + } catch (UpgradeTemplatesNotificationException e) { + if (askUserToContinueWithUpgrade(e)) { templateAdapter.upgradeMonolithicTemplates(); } - } else { - List templateJars = templateAdapter.getTemplateSetJars(); + } catch (TemplateSelectionForAdaptionException e) { + List templateJars = e.getTemplateSets(); if (templateJars != null && !templateJars.isEmpty()) { List templateJarsToAdapt = getJarsToAdapt(templateAdapter, templateJars); if (!templateJarsToAdapt.isEmpty()) { @@ -112,10 +111,9 @@ private void printJarsForSelection(TemplateAdapter templateAdapter, List t * * @return Returns {@code true} if the user want to continue with the uprade of the templates. */ - private boolean askUserToContinueWithUpgrade() { + private boolean askUserToContinueWithUpgrade(UpgradeTemplatesNotificationException e) { - LOG.info( - "Do you want to upgrade your monolithic template structure to the new template structure with independent template sets?"); + LOG.info(e.getMessage()); LOG.info("Type 'y' or 'yes' to upgrade the configuration?"); String userInput = ValidationUtils.getUserInput(); if (userInput != null && (userInput.toLowerCase().equals("y") || userInput.toLowerCase().equals("yes"))) { diff --git a/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/TemplateAdapter.java b/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/TemplateAdapter.java index 977252893b..26e01266de 100644 --- a/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/TemplateAdapter.java +++ b/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/TemplateAdapter.java @@ -4,9 +4,24 @@ import java.nio.file.Path; import java.util.List; +import com.devonfw.cobigen.api.exception.TemplateSelectionForAdaptionException; +import com.devonfw.cobigen.api.exception.UpgradeTemplatesNotificationException; + /** The TemplateAdapter implements methods for adapting template jars */ public interface TemplateAdapter { + /** + * Adapt the templates. Can either adapt an old monolithic template structure or independent template sets. + * + * @throws IOException If CobiGen is not able to extract the jar file to the destination folder + * @throws UpgradeTemplatesNotificationException If an old monolithic structure was adapted. Can be catched to ask the + * user for an upgrade of the templates. + * @throws TemplateSelectionForAdaptionException If a new template structure is given. To ask the user to select the + * template sets to adapt. + */ + public void adaptTemplates() + throws IOException, UpgradeTemplatesNotificationException, TemplateSelectionForAdaptionException; + /** * Adapt a given set of template set jars. * diff --git a/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/exception/TemplateSelectionForAdaptionException.java b/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/exception/TemplateSelectionForAdaptionException.java new file mode 100644 index 0000000000..f3ba1dde1d --- /dev/null +++ b/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/exception/TemplateSelectionForAdaptionException.java @@ -0,0 +1,37 @@ +package com.devonfw.cobigen.api.exception; + +import java.nio.file.Path; +import java.util.List; + +/** + * Exception that indicates that a new template structure is available. For asking which template sets should be + * adapted. + */ +public class TemplateSelectionForAdaptionException extends Exception { + + /** Generated serial version UID */ + private static final long serialVersionUID = 1; + + /** List of available template sets. */ + private List templateSets; + + /** + * Creates a new {@link TemplateSelectionForAdaptionException} + * + * @param templateSets A list with available template sets to adapt. + * + */ + public TemplateSelectionForAdaptionException(List templateSets) { + + super("Select the template sets you want to adapt."); + this.templateSets = templateSets; + } + + /** + * @return templateSets All available template sets. + */ + public List getTemplateSets() { + + return this.templateSets; + } +} diff --git a/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/exception/UpgradeTemplatesNotificationException.java b/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/exception/UpgradeTemplatesNotificationException.java new file mode 100644 index 0000000000..ad6dd32e7a --- /dev/null +++ b/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/exception/UpgradeTemplatesNotificationException.java @@ -0,0 +1,22 @@ +package com.devonfw.cobigen.api.exception; + +/** + * Exception that indicates that an old monolithic template structure has been adapted. For asking if the template + * structure should be upgraded. + */ +public class UpgradeTemplatesNotificationException extends Exception { + + /** Generated serial version UID */ + private static final long serialVersionUID = 1; + + /** + * Creates a new {@link UpgradeTemplatesNotificationException} with a proper notification message + * + */ + public UpgradeTemplatesNotificationException() { + + super( + "You are using an old, monolithic template project. Do you want to upgrade your template project to the new template structure with independent template sets?"); + } + +} diff --git a/cobigen/cobigen-core-systemtest/src/test/java/com/devonfw/cobigen/systemtest/TemplateProcessingTest.java b/cobigen/cobigen-core-systemtest/src/test/java/com/devonfw/cobigen/systemtest/TemplateProcessingTest.java index dc28c7bba8..a814f8c08a 100644 --- a/cobigen/cobigen-core-systemtest/src/test/java/com/devonfw/cobigen/systemtest/TemplateProcessingTest.java +++ b/cobigen/cobigen-core-systemtest/src/test/java/com/devonfw/cobigen/systemtest/TemplateProcessingTest.java @@ -1,6 +1,7 @@ package com.devonfw.cobigen.systemtest; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertThrows; import java.io.File; import java.io.IOException; @@ -15,6 +16,8 @@ import com.devonfw.cobigen.api.TemplateAdapter; import com.devonfw.cobigen.api.constants.ConfigurationConstants; +import com.devonfw.cobigen.api.exception.TemplateSelectionForAdaptionException; +import com.devonfw.cobigen.api.exception.UpgradeTemplatesNotificationException; import com.devonfw.cobigen.impl.adapter.TemplateAdapterImpl; import com.devonfw.cobigen.systemtest.common.AbstractApiTest; @@ -76,8 +79,13 @@ public void extractTemplateSetsTest() throws IOException { Path adaptedFolder = templateSetsFolder.resolve(ConfigurationConstants.ADAPTED_FOLDER); TemplateAdapter templateAdapter = new TemplateAdapterImpl(downloadedFolder.getParent()); - List templates = templateAdapter.getTemplateSetJars(); - templateAdapter.adaptTemplateSets(templates, adaptedFolder, false); + + Exception exception = assertThrows(TemplateSelectionForAdaptionException.class, () -> { + templateAdapter.adaptTemplates(); + }); + + List templateSetJars = ((TemplateSelectionForAdaptionException) exception).getTemplateSets(); + templateAdapter.adaptTemplateSets(templateSetJars, adaptedFolder, false); Path extractedJar1 = adaptedFolder.resolve("template-test1-0.0.1") .resolve(ConfigurationConstants.TEMPLATE_RESOURCE_FOLDER); @@ -104,7 +112,9 @@ public void extractTemplatesWithOldConfiguration() throws IOException { Path cobigenTemplatesProject = cobigenTemplatesParent.resolve(ConfigurationConstants.COBIGEN_TEMPLATES); TemplateAdapter templateAdapter = new TemplateAdapterImpl(cobigenTemplatesParent); - templateAdapter.adaptMonolithicTemplates(cobigenTemplatesProject, false); + assertThrows(UpgradeTemplatesNotificationException.class, () -> { + templateAdapter.adaptTemplates(); + }); assertThat(cobigenTemplatesProject).exists().isDirectory(); assertThat(cobigenTemplatesProject.resolve(ConfigurationConstants.TEMPLATE_RESOURCE_FOLDER)).exists().isDirectory(); diff --git a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/adapter/TemplateAdapterImpl.java b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/adapter/TemplateAdapterImpl.java index f30174cc2c..d08f9fa095 100644 --- a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/adapter/TemplateAdapterImpl.java +++ b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/adapter/TemplateAdapterImpl.java @@ -24,6 +24,8 @@ import com.devonfw.cobigen.api.TemplateAdapter; import com.devonfw.cobigen.api.constants.ConfigurationConstants; import com.devonfw.cobigen.api.exception.CobiGenRuntimeException; +import com.devonfw.cobigen.api.exception.TemplateSelectionForAdaptionException; +import com.devonfw.cobigen.api.exception.UpgradeTemplatesNotificationException; import com.devonfw.cobigen.api.util.CobiGenPaths; import com.devonfw.cobigen.api.util.TemplatesJarUtil; import com.devonfw.cobigen.impl.util.FileSystemUtil; @@ -57,6 +59,20 @@ public TemplateAdapterImpl() { } } + @Override + public void adaptTemplates() + throws IOException, UpgradeTemplatesNotificationException, TemplateSelectionForAdaptionException { + + if (isMonolithicTemplatesConfiguration()) { + Path destinationPath = this.templatesLocation.resolve(ConfigurationConstants.COBIGEN_TEMPLATES); + adaptMonolithicTemplates(destinationPath, false); + + throw new UpgradeTemplatesNotificationException(); + } else { + throw new TemplateSelectionForAdaptionException(getTemplateSetJars()); + } + } + /** * Creates a new {@link TemplateAdapter} instance that handles the adaption of templates at the given templates * location. From 2c35c0c9288bbcf583e03d3afc1df45a7bd46be5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20G=C3=BCnther?= Date: Wed, 27 Apr 2022 10:37:27 +0200 Subject: [PATCH 8/8] implemented change requests --- .../com/devonfw/cobigen/systemtest/TemplateProcessingTest.java | 3 +-- .../com/devonfw/cobigen/impl/adapter/TemplateAdapterImpl.java | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cobigen/cobigen-core-systemtest/src/test/java/com/devonfw/cobigen/systemtest/TemplateProcessingTest.java b/cobigen/cobigen-core-systemtest/src/test/java/com/devonfw/cobigen/systemtest/TemplateProcessingTest.java index a814f8c08a..57081fb67f 100644 --- a/cobigen/cobigen-core-systemtest/src/test/java/com/devonfw/cobigen/systemtest/TemplateProcessingTest.java +++ b/cobigen/cobigen-core-systemtest/src/test/java/com/devonfw/cobigen/systemtest/TemplateProcessingTest.java @@ -75,10 +75,9 @@ public void extractTemplateSetsTest() throws IOException { Path templateSetsFolder = this.cobiGenHomeTemplateSets .resolve(ConfigurationConstants.CONFIG_PROPERTY_TEMPLATE_SETS_PATH); - Path downloadedFolder = templateSetsFolder.resolve(ConfigurationConstants.DOWNLOADED_FOLDER); Path adaptedFolder = templateSetsFolder.resolve(ConfigurationConstants.ADAPTED_FOLDER); - TemplateAdapter templateAdapter = new TemplateAdapterImpl(downloadedFolder.getParent()); + TemplateAdapter templateAdapter = new TemplateAdapterImpl(templateSetsFolder); Exception exception = assertThrows(TemplateSelectionForAdaptionException.class, () -> { templateAdapter.adaptTemplates(); diff --git a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/adapter/TemplateAdapterImpl.java b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/adapter/TemplateAdapterImpl.java index d08f9fa095..e7ef82c4d2 100644 --- a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/adapter/TemplateAdapterImpl.java +++ b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/adapter/TemplateAdapterImpl.java @@ -134,6 +134,8 @@ private void processTemplateSetJars(List templateSetJarsToAdapt, Path dest } extractArchive(templateSetJar, destination); + // com folder with precompiled util classes is not needed. The utils compiled at first generation into the + // target folder if (Files.exists(destination.resolve("com"))) { FileUtils.deleteDirectory(destination.resolve("com").toFile()); }