Elementi MSBuild
Gli elementi MSBuild, forniti come input al sistema di compilazione, in genere rappresentano file. I file sono specificati nell'attributo Include
. Gli elementi sono raggruppati in tipi di elemento in base ai nomi degli elementi. I tipi di elementi sono elenchi denominati di elementi che possono essere usati come parametri per le attività. Le attività usano i valori degli elementi per eseguire i passaggi del processo di compilazione.
Poiché gli elementi vengono denominati in base al tipo di elemento a cui appartengono, i termini "elemento" e "valore dell'elemento" sono interscambiabili.
Creare elementi in un file di progetto
Si dichiarano gli elementi nel file di progetto come elementi figlio di un elemento ItemGroup. I nomi degli elementi validi iniziano con una lettera maiuscola o minuscola o un carattere di sottolineatura (_
); i caratteri successivi validi includono caratteri alfanumerici (lettere o cifre), carattere di sottolineatura e trattino (-
). Il nome dell'elemento figlio è il tipo dell'elemento. L'attributo Include
dell'elemento specifica gli elementi (i file) da includere con tale tipo di elemento. Ad esempio, il codice XML seguente crea un tipo di elemento denominato Compile
che include due file.
<ItemGroup>
<Compile Include = "file1.cs"/>
<Compile Include = "file2.cs"/>
</ItemGroup>
L'elemento file2.cs non sostituisce l'elemento file1.cs. Il nome file viene invece aggiunto all'elenco di valori per il tipo di elemento Compile
.
Il codice XML seguente crea lo stesso tipo di elemento dichiarando entrambi i file in un solo attributo Include
. Si noti che i nomi file sono separati da punto e virgola.
<ItemGroup>
<Compile Include = "file1.cs;file2.cs"/>
</ItemGroup>
L'attributo Include
è un percorso interpretato rispetto alla cartella del file di progetto, $(MSBuildProjectPath)
, anche se l'elemento si trova in un file importato, ad esempio un .targets
file.
Creare elementi durante l'esecuzione
Agli elementi non compresi in elementi Target vengono assegnati valori durante la fase di valutazione di una compilazione. Durante la fase di esecuzione successiva, gli elementi possono essere creati o modificati nei modi seguenti:
Le attività possono creare un elemento. Per creare un elemento, l'elemento Task deve avere un elemento Output figlio con un attributo
ItemName
.L'attività CreateItem può creare un elemento. Questo utilizzo è deprecato.
Target
gli elementi possono contenere elementi ItemGroup che possono contenere elementi dell'elemento.
Fare riferimento a elementi in un file di progetto
Per fare riferimento ai tipi di elemento nel file di progetto, usare la sintassi @(ItemType)
. Ad esempio, per fare riferimento al tipo di elemento nell'esempio precedente, si userà @(Compile)
. Usando questa sintassi, è possibile passare gli elementi alle attività specificando il tipo di elemento come parametro di tale attività. Per altre informazioni, vedere Procedura: Selezionare i file da compilare.
Per impostazione predefinita, gli elementi di un tipo di elemento vengono separati da punto e virgola (;) quando viene espanso. È possibile usare la sintassi @(ItemType, 'separator')
per specificare un separatore diverso da quello predefinito. Per altre informazioni, vedere Procedura: Visualizzare un elenco di elementi separati da virgole.
Usare caratteri jolly per specificare gli elementi
È possibile usare i caratteri jolly **
, *
e ?
per specificare un gruppo di file come input per una compilazione anziché elencare ogni file separatamente.
- Il carattere jolly
?
corrisponde a un singolo carattere. - Il carattere jolly
*
corrisponde a zero o più caratteri. - La sequenza di caratteri jolly
**
corrisponde a un percorso parziale.
Ad esempio, è possibile specificare tutti i file .cs
nella directory che contiene il file di progetto usando l'elemento seguente nel file di progetto.
<CSFile Include="*.cs"/>
L'elemento seguente seleziona tutti i file .vb
nell'unità D:
:
<VBFile Include="D:/**/*.vb"/>
Se si desidera includere caratteri letterali *
o ?
in un elemento privo di espansione di caratteri jolly, è necessario aggiungere un carattere di escape ai caratteri jolly.
Per altre informazioni sui caratteri jolly, vedere Procedura: Selezionare i file da compilare.
Usare l'attributo Exclude
Gli elementi Item possono contenere l'attributo Exclude
, che esclude elementi (file) specifici dal tipo di elemento. L'attributo Exclude
viene in genere usato con i caratteri jolly. Ad esempio, il codice XML seguente aggiunge ogni file .cs nella directory al CSFile
tipo di elemento, ad eccezione del file DoNotBuild.cs .
<ItemGroup>
<CSFile Include="*.cs" Exclude="DoNotBuild.cs"/>
</ItemGroup>
L'attributo Exclude
interessa solo gli elementi che vengono aggiunti dall'attributo Include
nell'elemento item che li contiene entrambi. L'esempio seguente non escluderà il file Form1.cs, che è stato aggiunto nell'elemento item precedente.
<Compile Include="*.cs" />
<Compile Include="*.res" Exclude="Form1.cs">
Per altre informazioni, vedere Procedura: Escludere file dalla compilazione.
Metadati degli elementi
Gli elementi possono contenere metadati oltre alle informazioni negli attributi Include
e Exclude
. Questi metadati possono essere usati dalle attività che richiedono altre informazioni sugli elementi o per dividere in batch le attività e le destinazioni. Per altre informazioni, vedere Batch.
I metadati sono una raccolta di coppie chiave-valore che vengono dichiarate nel file di progetto come elementi figlio di un elemento item. Il nome dell'elemento figlio è il nome dei metadati e il valore dell'elemento figlio è il valore dei metadati.
I metadati sono associati all'elemento item che li contiene. Ad esempio, il codice XML seguente aggiunge Culture
metadati con valore Fr
sia al one.cs che agli elementi two.cs del CSFile
tipo di elemento.
<ItemGroup>
<CSFile Include="one.cs;two.cs">
<Culture>Fr</Culture>
</CSFile>
</ItemGroup>
Un elemento può avere zero o più valori di metadati. È possibile modificare i valori dei metadati in qualsiasi momento. Se si impostano i metadati su un valore vuoto, di fatto li si rimuove dalla compilazione.
Metadati degli elementi di riferimento in un file di progetto
È possibile fare riferimento ai metadati degli elementi nel file di progetto usando la sintassi %(ItemMetadataName)
. In caso di ambiguità, è possibile qualificare un riferimento usando il nome del tipo di elemento. Ad esempio, è possibile specificare %(ItemType.ItemMetaDataName)
. Nell'esempio seguente vengono usati i Display
metadati per eseguire il batch dell'attività Message
. Per altre informazioni su come usare i metadati di un elemento per la suddivisione in batch, vedere Metadati degli elementi nella suddivisione in batch delle attività.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Stuff Include="One.cs" >
<Display>false</Display>
</Stuff>
<Stuff Include="Two.cs">
<Display>true</Display>
</Stuff>
</ItemGroup>
<Target Name="Batching">
<Message Text="@(Stuff)" Condition=" '%(Display)' == 'true' "/>
</Target>
</Project>
Metadati noti degli elementi
Quando un elemento viene aggiunto a un tipo di elemento, a tale elemento vengono assegnati alcuni metadati noti. Ad esempio, tutti gli elementi hanno i metadati %(Filename)
noti , il cui valore è il nome file dell'elemento (senza l'estensione). Per altre informazioni, vedere Metadati noti degli elementi.
Trasformare i tipi di elemento usando i metadati
È possibile trasformare gli elenchi di elementi in nuovi elenchi di elementi usando i metadati. Ad esempio, è possibile trasformare un tipo di CppFiles
elemento con elementi che rappresentano .cpp
i file in un elenco corrispondente di .obj
file usando l'espressione @(CppFiles -> '%(Filename).obj')
.
Il codice seguente crea un tipo di elemento CultureResource
che contiene copie di tutti gli elementi EmbeddedResource
con i metadati Culture
. Il valore dei metadati Culture
diventa il valore dei nuovi metadati CultureResource.TargetDirectory
.
<Target Name="ProcessCultureResources">
<ItemGroup>
<CultureResource Include="@(EmbeddedResource)"
Condition="'%(EmbeddedResource.Culture)' != ''">
<TargetDirectory>%(EmbeddedResource.Culture) </TargetDirectory>
</CultureResource>
</ItemGroup>
</Target>
Per altre operazioni sugli elementi, vedere Funzioni degli elementi di MSBuild e Trasformazioni.
Definizioni degli elementi
È possibile aggiungere metadati predefiniti a qualsiasi tipo di elemento usando l'elemento ItemDefinitionGroup. Come i metadati noti, i metadati predefiniti sono associati a tutti gli elementi del tipo di elemento specificato. È possibile eseguire l'override esplicito dei metadati predefiniti nella definizione di un elemento. Il codice XML seguente, ad esempio, assegna agli elementi Compile
one.cs e three.cs i metadati BuildDay
con il valore "Monday". Il codice assegna all'elemento two.cs i metadati BuildDay
con il valore "Tuesday".
<ItemDefinitionGroup>
<Compile>
<BuildDay>Monday</BuildDay>
</Compile>
</ItemDefinitionGroup>
<ItemGroup>
<Compile Include="one.cs;three.cs" />
<Compile Include="two.cs">
<BuildDay>Tuesday</BuildDay>
</Compile>
</ItemGroup>
Per altre informazioni, vedere Definizioni degli elementi.
Attributi per gli elementi in un ItemGroup di una destinazione
Target
gli elementi possono contenere elementi ItemGroup che possono contenere elementi dell'elemento. Gli attributi in questa sezione sono validi quando vengono specificati per un elemento in un ItemGroup
oggetto che si trova in un oggetto Target
.
Remove attribute
L'attributo Remove
rimuove elementi (file) specifici dal tipo di elemento. Questo attributo è stato introdotto in .NET Framework 3.5 (solo all'interno di destinazioni). Le destinazioni interne e esterne sono supportate a partire da MSBuild 15.0.
Nell'esempio seguente viene rimosso ogni .config
file dal Compile
tipo di elemento.
<Target>
<ItemGroup>
<Compile Remove="*.config"/>
</ItemGroup>
</Target>
Attributo MatchOnMetadata
L'attributo MatchOnMetadata
è applicabile solo agli attributi che fanno riferimento ad Remove
altri elementi (ad esempio, Remove="@(Compile);@(Content)"
) e indica all'operazione Remove
di trovare le corrispondenze tra gli elementi in base ai valori dei nomi di metadati specificati, anziché la corrispondenza in base ai valori dell'elemento.
Regola di corrispondenza per B Remove="@(A)" MatchOnMetadata="M"
: rimuovere tutti gli elementi da B
con metadati M
, il cui valore V
dei metadati per corrisponde a M
qualsiasi elemento da A
con i metadati M
di valore V
.
<Project>
<ItemGroup>
<A Include='a1' M1='1' M2='a' M3="e"/>
<A Include='b1' M1='2' M2='x' M3="f"/>
<A Include='c1' M1='3' M2='y' M3="g"/>
<A Include='d1' M1='4' M2='b' M3="h"/>
<B Include='a2' M1='x' m2='c' M3="m"/>
<B Include='b2' M1='2' m2='x' M3="n"/>
<B Include='c2' M1='2' m2='x' M3="o"/>
<B Include='d2' M1='3' m2='y' M3="p"/>
<B Include='e2' M1='3' m2='Y' M3="p"/>
<B Include='f2' M1='4' M3="r"/>
<B Include='g2' M3="s"/>
<B Remove='@(A)' MatchOnMetadata='M1;M2'/>
</ItemGroup>
<Target Name="PrintEvaluation">
<Message Text="%(B.Identity) M1='%(B.M1)' M2='%(B.M2)' M3='%(B.M3)'" />
</Target>
</Project>
Nell'esempio i valori b2
dell'elemento , c2
e d2
vengono rimossi dall'elemento B
perché:
b2
ec2
dallaB
partita controb1
daA
onM1=2
eM2=x
d2
dalleB
corrispondenze controc1
da onA
M1=3
eM2=y
L'attività Message
restituisce quanto segue:
a2 M1='x' M2='c' M3='m'
e2 M1='3' M2='Y' M3='p'
f2 M1='4' M2='' M3='r'
g2 M1='' M2='' M3='s'
Esempio di utilizzo di MatchOnMetadata
da MSBuild:
<_TransitiveItemsToCopyToOutputDirectory Remove="@(_ThisProjectItemsToCopyToOutputDirectory)" MatchOnMetadata="TargetPath" MatchOnMetadataOptions="PathLike" />
Questa riga rimuove gli elementi da _TransitiveItemsToCopyToOutputDirectory
con gli stessi TargetPath
valori di metadati dagli elementi in _ThisProjectItemsToCopyToOutputDirectory
Attributo MatchOnMetadataOptions
Specifica la strategia di corrispondenza delle stringhe usata da MatchOnMetadata
per trovare la corrispondenza dei valori dei metadati tra gli elementi (i nomi dei metadati sono sempre senza distinzione tra maiuscole e minuscole). I valori possibili sono CaseSensitive
, CaseInsensitive
o PathLike
. Il valore predefinito è CaseSensitive
.
PathLike
applica la normalizzazione compatibile con il percorso ai valori come la normalizzazione degli orientamenti delle barre, ignorando le barre finali, eliminando .
e ..
e rendendo assoluti tutti i percorsi relativi rispetto alla directory corrente.
Attributo KeepMetadata
Un elemento item, se viene generato in una destinazione, può contenere l'attributo KeepMetadata
. Se questo attributo è specificato, solo i metadati specificati nell'elenco di nomi delimitati da punto e virgola verranno trasferiti dall'elemento di origine a quello di destinazione. Un valore vuoto per questo attributo equivale a non specificarlo. L'attributo KeepMetadata
è stato introdotto in .NET Framework 4.5.
L'esempio seguente mostra come usare l'attributo KeepMetadata
.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
ToolsVersion="4.0">
<ItemGroup>
<FirstItem Include="rhinoceros">
<Class>mammal</Class>
<Size>large</Size>
</FirstItem>
</ItemGroup>
<Target Name="MyTarget">
<ItemGroup>
<SecondItem Include="@(FirstItem)" KeepMetadata="Class" />
</ItemGroup>
<Message Text="FirstItem: %(FirstItem.Identity)" />
<Message Text=" Class: %(FirstItem.Class)" />
<Message Text=" Size: %(FirstItem.Size)" />
<Message Text="SecondItem: %(SecondItem.Identity)" />
<Message Text=" Class: %(SecondItem.Class)" />
<Message Text=" Size: %(SecondItem.Size)" />
</Target>
</Project>
<!--
Output:
FirstItem: rhinoceros
Class: mammal
Size: large
SecondItem: rhinoceros
Class: mammal
Size:
-->
Attributo RemoveMetadata
Un elemento item, se viene generato in una destinazione, può contenere l'attributo RemoveMetadata
. Se questo attributo è specificato, tutti i metadati vengono trasferiti dall'elemento di origine all'elemento di destinazione, a eccezione dei metadati i cui nomi sono contenuti nell'elenco di nomi separati da punto e virgola. Un valore vuoto per questo attributo equivale a non specificarlo. L'attributo RemoveMetadata
è stato introdotto in .NET Framework 4.5.
L'esempio seguente mostra come usare l'attributo RemoveMetadata
.
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MetadataToRemove>Size;Material</MetadataToRemove>
</PropertyGroup>
<ItemGroup>
<Item1 Include="stapler">
<Size>medium</Size>
<Color>black</Color>
<Material>plastic</Material>
</Item1>
</ItemGroup>
<Target Name="MyTarget">
<ItemGroup>
<Item2 Include="@(Item1)" RemoveMetadata="$(MetadataToRemove)" />
</ItemGroup>
<Message Text="Item1: %(Item1.Identity)" />
<Message Text=" Size: %(Item1.Size)" />
<Message Text=" Color: %(Item1.Color)" />
<Message Text=" Material: %(Item1.Material)" />
<Message Text="Item2: %(Item2.Identity)" />
<Message Text=" Size: %(Item2.Size)" />
<Message Text=" Color: %(Item2.Color)" />
<Message Text=" Material: %(Item2.Material)" />
</Target>
</Project>
<!--
Output:
Item1: stapler
Size: medium
Color: black
Material: plastic
Item2: stapler
Size:
Color: black
Material:
-->
Per altre operazioni sugli elementi, vedere Funzioni dell'elemento MSBuild.
Attributo KeepDuplicates
Un elemento item, se viene generato in una destinazione, può contenere l'attributo KeepDuplicates
. KeepDuplicates
è un attributo Boolean
che specifica se un elemento deve essere aggiunto al gruppo di destinazione se l'elemento è un duplicato esatto di un elemento esistente.
Se l'elemento di origine e destinazione hanno lo stesso valore Include
, ma metadati diversi, l'elemento viene aggiunto anche se KeepDuplicates
è impostato su false
. Un valore vuoto per questo attributo equivale a non specificarlo. L'attributo KeepDuplicates
è stato introdotto in .NET Framework 4.5.
L'esempio seguente mostra come usare l'attributo KeepDuplicates
.
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Item1 Include="hourglass;boomerang" />
<Item2 Include="hourglass;boomerang" />
</ItemGroup>
<Target Name="MyTarget">
<ItemGroup>
<Item1 Include="hourglass" KeepDuplicates="false" />
<Item2 Include="hourglass" />
</ItemGroup>
<Message Text="Item1: @(Item1)" />
<Message Text=" %(Item1.Identity) Count: @(Item1->Count())" />
<Message Text="Item2: @(Item2)" />
<Message Text=" %(Item2.Identity) Count: @(Item2->Count())" />
</Target>
</Project>
<!--
Output:
Item1: hourglass;boomerang
hourglass Count: 1
boomerang Count: 1
Item2: hourglass;boomerang;hourglass
hourglass Count: 2
boomerang Count: 1
-->
Poiché l'attributo KeepDuplicates
considera i metadati degli elementi oltre ai valori dell'elemento, è importante sapere cosa accade con i metadati. Ad esempio, vedere Rilevamento di duplicati quando si usa la funzione Elemento metadati.
Aggiornamento dei metadati per gli elementi in un ItemGroup all'esterno di una destinazione
Gli elementi esterni alle destinazioni possono avere i metadati esistenti aggiornati tramite l'attributo Update
. Questo attributo non è disponibile per gli elementi nelle destinazioni.
<Project>
<PropertyGroup>
<MetadataToUpdate>pencil</MetadataToUpdate>
</PropertyGroup>
<ItemGroup>
<Item1 Include="stapler">
<Size>medium</Size>
<Color>black</Color>
<Material>plastic</Material>
</Item1>
<Item1 Include="pencil">
<Size>small</Size>
<Color>yellow</Color>
<Material>wood</Material>
</Item1>
<Item1 Include="eraser">
<Color>red</Color>
</Item1>
<Item1 Include="notebook">
<Size>large</Size>
<Color>white</Color>
<Material>paper</Material>
</Item1>
<Item2 Include="notebook">
<Size>SMALL</Size>
<Color>YELLOW</Color>
</Item2>
<!-- Metadata can be expressed either as attributes or as elements -->
<Item1 Update="$(MetadataToUpdate);stapler;er*r;@(Item2)" Price="10" Material="">
<Color>RED</Color>
</Item1>
</ItemGroup>
<Target Name="MyTarget">
<Message Text="Item1: %(Item1.Identity)
Size: %(Item1.Size)
Color: %(Item1.Color)
Material: %(Item1.Material)
Price: %(Item1.Price)" />
</Target>
</Project>
<!--
Item1: stapler
Size: medium
Color: RED
Material:
Price: 10
Item1: pencil
Size: small
Color: RED
Material:
Price: 10
Item1: eraser
Size:
Color: RED
Material:
Price: 10
Item1: notebook
Size: large
Color: RED
Material:
Price: 10
-->
In MSBuild versione 16.6 e successive, l'attributo Update
supporta riferimenti ai metadati qualificati per facilitare l'importazione di metadati da due o più elementi.
<Project>
<ItemGroup>
<Item1 Include="stapler">
<Size>medium</Size>
<Color>black</Color>
<Material>plastic</Material>
</Item1>
<Item1 Include="pencil">
<Size>small</Size>
<Color>yellow</Color>
<Material>wood</Material>
</Item1>
<Item1 Include="eraser">
<Size>small</Size>
<Color>red</Color>
<Material>gum</Material>
</Item1>
<Item1 Include="notebook">
<Size>large</Size>
<Color>white</Color>
<Material>paper</Material>
</Item1>
<Item2 Include="pencil">
<Size>MEDIUM</Size>
<Color>RED</Color>
<Material>PLASTIC</Material>
<Price>10</Price>
</Item2>
<Item3 Include="notebook">
<Size>SMALL</Size>
<Color>BLUE</Color>
<Price>20</Price>
</Item3>
<!-- Metadata can be expressed either as attributes or as elements -->
<Item1 Update="@(Item2);er*r;@(Item3)" Size="%(Size)" Color="%(Item2.Color)" Price="%(Item3.Price)" Model="2020">
<Material Condition="'%(Item2.Material)' != ''">Premium %(Item2.Material)</Material>
</Item1>
</ItemGroup>
<Target Name="MyTarget">
<Message Text="Item1: %(Item1.Identity)
Size: %(Item1.Size)
Color: %(Item1.Color)
Material: %(Item1.Material)
Price: %(Item1.Price)
Model: %(Item1.Model)" />
</Target>
</Project>
<!--
Item1: stapler
Size: medium
Color: black
Material: plastic
Price:
Model:
Item1: pencil
Size: small
Color: RED
Material: Premium PLASTIC
Price:
Model: 2020
Item1: eraser
Size: small
Color:
Material: gum
Price:
Model: 2020
Item1: notebook
Size: large
Color:
Material: paper
Price: 20
Model: 2020
-->
Note:
- I metadati non qualificati (
%(MetadataName)
) vengono associati al tipo di elemento da aggiornare (Item1
nell'esempio precedente). I metadati qualificati (%(Item2.Color)
) vengono associati all'interno del set di tipi di elementi corrispondenti acquisiti dall'espressione Update. - Se un elemento corrisponde più volte all'interno e tra più elementi a cui si fa riferimento:
- L'ultima occorrenza di ogni tipo di elemento a cui viene fatto riferimento viene acquisita (quindi un elemento acquisito per ogni tipo di elemento).
- Questo corrisponde al comportamento dell'invio in batch degli elementi dell'attività nelle destinazioni.
- Dove è possibile inserire %() riferimenti:
- Metadati UFX
- Condizioni dei metadati
- La corrispondenza dei nomi dei metadati non fa distinzione tra maiuscole e minuscole.
Aggiornamento dei metadati per gli elementi in un ItemGroup di una destinazione
I metadati possono essere modificati anche all'interno delle destinazioni, con una sintassi meno espressiva di Update
:
<Project>
<ItemGroup>
<Item1 Include="stapler">
<Size>medium</Size>
<Color>black</Color>
<Material>plastic</Material>
</Item1>
<Item1 Include="pencil">
<Size>small</Size>
<Color>yellow</Color>
<Material>wood</Material>
</Item1>
<Item1 Include="eraser">
<Size>small</Size>
<Color>red</Color>
<Material>gum</Material>
</Item1>
<Item1 Include="notebook">
<Size>large</Size>
<Color>white</Color>
<Material>paper</Material>
</Item1>
<Item2 Include="pencil">
<Size>MEDIUM</Size>
<Color>RED</Color>
<Material>PLASTIC</Material>
<Price>10</Price>
</Item2>
<Item2 Include="ruler">
<Color>GREEN</Color>
</Item2>
</ItemGroup>
<Target Name="MyTarget">
<ItemGroup>
<!-- Metadata can be expressed either as attributes or as elements -->
<Item1 Size="GIGANTIC" Color="%(Item2.Color)">
<Material Condition="'%(Item2.Material)' != ''">Premium %(Item2.Material)</Material>
</Item1>
</ItemGroup>
<Message Text="Item1: %(Item1.Identity)
Size: %(Item1.Size)
Color: %(Item1.Color)
Material: %(Item1.Material)
Price: %(Item1.Price)
Model: %(Item1.Model)" />
</Target>
</Project>
<!--
Item1: stapler
Size: GIGANTIC
Color: GREEN
Material: Premium PLASTIC
Price:
Model:
Item1: pencil
Size: GIGANTIC
Color: GREEN
Material: Premium PLASTIC
Price:
Model:
Item1: eraser
Size: GIGANTIC
Color: GREEN
Material: Premium PLASTIC
Price:
Model:
Item1: notebook
Size: GIGANTIC
Color: GREEN
Material: Premium PLASTIC
Price:
Model:
-->