

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

# Travailler avec des résultats paginés : scans et requêtes
<a name="ddb-en-client-use-multirecord"></a>

*Les `scan` `batch` méthodes `query` et de l'API DynamoDB Enhanced Client renvoient des réponses contenant une ou plusieurs pages.* Une page contient un ou plusieurs éléments. Votre code peut traiter la réponse page par page ou traiter des éléments individuels.

Une réponse paginée renvoyée par le `DynamoDbEnhancedClient` client synchrone renvoie un [PageIterable](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/PageIterable.html)objet, tandis qu'une réponse renvoyée par le client asynchrone `DynamoDbEnhancedAsyncClient` renvoie un objet. [PagePublisher](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/PagePublisher.html)

Cette section traite du traitement des résultats paginés et fournit des exemples d'utilisation du scan et de la requête APIs.

## Analyser une table
<a name="ddb-en-client-use-multirecord-scan"></a>

La [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbAsyncTable.html#scan(java.util.function.Consumer)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbAsyncTable.html#scan(java.util.function.Consumer))méthode du SDK correspond à l'opération [DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html) du même nom. L'API DynamoDB Enhanced Client propose les mêmes options, mais elle utilise un modèle d'objet familier et gère la pagination à votre place.

Tout d'abord, nous explorons l'`PageIterable`interface en examinant la `scan` méthode de la classe de mappage synchrone, [DynamoDbTable](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html).

### Utiliser l'API synchrone
<a name="ddb-en-client-use-multirecord-scan-sync"></a>

L'exemple suivant montre la `scan` méthode qui utilise une [expression](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Expression.html) pour filtrer les éléments renvoyés. [ProductCatalog](ddb-en-client-use.md#ddb-en-client-use-compare-cs3)Il s'agit de l'objet modèle présenté précédemment.

L'expression de filtrage affichée après la ligne de commentaire 2 limite les `ProductCatalog` articles renvoyés à ceux dont le prix est compris entre 8,00 et 80,00€ inclusivement.

Cet exemple exclut également les `isbn` valeurs en utilisant la `attributesToProject` méthode indiquée après la ligne de commentaire 1.

Après la ligne de commentaire 3`pagedResults`, l'`PageIterable`objet est renvoyé par la `scan` méthode. La `stream` méthode de `PageIterable` renvoi d'un [https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html)objet, que vous pouvez utiliser pour traiter les pages. Dans cet exemple, le nombre de pages est compté et enregistré.

À partir de la ligne de commentaire 4, l'exemple montre deux variantes d'accès aux `ProductCatalog` éléments. La version située après la ligne de commentaire 4a parcourt chaque page et trie et enregistre les éléments de chaque page. La version située après la ligne de commentaire 4b ignore l'itération de la page et accède directement aux éléments.

L'`PageIterable`interface offre plusieurs manières de traiter les résultats grâce à ses deux interfaces parentes : [https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html](https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html)et [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/pagination/sync/SdkIterable.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/pagination/sync/SdkIterable.html). `Iterable`apporte les `forEach` `spliterator` méthodes, et `SdkIterable` apporte la `stream` méthode. `iterator`

```
    public static void scanSync(DynamoDbTable<ProductCatalog> productCatalog) {

        Map<String, AttributeValue> expressionValues = Map.of(
                ":min_value", numberValue(8.00),
                ":max_value", numberValue(80.00));

        ScanEnhancedRequest request = ScanEnhancedRequest.builder()
                .consistentRead(true)
                // 1. the 'attributesToProject()' method allows you to specify which values you want returned.
                .attributesToProject("id", "title", "authors", "price")
                // 2. Filter expression limits the items returned that match the provided criteria.
                .filterExpression(Expression.builder()
                        .expression("price >= :min_value AND price <= :max_value")
                        .expressionValues(expressionValues)
                        .build())
                .build();

        // 3. A PageIterable object is returned by the scan method.
        PageIterable<ProductCatalog> pagedResults = productCatalog.scan(request);
        logger.info("page count: {}", pagedResults.stream().count());

        // 4. Log the returned ProductCatalog items using two variations.
        // 4a. This version sorts and logs the items of each page.
        pagedResults.stream().forEach(p -> p.items().stream()
                .sorted(Comparator.comparing(ProductCatalog::price))
                .forEach(
                        item -> logger.info(item.toString())
                ));
        // 4b. This version sorts and logs all items for all pages.
        pagedResults.items().stream()
                .sorted(Comparator.comparing(ProductCatalog::price))
                .forEach(
                        item -> logger.info(item.toString())
                );
    }
```

### Utiliser l'API asynchrone
<a name="ddb-en-client-use-multirecord-scan-async"></a>

La `scan` méthode asynchrone renvoie les résultats sous forme d'`PagePublisher`objet. L'`PagePublisher`interface comporte deux `subscribe` méthodes que vous pouvez utiliser pour traiter les pages de réponse. L'une des `subscribe` méthodes provient de l'interface `org.reactivestreams.Publisher` parent. Pour traiter les pages à l'aide de cette première option, transmettez une `[Subscriber](https://www.reactive-streams.org/reactive-streams-1.0.0-javadoc/org/reactivestreams/Subscriber.html)` instance à la `subscribe` méthode. Le premier exemple qui suit montre l'utilisation de la `subscribe` méthode.

La deuxième `subscribe` méthode provient de l'[SdkPublisher](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/async/SdkPublisher.html)interface. Cette version de `subscribe` accepte un [https://docs.oracle.com/javase/8/docs/api/java/util/function/Consumer.html](https://docs.oracle.com/javase/8/docs/api/java/util/function/Consumer.html)plutôt qu'un`Subscriber`. Cette variante de `subscribe` méthode est illustrée dans le deuxième exemple qui suit.

L'exemple suivant montre la version asynchrone de la `scan` méthode qui utilise la même expression de filtre que dans l'exemple précédent. 

Après la ligne de commentaire 3, `DynamoDbAsyncTable.scan` renvoie un `PagePublisher` objet. Sur la ligne suivante, le code crée une instance de l'`org.reactivestreams.Subscriber`interface`ProductCatalogSubscriber`, qui s'abonne à la ligne de commentaire 4 `PagePublisher` après.

L'`Subscriber`objet collecte les `ProductCatalog` éléments de chaque page de la `onNext` méthode après la ligne de commentaire 8 dans l'exemple `ProductCatalogSubscriber` de classe. Les éléments sont stockés dans la `List` variable privée et sont accessibles dans le code d'appel avec la `ProductCatalogSubscriber.getSubscribedItems()` méthode. Ceci est appelé après la ligne de commentaire 5.

Une fois la liste récupérée, le code trie tous les `ProductCatalog` articles par prix et enregistre chaque article.

La `ProductCatalogSubscriber` classe [CountDownLatch](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html)in bloque le fil d'appel jusqu'à ce que tous les éléments aient été ajoutés à la liste avant de continuer après la ligne de commentaire 5. 

```
    public static void scanAsync(DynamoDbAsyncTable productCatalog) {
        ScanEnhancedRequest request = ScanEnhancedRequest.builder()
                .consistentRead(true)
                .attributesToProject("id", "title", "authors", "price")
                .filterExpression(Expression.builder()
                        // 1. :min_value and :max_value are placeholders for the values provided by the map
                        .expression("price >= :min_value AND price <= :max_value")
                        // 2. Two values are needed for the expression and each is supplied as a map entry.
                        .expressionValues(
                                Map.of( ":min_value", numberValue(8.00),
                                        ":max_value", numberValue(400_000.00)))
                        .build())
                .build();

        // 3. A PagePublisher object is returned by the scan method.
        PagePublisher<ProductCatalog> pagePublisher = productCatalog.scan(request);
        ProductCatalogSubscriber subscriber = new ProductCatalogSubscriber();
        // 4. Subscribe the ProductCatalogSubscriber to the PagePublisher.
        pagePublisher.subscribe(subscriber);
        // 5. Retrieve all collected ProductCatalog items accumulated by the subscriber.
        subscriber.getSubscribedItems().stream()
                .sorted(Comparator.comparing(ProductCatalog::price))
                .forEach(item ->
                        logger.info(item.toString()));
        // 6. Use a Consumer to work through each page.
        pagePublisher.subscribe(page -> page
                        .items().stream()
                        .sorted(Comparator.comparing(ProductCatalog::price))
                        .forEach(item ->
                                logger.info(item.toString())))
                .join(); // If needed, blocks the subscribe() method thread until it is finished processing.
        // 7. Use a Consumer to work through each ProductCatalog item.
        pagePublisher.items()
                .subscribe(product -> logger.info(product.toString()))
                .exceptionally(failure -> {
                    logger.error("ERROR  - ", failure);
                    return null;
                })
                .join(); // If needed, blocks the subscribe() method thread until it is finished processing.
    }
```

```
    private static class ProductCatalogSubscriber implements Subscriber<Page<ProductCatalog>> {
        private CountDownLatch latch = new CountDownLatch(1);
        private Subscription subscription;
        private List<ProductCatalog> itemsFromAllPages = new ArrayList<>();

        @Override
        public void onSubscribe(Subscription sub) {
            subscription = sub;
            subscription.request(1L);
            try {
                latch.await(); // Called by main thread blocking it until latch is released.
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public void onNext(Page<ProductCatalog> productCatalogPage) {
            // 8. Collect all the ProductCatalog instances in the page, then ask the publisher for one more page.
            itemsFromAllPages.addAll(productCatalogPage.items());
            subscription.request(1L);
        }

        @Override
        public void onError(Throwable throwable) {
        }

        @Override
        public void onComplete() {
            latch.countDown(); // Call by subscription thread; latch releases.
        }

        List<ProductCatalog> getSubscribedItems() {
            return this.itemsFromAllPages;
        }
    }
```

L'exemple d'extrait de code suivant utilise la version de la `PagePublisher.subscribe` méthode qui accepte une ligne de commentaire `Consumer` 6 après. Le paramètre Java lambda consomme des pages, qui traitent ensuite chaque élément. Dans cet exemple, chaque page est traitée et les éléments de chaque page sont triés puis enregistrés.

```
        // 6. Use a Consumer to work through each page.
        pagePublisher.subscribe(page -> page
                        .items().stream()
                        .sorted(Comparator.comparing(ProductCatalog::price))
                        .forEach(item ->
                                logger.info(item.toString())))
                .join(); // If needed, blocks the subscribe() method thread until it is finished processing.
```

La `items` méthode qui consiste à `PagePublisher` déballer les instances du modèle afin que votre code puisse traiter les éléments directement. Cette approche est illustrée dans l'extrait suivant.

```
        // 7. Use a Consumer to work through each ProductCatalog item.
        pagePublisher.items()
                .subscribe(product -> logger.info(product.toString()))
                .exceptionally(failure -> {
                    logger.error("ERROR  - ", failure);
                    return null;
                })
                .join(); // If needed, blocks the subscribe() method thread until it is finished processing.
```

## Interroger une table
<a name="ddb-en-client-use-multirecord-query"></a>

Vous pouvez utiliser le client DynamoDB amélioré pour interroger votre table et récupérer plusieurs éléments répondant à des critères spécifiques. La [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html#query(software.amazon.awssdk.enhanced.dynamodb.model.QueryEnhancedRequest)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html#query(software.amazon.awssdk.enhanced.dynamodb.model.QueryEnhancedRequest))méthode recherche des éléments en fonction des valeurs de clé primaire à l'`@DynamoDbPartitionKey`aide `@DynamoDbSortKey` des annotations facultatives définies dans votre classe de données.

La `query()` méthode nécessite une valeur de clé de partition et accepte éventuellement les conditions de clé de tri pour affiner davantage les résultats. Comme l'`scan`API, les requêtes renvoient a `PageIterable` pour les appels synchrones et a `PagePublisher` pour les appels asynchrones.

### `Query`exemples de méthodes
<a name="ddb-en-client-use-multirecord-query-example"></a>

L'exemple de code de `query()` méthode qui suit utilise la `MovieActor` classe. La classe de données définit une clé primaire composite composée de l'**`movie`**attribut en tant que clé de partition et de l'**`actor`**attribut en tant que clé de tri. 

#### classe `MovieActor`
<a name="ddb-en-client-use-movieactor-class"></a>

```
package org.example.tests.model;

import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbAttribute;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondaryPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondarySortKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSortKey;

import java.util.Objects;

@DynamoDbBean
public class MovieActor implements Comparable<MovieActor> {

    private String movieName;
    private String actorName;
    private String actingAward;
    private Integer actingYear;
    private String actingSchoolName;

    @DynamoDbPartitionKey
    @DynamoDbAttribute("movie")
    public String getMovieName() {
        return movieName;
    }

    public void setMovieName(String movieName) {
        this.movieName = movieName;
    }

    @DynamoDbSortKey
    @DynamoDbAttribute("actor")
    public String getActorName() {
        return actorName;
    }

    public void setActorName(String actorName) {
        this.actorName = actorName;
    }

    @DynamoDbSecondaryPartitionKey(indexNames = "acting_award_year")
    @DynamoDbAttribute("actingaward")
    public String getActingAward() {
        return actingAward;
    }

    public void setActingAward(String actingAward) {
        this.actingAward = actingAward;
    }

    @DynamoDbSecondarySortKey(indexNames = {"acting_award_year", "movie_year"})
    @DynamoDbAttribute("actingyear")
    public Integer getActingYear() {
        return actingYear;
    }

    public void setActingYear(Integer actingYear) {
        this.actingYear = actingYear;
    }

    @DynamoDbAttribute("actingschoolname")
    public String getActingSchoolName() {
        return actingSchoolName;
    }

    public void setActingSchoolName(String actingSchoolName) {
        this.actingSchoolName = actingSchoolName;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("MovieActor{");
        sb.append("movieName='").append(movieName).append('\'');
        sb.append(", actorName='").append(actorName).append('\'');
        sb.append(", actingAward='").append(actingAward).append('\'');
        sb.append(", actingYear=").append(actingYear);
        sb.append(", actingSchoolName='").append(actingSchoolName).append('\'');
        sb.append('}');
        return sb.toString();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MovieActor that = (MovieActor) o;
        return Objects.equals(movieName, that.movieName) && Objects.equals(actorName, that.actorName) && Objects.equals(actingAward, that.actingAward) && Objects.equals(actingYear, that.actingYear) && Objects.equals(actingSchoolName, that.actingSchoolName);
    }

    @Override
    public int hashCode() {
        return Objects.hash(movieName, actorName, actingAward, actingYear, actingSchoolName);
    }

    @Override
    public int compareTo(MovieActor o) {
        if (this.movieName.compareTo(o.movieName) != 0){
            return this.movieName.compareTo(o.movieName);
        } else {
            return this.actorName.compareTo(o.actorName);
        }
    }
}
```

Les exemples de code qui suivent portent sur les éléments suivants.

#### Éléments du `MovieActor` tableau
<a name="ddb-en-client-use-movieactor-items"></a>

```
MovieActor{movieName='movie01', actorName='actor0', actingAward='actingaward0', actingYear=2001, actingSchoolName='null'}
MovieActor{movieName='movie01', actorName='actor1', actingAward='actingaward1', actingYear=2001, actingSchoolName='actingschool1'}
MovieActor{movieName='movie01', actorName='actor2', actingAward='actingaward2', actingYear=2001, actingSchoolName='actingschool2'}
MovieActor{movieName='movie01', actorName='actor3', actingAward='actingaward3', actingYear=2001, actingSchoolName='null'}
MovieActor{movieName='movie01', actorName='actor4', actingAward='actingaward4', actingYear=2001, actingSchoolName='actingschool4'}
MovieActor{movieName='movie02', actorName='actor0', actingAward='actingaward0', actingYear=2002, actingSchoolName='null'}
MovieActor{movieName='movie02', actorName='actor1', actingAward='actingaward1', actingYear=2002, actingSchoolName='actingschool1'}
MovieActor{movieName='movie02', actorName='actor2', actingAward='actingaward2', actingYear=2002, actingSchoolName='actingschool2'}
MovieActor{movieName='movie02', actorName='actor3', actingAward='actingaward3', actingYear=2002, actingSchoolName='null'}
MovieActor{movieName='movie02', actorName='actor4', actingAward='actingaward4', actingYear=2002, actingSchoolName='actingschool4'}
MovieActor{movieName='movie03', actorName='actor0', actingAward='actingaward0', actingYear=2003, actingSchoolName='null'}
MovieActor{movieName='movie03', actorName='actor1', actingAward='actingaward1', actingYear=2003, actingSchoolName='actingschool1'}
MovieActor{movieName='movie03', actorName='actor2', actingAward='actingaward2', actingYear=2003, actingSchoolName='actingschool2'}
MovieActor{movieName='movie03', actorName='actor3', actingAward='actingaward3', actingYear=2003, actingSchoolName='null'}
MovieActor{movieName='movie03', actorName='actor4', actingAward='actingaward4', actingYear=2003, actingSchoolName='actingschool4'}
```

Le code suivant définit deux `QueryConditional` instances : `keyEqual` (après la ligne de commentaire 1) et `sortGreaterThanOrEqualTo` (après la ligne de commentaire 1a).

#### Éléments de requête par clé de partition
<a name="keyEqual-query-conditional-example"></a>

L'`keyEqual`instance fait correspondre les éléments dont la valeur de clé de partition est de **`movie01`**. 

Cet exemple définit également une expression de filtre après la ligne de commentaire 2 qui filtre tout élément dépourvu de **`actingschoolname`**valeur.

`QueryEnhancedRequest`Combine la condition clé et l'expression du filtre pour la requête.

```
    public static void query(DynamoDbTable movieActorTable) {

        // 1. Define a QueryConditional instance to return items matching a partition value.
        QueryConditional keyEqual = QueryConditional.keyEqualTo(b -> b.partitionValue("movie01"));
        // 1a. Define a QueryConditional that adds a sort key criteria to the partition value criteria.
        QueryConditional sortGreaterThanOrEqualTo = QueryConditional.sortGreaterThanOrEqualTo(b -> b.partitionValue("movie01").sortValue("actor2"));
        // 2. Define a filter expression that filters out items whose attribute value is null.
        final Expression filterOutNoActingschoolname = Expression.builder().expression("attribute_exists(actingschoolname)").build();

        // 3. Build the query request.
        QueryEnhancedRequest tableQuery = QueryEnhancedRequest.builder()
                .queryConditional(keyEqual)
                .filterExpression(filterOutNoActingschoolname)
                .build();
        // 4. Perform the query using the "keyEqual" conditional and filter expression.
        PageIterable<MovieActor> pagedResults = movieActorTable.query(tableQuery);
        logger.info("page count: {}", pagedResults.stream().count()); // Log  number of pages.

        pagedResults.items().stream()
                .sorted()
                .forEach(
                        item -> logger.info(item.toString()) // Log the sorted list of items.
                );
```

**Example — Sortie utilisant la `keyEqual` requête conditionnelle**  
Voici le résultat de l'exécution de la méthode. La sortie affiche les éléments dont `movieName` la valeur est **movie01** et n'affiche aucun élément dont la valeur est `actingSchoolName` égale à. **`null`**  

```
2023-03-05 13:11:05 [main] INFO  org.example.tests.QueryDemo:46 - page count: 1
2023-03-05 13:11:05 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor1', actingAward='actingaward1', actingYear=2001, actingSchoolName='actingschool1'}
2023-03-05 13:11:05 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor2', actingAward='actingaward2', actingYear=2001, actingSchoolName='actingschool2'}
2023-03-05 13:11:05 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor4', actingAward='actingaward4', actingYear=2001, actingSchoolName='actingschool4'}
```

#### Rechercher des éléments par clé de partition et clé de tri
<a name="sort-type-query-conditional-example"></a>

`sortGreaterThanOrEqualTo``QueryConditional`**Affine une correspondance de clé de partition (**movie01**) en ajoutant une condition de clé de tri pour les valeurs supérieures ou égales à actor2.**

[`QueryConditional`les méthodes](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html) qui commencent par `sort` nécessitent qu'une valeur de clé de partition corresponde et affinent davantage la requête par une comparaison basée sur la valeur de la clé de tri. `Sort`dans le nom de la méthode ne signifie pas que les résultats sont triés, mais qu'une valeur de clé de tri sera utilisée pour la comparaison.

Dans l'extrait suivant, nous modifions la demande de requête affichée précédemment après la ligne de commentaire 3. Cet extrait remplace la requête conditionnelle « KeyEqual » par la requête conditionnelle « sortGreaterThan OrEqualTo » définie après la ligne de commentaire 1a. Le code suivant supprime également l'expression du filtre.

```
        QueryEnhancedRequest tableQuery = QueryEnhancedRequest.builder()
                .queryConditional(sortGreaterThanOrEqualTo).build();
```

**Example — Sortie utilisant la `sortGreaterThanOrEqualTo` requête conditionnelle**  
La sortie suivante affiche les résultats de la requête. **La requête renvoie les éléments dont `movieName` la valeur est égale à **movie01** et uniquement les éléments dont `actorName` la valeur est supérieure ou égale à actor2.** Comme nous supprimons le filtre, la requête renvoie des éléments qui n'ont aucune valeur pour l'`actingSchoolName`attribut.  

```
2023-03-05 13:15:00 [main] INFO  org.example.tests.QueryDemo:46 - page count: 1
2023-03-05 13:15:00 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor2', actingAward='actingaward2', actingYear=2001, actingSchoolName='actingschool2'}
2023-03-05 13:15:00 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor3', actingAward='actingaward3', actingYear=2001, actingSchoolName='null'}
2023-03-05 13:15:00 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor4', actingAward='actingaward4', actingYear=2001, actingSchoolName='actingschool4'}
```