Bekanta dig med grundläggande AEM Project Archetype-användningoch Plugin-programmet FileVault Content Maven eftersom den här artikeln bygger på dessa inlärningar och begrepp.
I den här artikeln beskrivs de ändringar som krävs för Adobe Experience Manager Maven-projekt som är AEM as a Cloud Service kompatibla genom att säkerställa att de respekterar uppdelningen av muterbart och oföränderligt innehåll, att beroenden etableras för att skapa icke-konfliktskapande, deterministiska distributioner och att de paketeras i en driftsättningsbar struktur.
AEM programdistributioner måste bestå av ett enda AEM. Paketet ska i sin tur innehålla underpaket som innehåller allt som programmet behöver för att fungera, inklusive kod, konfiguration och eventuellt baslinjeinnehåll som stöds.
AEM kräver separation av innehåll och kod, vilket innebär ett enda innehållspaket inte distribuera till båda /apps
och körningssäkra områden (t.ex. /content
, /conf
, /home
eller något som inte /apps
) för databasen. Programmet måste i stället separera kod och innehåll i separata paket för distribution till AEM.
Den paketstruktur som beskrivs i det här dokumentet är kompatibel med både lokala utvecklingsdistributioner och AEM Cloud Service-distributioner.
Konfigurationerna som beskrivs i det här dokumentet tillhandahålls av AEM Project Maven Archetype 24 eller senare.
/apps
och /libs
betraktas som oföränderliga områden i AEM, eftersom de inte kan ändras (skapa, uppdatera, ta bort) efter att AEM startats (dvs. vid körning). Alla försök att ändra ett oföränderligt område vid körning misslyckas.
Allt annat i databasen, /content
, /conf
, /var
, /etc
, /oak:index
, /system
, /tmp
, osv. är alla mutabel områden, vilket innebär att de kan ändras under körning.
Precis som i tidigare versioner av AEM /libs
bör inte ändras. Endast AEM produktkod kan distribueras till /libs
.
Oak indexes (/oak:index
) hanteras specifikt av den AEM as a Cloud Service distributionsprocessen. Detta beror på att Cloud Manager måste vänta tills ett nytt index har distribuerats och indexerats om fullständigt innan det går över till den nya kodbilden.
Därför måste Oak-index, även om de kan ändras vid körning, distribueras som kod så att de kan installeras innan några ändringsbara paket installeras. Därför /oak:index
konfigurationer är en del av kodpaketet och inte en del av innehållspaketet enligt nedan.
Mer information om indexering på AEM as a Cloud Service finns i dokumentet Innehållssökning och indexering.
I det här diagrammet visas en översikt över den rekommenderade projektstrukturen och artefakter för paketdistribution.
Den rekommenderade programdistributionsstrukturen är följande:
OSGi-paketfilen genereras och bäddas in direkt i hela projektet.
The ui.apps
paketet innehåller all kod som ska distribueras och endast distribueras till /apps
. Vanliga element i ui.apps
paketet innehåller, men är inte begränsat till:
/apps/my-app/components
/apps/my-app/clientlibs
/libs
/apps/cq
, /apps/dam/
, osv./apps/settings
rep:policy
för alla banor under /apps
Samma kod måste distribueras till alla miljöer. Detta är nödvändigt för att säkerställa en nivå av konfidensvalidering i scenmiljön som också är i produktion. Mer information finns i avsnittet om Runmodes.
ui.content
paketet innehåller allt innehåll och all konfiguration. Innehållspaketet innehåller alla noddefinitioner som inte finns i ui.apps
eller ui.config
paket, med andra ord, ingenting i /apps
eller /oak:index
. Vanliga element i ui.content
paketet innehåller, men är inte begränsat till:
/conf
/content
, /content/dam
, osv./content/cq:tags
/etc
The all
paketet är ett behållarpaket som ENDAST innehåller installerbara artefakter, den oSGI-paketerade JAR-filen, ui.apps
, ui.config
och ui.content
paket som inbäddade. The all
paketet får inte ha allt innehåll och all kod själva, men delegera i stället all distribution till databasen till dess underpaket eller OSGi-paket med Jar-filer.
Paket ingår nu i Maven Konfiguration för plugin-programmet FileVault Package Maveni stället för <subPackages>
konfiguration.
För komplexa Experience Manager-distributioner kan det vara önskvärt att skapa flera ui.apps
, ui.config
och ui.content
projekt/paket som representerar specifika webbplatser eller klientorganisationer i AEM. Om detta görs ser du till att delningen mellan ändringsbart och icke-ändringsbart innehåll respekteras och att de nödvändiga innehållspaketen och OSGi bundle JAR-filerna bäddas in som underpaket i all
behållarinnehållspaket.
En innehållsstruktur för en komplex distribution kan till exempel se ut så här:
all
innehållspaketet bäddar in följande paket för att skapa en enda distributionsartefakt
common.ui.apps
distribuerar kod som krävs av båda plats A och plats Bsite-a.core
OSGi bundle Jar krävs av webbplats Asite-a.ui.apps
distribuerar kod som krävs av plats Asite-a.ui.config
distribuerar OSGi-konfigurationer som krävs av plats Asite-a.ui.content
distribuerar innehåll och konfiguration som krävs av plats Asite-b.core
OSGi bundle Jar krävs av webbplats Bsite-b.ui.apps
distribuerar kod som krävs av plats Bsite-b.ui.config
distribuerar OSGi-konfigurationer som krävs av plats Bsite-b.ui.content
distribuerar innehåll och konfiguration som krävs av plats BThe ui.config
paketet innehåller alla OSGi-konfigurationer:
/apps/my-app/osgiconfig
/apps/my-app/osgiconfig/config
/apps/my-app/osgiconfig/config.<author|publish>.<dev|stage|prod>
config.<runmode>
enligt ovan och användas för att definiera:
Om andra AEM, som i sig själva består av sina egna kod- och innehållspaket, används av den AEM distributionen, bör deras behållarpaket bäddas in i projektets all
paket.
Ett AEM projekt som innehåller 2 AEM program kan se ut så här:
all
innehållspaketet bäddar in följande paket för att skapa en enda distributionsartefakt
core
OSGi bundle Jar krävs av AEMui.apps
distribuerar kod som krävs av AEMui.config
distribuerar OSGi-konfigurationer som krävs av AEMui.content
distribuerar innehåll och konfiguration som krävs för AEMvendor-x.all
distribuerar allt (kod och innehåll) som krävs av X-leverantörens programvendor-y.all
distribuerar allt (kod och innehåll) som krävs av leverantörens Y-programPaket ska märkas med sin deklarerade pakettyp. Pakettyper gör det lättare att klargöra syftet med och distributionen av ett paket.
packageType
till container
. Behållarpaket får inte innehålla vanliga noder. Endast OSGi-paket, konfigurationer och underpaket tillåts. Behållare i AEM as a Cloud Service får inte användas installera kopplingar.packageType
till application
.packageType
till content
.Mer information finns i Apache Jackrabbit FileVault - dokumentation för Plugin-programmet Package Maven, Pakettyper för Apache Jackrabbitoch FileVault Maven-konfigurationsfragment nedan.
Se POM XML-kodfragment nedan om du vill ha ett fullständigt kodfragment.
Som standard hämtar Adobe Cloud Manager alla paket som skapas av Maven-bygget, men eftersom behållarpaketet (all
) är en enda distributionsartefakt som innehåller all kod och alla innehållspaket måste vi se till att endast behållarpaketet (all
) distribueras. För att säkerställa detta måste andra paket som genereras av Maven-bygget markeras med FileVaults Maven-pluginkonfiguration <properties><cloudManagerTarget>none</cloudManageTarget></properties>
för innehållspaket.
Se POM XML-kodfragment nedan om du vill ha ett fullständigt kodfragment.
Repo Init innehåller instruktioner, eller skript, som definierar JCR-strukturer, från vanliga nodstrukturer som mappträd till användare, tjänstanvändare, grupper och ACL-definition.
De viktigaste fördelarna med Repo Init är att de har implicit behörighet att utföra alla åtgärder som definieras av deras skript, och att de anropas tidigt under distributionens livscykel för att säkerställa att alla nödvändiga JCR-strukturer finns när koden körs.
Medan Repo Init-skripten finns i ui.config
-projekt som skript, kan och bör användas för att definiera följande muterbara strukturer:
Repo Init-skript lagras som scripts
poster i RepositoryInitializer
OSGi-fabrikskonfigurationer, och därmed även indirekt riktade sig till körningsläge, vilket möjliggör skillnader mellan AEM Author och AEM Publish Services Repo Init-skript, eller till och med mellan miljöer (Dev, Stage och Prod).
Repo Init OSGi-konfigurationer skrivs bäst i .config
Konfigurationsformat för OSGi eftersom de har stöd för flera rader, vilket är ett undantag till de bästa sätten att använda .cfg.json
för att definiera OSGi-konfigurationer.
Observera, att när du definierar Användare, och Grupper, anses bara grupper vara en del av programmet, och att de är en del av dess funktion bör definieras här. Organisationens användare och grupper bör fortfarande definieras vid körning i AEM. Om ett anpassat arbetsflöde till exempel tilldelar arbete till en namngiven grupp, bör den gruppen definieras i via Repo Init i AEM, men om grupperingen bara är organisatorisk, till exempel"Wendy's Team" och"Sean's Team", är dessa bäst definierade och hanteras vid körning i AEM.
Repo Init-skript måste definieras i den infogade scripts
och references
kommer inte att fungera.
Det fullständiga språket för Repo Init-skript finns på Dokumentation för Apache Sling Repo Init.
Se Repo Init-fragment nedan om du vill ha ett fullständigt kodfragment.
Kodpaket kräver att konfigurationen för plugin-programmet FileVault Maven konfigureras för att referera till en <repositoryStructurePackage>
som framtvingar korrekthet för strukturella beroenden (för att säkerställa att ett kodpaket inte installeras över ett annat). Du kan skapa ett eget strukturpaket för databasen för ditt projekt.
Detta krävs endast för kodpaket, vilket innebär alla paket som är markerade med <packageType>application</packageType>
.
Mer information om hur du skapar ett databasstrukturpaket för ditt program finns i Utveckla ett databasstrukturpaket.
Observera att innehållspaket (<packageType>content</packageType>
) inte kräver det här strukturpaketet för databasen.
Se POM XML-kodfragment nedan om du vill ha ett fullständigt kodfragment.
Innehåll eller kodpaket placeras i en speciell "side-car"-mapp och kan installeras antingen AEM författare, AEM publicering eller båda med hjälp av plugin-programmet FileVault Maven <embeddeds>
konfiguration. Observera att <subPackages>
ska inte användas.
Vanliga användningsfall är:
Om du vill ange AEM författare, AEM publicera eller båda, är paketet inbäddat i all
behållarpaket i en speciell mappsökväg, i följande format:
/apps/<app-name>-packages/(content|application|container)/install(.author|.publish)?
Bryter ned mappstrukturen:
Den första nivåmappen måste vara /apps
.
Mappen på den andra nivån representerar programmet med -packages
efter korrigering till mappnamnet. Ofta finns det bara en mapp på andra nivån som alla underpaket är inbäddade i, men du kan skapa valfritt antal mappar på andra nivån för att bäst representera programmets logiska struktur:
/apps/my-app-packages
/apps/my-other-app-packages
/apps/vendor-packages
Mappar som bäddats in i underpaket namnges med suffixet -packages
. Detta garanterar att distributionskoden och innehållspaketen inte distribueras till målmappen/målmapparna i något underpaket /apps/<app-name>/...
, vilket skulle leda till destruktivt och cykliskt installationsbeteende.
Mappen på den tredje nivån måste vara antingen
application
, content
eller container
application
mapp innehåller kodpaketcontent
mapp innehåller innehållspaketcontainer
mappen innehåller alla extra programpaket som kan ingå i AEM.Mappen på den fjärde nivån innehåller underpaketen och måste vara någon av:
install
för installation på både AEM-redigerare och AEM-publiceringinstall.author
för installation endast på AEM-redigerareinstall.publish
till endast installera AEM publicera Obs! install.author
och install.publish
är mål som stöds. Andra körningslägen stöds inte.En distribution som innehåller AEM författare och publicerar specifika paket kan till exempel se ut så här:
all
Behållarpaket bäddar in följande paket för att skapa en enda distributionsartefakt
ui.apps
inbäddad i /apps/my-app-packages/application/install
distribuerar kod till både AEM författare och AEM publiceraui.apps.author
inbäddad i /apps/my-app-packages/application/install.author
distribuerar kod till endast AEM författareui.content
inbäddad i /apps/my-app-packages/content/install
distribuerar innehåll och konfiguration till både AEM författare och AEM publiceraui.content.publish
inbäddad i /apps/my-app-packages/content/install.publish
distribuerar innehåll och konfiguration till endast AEM publiceraSe POM XML-kodfragment nedan om du vill ha ett fullständigt kodfragment.
På grund av inbäddningen av kod- och innehållsunderpaket i behållarpaketet måste de inbäddade målsökvägarna läggas till i behållarprojektets filter.xml
för att säkerställa att de inbäddade paketen inkluderas i behållarpaketet när de byggs.
Lägg bara till <filter root="/apps/<my-app>-packages"/>
poster för mappar på andra nivån som innehåller underpaket som ska distribueras.
Se POM XML-kodfragment nedan om du vill ha ett fullständigt kodfragment.
Alla paket måste vara tillgängliga via Adobe allmänna Maven-arkivet eller en tillgänglig och refererbar databas för Maven-felaktigheter från tredje part.
Om tredjepartspaketen finns i Adobes offentliga Maven-databas behövs ingen ytterligare konfiguration för att Adobe Cloud Manager ska kunna lösa artefakterna.
Om tredjepartspaketen finns i en offentlig tredjepartsdatabas för Maven-felaktigheter måste den här databasen registreras i projektets pom.xml
och bäddas in enligt den metod som beskrivs ovan.
Tredjepartsprogram/-anslutningar bör bäddas in med dess all
paket som en behållare i projektbehållaren (all
).
Om du lägger till Maven-beroenden följer standardMaven-rutiner, och inbäddning av artefakter från tredje part (kod- och innehållspaket) görs ovan.
Se POM XML-kodfragment nedan om du vill ha ett fullständigt kodfragment.
ui.apps
från ui.content
PaketFör att paketen ska kunna installeras på rätt sätt rekommenderar vi att du skapar beroenden mellan paketen.
Den allmänna regeln är paket som innehåller ändringsbart innehåll (ui.content
) ska vara beroende av den oföränderliga koden (ui.apps
) som har stöd för återgivning och användning av det ändringsbara innehållet.
Ett betydande undantag från den här allmänna regeln är om det oföränderliga kodpaketet (ui.apps
eller något annat), endast innehåller OSGi-paket. I så fall ska inget AEM deklarera ett beroende av det. Detta beror på att kodpaket som inte kan ändras endast som innehåller OSGi-paket är inte registrerade med AEM Package Manager, och därför kommer alla AEM som är beroende av det att ha ett otillfredsställande beroende och inte kunna installeras.
Se POM XML-kodfragment nedan om du vill ha ett fullständigt kodfragment.
De vanligaste mönstren för innehållspaketberoenden är:
Det enkla skiftläget anger ui.content
varierbart innehållspaket som är beroende av ui.apps
oföränderligt kodpaket.
all
har inga beroenden
ui.apps
har inga beroendenui.content
är beroende av ui.apps
Komplexa driftsättningar bygger vidare på det enkla fallet och ställer in beroenden mellan motsvarande muterbara innehåll och oföränderliga kodpaket. Om det behövs kan beroenden etableras även mellan oföränderliga kodpaket.
all
har inga beroenden
common.ui.apps.common
har inga beroendensite-a.ui.apps
är beroende av common.ui.apps
site-a.ui.content
är beroende av site-a.ui.apps
site-b.ui.apps
är beroende av common.ui.apps
site-b.ui.content
är beroende av site-b.ui.apps
De projektstrukturer och den organisation som beskrivs i den här artikeln är fullständigt kompatibel lokala AEM.
Följande är Maven pom.xml
konfigurationsksnuttar som kan läggas till i Maven-projekt för att anpassas till ovanstående rekommendationer.
Kod- och innehållspaket, som distribueras som underpaket, måste deklarera pakettypen application eller content, beroende på vad de innehåller.
Behållaren all/pom.xml
projekt inte deklarera <packageType>
.
Kodpaket måste ange sina packageType
till application
.
I ui.apps/pom.xml
, <packageType>application</packageType>
bygg konfigurationsdirektiv för filevault-package-maven-plugin
plugin-deklarationen deklarerar pakettypen.
...
<build>
<plugins>
<plugin>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>filevault-package-maven-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<group>${project.groupId}</group>
<name>my-app.ui.apps</name>
<packageType>application</packageType>
<accessControlHandling>merge</accessControlHandling>
<properties>
<cloudManagerTarget>none</cloudManagerTarget>
</properties>
</configuration>
</plugin>
...
Innehållspaket måste ange sina packageType
till content
.
I ui.content/pom.xml
, <packageType>content</packageType>
byggkonfigurationsdirektivet för filevault-package-maven-plugin
plugin-deklarationen deklarerar pakettypen.
...
<build>
<plugins>
<plugin>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>filevault-package-maven-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<group>${project.groupId}</group>
<name>my-app.ui.content</name>
<packageType>content</packageType>
<accessControlHandling>merge</accessControlHandling>
<properties>
<cloudManagerTarget>none</cloudManagerTarget>
</properties>
</configuration>
</plugin>
...
I alla projekt som genererar ett paket, utom för behållarprojektet (all
), lägger du till <cloudManagerTarget>none</cloudManagerTarget>
i <properties>
-konfigurationen för plugin-deklarationen filevault-package-maven-plugin
för att vara säker på att de inte distribueras av Adobe Cloud Manager. Behållaren (all
) ska vara det fristående paket som distribueras via Cloud Manager, som i sin tur bäddar in all kod och alla innehållspaket som krävs.
...
<build>
<plugins>
<plugin>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>filevault-package-maven-plugin</artifactId>
<extensions>true</extensions>
<configuration>
...
<properties>
<cloudManagerTarget>none</cloudManagerTarget>
</properties>
</configuration>
</plugin>
...
Repo Init-skript som innehåller Repo Init-skript definieras i RepositoryInitializer
OSGi-fabrikskonfiguration via scripts
-egenskap. Observera att eftersom dessa skript definieras i OSGi-konfigurationer kan de enkelt omfångas i körningsläge med hjälp av de vanliga ../config.<runmode>
mappsemantik.
Observera att eftersom skript vanligtvis är flerradsdeklarationer är det enklare att definiera dem i .config
-filen, än den JSON-baserade .cfg.json
format.
/apps/my-app/config.author/org.apache.sling.jcr.repoinit.RepositoryInitializer-author.config
scripts=["
create service user my-data-reader-service
set ACL on /var/my-data
allow jcr:read for my-data-reader-service
end
create path (sling:Folder) /conf/my-app/settings
"]
The scripts
OSGi-egenskapen innehåller direktiv enligt definitionen i Apache Sling's Repo Init language.
I ui.apps/pom.xml
och andra pom.xml
som deklarerar ett kodpaket (<packageType>application</packageType>
) lägger du till följande konfiguration av databasstrukturpaket i plugin-programmet FileVault Maven. Du kan skapa ett eget strukturpaket för databasen för ditt projekt.
...
<build>
<plugins>
<plugin>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>filevault-package-maven-plugin</artifactId>
<extensions>true</extensions>
<configuration>
...
<repositoryStructurePackages>
<repositoryStructurePackage>
<groupId>${project.groupId}</groupId>
<artifactId>ui.apps.structure</artifactId>
<version>${project.version}</version>
</repositoryStructurePackage>
</repositoryStructurePackages>
</configuration>
</plugin>
...
I all/pom.xml
lägger du till följande <embeddeds>
direktiv till filevault-package-maven-plugin
plugin-deklaration. Kom ihåg: inte använder <subPackages>
konfiguration, eftersom detta inkluderar underpaketen i /etc/packages
i stället för /apps/my-app-packages/<application|content|container>/install(.author|.publish)?
.
...
<plugin>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>filevault-package-maven-plugin</artifactId>
<extensions>true</extensions>
<configuration>
...
<embeddeds>
<!-- Include the application's ui.apps and ui.content packages -->
<!-- Ensure the artifactIds are correct -->
<!-- OSGi Bundle Jar file that deploys to BOTH AEM Author and AEM Publish -->
<embedded>
<groupId>${project.groupId}</groupId>
<artifactId>my-app.core</artifactId>
<type>jar</type>
<target>/apps/my-app-packages/application/install</target>
</embedded>
<!-- Code package that deploys to BOTH AEM Author and AEM Publish -->
<embedded>
<groupId>${project.groupId}</groupId>
<artifactId>my-app.ui.apps</artifactId>
<type>zip</type>
<target>/apps/my-app-packages/application/install</target>
</embedded>
<!-- OSGi configuration code package that deploys to BOTH AEM Author and AEM Publish -->
<embedded>
<groupId>${project.groupId}</groupId>
<artifactId>my-app.ui.config</artifactId>
<type>zip</type>
<target>/apps/my-app-packages/application/install</target>
</embedded>
<!-- Code package that deploys ONLY to AEM Author -->
<embedded>
<groupId>${project.groupId}</groupId>
<artifactId>my-app.ui.apps.author</artifactId>
<type>zip</type>
<target>/apps/my-app-packages/application/install.author</target>
</embedded>
<!-- Content package that deploys to BOTH AEM Author and AEM Publish -->
<embedded>
<groupId>${project.groupId}</groupId>
<artifactId>my-app.ui.content</artifactId>
<type>zip</type>
<target>/apps/my-app-packages/content/install</target>
</embedded>
<!-- Content package that deploys ONLY to AEM Publish -->
<embedded>
<groupId>${project.groupId}</groupId>
<artifactId>my-app.ui.content.publish-only</artifactId>
<type>zip</type>
<target>/apps/my-app-packages/content/install.publish</target>
</embedded>
<!-- Include any other extra packages -->
<embedded>
<groupId>com.vendor.x</groupId>
<artifactId>vendor.plug-in.all</artifactId>
<type>zip</type>
<target>/apps/vendor-packages/container/install</target>
</embedded>
<embeddeds>
</configuration>
</plugin>
...
I all
-projektets filter.xml
(all/src/main/content/jcr_root/META-INF/vault/definition/filter.xml
) inkluderar du alla -packages
-mappar som innehåller underpaket som ska distribueras:
<filter root="/apps/my-app-packages"/>
Om flera /apps/*-packages
används i de inbäddade målen, måste alla räknas upp här.
Om du lägger till fler Maven-databaser kan det ta längre tid att bygga maven när ytterligare Maven-databaser kontrolleras om det finns beroenden.
I reaktorprojektets pom.xml
, lägger du till eventuella nödvändiga direktiv från tredje part för databasen Maven. Den fullständiga <repository>
-konfigurationen bör vara tillgänglig från tredjepartsprovidern för databas.
<repositories>
...
<repository>
<id>3rd-party-repository</id>
<name>Public 3rd Party Repository</name>
<url>https://repo.3rdparty.example.com/...</url>
<releases>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
...
</repositories>
ui.apps
från ui.content
PaketI ui.content/pom.xml
lägger du till följande <dependencies>
direktiv till filevault-package-maven-plugin
plugin-deklaration.
...
<plugin>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>filevault-package-maven-plugin</artifactId>
<extensions>true</extensions>
<configuration>
...
<dependencies>
<!-- Declare the content package dependency in the ui.content/pom.xml on the ui.apps project -->
<dependency>
<groupId${project.groupId}</groupId>
<artifactId>my-app.ui.apps</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
...
</configuration>
</plugin>
...
I all/pom.xml
lägg till maven-clean-plugin
plugin-program som rensar målkatalogen innan en Maven byggs.
<plugins>
...
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<executions>
<execution>
<id>auto-clean</id>
<!-- Run at the beginning of the build rather than the default, which is after the build is done -->
<phase>initialize</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
...
</plugins>