From d5fc449c4e21dc49883e425d7079b77a3970d3b1 Mon Sep 17 00:00:00 2001 From: Yuan Tong Date: Wed, 18 Mar 2026 17:32:46 +0800 Subject: [PATCH 01/17] Support rendered size override for layered image --- apps/avifenc.c | 100 +++++++++++++- include/avif/avif.h | 8 ++ src/codec_aom.c | 16 ++- src/codec_avm.c | 5 + src/codec_rav1e.c | 6 + src/codec_svt.c | 7 + src/write.c | 150 +++++++++++++++++++-- tests/data/kodim03_yuv420_8bpc_384x256.y4m | 3 + tests/gtest/avifchangesettingtest.cc | 30 +++++ tests/gtest/avifprogressivetest.cc | 59 ++++++++ tests/test_cmd_progressive.sh | 16 ++- 11 files changed, 377 insertions(+), 23 deletions(-) create mode 100644 tests/data/kodim03_yuv420_8bpc_384x256.y4m diff --git a/apps/avifenc.c b/apps/avifenc.c index e169839dbc..2b8de51a61 100644 --- a/apps/avifenc.c +++ b/apps/avifenc.c @@ -44,6 +44,8 @@ typedef struct avifHeaderFormatFlags headerFormat; uint64_t creationTime; uint64_t modificationTime; + uint32_t width; + uint32_t height; avifBool paspPresent; uint32_t paspValues[2]; @@ -242,6 +244,8 @@ static void syntaxLong(void) printf(" --progressive : Automatically set parameters to encode a simple layered image supporting progressive rendering from a single input frame.\n"); printf(" --layered : Encode a layered AVIF. Each input is encoded as one layer and at most %d layers can be encoded.\n", AVIF_MAX_AV1_LAYER_COUNT); + printf(" --render-size WxH : Set the rendered size of the AVIF image.\n"); + printf(" Supported for still images and layered still images only.\n"); printf(" -g,--grid MxN : Encode a single-image grid AVIF with M cols & N rows. Either supply MxN identical W/H/D images, or a single\n"); printf(" image that can be evenly split into the MxN grid and follow AVIF grid image restrictions. The grid will adopt\n"); printf(" the color profile of the first image supplied.\n"); @@ -454,6 +458,35 @@ static avifBool convertCropToClap(uint32_t srcW, uint32_t srcH, uint32_t clapVal return AVIF_TRUE; } +static avifBool avifSettingsUsesRenderedSizeOverride(const avifSettings * settings) +{ + return (settings->width != 0) || (settings->height != 0); +} + +static void avifSettingsGetEffectiveOutputDimensions(const avifSettings * settings, const avifImage * image, uint32_t * width, uint32_t * height) +{ + *width = settings->width ? settings->width : image->width; + *height = settings->height ? settings->height : image->height; +} + +static avifBool avifSettingsVerifyRenderedSizeBounds(const avifSettings * settings, const avifImage * image, const char * filename) +{ + if (!avifSettingsUsesRenderedSizeOverride(settings)) { + return AVIF_TRUE; + } + if ((image->width > settings->width) || (image->height > settings->height)) { + fprintf(stderr, + "ERROR: Input image dimensions [%ux%u] exceed rendered size [%ux%u]: %s\n", + image->width, + image->height, + settings->width, + settings->height, + filename); + return AVIF_FALSE; + } + return AVIF_TRUE; +} + static avifBool avifInputAddCachedImage(avifInput * input) { avifImage * newImage = avifImageCreateEmpty(); @@ -860,10 +893,11 @@ static avifBool avifEncodeUpdateEncoderSettings(avifEncoder * encoder, const avi static avifBool avifEncoderVerifyImageCompatibility(const avifImage * refImage, const avifImage * testImage, const char * seriesType, - const char * filename) + const char * filename, + avifBool allowDimensionChange) { // Verify that this frame's properties matches the first frame's properties - if ((refImage->width != testImage->width) || (refImage->height != testImage->height)) { + if (!allowDimensionChange && ((refImage->width != testImage->width) || (refImage->height != testImage->height))) { fprintf(stderr, "ERROR: Image %s dimensions mismatch, [%ux%u] vs [%ux%u]: %s\n", seriesType, @@ -954,7 +988,14 @@ static avifBool avifEncodeRestOfImageSequence(avifEncoder * encoder, settings->inputFormat)) { goto cleanup; } - if (!avifEncoderVerifyImageCompatibility(firstImage, nextImage, "sequence", avifPrettyFilename(nextFile->filename))) { + if (!avifSettingsVerifyRenderedSizeBounds(settings, nextImage, avifPrettyFilename(nextFile->filename))) { + goto cleanup; + } + if (!avifEncoderVerifyImageCompatibility(firstImage, + nextImage, + "sequence", + avifPrettyFilename(nextFile->filename), + /*allowDimensionChange=*/AVIF_FALSE)) { goto cleanup; } if (!avifEncodeUpdateEncoderSettings(encoder, nextSettings)) { @@ -1061,6 +1102,9 @@ static avifBool avifEncodeRestOfLayeredImage(avifEncoder * encoder, settings->inputFormat)) { goto cleanup; } + if (!avifSettingsVerifyRenderedSizeBounds(settings, nextImage, avifPrettyFilename(nextFile->filename))) { + goto cleanup; + } // frameIter is NULL if y4m reached end, so single frame y4m is still supported. if (input->frameIter) { fprintf(stderr, @@ -1068,7 +1112,11 @@ static avifBool avifEncodeRestOfLayeredImage(avifEncoder * encoder, avifPrettyFilename(nextFile->filename)); goto cleanup; } - if (!avifEncoderVerifyImageCompatibility(firstImage, nextImage, "layer", avifPrettyFilename(nextFile->filename))) { + if (!avifEncoderVerifyImageCompatibility(firstImage, + nextImage, + "layer", + avifPrettyFilename(nextFile->filename), + avifSettingsUsesRenderedSizeOverride(settings))) { goto cleanup; } if (!avifEncodeUpdateEncoderSettings(encoder, nextSettings)) { @@ -1129,6 +1177,8 @@ static avifBool avifEncodeImagesFixedQuality(const avifSettings * settings, encoder->creationTime = settings->creationTime; encoder->modificationTime = settings->modificationTime; encoder->extraLayerCount = settings->layers - 1; + encoder->width = settings->width; + encoder->height = settings->height; if (!avifEncodeUpdateEncoderSettings(encoder, &firstFile->settings)) { goto cleanup; } @@ -1774,6 +1824,15 @@ int main(int argc, char * argv[]) goto cleanup; } settings.layered = AVIF_TRUE; + } else if (!strcmp(arg, "--render-size")) { + uint32_t renderSize[2] = { 0 }; + NEXTARG(); + if (!parseU32List(renderSize, 2, arg, 'x') || (renderSize[0] == 0) || (renderSize[1] == 0)) { + fprintf(stderr, "ERROR: Invalid render size: %s\n", arg); + goto cleanup; + } + settings.width = renderSize[0]; + settings.height = renderSize[1]; } else if (!strcmp(arg, "--scaling-mode") || strpre(arg, "--scaling-mode:")) { avifOptionSuffixType type = parseOptionSuffix(arg, input.filesCount != 0); if (type == AVIF_OPTION_SUFFIX_INVALID) { @@ -2134,6 +2193,11 @@ int main(int argc, char * argv[]) fprintf(stderr, "WARNING: Trailing options with update suffix has no effect. Place them before the input you intend to apply to.\n"); } + if (avifSettingsUsesRenderedSizeOverride(&settings) && ((settings.width == 0) || (settings.height == 0))) { + fprintf(stderr, "ERROR: --render-size must be specified as WxH.\n"); + goto cleanup; + } + // Check layer config if (settings.progressive) { assert(!settings.layered); @@ -2161,6 +2225,14 @@ int main(int argc, char * argv[]) fprintf(stderr, "Layered grid image unimplemented in avifenc.\n"); goto cleanup; } + if (avifSettingsUsesRenderedSizeOverride(&settings) && settings.gridDimsPresent) { + fprintf(stderr, "ERROR: --render-size is not supported with --grid.\n"); + goto cleanup; + } + if (avifSettingsUsesRenderedSizeOverride(&settings) && (settings.layers == 1) && (input.filesCount > 1)) { + fprintf(stderr, "ERROR: --render-size is not supported with image sequences. Use --layered for multiple still inputs.\n"); + goto cleanup; + } for (int i = 0; i < input.filesCount; ++i) { avifInputFile * file = &input.files[i]; @@ -2381,6 +2453,19 @@ int main(int argc, char * argv[]) goto cleanup; } + if (!avifSettingsVerifyRenderedSizeBounds(&settings, image, avifPrettyFilename(firstFile->filename))) { + goto cleanup; + } + + if (avifSettingsUsesRenderedSizeOverride(&settings) && (settings.layers == 1) && input.frameIter) { + fprintf(stderr, "ERROR: --render-size is not supported with image sequences.\n"); + goto cleanup; + } + + uint32_t outputImageWidth; + uint32_t outputImageHeight; + avifSettingsGetEffectiveOutputDimensions(&settings, image, &outputImageWidth, &outputImageHeight); + printf("Successfully loaded: %s\n", avifPrettyFilename(firstFile->filename)); // Prepare image timings @@ -2433,7 +2518,7 @@ int main(int argc, char * argv[]) image->pasp.vSpacing = settings.paspValues[1]; } if (cropConversionRequired) { - if (!convertCropToClap(image->width, image->height, settings.clapValues)) { + if (!convertCropToClap(outputImageWidth, outputImageHeight, settings.clapValues)) { goto cleanup; } settings.clapValid = AVIF_TRUE; @@ -2453,7 +2538,7 @@ int main(int argc, char * argv[]) avifCropRect cropRect; avifDiagnostics diag; avifDiagnosticsClearError(&diag); - if (!avifCropRectFromCleanApertureBox(&cropRect, &image->clap, image->width, image->height, &diag)) { + if (!avifCropRectFromCleanApertureBox(&cropRect, &image->clap, outputImageWidth, outputImageHeight, &diag)) { fprintf(stderr, "ERROR: Invalid clap: width:[%d / %d], height:[%d / %d], horizOff:[%d / %d], vertOff:[%d / %d] - %s\n", (int32_t)image->clap.widthN, @@ -2639,6 +2724,9 @@ int main(int argc, char * argv[]) settings.gridDims[0], settings.gridDims[1], settings.layers > 1 ? AVIF_PROGRESSIVE_STATE_AVAILABLE : AVIF_PROGRESSIVE_STATE_UNAVAILABLE); + if (avifSettingsUsesRenderedSizeOverride(&settings)) { + printf(" * Rendered Size : %ux%u\n", settings.width, settings.height); + } avifEncodedByteSizes byteSizes = { 0, 0, 0 }; if (!avifEncodeImages(&settings, &input, firstFile, image, (const avifImage **)gridCells, &raw, &byteSizes)) { diff --git a/include/avif/avif.h b/include/avif/avif.h index bd81044fa8..6c57323d75 100644 --- a/include/avif/avif.h +++ b/include/avif/avif.h @@ -1582,6 +1582,7 @@ typedef struct avifEncoder avifBool autoTiling; // Up/down scaling of the image to perform before encoding. + // This cannot be used together with encoder->width / encoder->height. avifScalingMode scalingMode; // -------------------------------------------------------------------------------------------- @@ -1628,6 +1629,13 @@ typedef struct avifEncoder // Version 1.4.0 ends here. Add any new members after this line. // -------------------------------------------------------------------------------------------- + + // Override the rendered size of the encoded image. + // Defaults to 0. When set to 0, libavif uses the width and height of the first added image. + // Typical use case is layered image, where these are set to the size of the last layer, + // while encoding smaller images as the previous layers. + uint32_t width; + uint32_t height; } avifEncoder; // Creates an encoder initialized with default settings values. diff --git a/src/codec_aom.c b/src/codec_aom.c index ec4a50a949..7e305ba77e 100644 --- a/src/codec_aom.c +++ b/src/codec_aom.c @@ -871,6 +871,8 @@ static avifResult aomCodecEncodeImage(avifCodec * codec, cfg->g_input_bit_depth = image->depth; cfg->g_w = image->width; cfg->g_h = image->height; + cfg->g_forced_max_frame_width = encoder->width; + cfg->g_forced_max_frame_height = encoder->height; // Detect the libaom v3.6.0 bug described in // https://crbug.com/aomedia/2871#c12. See the changes to @@ -891,10 +893,12 @@ static avifResult aomCodecEncodeImage(avifCodec * codec, } } - if (addImageFlags & AVIF_ADD_IMAGE_FLAG_SINGLE) { + if ((addImageFlags & AVIF_ADD_IMAGE_FLAG_SINGLE) && (encoder->width == 0) && (encoder->height == 0)) { // Set the maximum number of frames to encode to 1. This instructs // libaom to set still_picture and reduced_still_picture_header to // 1 in AV1 sequence headers. + // Still picture header requires image size and render size to match + // or the produced file is not decodable. cfg->g_limit = 1; } if (useAllIntra) { @@ -933,6 +937,11 @@ static avifResult aomCodecEncodeImage(avifCodec * codec, if (disableLaggedOutput) { cfg->g_lag_in_frames = 0; } + if ((encoder->width || encoder->height) && (cfg->g_lag_in_frames > 1)) { + // libaom does not allow changing frame dimension if + // g_lag_in_frames > 1. + cfg->g_lag_in_frames = 1; + } if (encoder->maxThreads > 1) { // libaom fails if cfg->g_threads is greater than 64 threads. See MAX_NUM_THREADS in // aom/aom_util/aom_thread.h. @@ -1082,8 +1091,9 @@ static avifResult aomCodecEncodeImage(avifCodec * codec, } else { avifBool dimensionsChanged = AVIF_FALSE; if ((cfg->g_w != image->width) || (cfg->g_h != image->height)) { - // We are not ready for dimension change for now. - return AVIF_RESULT_NOT_IMPLEMENTED; + cfg->g_w = image->width; + cfg->g_h = image->height; + dimensionsChanged = AVIF_TRUE; } if (alpha) { if (encoderChanges & (AVIF_ENCODER_CHANGE_MIN_QUANTIZER_ALPHA | AVIF_ENCODER_CHANGE_MAX_QUANTIZER_ALPHA)) { diff --git a/src/codec_avm.c b/src/codec_avm.c index 6222f7fa6d..01fe18a842 100644 --- a/src/codec_avm.c +++ b/src/codec_avm.c @@ -453,6 +453,11 @@ static avifResult avmCodecEncodeImage(avifCodec * codec, // two fields. encoderChanges &= ~AVIF_ENCODER_CHANGE_SCALING_MODE; + if (encoder->width || encoder->height) { + avifDiagnosticsPrintf(codec->diag, "AVM does not support rendered-size override"); + return AVIF_RESULT_NOT_IMPLEMENTED; + } + if (!codec->internal->encoderInitialized) { int avmCpuUsed = -1; if (encoder->speed != AVIF_SPEED_DEFAULT) { diff --git a/src/codec_rav1e.c b/src/codec_rav1e.c index 97c92be3a7..1a24fa5443 100644 --- a/src/codec_rav1e.c +++ b/src/codec_rav1e.c @@ -90,6 +90,12 @@ static avifResult rav1eCodecEncodeImage(avifCodec * codec, // rav1e does not support disabling lagged output. See https://github.com/xiph/rav1e/issues/2267. Ignore this setting. (void)disableLaggedOutput; + // rav1e does not support overriding maximum frame width/height in sequence header + if (encoder->width || encoder->height) { + avifDiagnosticsPrintf(codec->diag, "rav1e does not support rendered-size override"); + return AVIF_RESULT_NOT_IMPLEMENTED; + } + avifResult result = AVIF_RESULT_UNKNOWN_ERROR; RaConfig * rav1eConfig = NULL; diff --git a/src/codec_svt.c b/src/codec_svt.c index a76fb5bd53..d5d1b88486 100644 --- a/src/codec_svt.c +++ b/src/codec_svt.c @@ -83,6 +83,11 @@ static avifResult svtCodecEncodeImage(avifCodec * codec, // SVT-AV1 does not support disabling lagged output. Ignore this setting. (void)disableLaggedOutput; + if (encoder->width || encoder->height) { + avifDiagnosticsPrintf(codec->diag, "SVT-AV1 does not support rendered-size override"); + return AVIF_RESULT_NOT_IMPLEMENTED; + } + avifResult result = AVIF_RESULT_UNKNOWN_ERROR; EbColorFormat color_format = EB_YUV420; uint8_t * uvPlanes = NULL; // 4:2:0 U and V placeholder for alpha because SVT-AV1 does not support 4:0:0. @@ -165,6 +170,8 @@ static avifResult svtCodecEncodeImage(avifCodec * codec, #endif svt_config->source_width = image->width; svt_config->source_height = image->height; + svt_config->forced_max_frame_width = encoder->width; + svt_config->forced_max_frame_height = encoder->height; #if SVT_AV1_CHECK_VERSION(3, 0, 0) svt_config->level_of_parallelism = encoder->maxThreads; #else diff --git a/src/write.c b/src/write.c index 6980909fef..b8cd40fa77 100644 --- a/src/write.c +++ b/src/write.c @@ -466,6 +466,49 @@ static avifResult avifItemPropertyDedupFinish(avifItemPropertyDedup * dedup, static const avifScalingMode noScaling = { { 1, 1 }, { 1, 1 } }; +static avifBool avifEncoderUsesRenderedSizeOverride(const avifEncoder * encoder) +{ + return (encoder->width != 0) || (encoder->height != 0); +} + +static avifBool avifScalingModeIsNoScaling(const avifScalingMode * scalingMode) +{ + avifFraction horizontal = scalingMode->horizontal; + avifFraction vertical = scalingMode->vertical; + avifFractionSimplify(&horizontal); + avifFractionSimplify(&vertical); + return (horizontal.n == 1) && (horizontal.d == 1) && (vertical.n == 1) && (vertical.d == 1); +} + +static avifBool avifImageHasEquivalentTransformProperties(const avifImage * lhs, const avifImage * rhs) +{ + const uint32_t lhsTransformFlags = lhs->transformFlags & + (AVIF_TRANSFORM_PASP | AVIF_TRANSFORM_CLAP | AVIF_TRANSFORM_IROT | AVIF_TRANSFORM_IMIR); + const uint32_t rhsTransformFlags = rhs->transformFlags & + (AVIF_TRANSFORM_PASP | AVIF_TRANSFORM_CLAP | AVIF_TRANSFORM_IROT | AVIF_TRANSFORM_IMIR); + if (lhsTransformFlags != rhsTransformFlags) { + return AVIF_FALSE; + } + if ((lhsTransformFlags & AVIF_TRANSFORM_PASP) && + ((lhs->pasp.hSpacing != rhs->pasp.hSpacing) || (lhs->pasp.vSpacing != rhs->pasp.vSpacing))) { + return AVIF_FALSE; + } + if ((lhsTransformFlags & AVIF_TRANSFORM_CLAP) && + ((lhs->clap.widthN != rhs->clap.widthN) || (lhs->clap.widthD != rhs->clap.widthD) || + (lhs->clap.heightN != rhs->clap.heightN) || (lhs->clap.heightD != rhs->clap.heightD) || + (lhs->clap.horizOffN != rhs->clap.horizOffN) || (lhs->clap.horizOffD != rhs->clap.horizOffD) || + (lhs->clap.vertOffN != rhs->clap.vertOffN) || (lhs->clap.vertOffD != rhs->clap.vertOffD))) { + return AVIF_FALSE; + } + if ((lhsTransformFlags & AVIF_TRANSFORM_IROT) && (lhs->irot.angle != rhs->irot.angle)) { + return AVIF_FALSE; + } + if ((lhsTransformFlags & AVIF_TRANSFORM_IMIR) && (lhs->imir.axis != rhs->imir.axis)) { + return AVIF_FALSE; + } + return AVIF_TRUE; +} + avifEncoder * avifEncoderCreate(void) { avifEncoder * encoder = (avifEncoder *)avifAlloc(sizeof(avifEncoder)); @@ -486,6 +529,8 @@ avifEncoder * avifEncoderCreate(void) encoder->maxQuantizer = AVIF_QUANTIZER_WORST_QUALITY; encoder->minQuantizerAlpha = AVIF_QUANTIZER_BEST_QUALITY; encoder->maxQuantizerAlpha = AVIF_QUANTIZER_WORST_QUALITY; + encoder->width = 0; + encoder->height = 0; encoder->tileRowsLog2 = 0; encoder->tileColsLog2 = 0; encoder->autoTiling = AVIF_FALSE; @@ -533,6 +578,8 @@ static void avifEncoderBackupSettings(avifEncoder * encoder) lastEncoder->timescale = encoder->timescale; lastEncoder->repetitionCount = encoder->repetitionCount; lastEncoder->extraLayerCount = encoder->extraLayerCount; + lastEncoder->width = encoder->width; + lastEncoder->height = encoder->height; lastEncoder->minQuantizer = encoder->minQuantizer; lastEncoder->maxQuantizer = encoder->maxQuantizer; lastEncoder->minQuantizerAlpha = encoder->minQuantizerAlpha; @@ -561,7 +608,8 @@ static avifBool avifEncoderDetectChanges(const avifEncoder * encoder, avifEncode if ((lastEncoder->codecChoice != encoder->codecChoice) || (lastEncoder->maxThreads != encoder->maxThreads) || (lastEncoder->speed != encoder->speed) || (lastEncoder->keyframeInterval != encoder->keyframeInterval) || (lastEncoder->timescale != encoder->timescale) || (lastEncoder->repetitionCount != encoder->repetitionCount) || - (lastEncoder->extraLayerCount != encoder->extraLayerCount)) { + (lastEncoder->extraLayerCount != encoder->extraLayerCount) || (lastEncoder->width != encoder->width) || + (lastEncoder->height != encoder->height)) { return AVIF_FALSE; } @@ -1554,6 +1602,69 @@ static avifCodecType avifEncoderGetCodecType(const avifEncoder * encoder) return avifCodecTypeFromChoice(encoder->codecChoice, AVIF_CODEC_FLAG_CAN_ENCODE); } +static avifResult avifEncoderValidateRenderedSizeOverride(avifEncoder * encoder, uint32_t gridCols, uint32_t gridRows, const avifImage * firstCell) +{ + if (!avifEncoderUsesRenderedSizeOverride(encoder)) { + return AVIF_RESULT_OK; + } + + if ((encoder->width == 0) || (encoder->height == 0)) { + avifDiagnosticsPrintf(&encoder->diag, + "rendered-size override requires both avifEncoder.width and avifEncoder.height to be non-zero"); + return AVIF_RESULT_INVALID_ARGUMENT; + } + + if ((gridCols > 1) || (gridRows > 1)) { + avifDiagnosticsPrintf(&encoder->diag, "rendered-size override is not supported with grid images"); + return AVIF_RESULT_NOT_IMPLEMENTED; + } + + if (!avifScalingModeIsNoScaling(&encoder->scalingMode)) { + avifDiagnosticsPrintf(&encoder->diag, "rendered-size override is not supported with encoder->scalingMode"); + return AVIF_RESULT_NOT_IMPLEMENTED; + } + + if (encoder->sampleTransformRecipe != AVIF_SAMPLE_TRANSFORM_NONE) { + avifDiagnosticsPrintf(&encoder->diag, "rendered-size override is not supported with sample transforms"); + return AVIF_RESULT_NOT_IMPLEMENTED; + } + + if (firstCell->gainMap && firstCell->gainMap->image) { + avifDiagnosticsPrintf(&encoder->diag, "rendered-size override is not supported with gain maps"); + return AVIF_RESULT_NOT_IMPLEMENTED; + } + + if ((encoder->data->items.count > 0) && (encoder->extraLayerCount == 0)) { + avifDiagnosticsPrintf(&encoder->diag, "rendered-size override is not supported for image sequences"); + return AVIF_RESULT_NOT_IMPLEMENTED; + } + + if ((encoder->width < firstCell->width) || (encoder->height < firstCell->height)) { + avifDiagnosticsPrintf(&encoder->diag, + "rendered-size override %ux%u must be at least the coded image size %ux%u", + encoder->width, + encoder->height, + firstCell->width, + firstCell->height); + return AVIF_RESULT_INCOMPATIBLE_IMAGE; + } + + if (firstCell->transformFlags & AVIF_TRANSFORM_CLAP) { + avifCropRect cropRect; + if (!avifCropRectFromCleanApertureBox(&cropRect, &firstCell->clap, encoder->width, encoder->height, &encoder->diag)) { + return AVIF_RESULT_INVALID_ARGUMENT; + } + } + + if ((encoder->data->items.count > 0) && (encoder->extraLayerCount > 0) && + !avifImageHasEquivalentTransformProperties(firstCell, encoder->data->imageMetadata)) { + avifDiagnosticsPrintf(&encoder->diag, "rendered-size override requires 'pasp', 'clap', 'irot' and 'imir' to match across layers"); + return AVIF_RESULT_INCOMPATIBLE_IMAGE; + } + + return AVIF_RESULT_OK; +} + // This function is called after every color frame is encoded. It returns AVIF_TRUE if a keyframe needs to be forced for the next // alpha frame to be encoded, AVIF_FALSE otherwise. static avifBool avifEncoderDataShouldForceKeyframeForAlpha(const avifEncoderData * data, @@ -1736,6 +1847,8 @@ static avifResult avifEncoderAddImageInternal(avifEncoder * encoder, return AVIF_RESULT_NO_CONTENT; } + AVIF_CHECKRES(avifEncoderValidateRenderedSizeOverride(encoder, gridCols, gridRows, firstCell)); + AVIF_CHECKRES(avifValidateGrid(gridCols, gridRows, cellImages, /*validateGainMap=*/AVIF_FALSE, &encoder->diag)); const avifBool hasGainMap = (firstCell->gainMap && firstCell->gainMap->image != NULL); @@ -1866,6 +1979,10 @@ static avifResult avifEncoderAddImageInternal(avifEncoder * encoder, if (encoder->data->items.count == 0) { // Make a copy of the first image's metadata (sans pixels) for future writing/validation AVIF_CHECKRES(avifImageCopy(encoder->data->imageMetadata, firstCell, 0)); + if (avifEncoderUsesRenderedSizeOverride(encoder)) { + encoder->data->imageMetadata->width = encoder->width; + encoder->data->imageMetadata->height = encoder->height; + } const uint32_t gridWidth = avifGridWidth(gridCols, firstCell, bottomRightCell); const uint32_t gridHeight = avifGridHeight(gridRows, firstCell, bottomRightCell); @@ -2154,6 +2271,10 @@ avifResult avifEncoderAddImageGrid(avifEncoder * encoder, if ((gridCols == 0) || (gridCols > 256) || (gridRows == 0) || (gridRows > 256)) { return AVIF_RESULT_INVALID_IMAGE_GRID; } + if (avifEncoderUsesRenderedSizeOverride(encoder)) { + avifDiagnosticsPrintf(&encoder->diag, "rendered-size override is not supported with avifEncoderAddImageGrid()"); + return AVIF_RESULT_NOT_IMPLEMENTED; + } if (encoder->extraLayerCount == 0) { addImageFlags |= AVIF_ADD_IMAGE_FLAG_SINGLE; // image grids cannot be image sequences } @@ -3214,6 +3335,9 @@ avifResult avifEncoderFinish(avifEncoder * encoder, avifRWData * output) #endif // AVIF_ENABLE_EXPERIMENTAL_MINI const avifImage * imageMetadata = encoder->data->imageMetadata; + const uint32_t imageWidth = encoder->width ? encoder->width : imageMetadata->width; + const uint32_t imageHeight = encoder->height ? encoder->height : imageMetadata->height; + uint64_t now = (uint64_t)time(NULL); uint64_t modificationTime = (encoder->modificationTime != 0) ? encoder->modificationTime : now; uint64_t creationTime = (encoder->creationTime != 0) ? encoder->creationTime : modificationTime; @@ -3628,8 +3752,8 @@ avifResult avifEncoderFinish(avifEncoder * encoder, avifRWData * output) AVIF_CHECKRES(avifRWStreamWriteU16(&s, 0)); // template int(16) volume = {if track_is_audio 0x0100 else 0}; AVIF_CHECKRES(avifRWStreamWriteU16(&s, 0)); // const unsigned int(16) reserved = 0; AVIF_CHECKRES(avifRWStreamWrite(&s, unityMatrix, sizeof(unityMatrix))); // template int(32)[9] matrix= // { 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 }; - AVIF_CHECKRES(avifRWStreamWriteU32(&s, imageMetadata->width << 16)); // unsigned int(32) width; - AVIF_CHECKRES(avifRWStreamWriteU32(&s, imageMetadata->height << 16)); // unsigned int(32) height; + AVIF_CHECKRES(avifRWStreamWriteU32(&s, imageWidth << 16)); // unsigned int(32) width; + AVIF_CHECKRES(avifRWStreamWriteU32(&s, imageHeight << 16)); // unsigned int(32) height; AVIF_CHECKRES(avifRWStreamFinishBox(&s, tkhd)); if (item->irefToID != 0) { @@ -3705,16 +3829,16 @@ avifResult avifEncoderFinish(avifEncoder * encoder, avifRWData * output) AVIF_CHECKRES(avifRWStreamWriteU32(&s, 1)); // unsigned int(32) entry_count; avifBoxMarker imageItem; AVIF_CHECKRES(avifRWStreamWriteBox(&s, encoder->data->imageItemType, AVIF_BOX_SIZE_TBD, &imageItem)); - AVIF_CHECKRES(avifRWStreamWriteZeros(&s, 6)); // const unsigned int(8)[6] reserved = 0; - AVIF_CHECKRES(avifRWStreamWriteU16(&s, 1)); // unsigned int(16) data_reference_index; - AVIF_CHECKRES(avifRWStreamWriteU16(&s, 0)); // unsigned int(16) pre_defined = 0; - AVIF_CHECKRES(avifRWStreamWriteU16(&s, 0)); // const unsigned int(16) reserved = 0; - AVIF_CHECKRES(avifRWStreamWriteZeros(&s, sizeof(uint32_t) * 3)); // unsigned int(32)[3] pre_defined = 0; - AVIF_CHECKRES(avifRWStreamWriteU16(&s, (uint16_t)imageMetadata->width)); // unsigned int(16) width; - AVIF_CHECKRES(avifRWStreamWriteU16(&s, (uint16_t)imageMetadata->height)); // unsigned int(16) height; - AVIF_CHECKRES(avifRWStreamWriteU32(&s, 0x00480000)); // template unsigned int(32) horizresolution - AVIF_CHECKRES(avifRWStreamWriteU32(&s, 0x00480000)); // template unsigned int(32) vertresolution - AVIF_CHECKRES(avifRWStreamWriteU32(&s, 0)); // const unsigned int(32) reserved = 0; + AVIF_CHECKRES(avifRWStreamWriteZeros(&s, 6)); // const unsigned int(8)[6] reserved = 0; + AVIF_CHECKRES(avifRWStreamWriteU16(&s, 1)); // unsigned int(16) data_reference_index; + AVIF_CHECKRES(avifRWStreamWriteU16(&s, 0)); // unsigned int(16) pre_defined = 0; + AVIF_CHECKRES(avifRWStreamWriteU16(&s, 0)); // const unsigned int(16) reserved = 0; + AVIF_CHECKRES(avifRWStreamWriteZeros(&s, sizeof(uint32_t) * 3)); // unsigned int(32)[3] pre_defined = 0; + AVIF_CHECKRES(avifRWStreamWriteU16(&s, (uint16_t)imageWidth)); // unsigned int(16) width; + AVIF_CHECKRES(avifRWStreamWriteU16(&s, (uint16_t)imageHeight)); // unsigned int(16) height; + AVIF_CHECKRES(avifRWStreamWriteU32(&s, 0x00480000)); // template unsigned int(32) horizresolution + AVIF_CHECKRES(avifRWStreamWriteU32(&s, 0x00480000)); // template unsigned int(32) vertresolution + AVIF_CHECKRES(avifRWStreamWriteU32(&s, 0)); // const unsigned int(32) reserved = 0; AVIF_CHECKRES(avifRWStreamWriteU16(&s, 1)); // template unsigned int(16) frame_count = 1; AVIF_CHECKRES(avifRWStreamWriteChars(&s, "\012AOM Coding", 11)); // string[32] compressorname; AVIF_CHECKRES(avifRWStreamWriteZeros(&s, 32 - 11)); // diff --git a/tests/data/kodim03_yuv420_8bpc_384x256.y4m b/tests/data/kodim03_yuv420_8bpc_384x256.y4m new file mode 100644 index 0000000000..3301162637 --- /dev/null +++ b/tests/data/kodim03_yuv420_8bpc_384x256.y4m @@ -0,0 +1,3 @@ +YUV4MPEG2 W384 H256 F25:1 Ip A0:0 C420jpeg XYSCSS=420JPEG XCOLORRANGE=FULL +FRAME +ccca`a_`eeccdddeeeeeeeeeeedddddddddddddddddddddddddddddddddddddddddddeddddddeddddddeeeedeededdddddddddddddddddddddcdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddcccccdcdcccdccdccccccccccccccehgghebfhhghghgdbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbbbaaa``__^__``abbccccbaabbbbaa`__^]\\[[Z[[[[[[[[\\\\\\\\]]]]]]]]]]]]]]]]^^^^^^^^^^^^^^^^^]\bdcci{{{†sOWdb]WVTTTSTSTTTUUVVVXWWWWWWWXWYXYYYXXZZXXXWXWWWWVVVWWWWVWWXXYYXYYXXXYYXXYYZZZZZ[[Z[[\[\\\[\\\\\\]^]]^^^^^^^^^^^^^^^_^_______^^__^__^`___``____``_________`___`_````a```aaaaabbbbabcacbabbacbabcbcbcccbbdW;<@>MhT>>A??<;Tgfeffggffffggfggfffffffffeefeefeeffeeeffeeggfeeeeefgghghhhhhghghjkmpstx{|„‹�‹‡„�zsnkhhgntupmosw{€…‹’šŸ£§«°¬«©©ª«©¦¢¢¢¡¡ Ÿžž�œœ››š™˜——––—––••”””“““’‘‘‘‘’“”•—�n`cb…�—‘†œ†[T_ZOJHFEEFFFGGGHIIKNOMMMNNMOONRRQQPPQQPPOMMMLMNMLMMMNNONNNOPPPPQOPOPQPQQQQQQQQRSSTTUUUTUUUUUUUWWXXYZXYYYZYYZYZYYYYZZZ[[[Z[ZZZZZ[\[[\[[]\\\\]]\]\\\]]\\[\]\[]]]]^^]]^^^__^__`aaa``a`a``aaabbababaaabcbafLKR(" =dihghihghiiiiiihhhhghggghfggghhgggghhhhhhihihhhhhghhijjjklllkjiklnqv|‚‡�™�¤®¯¨Ÿ˜‘�upnlkny‚€wuxzƒŒ•£´ÆÔÞãèìôîêççëìåßÙÖÖØÖÕÓÑÐÏÎÍÎÌÊÈÇÅÃÃÄÃÃÁÀ¿¾¾¾½¼¼»ºººº¼¾ÁÄÉÔw]c_�™Š”†|••wYSWMIHHHGHIIIIJIJLMOMOPQPQQQRTTSSSRSSSSQPOOOOOOPPOPPPQPQPQQQQRSQRRRRRRSSSSSTSTTTUUUVVVVVVVWWWXXXXYZYZYZYXZZZ[Z[ZZZ[[[[[[[Z[[\[Z[\\\\\]]]]^\\]]]\\]]]]]]]]]]]]^]^]]]]___^_^__```a`aa``a`abba`abbccbccbeY)%*8(#&&#!Fkigfgghghhfhhhihhghgghhgghghhhihhghhiijiiihijhgghgghhiiijijjjihijknty€‡�˜�¡£¦ –�‡}rjijmrv{~ztrqsy‚‰›°¿ÐÛààâæßÙÙÝÞÛÖÐËÈÉÊÈÇÆÆÄÃÄÄÁ¿¾½»¹¸¸¸····µ´´´´³´´±°²´¶¸º¿ÃÌv]cbk‰‘Ž‘���›�eMKIFHGGGHHHHHHIKKKLNNPOQQQRSSSSSSSSSSRPOOPPNOQQQPOPPPPRQQQQQQQRQRQRRRSRSTTSSSUTUTUVVVVVWWWWWXXYXXYXYYZZYY[[ZZZZ[Z[[Z[[ZZZ[Z[\[[[\]\\]\\]]]\\\\\\\]]\\\\]]\\]]^]]^^]^^^^___`````````a_`aa`aababccbccccM-$($#$$$ Ijgfghggffhhggghghhggggghhihgghhiihghijjijjjihhhhhffggghihjhiijihilmpy�†Ž—¡¦¥¥£›�‡vmijnu{~}~{uqnpy€Š—¤·ÍÝãããàÝÛÝÝÝÛÖÐÍËÌÍËÊÈÇÇÆÅÄÃÀ¾½»¹¸¸¹¹·¸·¶¶µ¶µµ´µ´³´¶¹½ÂÆÉÒv]ccmpˆ�’•™Ž‰“zOBHHGGGGGHHHIIKKLLLMNOOPQRSTTUUUUSSSSRQQPQPOPPPPQQQQQRRQRQQQRRQTSRRRRTTSSTUSSUUUVVVVVVWVWYWWWXXXWXZYYYYYZZ[ZZZZZZZ[Z[[[Z[[\[[[\\\\\]]\\\]\\]]]]]]]]]]\\]]\^^^^^^^^^____`_`a``_``````aaaaabbacbbdbccdeX7!#&&%!%Ligfeffhgghgfiggghhhhgggghhigghhiikjihijjjjjjiiihghghhggghijijjikjlnnr{�†‹•ž££¢�“‰wqllrv{}zxtolpx€Š�–°ÊÙÝàßÞÝÜÝÝÜØÓÏÐÒÌÍÌÊÉÈÇÅÄÃÀ¿¿¼º¹º¸¸¸¹···¶·µµ¶·¶µµ¶¸½ÂÆÌÎ×w]ca…uk‡‹~Š•˜±�kp]?BJHHHHHIIIJKKKLLMNOOPRQSTTVVVUTTSSSRQPPPPQQQRRRRRRRQQQQRRRQRRRRTSSSSTTTTVUUUVUVVVVWWVWXXXWXWWXWXYXXXYZZ[ZZYZZ[[Z[ZZ[Z[[Z[[[\\\]]\\]]\[]]][\]]]]\[]\]]]^_^^^^____^^_`__```````a`a``aaababbbbcbccdcdf_>!##.Tjgehgeffffhggghhgghghihghhhiihjiikpnjijkkkjkjkhhhgghghghhiijjihjkmoposy|~…�˜š��•Œ�wqnkp|€~|{xvsqolnw†…“·ÎרÛÞÝÜÜÞÝÙÕÑÍÏÒÍÎËÊÊÈÇÆÅÃÁ¾¼º¹¸¹···¹··¸·····¹¹¸¹¹¼ÁÅÊÎÑÙx\c`zŠ�yz�t{��¢˜ƒ„L:HJHHHIIIJJKKLLLMNOPRRRSSUVVWWUTTTSSSQQRSSSRQRRRRRSRQRQRRRRRRSURRSSSTUUUVUUVVVVVVWVWWWWWXWWWWXYXXXYZYY[ZYZZZZ[[Z[ZZ[[[Z[Z[[\[\\\\\\][\]\]\]][\[]]\]]]]^^]^^_^^_`__````_`_``_aa```aabbababbbbbccddcfcF24F_ieeegfefffggghggggghihhihhiijjijjikqsmkkkkkkjijhihhhighhhijjjkkklmpqqoruvw‹’•—–�…zsomjq~�}xvtqnonlmu‚“»ÒÕ×ÚÛÜÛÝÜÛ×ÒÏÌÌÏÎÎÍÌÉÉÈÇÅÂÁ¿»»º··¸¸¹¹º¸·¹¸¹ºººº¼¼¾ÁÅÈÌÑÒÛx\cbqx•“{w{osPf™¤œ™¨yA?JIIJIJJKKKLLMMMNOPRSTTUVWWWWWVUSSSRQRSSSSRRRSRRRRRRRRRRRRSSRSSSSUVUVTTUUUVVVWWVVWWWWXWWXXXXXXXXXYYZYYZYYZZZ[Z[[ZZZ[[[Z[[[[[[\[[[[[[\\\]]]]\\]]]]^]]]^^^^^_`^_````a```a`_```aaaaabbbaabbbcccdcdedefacggddeffeefefhgfhggghiiiiihhhijiikjjknstomklkkkjjjihhhigghiiijjkkkmnpqspnoprsyƒ‹���Š~urqoipy{yvtqmkkkkkrz|wгÍÔÕÙÛÚÚÛÚÖÓÎËÉÊÎÏÐÎÍËÉÈÇÅÃÁÀ¼º¹¸¸¹¹¹¹ºº»»¹»¼½¾¾¿ÁÂÅÈÍÐÒÓÞy\c`Šƒit–Š��‹zvzy—™ˆ£œa=EKIJKKLKLLLLMNMNPQRUUVVWVWXWXWUSSSSSQSSSSTSSSTSSTSSSSSRSRTTSTUTUVUUTUUUVVVVVWVWVVWWWXWVXXWXYYXXYXXYZYYZZZZZZZZZ[ZZZZZ[[[Z[[[\[\\\\\\][\\]]]]]]]]^]^^^^^]^__^^____`a``a```aaaa`bbabaccbbbdccdddeddfeeeeefeeeefefgghgggghhihjihiiiiijkkjntxupnllkkkjiihihhihhijjijkkknoqqponmmoppry~…‹‹�wqnponrvwtsqpmjijkkpvvr…­ÊÑÓÖÙÖÕÖÕÓÎÊÈÅÉÌÏÏÎÌËËÈÈÆÃÁ¿½»¸¹ºº»º»»»¼»»½½¿ÁÁÃÄÆÈÊÎÒÔÔÝy\d`{�Œsp“—‘…š…€€oŠŸŠ�¤‹R?LKJKLLMLLMMNNOOPRSUVVWWWWXXWVVUSSRRSSSRTSSSSSTSSSSSTTSTTTTTTUTUUUUVVVVUVVWVVWVXXWXXWXWWXWXXXXYYYYXYYZYZZZZZZZZZZZ[ZZ[[Z[[[\[[[[]\\\\]\\\]]]]]]]]^^]]]^^^^______``a`a`aaabaaabaaabbbbbcccccddcdcddeeeeeeffefffggghghiihhiihihiiijikkls~}wsonmjjjjiiijlliilmllkkklmprronnmmnooopu{ƒˆ…{qmlnoqttsqsonnkjijjmpqr�µÍÒÐÒÓÒÐÐÎÌÉÆÅÆÈÉÍÎÍÍËËÉÈÇÿ½¼¼»º¼½½½¼¼½¼¾À¿ÁÃÄÇÇÈËÍÏÑÓÔÜy\cb|Š…Žvs…‘„‡–Љ‹}~˜�‚’•b?ILJKLMMLMMNOOPPQSSUUWYXXXXXWXUSSSSTTTSSSTSSSSUSTTSTTTUUUUUUUTVUUVVVVVVVVVVWWVVWWWWWXXXWWWXYXWYYXYXYYZZZZZZZZZZZZZ[[[[Z[[[[\\\\]]\[\\\]\]\]\]]]]]]]]^^^^^^^_``_``aaa`aabbbaaaaaaabccbccccdccddddeeeeeeeeffeeffghhhihiiiijjiiihjjjknv……~xspmkjjjjhjovtpuzyqmlnonprqpnmlmmmmmmr}ƒ††~rmkkknorqqppomkjjiijlloƒ§ÃÒÓÏÎÐÐÏÌÉÇÅÂÃÇÈÈÉÌÍÌÌËËÈÇÅÃÀ¿½¾¼½½¾À¿½¿¾¾¿ÁÁÃÅÆÉÉËÍÏÐÒÓÓÚx\c`†‘Œ€�‚~Œ‹~Ž˜�†Œ€|‹’‘‰‘zAFMLLLMMMMNOOPQQRRSTWYXXYYXXXXVUTTUUSSSRSSTTSSSSSTSTTUUUUUUUUUVVVVVUWVVVVVVWVVWWWWWWWWXXXWXXXYWYXYYXYZYZZZZZZ[ZZ[ZZ[Z[[[[\\]\\\\\\\]]\]]]\]]]]]^]^]]]^^^^_^____````aaaaabaaaaabaabbbcbcbbcdccddeddedeeeeeffeffffhhiiiihjjijjiijjkt†‰ˆ�ytqmkijjhikp{€…†€tlnrsrqponmklmkmkjlx†‹‹‡{pljijlnnqpoqomkjjjiikip�²ÉÐÐÌÊÌÌÌÊÅÃÀ¾¾ÀÄÆÇÉËÌËÉÊÉÉÆÃÃÁ¿½¾¿ÀÁÁ¿¿¿À¿ÁÃÄÅÇÈÉËÌÌÎÑÓÒÒÚx\ca��“Œ‡ŒŒŠ“Ž€ˆ�‘�‹„ƒ…†�Žš‘M@HNLMNONMNPQQRRSSUVWXXYYYZYXYWWVUTTTSSSTTTTTSTSTTUUTTUUVUUVVVVVUWVUVVVVVWVYXWXWWWWWWWXYWXWXXXYYYYYYYZZZZZZZZ[ZZZZZ[Z[[[[[[][\\\]\\]\]]]]]]^]\^]]]^]^^]^_^_`___a``aa`aaaabaaaaaccccbccbccdcceddfddddedeegfeggggghiihihhjijjiijjlv�†ˆ…~vqoliijihiio}‡‹‰…|rmpuurponnnnnmlkkjq~Œ��†ynkiijkmmnnpspmkjjjjkkjk‚ ¸ÊÏÈÉËËÊÆÂ¿¼»¼¿ÂÃÅÇÊÊÌÍÌÊÊÇÆÆÃÂÁÁÃÄÃÃÂÁÂÂÂÄÆÇÇÈÊÊÌÎÎÏÑÒÒÒØw\cbs‚~‰Œ‡…‘�“Š�‰‰–Žˆ‹‡�‚“—‚Q@QPOQQONOOOQRRSTUVWYXYZZZYYYZYWVUUTTSTUUTTUTUUTTUUUVUTVVVVVVVWVVVVVVVVVVWVVWWWWWWVWWWXXXXXXWXXXYYYYYYZZZZZZZZZZ[Z[[\\\[\]\]]]]]]]]]\]]]^]^]]]^^]]]]^^^___```a`_a``aaaaaaabbbbbbbbcccdcdcceedddedeedfffffgghgihhihhhihjijjiijnwƒ†…€yrnmkjiiiihip}ˆˆ‚{wqqstsrponmnopomlls€‹“•’ˆxmkiijjkklmqurmkjkloqoljl~¥ÂÊÈÈËÊÈÿºº»»¼¾ÁÃÅÇÊËÍÌËËÉÈÅÅÄÄÄÅÆÇÅÄÃÄÅÅÄÆÈÈÊËÊÍÍÏÏÐÐÐÏÕv]cb�~‚r}‰†z…ˆŒ•Ž›��œˆ…�Š�‡|†“©n6JRQPNMMONPPPRSUVVWXWYXYYYYZZZXVVUTTTTTTUTUVUUUVVVVVVVVVWVVVWWWVVWWVVVWVVVVWWVWWWXWWXXWXYWWYYYYXYZYYZYYY[Z[ZZZZZZ[]\[[[\\\]]]]]\]]]^]]]]]^]]]^^]^^^^^^___aaa````aaaaaaabbcaabcbbccccbcddddedddddedeeeeffghgiihhihhhhjijihhjp{†ˆƒ{urpliihihihjqz~yvtuutrpnonnnoonpsqs‹˜ ¡™‹|rjjijikkjlprpmllpsutqkii{¢¾ÆÆÈÈÇþ¹µ·ºº½½¿ÀÃÆÈËÌÍÎÌËÊÈÈÇÇÈÊÉÉÈÇÅÅÇÇÅÇÉÉÉËÌÍÎÎÏÏÏÍËÎu]d`~‘Ž‘�ƒŠ„‚|Œ”�™Œ‹–ŽŽ†�¡•‡˜‘«­PAMQNNONOPOQQSSUUWVVXXXYYZZZ[ZXWVTUTTTTUUVUUUWXWUWWWVWVVVWWWWWVWWVWVVVVVWVWWWVWWWWXXWWWXXXWWYYYYYXYZYZZZZZZZZ[[[[[[\[[\\]]]\]]]]\]^]^^]^]^]]^^^___`__`_``````a```aaaaabaaabbcbcbcccccddedddddedddeedeeffghghhhihihhijijhjltƒŒˆ|sopoljhihijjmoqvwxwvttrqommnnoonntyxz�Š–¢¢–‡}rkkjjjkjkmmnnmmmrtuqnjjoƒ¤º¾ÂÅ¿½¸´³µ¸¼½½½¿ÀÅÈËÌÎÎÍËÊËÉÊÊÌÍÍÍËÈÇÈÇÈÈÈÉÉÊËÌÏÍÎÎÎÏÌÅÑw]cb|�‰„‘ƒƒ…��‰ˆƒˆ†”�˜š’�y~›”ˆžˆÇ¯tPBPOOOPRSTTTTUVVVVVWVXYYYYZ[ZYWUVUTTUTUUVVVVWWWWXWWWXXXXXXWWWVVVVWVVWWWVWWWWWVXXXXXXXYXXXXXYYYYXZYYZYZZZZZ[\[[[[[[\[[\\\]]\]]]]]^_^^]^^^^^^_`_^^`____``_`a`aaa`aaabbbbabbbbcccdbddcdddddcddecdeddeefefgghihihhihhhhhjikozŠ”‹{pmmmljjihjikmnmpuxxuqoonnommpqpoov{{{€„Ž—–Švmjikjkiilmmllkknrrnkkkim}™®¶¼¾»µ´³³³µ¸¼½¼½½ÀÃÇÊÌÎÍÌËÊÌÌÌÍÏÏÏÎÌÊÇÉÉÉÉÉÉÉÊÊËÌÍÌÍÍÌÇÎÒs^c`‡…}ƒˆ�Œ�Š—��„…‰ŒŠŒ‡�™–�Š””„”u›¥”rDHNQSUWUVVVVVVWWVVWXXYYYZZ[ZYWUVUUUTUVVVWWWWWWWXWXXXXXXYWWYWWWWWVWWWVVWWWWWVWXWXWXWXWXXYXXXXYXXYYYYZZZZZZZ[\\Z[\[\\\[\]]]]]]^]^^^^^__^^_^_```____````a```a``aaabbbbbabbbdcbcccdddddcddddddeeeedfgffggghihhiihhhhjjjmx~„�›–ƒunnnllkjhhijlkkmqttqnmmmnoonopnoquyzz�„†ˆunkjijjjjkkmlkjjlopnkjiiigp‹£´¶¸´¯°±²²³·º¼¼¼¾ÁÄÇËËÍÍÌËËÍÎÍÍÏÐÑÐÍËËÈÊËÊÊÈÈÉÊÊÊÊÊËÊÆÆÉ¿s^cbvƒ~ƒ‰Œ‚ƒ‚|‡�“ŒŒŽ˜Š�’‹•©��’“‰“~ž•£‹TEJUYXWVWWVVVWXWVWXXYYYZ[]\[ZXVVWVVVVVUUVVVVVVVVWWXYXZXXXYXYXYYXWWXXWXXWWWXXXXWWXXXYXXYXXYXYYYYYYZZYZZ[[[[[\\[\\\]]\]\]]^^^^]^_^__`__`````a``a``_a``````aaaaaabbbbcbbcabccbccddcdeddddedddeeeeeffhfhiihiiijiiinxunu…Ž’—ž�Žyqqolljjhiiijjjknopommmmmnnoommnorvwy{|ywvtnljiijjkllllkjjkmnmkjiihggiž¯´²±­¯°­­¯´¸º»¼¿ÁÆÈËÌÌÌÌÌËÍÏÏÏÑÒÓÒÎÎÌÊËÌËËÉÉÉÈÈÉÈÆÇÆÁǾ»r^c`‚‰ƒ||‹’„ƒŽ„Š’“�„�—‘ˆ”’”›��‘““”‚›—�¯±^MTZYVVWVUUVUVVWWXXXYZ[]^]\ZYWWWWVTUTUUUUTUVVVWWXYXYYXYYYZZZXYXYYYYXXWYYYYWYXXYYXXYYYYYWYYZYYYZYZY[Z[Z[Z[[[[[\]\]\\]]]]]]]]]^^^^__`a``a```a`````a`_`__aaababcbbabccccccbccdddcddedddeeeeeefeffgfghiiiihihjijw†‚sx‰–›¡¢¡–‚ttokjjihhjjiikjmnnlllllmlmnlllmnorvwwuqommliihhjkkklllkkkklmkiiihihhiy–¬±®¨¥¥¨§¨¬±´¹º¼ÀÂÅÇÉËÊÉÊÈÉËÎÑÑÓÔÔÓÑÎÍÍÎÎÌËÉÉÈÇÆÆÅÄÄÀ¾Ã¶·q^ca…˜–’‚{}š��Œ†ŽŒŠŽƒ‹’‘†“’˜›˜”’�”’‡˜ §½®†`QPXVVUUTUTTUVWWWVXYY[\\\[ZXWWVVVUUUUTUUTUVUUVVVWXXXYYZYZZZZZZZZZYXYYZZYYXZYZYYYYZYYYYYYYYYYYZZ[[[[[[[\[\\\]\\\[]]\]]\]]^^^_^^^^^_``__`a``_aa`````_``aabaaabccbaccbcbbccdedddddeeedeefdeeefhhfgiihghhhhikky‰‡|}‹—� ¢¤žŽƒ~vjijjjjikjjjkkllkjklkklmmklkllnqtvusomkkkjjjiikkkklmlkkkljjjiiiihhhv’¨«¦�”’—œ¡§®³·»½ÁÃÄÅÇÉÇÈÇÉÉÌÏÑÓÖ×ÕÔÑÐÏÎÎÎÎËÊÊÇÅÅÃÃÁ¾¼º½±´p^ca‚„‡‹•�cƒŠ’��¡””‘‹Š—‡€�•›“–�˜ŽŠ�‰š‘”œ®•�jHTUTTTSRTTTUVUVVWXYZ[\[ZYWVVVVVVVUUUUUUVUVUVVWWWYYYYZZZZZZ[[[ZZZZZZZZ[Y[Z[ZZYYZYZYZYYYZZZYZZZ[[Z[\\\\\^]]]\]]]]]^^]]^]_^^^^_^^__^^__^^`__``__```aa`bbabbabbabbbbbbcbcddceddcdeeeeeeeeffffggghihhhhhihjmv‚…‚…�•–›¡¥¢š’Š~pijjijjjjjijlllljjkkkklllklkklopssoljjjiiiiikjkklnnlkmmljiiihhhghhz˜¦¤�—Œ…ˆ’š¡ª¯³¸½ÀÂÄÅÅÆÄÅÇÈÊÍÐÒÕ×רÕÓÑÐÏÑÐÎÌÌÈÅÃÁÁ¾¼º·¶»¯°p_caƒ‹…}|‡“��|y€z�–ƒ†�‹‰—Šˆˆ�›Ž‡œ–š–��•“™¢¬š°ƒIHRTSRRSSSUUUUVWWXXZZZZZYWVUVVVUUUUUUUUVUVVVVVVWXXYZYZZZ[[[[[[[[[ZZZZ[ZZZ[Z[ZYZYYZYZYZZZZZZZ[[Z[[[\\]]]^^]\]]^]^^]]]^_^_^^^^_^_]_^]^^____`_````a`babbbabbbaabbbcbbccdddeddddeeeeeeeeeffghghhhghhggghinrz}€‰‘�’›§ª¨¢•�‡�sijijiijjjkkmmjjkjklmnnlmlkkllmpoljjjiihijjkkjkopmlmnmliiighhhhgmŠ¢¤š”“�‰ˆŽ–ž¦ª¯µ»¾ÂÄÃÃÂÁÃÆÈËÎÐÕÖ×ÙØ×ÓÏÒÒÒÑÐÌÊÆÃÁ¾¼¹¸¶´±·­®q_d`‚’�˜�Œ”—–‹��ˆŠŠ’Œ““ˆ�•™˜’�Ÿ�…–Ž””Ž›�–’›®�°«rGFQSRRRTRSUTTUVVWYYZYZZZXWVVVVWVUVVVWVVVVVVVVVWWXYYYYZZ[[[\\Z[[ZZY[[ZZZ[[ZYYYYYZZYYYZZ[Z^_Z[Z[[[\]][]^^]^]^^^^^]]]]^^^^^^^^]_]^]]^_^__^^_````aaabbcbaababbbbbbbcdccddcddeedeeeeefeeeffghgghggggghhhmpsw‹“�’Ÿ¨ªª¢—Ž�Œzkikjiijjjklmpljkjjmqrqopolkjkjkkjiihiihhjjkjkowwrnnnlkiihhhhiiit‘¢™�‰‰‹‹Œ�‘𢧬±¶ºÀÃÀ¿¾¾ÁÆÉËÏÓÕØÛÚÙ×ÔÔÒÓÕÓÐÌÈÅÁ½¹¶µ´²±®³¬«p_cbƒŠŠ’’���ˆŽ‰‘~„€—˜‘�•�„ŒˆŽ‘Žœ•ЕЕ“…�—œ™™¢”©¼§wPLSSRRRSRSSTTUVVWXYYZ[ZZXWWVVWVWWWWWWVVVVVVWWWWWXYYYY[[[[\\[][[[[ZZ[ZZ[[YYZZZZYZZZ[ZZYagZ\\\[\\]\[]^]^^]]^^^^]^^]]^]^^]^^]]^]^^^_^^^___````aabaaabaaaaabccccdbcedddededdeeeffeffeffggggghgghfghfgilrz‚���— £¥£š••’‡wklnljijjjjkmoomjhjmrtrurokjkiiiijihhhhihijikmu|}tnmkjjiihijihkpv‰’‹€||€‡ˆˆ�•œ£«¯±¶½Á¾¹¹¾ÂÆÉÍÏÓÖÙÛÛÙ×ÖÔÒÔÕÓÍÌǾº¶´²±®®¬¬¯°p_c`„�ŽŽ‚‘™œ�†††‰~„„–ŒŒ�ž‹„�†”�–¤¢‘ƒ‘›Ÿ�…’—‘�¢¤«¹Æ¤]CLSQPQQRSSSSTTUVVXYZZZ[YXXWZWWXXWVWVVWWWVWXWXXYXXZYZ[[[[]\\\\[Z\[[Z\[ZZ[ZZZZZZZ[[\[[ZZ\\]]\\\[\]\\]]]^\]]]]\^]]]]]^]]]^]\]]^]]_^__^__``````aaaaaaababbacbbdccddddeeeeeddeeedffeffffgghffffggfggir~„‡‰�’™›™—“�”–‹|soqssokkjjjknrsokikmopprqokjiiiihiihihghhihikouzytnnpojihjikkkrutx€�~xuy€ƒ…Œ”˜¢­±¯±¹¼¹¶ºÂÅÊÌÍÐÒÖØÚÛÙÚ×ÔÓÓÓÒÍÉÅÀº·´°¯­¬«©¨¨®q^c`‡˜Œ”“†‚‘Ÿ–“‘�ŽŠyˆˆ—�Œž”“ކ ••˜¨¥�“Ž¤šŽ™›“�™¢¨£›¡–TBORPQQRRRSSSSUUUWXY[[[ZXYXYYWXXXXXYYYYYYXWWWXYYZXZZ[[\\[[[\\\\\\\\\[Z[[[\\[ZZ[\[\[\\\[[[]]\]]]]\]]\\]]]]]]]]]]]]]]]\\]^]]_^^^^_^^_^___``aaaaaaaaabbbbccccddedddddddeddeeeeeeeefeffgffffffgffglyˆŒŠˆˆ�••“�‡‡’’„yxvw{}xnjjkmotxvpkjklmmmmnmljjjihhiiijihhiijilquyyvty{umhhgiouwvtpow||vqw~€ƒŠ‘–¡¬±¬­²º¹ºÁÅÊÌÌÎÐÔÖØÛÛÚÙÖÓÒÐÏÎËÆÅ¼¸´²°®¬«©§§¦¨o_ca‰’”’´¬�€‘–•‘�•™�•‘†›‹‹�œ˜’}�Ž•™›œž˜•Ÿ†~‡——”Ž¢®¥ ®µwHHONSQRQSSSSSTTTVWXYZ[ZZYYYYZYYZYYYYXYZXXWXXYYXXYZ[\\Z[\[]]]\\][][]\\]\\\\[[[Z\[\[[\\[[\\\]]]\^]]]]]]^]]]]]]^]]]\\]\]]]]^^^]^_^^`^___a``a``aa`aaababbcddddddddeddddddddddeeffffefffggefgffggmzˆŠ‡ƒƒˆŒŒŽŠ…ˆ�Š�}~~ƒ…}nlorrtxzumkkkkjkklmlkkjiiihiijjjigijjikv}{{z{�wkhhfit~~wpkkqutrps}‚„ˆŒ�žª±¯®´½¿ÀÅÈËÍÏÐÓÓÔ×ÚÙÚØÕÑÐÏÍËÇþ¹·²°¯­«©§§¦¦¨o_c_�š��¢â»œˆ–••�†�•‘“ŠŠ“‡yˆ—“�y‡‰“Š˜¦—𢑋�–™ª�”°³ª©¹£gSSEPSPQRSSSSSSTUUWYZ[[[ZZZYYYYZZYYYZZYXXXYWXXXYZZZZ\]\]]\]]]^^^]^]^]]\\\\[\[\]]]]\\\\[]]]]]]]]]]]]^]]]]]\]\\]]\]]^]]\]]^]^^____a`_`_`__`a``aaaabbcdcdedddcdcddddccccddeddeeeeeefgfefegggggjt‚|~€‚„ˆ††‰‹„}|€�…ˆ~pr}}vtutpmllkjjkkkkkkjjihjjjkkkiijjkjjr~�{zz{€}rhgghhpz{riijloppnqz†‹‰ˆŒ—§²¶·ÁÆÆÅÆÊÌÐÒÓÒÒÓÕÖר×ÔÐÎËËÇÿ»¸´±®¬ª©§¦¥¥¤©o_ca…’Œ˜gW‘¸ž‡‘�œš“Š–�—‚‹¢˜}‰˜ ¯•›—‘•Š�›š¤š¡™’Ž”¨�Š›—•¥¬¹�•uJIRQRRRRRQRSSTVVXYZ[[ZZYYYZZZYYZ[[ZZYXYXXYYYZ[[Z[\[\]\\]]^^^^^_^]]]]\\\\\^]\]]\]]\]^]]]]]\\\]]]]]]]\\]]]]]]^^]]_]]]]_]^_^^``a`````````aaabaaccccddddeeccccccccacdccdddedeeeeefffefgfghgjntwvy{{z~‚€ƒ†„}ywxz}€„v|‡…ztsponkkjkkikkkkkiijikjlmmljjmmlknv||yx~‚wmhghhhjopljhhlnoomp|�”’ŒŒ“£³½ÄÊËÈÄÆÌÏÒÒÕÒÒÒÓÖÖÖÕÒÎËÈÆÂÀ¼¹µ²°­«©¨§¦¤¥¤§o_c`Š˜Š…�sQoª–†�“™œ‡Œœ•©”•ª¡‚‘—– Ž�¤¦¥ŒŠƒ’¢”—�•’‘ š£ª�’ £…y²§gENQSPQQRRSTTTVWYZZZ[[Z[Z[ZZZZZ[[\[ZYZZYYYYZ[ZZ[[\\\\\\\]]]____^^^]]]]]]\\\]]\]]]]^^^]^^]]\]]]]]]]]]]\]]\\]]]]]]]]]^^___```__``````a`aaaacbcdbdedddccbcbbbbbbcbcbbdddddddeefefffgffgggillnortrty|}€~zvtutuwy‚‚ˆŽŒ„~zutqljjjkkjkjjjjhiijklnnljkorrsuvxz|ƒŠ‹�qhggghiiijjighjlmnms‚’šš›š�§µÀÉÏÌÅÄÈÎÒÒÔÕÔÒÒÓÕÕÖÓÑÍÉÅ¿½º¶´°®¬«¨¦¥¤££¢¦o_ca€�˜‘�¨�g~�–‘‘…�™‘‘—”¤–ŒŸ “–�“•�Š� ¡�šŠ™¤˜—˜�™”…s›²•‡�h~˜ŸmVJHQPQQRRRSSTUWXYZYZ[Z\[[[[Z[[\]\\ZZYYYZYZZZZZ[Z[[ZZ[[\\]]]]]]\^^^]]]]]]]^\]]]]\^^]^^]^^]^]^^]^]]]\]]]]^]]^]]^]]^_^^`__a`````````aaabbbbbcdeddccccbbbaabbaccbcbcbcdcddeeefgfgfeffggghklmmmnmpsuyzwrpopqtvz�Š’•—’�‰„~ysljkjkkkjjijkjjijkmnnmjkqwy{yvzƒ‰‹�‹{jggghghhhiihhhikllns‚�˜¡«¯®±¸ÃËÏÉÃÃÌÒÕÕÖÖÔÓÒÓÖÖÕÒÏÌÆÂ¿½º¶³²®¬ª©§¦¤¤¢¢¡¤n_cbx†�ˆ‡Œœ�‹Œ•—§š�…’Œ…�“›ž–Œ’–•�Ž’��‰–™¦¥•”¤›š›†  nao”©¬zŒ–�›ž–eGOQQQRRRRTUUUVWXYYZZ[[\\[\[]]^_\[[YYZZZZZYZZZ[[[ZZZZZ[[[[[\[]_]]^]]^]]]]]]^^]^^^]^_^]]]^]\^]]\]]]]^^^^^^^^^^^^__``__````````a``baaabbccdddbbbbbaaaaaabbbbcbbcbccddddeffgfffefffghjjkkkllmmoswwrmlkmnryƒ‹‘šž™‘�‹ˆ€wpkkjikjkjijkkkkkklnomljlqw{{xx€ˆ‹‹‹�qhghggggggghihghjknqu‰™©·ºµ¶¼ÆÌÍÈÃÆÏÔÙØÖ×ÔÒÒÔרÓÑÎÈÄÀ¼¹·´±°­«¨§¦¤¤¢¡¡¡¤o_ca‰�‘Š��‘ž–ŠŠ˜‡“ž„|–š‡‹’‘�¤ŠŽžœŽ“™–œŸ�—¨�œ– ž££Ž¦³Žxj”…Z†¡›“—‘œ¬…PPRPQQQRSSSSTVVXXXZZZZ[\[[]__`^\[Z[[ZZZZZ[ZZ[ZZYYYYZZZZZ[Z[\]\\]^^^^]^^]]^^^_^^^^^^^^]^^^]]^\^^^]^^_^^^__`^^_```__`_`__```a`aa`aaaccccccaaaaaaaaaaaaaaabcbabbcddcdeeefefffeefghgijjkjjjklotvrnlkkklr‚�““›�–�ˆ‡†€wljkjjkjijijllklmmmnomlkmptuutx~€„„{mgfggfhhggghghgimpqu|‚�ž´¿À¹µ»ÅÈËÊÈËÓÚÛÛÙÕÕÓÓרØÓÐÌÆÃ½º¶´²°­«©¨¦¥£¢¢¢  £o_c`Š–Ž’�”�”¡™…ƒž� ©‘�››�‰‹ˆš¡†Œ¢£�šŸ‘‘œ”‹¢¤¤�™‘˜Ž„�¬¶‡“zE|•—”•”ŠŽ„`BQSOQRQRSSTTUVWXWYYZZ[[[\^_^__^]^\[\\\\[[[[ZZZZXYY[YXY[ZZZ\\[[\]]]]^^^^^_^]__^]__^]^^__^^^]^^__^^___^`__`^^_``^_``^_``aa_`a`aaabcbbbabbaaa``aa`aaaaa`bbbbbbbcddeeeefeeffeeeefghhijjiijjknssolkkjjny‹——“’�ˆ†…‚€{umijjkjiijiklkkkllnoolkkkmnpou|zsw~vmihfffggfggffhilpstxƒŠ•ª½ÄÄ»´¹ÄÊÌÎÐÔØÜÝÝÚÖÕÔÓÖÙ×ÔÏÉÅÀ»¹¶³±®¬¬©§¦£¤¡¡¡ Ÿ¢n_c`†—�“‘„�˜›®µœ�¡“�›Ž…‘‘�ޑޑž—Œ—›…�¤œœŸ�ž–𥥢œ«—˜œ¢— �J†�…Ž”–“”rˆ|EFRSQQRRRTUWXZZYXYZZZ\\]]\]^^]^]^^^^^]][\ZZYYYXYXZYYYYZY[\[[Z[[][]]]]]^]^]_^^^__^]^_^^^^]]^^^__^__`^__^^_`^_`_^____`_````_``aabbaaaa`a``aaaaaaa`aaaaaaabbabcdedeeefeeeeefegfgfhihhijiikmnomkkjilu��™–�ˆz|}ytqolkklkkihhjklkkllmnnmlkjjjlmpz€{sw{wpllkgfgfggeefghloptv~�š¤³¿ÃÀ¹´ºÉÎÐÔרÜÞßÝÚ×ÕÕÓÖÙ×ÓÌÈÄ¿º·µ²¯®¬«¨§¥££ ¡Ÿ  ¢n_cbu„…„�’�y‚–™œ‚„˜–“–™œ—’––™˜Œ�¦œœ¡”“��ž‘’œ“œ©§�’£ š™�™—U�…‚Š“–����γjCCMSQRUTQMIFIRVYZYZ[[\[ZZ[[\\[]\]^^^]\[ZYZYYYYXYYZZYZZZZZ[Z\[[[]]\]]]]^^^]_____^^^]^^^^]_^^^__^^_^__^^^^_^_^^__^^``_````````aaa`aa_``a`aaaa`_`aaa``aabbccddededdeeeddfffefgfgghhhijjjkkmljkmlp{ˆ’——�„vqstpkjikjjkkkjijllmklmmmnmljiihimrz€�{xzytnllihfgfgfefgghmqsv~�¢ª®±·¸¸·µ¿ÌÒÓÕÛÜßáàÝÚ×ÖÒÒÔÖ×ÑÊÅÁ½··³±®««ª¦¦¤¢¢¡   Ÿ¡n`cb}{�‡„��—~xŒ�•‰‹•’—ž��™� –“•�›œŸœ£›‰��Ÿ—Ž�Ž’Ÿªžœ¢Žžž�ŒU”ƒ…�“•™›€�¯Åз€TDKMFJWp‘¦„\VKKZYYYXXYYXYZZZ[\]]]]\]]][ZYYZYZYYYYYYYYZZZZ[[[\[\\[\]]^^^^^^_``____]^^__^_^^^__^]__^^^]^^^^^_^^^__^___``_``aaa`_`````_``aa````````aaabdccddeeeeeeedeefgffffggghghhijjjkjjjmstu‹’”–‘‡zonoljijkjkkklklmnmmmmmmnmlljhhhioz…‡€z|zurnjhggfgggffgghjmtx~ŒŸ®°ªª«°´µ¹ÃÎÑÒÖÙÞâãâßÚÖÓÑÒÔÓÓÍÈÁ¿»·µ³®­«©§¥£¢¢¡    ž n`c`‡•„wˆ��†Œ‡}�”Ž‘—š“Œ™¦§›¢›�’“”™š–™Ÿž�£¡¥¤ž˜—žž¡Ÿ¡¦‘¤®t[–’‡an•¢¡yŽ®Ÿž®Ä«ŠYX’ÉáòùÿûìßÈ|ERXUUWWWWXWYYZZ[\]]]]]]]\\ZZZZYYYYYYXYYYZ[ZZ\[\\\[\\\]__^^_a```_`_^^_________^^]^^^^]]^__]^^_]_`^^^`___`````aa```_````_````````aaaaaccabcdeedddeddffeefgfggghgghihjiijkiinvy}‚ŠŽ���‡{nlljiijjjkjkmmnoppmmmmmmlkkhgggis„Љƒ~{vrlhggffgfgghghjkox‡•§®¬¤¢¨®µ·¹ÄÍÏÐÔØÜáããßÚÕÒÑÒÒÐÏÊÅÀ¼¸µ³±­«©§¥¥£¡¢¡¡¡¡žž£n_c`Š“Ÿ™‚�Œ©—�’Ž™‰~Œ˜˜�‹š §¤­¦Ž“ž§œ—žšš—¢›’™¤ªš¡�¡¦¥¤ªŠ•~^š�Ÿh$U˜™zƒ�š“›©™­×Ýóðëèìíñö÷ûûµUIVTUVVVVXYYZZZ[\\]]\^^^\\ZZZYYXYZYYYZZZZYY[[\\\\]\]]]^^^___``__^^`__`___`__^^^^_^^^^_^^^_^^_____``__``_a```a````a`````a```a`aaa`bbbbdcddcdddceeeefdefeegffgggiiihihijjjnw{~�ƒ†‡‰‡uljjjiiiijjklmnopnnmmmmllkjihhgfhtƒ‡††‡ƒ{vrkgggffgihhhhihjrz†” ¨«¨£¦­³·¶»ÄÊÍÎÓØÝàáßÜØÓÐÐÐÏÏÌÈþº¶³²°¬ª§¦¤¥£¡¢ ¡¢ ŸŸ¡n_ca†‡Žž§š‚‡¤––•˜©˜Š”—”˜•�˜œœ£§š˜–¨’’§¥‘ƒš�™˜¡§™œšš�“–­’jYššœžqa��ƒˆ�—”‡Œ¶ÒÔßâçêîïîñóñïîýåzFYTTUUUXYYYZZ[[\\]^^__^^][ZZZZYYYYZYZZZY[[[\]\\][]\\^^^^^^__^^____________^]]]]^^^]_^^^__^_]___^]____``a``a``a```a`````````aabbbdbbccdcccccddcddfdefdeeffggghiihhgihhipvyz{{|~€}umkjihhhhikkkmlmnmmlmmmonmkiiihggipy}‡‰�volighhfgilkiiijlryˆ˜¥­¬«­ª®³¶¶¹¼ÃÈÊÎÑ×ÚÝÞÛØÔÐÍÌÎÎËÉÄÁ»·´±®¬ª©¦¤££¢¡¡¡    Ÿ¢n_c_‰�…Œ†‘–{|”�‰}�¡›�”• ’––› §¦£ �ž£‘�¨±§¥�’—’ššš¨˜ž¨—˜ªfX’™œ�œ Ÿ‘w˜¨ «ž±ÑƽÐáäèììííïòòñè÷út:TVWXWVWXXYZZZ[\\^__`__^]]\\[ZZZ[ZZZ[Z[\\\[][\]\\\]\]^_^^^^______^^____^]^^^^]__^^__`_`__^]^]_^^^^___```aaaa`_```````a`aa`aaaaacccccdcccbbbccddedeeeeeffggihihhhhihijqvwuuurtwvqmliihggijjklllllkkkllnppokjihfhghkpt{ƒ‡~rkihgigghjmkjjlpv~Š›«µ¶²±²µ¶µ²²¹ÁÇÊÍÍÏÑÔ×רÓÐÍËÊËËÇÆÁ¼¸´²°¬«©¦¦¤££¢¢¡¢¡¡ ŸŸ£o_cb„–Љ¥”Œ’ˆŠ›•“�Ž’£‹Š“ Ÿ–“•˜�œš«˜¦–”•—¬«±ª Ÿš¢›œ¬¥­­œ¥im¡›‘—–Œ˜˜{›©¢¡¾Ü×ÄÂÂÍåèëììîïóòôãÔôÝaSFEFMXXVVWYYYZ[[\]_```__]^^^]]\[\[[[[\\\\[[\\[\\\\][]]\\\^_^_^_^]^]]]]]^^_^__]^^___^^_^^_^^_^_``__``a`aab``````````aaaaa`aaaccbcccbbbbcbccbedeeddecddeefgghhhhhhiijnsutrqnnnptrpljhigghjijkkkkkijjkmnqqnjihgggggikpv�…~rkihhfgghijkjkoy…‹“¤²¸¸¶µ·»¸³®³ºÂÉÏÏËÊËÍÑÓÑÏÌÊÇÇÇÇÅÁ¾»¶³±¯¬©¨¥¤£££¢££¢¡¡¡ Ÿ¥n_c_˜—”{‰º—Š�…��ˆ’•‰�¡‡�†Š¢Ÿ¡Œ™ž¤�™£³¤©¦˜¡ ª®¦ªœš‘¡¡™ ¤°bf£Š‘š•‘™›ƒ–ªŸ§ÊÇÁÓÊÍØàíèêëíðóððõ½Éìîã½�…jCNVUVVWXYYZ[\^_```__`b``_]\]]\Z[[[[Z[Z\[\\\[[[\\]\[[]]]]^]^^^]]]^]^^____^_^^^^^^^^_^^^___`a```a``aaaa```__```aaaaaaaaabacbaaabbbbabbcbcddddccccdeeffghhhgghhhkqvvronnnnpqqmjgghggijiijjjiijijlmnooljighfegfgjmsƒ|qljihgfghhikjlr€�–𤝶·¸·»»µ¯°´¹ÁÉÑÎÉÇÇÉÍÐÍËÈÆÄÃÄÄÿ»¹¶²¯­ª©§¦¤£¢¢¢£¢¡ ¢¢ ¡§o_c`ƒ˜˜Ÿiy ˆ…�‘’—Ž–™‡’ž�—”’™�–šž¢�š“‘£™“£¢¢š«ŸËП¨•¢¥¡¤ŸTk§›•�›š”’vŒ«ÀÎÃËÓÓÏÒÏÜäìëêìïïóñóÝ©ÜØëèïùð¤hGRZWVVWYZ[Z\]^^_^``aaba``__^]\\[[[[[]\\][[[\^\\]\]\\]]]]^]]^_^_^^_^^__^_^^^^^]_^^^__```__`_``a`a`a`__````aabaaaaaaaaaababab`abbbcbcdddccbabccdcdegghhggghgilrwvokkkmnnmjiggfhgfhijjjhihhjjlnnnnmljhgfffeghilw}{smjjihhgghikkmnt�‘œ¡¦­²·¹»½¹°«±¸¼ÂÊÐÏÇÅÇÈÊËÊÇÅÃÂÀÀÁ¿½º·´±®«ª¨¦¥¤£¡£¢¡¢¡¢¢¢¢¢¨n_cbu…�„u[wœ—ƒ‡—Œ’›‘”›¢�š—Š— �•��©  šŽ¢—¢ ©£•–§» ¯°§‚‰ˆ�Ki¤¨›—‰ ™£¢ÏïêèäÝÓÑÌÚÝåèéçææîÞÝïñõ¹»ÖÖ³¬Æñþò§OEOXYXXYXXZZ]^^^^_`bccccbbb_^^]^]\]]]^]\\]^_^^]^_]]]^^\^^]^^_____`^_]^^^^_^^^_^___`_a``_````aaa```_`_```aaaaabaaaaaaaab`aaaaacacddccccbbbbcddccdfgggggghhhjotqlihijlmkhhggggghhiiijhhhijmorpnomlihgffffilmt|}umjjhhgfghjijmos{…“Ÿ¦­°µ¹»¾¾¸°®¶½ÂÇÎÑÍÆÅÇÇÈÇÅÃÁÁÀ¾¿¿¿¾º·³±¯­©¨¦¥¤£££¢¡¢¢£¢¢££¨o_c`‹•𒇇‡…¡Š€„|‹¦—…Ž–��Œ�”œ©ž„‘ª§«¦“Ÿ�£Šžµ¦Ÿ–”‹£zS­‹†`yš‘’¥Òìðñøöîííç×ÔÌÜâÝäçïíóðóöòôòõÚªÉÇÓÒÇÜðòûÞ dGFOVY[\]\^^^]]^_`ccbbbbccccba`^^___^^_^^```___^]^__^^^__^^_``_`^__^__^_____^__````__^_``a`a``_``````aaaaa``a`aaa`a`aa`abaacbcccccbabaaabbcccdeegfffffghhjmkihgghhihgggggfghhiiiihijjknrssqonmkiggfehlrx}€|rjggggfgjpqojmqx��𥬲··¸º½½·²´ºÀÆËÑÒÍÈÇÆÆÄÂÁÀÀ¿¿¾¿¿¿¾º¸´±¯¬©¨¦¦¥¤¤£¤££¤££££¥ªp_c`ƒ�‰›š¢–Šˆv’Œ“–„ŠŸ˜…˜˜ž‰„Žˆ�–§˜‘Ÿ›¥§¤¡«·�•¥¦¬´²�FIµ§Ž¡œ•˜ÊîÙÔèííññðêäáåäåáëðäßáÒÙÑãáåìðô¶»ÀÁÙÏØëòîééóË’dRKGIKOQXZ\^_acda`_``abbccb`_``_`____abb_```^]]]__^^__`___`````````__`_`_`````_`______``````_`___```a````_````a``aaaa`abbacbaaabbbaaabbbcfdeeeeeeefefhhihggfffffeeffffgggiiijihhikknpsvusqoligeehlrw|}|vnifggghhoy~vmmt}ˆ–¢«´¸¹¸¶¸»»·µ·»ÁÉÐÒÓÐÉÆÃÁÀ¾¾½¼½½¾Á¾¹·´±¯¬ª¨§¥¥¤¤¤¤£££¤££¥¥«p_ca€Œ�—”Œ£š™Ÿ–™Œš¡™Š ž�™’ž�wz…ŒŽ—ˆ“Œ‘¥Ÿ™‹’³«­»È¬±c3Nw˜››‘©ë㼪¹ÐæâìïíæìãÞÞâáßÓÜÖáÖãííìãéåîÜ´¿´ÊÏÜâïñðįÛêëÚË«ž�ztc^WRPPQX^a^^^^^^``bbbbba``_`acdccb``_^]^^__^^____^_```_```a``````a```_`````__^____``__`____``````^____a`a```aabaaabababaa`aaaabbccddeeedddddeeggfffeeedddeeeeegggijjjihhiikmquxxvsokihfhkotxwsolihgfghhhs�‚xnnw…‘œ¨²···¶µ·¸·´³¹¼ÄÌÒÔÑÏÉľ½º¹¹ºº»½ÀÃÄÿ»·µ²¯¬«©§¦¥¦¥¥¤¤£¤¤¥¥¨§­p_c`�‡u„‘�‹¢›˜™ŸŒ‚s”��œ˜“~�§Ÿ›š—�‘Švuzƒ‰�|Ÿ—€w›z+AO‡Š–ÄèϨ§¬¯»ÔÙÎÛÙÖÜÜÎÏÀ«¼ÏÙÝÔÌ´µ´ËÐáïòЯ¸ÊºÍãìððóÑ¡–­ÇÛùý÷óðîåÔÇ¿¶¥wVMX_]\[]]^`bcccba`_`acddcca``_^^^^__^^]_^^^_^^_``````a``a`__________^^^^^^^^____a_^_`_^__^_`````a``_`aaaaa`aabaa```aaabbbdddcddddddddeededdddcceddeeefeehjkiihhhijlnrvxxvpmjiggjmpqqmjihhfgfghijxƒvop�™¢¬´¶´°°±²´±¯²¹ÀÆÎÑÑÎÊÇÀ¹¶³µµ·º»¿ÃÃÃÁ¾»·µ±°®ª©§§¦§¦¥£¥¥¥¦§¨ª©°q^d_‹›Œ€„†‰‚}Žš¥Ÿ‘‡’•�Œ‘”�™£œ–€Š��›�’Œ‚y†�Ž‘›…”d)@R€œ¦Ðà­¥©ª¨¬·³µ¸»¿Æ¸§�••Ÿ¤˜¤¹¼ËÏÏÖÛÒÇÍäð¸½Ì¼ÅËèñîìóòݶ­Æãéæääíèìêõûÿ÷Û¤bIV^ZZ]_abaa`aaa`aaabca`a_^^\\^]]\]\[\]^]]]]^]^___````_`^_^^^]^^]]]\]]]^]]^^_^]^^^^__^___```_a`__`_``_``_`aaaaa`aaaababddcccdcccdcdddddcbdcbccdcdeeffhjkjighhiikkosuwvtnkihfhlqqmihigfgffgghhn{‚}vrs„–›¢­´³®¬ª««ª§¤¨³¿ÈËÌËÊÉû¶³²²´¶º¿ÁÃÅÿ¼¸µ²°­ª©§§§§§§¦¦¨¨ªªª¬ª°q^c`Œœ“‘–‘’œžŒv��‘Ÿ“”†‡Ÿž¢’‘‚‚“©”˜‹—¨› ª©•˜�}�«¤¦@,<]�©ßʵ¹¨Ÿ§¨ªª¦¡£¥«¯©¤›•™™•‘Œ“¦º¶ÎÖØäåëåÜìѶÑËÕÒØìñëíññéåÔãèãèæçÝâêëëéîöÿë®^IY\\]]^\[\]^___^___^\\\\[[[\\[[[Z[Z[[\[[[[\]]]_``_^__]]\\\\\][[[\[]\[]\]]]]]^^^^^^^_```____^_^_^^_```_`_aaba``aabbcaccccbcbbbcbccccbbbcccccbcddefgijjjiihiijklmosuuqlhgffhnqokhgfefgfffghhkt{}{wv‡˜�¢­²°«©¥£Ÿ�œ™œ®¿ÉËÈÇÅ¿¸³°°±´·º¿ÃÅÅÄÀ¾»¹µ³¯­«ª©§¦§§¥§§ª­««¨¨©±q^c`Œš‘�Ž�Š„�«›†�Š’˜—¥Žž¦™Ÿ˜ ‡ˆ—•”—�Œ›–•ž˜€“‘’’­œ9)@Z|Àκ¶©¯œ£¨«§¦§¦¦¦¤§£•–œ“••‘‘“–𗬲¾ÉÅÏââÞ¹ÚÏÁÑÖßîíîñîåäêðïðèìè×ËÅÊâéèíìóÿê•NN^]\[YYYZZ[]\\]\[[[[\[[\[[[[[ZZ[ZZZYYZ[Z[[\^_``_\\]\[[[\\\\[\[[\\\\]]]]][\]]]\^]]^^^]_^]^]]]_^]____``caaaa``aaababcccccabbcbbbccbcbbbbabbbcddefgijihiihiijkkkmoqsrligffhlmjhgfeeeffgggghjls|‚�}‡–œ¡©ªª«¨¥ ™—–•œ°ÂÊÇÿ¾½º´°®®°³¶»¿ÄÅÅÂÀ¾º¸µ²¯¬«©©§§¥§¦§©«¬ª¨§¦¨²q^c`ˆ˜™Š�ƒ‹�}wމ��€‡�™�„˜¡—Ÿ˜”††‰‘ ›–‘ œ‰Œ”•¦ —“�5*CWŠÉµ¿°”œ¢§©¤¨¨¦¨ª«§™“—–’”•ž¢ �£¯¹ÓÚ×ÝϼÁÔÇÂÍÃÈÓÞèîïñðëåäêãàÜèÙʽ¼ÅÑçææêìíõÿÖuH\\YXXYWYZZYZ[ZZZZZZ[[\\\Z[ZZZZYZZZZZZ[[[]^___]\[[[ZZZZ\\\[[\\][\^]]^]]^\\\\\]^]\]\]^\]]\\]]^]^^___`aaaa``aaaaaaacbabbacaaaabbbbbbaaaaaaabbcdeikjhhgghiiikkkmnpsrokjgfgihggfeeeeffhhghhijp}ˆˆ�‡’™�ŸŸ¡¥¥¥¢ž››�¦´ÂÆÃ¾¸µµµ°®­­®°µº¿ÂÂÂÁ¾¼¹·´²®¬«©¨§¦¦§§§ªª©©¦¤¥§¯q^c`�Œ—žŽ’�’‘‡„“‹—¨’‹�š‘Ž–—§¡•—›��Ÿœ›Ÿœš––Ї˜‰¢6.D\¨Ì¾ªŸ ”™£¨¨§©¨©¬«« •™”‘’”𣤠�¦«¯¼ÛßâëÒª¶×߯ÉËÍÚèíïððçÝíìêáÞëäÚÒÖØÙ×ÖÛåæíîïûøœKW\WWXXXXXXYYZZZYZZ[[[[ZZZZZZZZZYZZZZ[[Z\]]^][[ZZZ[Z[[[[[\]]\\]]^_^]^]^]]]\^]]\]]]]]\\]]]^]^^^^^__^_`aa`_`aaa`abbbaa`aa`aaaaaaaaaabaabcbbbcdgkkhffggghhiijjkmortqnlihhhgggggeeeffggghhiko{‰Š…ˆ�””’•š� £¤¢¢§¨­¶¾ÀÀºµ³³³¯­«¬­¯³¸¾¿ÁÀÀ½»¹¶´²¯­¬«©¨¦¦¦¨¨¨ª¨§¦¦§©¯q^c_‘•��–’ދД�~�‰‡˜�„ˆŸ¢›¢™”¥Ž�ž£�—ž–œŸ‘—–•……††z41q��„�’”˜Ÿ¤§§©¬±°°«™™—�‘—š—•“š£ŸžŸ£¬ÐÖÔËα¤ÙÐÙÒÑÞ×âòïîëïñïíëðìêçߨÜÞêïëîîëìèìîìÿÌTP\VWWWWWWWWXXYYYZZZZZZYZZZZZZZZZZZ[[ZZZZZ[[[ZZZ[[[[[[[\]\]]]]__a``_^^^]\]\]]]\]]]\\]]]^]]^]^]^__a````a````aaabaaaaaa`a`aaaaaaaaaaababbabdikighhhhfefgggjkmnpssrpnmmkihfefffdegghiijjkov‚‹Ž�‹ŠŒ�”—š›�Ÿ¢ª±¶º¾À¿º¶²³±®­ªªª¨§¬³¸½À¿¿¾¼º¸¶³°°®­«©¨§¥¤¥¥¢¢¢¥ª¬ª¬p_c`ƒžž• “•—˜››œž›‘Ž‚–¢›”††‡ˆ•£¦©�z—“rr…•™Š—›¥š—r7.AvŒ~ƒˆ�”–™�£¨§ª®°¯°«™š��–››˜–“’œ£žž¦¤²ßçѽʞÇÝËÖÔÝãÖÝððêîòãÖßìîïìîíîêéèéîçÝëïíëíìþØYK[WVWVWXWXXXXXYYYZYZYZYZZYZZZZZZ[ZZZZZZZ[[[Z[ZZZ[[[[[\\[\\]]]\]____^\^\\]]\\]\\]]\^\\^]]^]]__^``a``a`````aaaaa````aaa`aaa`aa``abbbaabbdfjjhhhghgfdfgghjklmorsttsromkjihghgffghijjijmqu~†ŒŽ�ŒŒ‘–™›œœž¤®µº¾ÀÀ½¸µ³³²®­ª©¦¤£¦«²¸ººº½»º·¶³²±±¯««¨¦¥£¢¡ Ÿ ¥¦§¥©o_cbo‚“˜”¦›”“”™”‹Œ•”�‹‹–œžš“–ƒ‰—Œ��‡œ�bhƒŠ”��‹Š€m;2Cp‹€ƒ‰Ž’•š�£§§«­°­®¨˜˜’”™››™˜’�‘ž£¡¤¢­ÈÇÁ§¶´¨ÞËÌÍÑéðÔáïòóññïîóñïíêäßßáêçéíïëííêîîëúßjEXYWVWWXXWXXXYYZYYYYYYZZYZZZZZZZYZZZZZZ[[ZZZZZZ[[[[\\\Z[ZZZZ[\]]^^]]^][]]]\]\\]]]]\]]][]]\]^^^_``^``ab`_`a````a```aa`aaa`aaaaaaaabbbcfikiggfeffeeeghjikmnorsuwwurqnlkikkjhgihjkjkmptv{�‰�Œ‹‹�”˜šœ��¤®µº»½¾»¸·µ´´°­©¨¤Ÿž ¤ª±´µ·»º··´³²²°±¬«©§¥¢Ÿ��žŸ¢¡¡Ÿ¢m_ccjp€�•…—’’���–��’““‘���—™•—™›¢›•”“�¡€|Œ�‚†~“p46Fp‹�…Š�”–›ž¥¦¦«¬¬¬­©š™“—›šš›™–“Ž�¡¡Ÿ¥¤²Èǵ¡¶©ÔÐÌÍÊÍéïËåïñññîñïêÞÏÒÕâêèåÙèïíèäéëæãàéùô”IOZVVWYXWXYZYYYXYYYYZYZZYYYZZZZZZZZZ[Z[Z[ZZ[ZZZ[Z[[\[ZZZZZZ[[\^[\\\\\\\\]]\\]\]]]]]^]\]\]]]^^^__^^_a`_````a__````````_`a`aa`a`aaaaceikiheeeedffggghjkkloopruxxwutsonmmmkijijklmoruwx|�‡Š‰‰ŠŒ’–˜š›�¡«°´¸»»¸¶µµ¶²°ª¨¥Ÿ›˜› ¥­²µ¸ºº¸¶´²±¯¯°­­¬©¥ ›—™��šš——›m`cb�vrs~›–—�š–™š��’”””‘”��˜šœ›œ˜—“˜˜œ–Ž”•™�‰Œ�“r64GsŠ„…‹�“—šž¢¥§§­«©©§˜–•—›š›šš˜•‘Œ–£¡ž�®ÄÍΪ©©ËØÊÇÕáÚéã×ñòñðîòïçãÞÛññíððòçØäèèáàéñçàáñÿÊcGYWWWWWWXYYYYYYYXYYYYYYYYYZZZZZYZZZZ[Z[ZYZZZZZ[[[Z[Z[ZZZZZ\[\Z[[[[[[[[\]]]][\]]]]]\]\]^\]^^^^^^_____`__```_`_____`````a_`a`aab`bchjjihfeeeefgggggijklmmoqtwwwvutrrqopolklmnnpswzyy{‚†ˆ‰ŠŒ�’””—™�¢«°¶»º·¶µ¶´±¯ª¦¢š—˜›Ÿ§¯´·¹¸·µ³³±°®­­­­¬«¤›•”–˜—“���”l`c_–—t…uw‰‹‹“ž”’•”‘–�™—‹•‹ˆ�™�™�“�’…�£˜’–‡…މЕj34DoŒ„‡Œ‘”—›Ÿ£¥¥§¦¤§§™’•—˜›››š›™—’’Ž™¤¡�¨ÄÍÖ«©ÄÚÈÉÂÓëØæêîòñïðñòòïïãÏÚàëäÚÝçÞåêïêêÖÊËͳÐúõ‘IXVVWWWWXZXXYYYYYYYYYYYYYYYYZYZZZYZZZZYXYZYZYZZZZZZZ[Z[ZZ[[[Z[\[[[\\[\\\\\[\]\\\\\\\\]]\]]]^^_^^_^_____`_^`_`^_``````_``a`babbcdijihggfeedffggghijjjjlnqtvxvvvuussqpponpoprsvyyyxy|~�…ˆˆŠŒ���’”–›¤®´¹»¸·µµµ³²­¤›•–œŸ£¬´¸º¸·´²±°®­¬«¬­­­ª¢™’�“’��ŠˆŠŒjac`Ž�¡}‡�~ˆ�’Œ“š”’”‘—���Š–—”•“އ”—¬ªƒ„“ŒŠ’‹‡ˆ�‘n15DkŒ…‡Œ’•—𠣦¦¥¢¢£¡�‘�•š�œ›™�š––’�’¢¡¡ž½ÌÎʲ¬»ÙÂÍÎÐãîØéóððîññíáÉ´²«ÎÖÍÇßììèÝÜÕÕȵ¶Âɽ·ÑÞ÷�E[VWVWXXXXXYXXYYYYYZZYZXYYYYYYYZZZZZZZZZYYZZZ[[ZZZZ[ZZ[[[[\[[[[[\\[Z[\\[\]\\[\\\\\][\]\]]]^^^^^^^]^`____`_``_``__```_``_aaaacdhkjhffggfedeffggiikjjlmnruvvwwxwxvttrrqqrsssuvxyyyz|}‚„…†ˆŠ‹‹Œ��— ª±³¶¹·µ³µ¶¶±§›”—¡¦«¯¶¹¸¶³±®®«ª©©©ªª­¬§Ÿ•��ŽŒ‰‡‚€‚†had`ƒ‘� ‹……€—–˜•�šŸ ž•œ‹ˆŒŒ‹Š|’™¥¦‹w�¢ˆ�¤¢˜›™{Œ›^14Ga�„‡‹’–—š¡¡Ÿ¡   š�“�Œ•™�››š�›˜˜•“‘™¤¢�£ÅÏβ°²ç¿ÈÑÒÛåéìññîïòïݼ«°­ÆÎÄÞæÓÀÃǵ«ºÓ×ÚÞðßèðëììîuJZUVWWWWWXXXWXXXYYYYYXYXYYYYYYZZZZZ[ZZZZYZZZZZZZ[[Z[[[\Z[\\\\[\[\\[[\\\\\\\\\\]\]]]\[]]]]]]^^^]^^`_```_```_____```_`a`aaabaehkkhggfffeeeeefghhjjjjknpruuvwyzzyxvvutttsttuvvxyxy|~€‚‚ƒ„…†‡ŠŽ–ž¤ª°´·¶³±³·¹¶¬�—�¥ª­²¶·µ±®¬ª¨¨¦¥¥¦§ª«©¥›’Œ‰‰‡„€}||~haca‚„{’—……‰„—’”“Ž‘–›¡•œ“€Š’œ‰{’Ž”˜�nƒ—zƒŒ•—�Qj£g72MbrމŒ‘–—�¡¡žœ�ž•�Œ�Ž�‘˜›œ››žšš–—–““Ÿ¤ž ÆÙÙ¼­²ìÒ¿ÍÐÛÛæïîììïòä¹¥¨©ºÕÕÜŨ¤¸ÉèãËáÚØëóòöõñðñïóî]OXUVUVXWWWXXXXXYYWXYXYXYYYXYYZYZYZ[ZZZZZZZZZZZ[Z[Z[[\Z\[[[[[\]\[]]]\[\[\]]]\]\]]\\]]_\]^]]\]^^^^____`_`__``__``____```aabcfjkigffeddeeeeffghhijijkmqtsuwyz{|{zywxxvvuvvvvxyzwx{�‚~}}~~~‚„‡Ž•™�¢ª¯²³²³µ¹¹·¯¥ £¥¨¬²µ³°¬§§¨¥¤££¢£¥¦§¥¡˜�‰…„„€~{zz{gac`‡�ƒz‹Œ‹�ag‚�–œ–Šˆ–š��£˜‰…�’…Љ‹”©˜—Œ…„y„v>Ihj;3JM[�‰�‘–˜ž Ÿ�šš”�ŽŽ‰”��™›œœ›�œš—˜™“’–¡¢�©ÓÔÆ¬°êäÁÑÒãìçìíìéîðñèáЮÎÁÌÕÓÝìéçëðú÷úýùø÷êèèÛîòðïÉNSWVVVXWWVWXWXXXYXWXWXYXYXXYXYZYYYYYZZZZYZZZZZZZ[[[Z[[[[Z[[ZZZ[[[\\\\\\\\]]^]\]]]]^]]]^^_^^^_^^^_^__a`___``____^_^^__```begijgeeecceeddffghhiijijlmpruwxzzz|~}}|z|{yzyxyz||{zy~ƒ‚�~|{{z{|ƒ…‹’•–˜ž§­°²µ·¹¹¶²­««¨¨ª­°®¨¤¢¢¢£¡¡¢ ¡¡¤£¢œ–�‡�~~~{zzzgac`Š—�Œƒ–œ”�Ž€t„Ž”œŸ…‘£ —Ÿ¢ŽŠ›§¡¢–‰•˜š®����aIJ@A<5I?IˆŒ�’”˜Ÿ ¡ ž–‰��‰ŒŒŽ“–›œœ���˜—™›–’“›¢¡—°Ý­°äô×ÍÛÑæîîëêèïñê×ÜíîØÛéÞÁ´³»ÚòóèåÙȾÃÍÚêéßßççâÞºJWVWWXWVWXXWWXWXWXXWXXWYYYYXXYZYZZYZZZYZZZZYY[Z[Z[[ZZZZZZY[[[[[[\\\\[\\\]]]]]^]]]^]\^]^^^^_^^__^`````__`__`__^__^^_`__`bdhhhfdedcddedfffhihhiiijlmqtvxyz{{|}€‚��€||{~€€~‚…„‚|zzzzz}‚„‡ŒŽ��–ž¦¬¯´··¸¶´²²°ªª©ª«¨¢œœŸ ŸŸ¡Ÿ��Ÿ  �˜”�‰�}zzz||zzgac`‘•©’”…“–’Šy‚˜“’އ�•©¦”ž’��’™�ª¥‹„ƒ�”œœ›hHKF>>0GDCu‘Œ’•›žž¢¡—ŒŠŽŒ��Š�’–šš›��›™™š››”“˜ž£ ¡Í߬°ãõïÓÒÆ×ñðïðóñóíèííÔÕɳ¡¤¾àìçϸ¨¬­¡žŸ ¤©¸ËÍÝìèÙß�EZUVWVWXWWXWXXXWXXXWWXXXXXXXXYYYYXYYYZZZZYZZZZZ[Z[ZZZZZZZZ\[\[[[\[[[[\\\]]]^]]^^]]]^]^]]^^^^_^_^___`a`^__^^^`^^___`__`beghfdcdcdcdcdefgiihijkhjmqtxzz{|}}}}€………ƒƒ�~~�‚ƒ�‚�ƒ…†…ƒ€}zz{{{}‚†‰‹�ޕ𡍭²¶¶¶µ¶´²­©¨¨ª©¤œ™˜›��œ�››™™™™—”’�ˆ‚|yyz{|zzgac_– ’�©œªš–‘Ÿ¡|tvkwŠ�‹ˆŸ œ®—œ‹}ƒ�—›™˜„†“š€SKJD=;5KDCa’�’—™�  ™��Š‹�Œ��’�•˜˜›œœ›š˜››œ™”–šŸ¡Ÿ£ÆË­ÛóðîØÙçåØÖÝéôìéæëéνÁÉÊÛ×Ä®¥¤¢¤ ¡©­­«ª«§ §ªÅåæäãjNXVVVWXWWXWWWWXWWWWWWWWWXXXXXXXXYYYYZYYZZZZZYZZZ[ZZ[[[Z[[Z\[[[\[[[[[\\\\\]]]]]\^^]^^^^]^_^^___^^_`^______]^^^^_^_^__aefggedbbbccdccddghijkklkmpuxy{|}€ƒ†‡‡„ƒ„‚€�‚„„ƒ„††…‡‡†…�~|}€€�ƒ†ŠŽ’•—™ ©¯²´´³²´´±«¦§©ª¨¡™•“•™š™˜˜——–•’��Ž‹ˆ�{yxxyzyzgad_�£ ”‰„z”›œ•¨²š‘¡©±« Ÿ”¦––ž�©¡‹„Š–§œœ�~‰{JKHE<;2OBFP‰Ž�—˜› œ�’Ž‰ŽŠ�“‘‘‘•——š�›šš™ššœœ˜•˜šž¤¯³ÈÕßôóôôì×ÎÊÉÍËØ¿Õêèö÷çÚÓÆµ¨¦©©§ªª¨¨ £©ª«¨ª­­¦¦ÐØæéÃKWVUWWWWWWWWXWWVWWWWWWXWWXWXXXYYYXYYYYYZYYZZZZZZ[[Z[Z[[[Z[[[][[[[[[\[[[\\\\[]]^]]]]]^^^]^`_^__^_```^_^__`_^^___`^_``dfghfecbbbacddedefgjkkklnqvxy{|}€��ƒ†‡Š‰‰‡…‚��„……†ˆ‰‰ŠŠ‰ŠŠ‡ƒ�‚…†„ƒ„†Š‘–˜™œ¤«¯°±±±±±²°«§¨©©¥Ÿ•ŽŒ�•——–—˜™—•‘ŽŒ�‹‡‚zyyyzyz{gaca„‘‰”Ÿ¨£š�Ÿ•‰�Ÿ«¦™Œ•Ÿ“~„��Ž‘Šœ©¥ž—‰�š•“–pGNJA;:4I>G@n��–˜› –�”�Ž���’’‘’”–•—š››šš˜š�œ›˜—˜šž³ªž¹Ùè×Óìݶ»»´©˜ˆÈÓÕäÐŽ¹µ³°¬«¨¦¨¨¦©¦¥§©¨¦¦¥¥¨Â»Ïêêô}KXVWVVWVWXWWWWWWWWVWVXWWWXXWXXXXYXXYYZYZYYYZZZZZ[[[ZZ[[[[[[[Z[Z[[[[[\\\\\[[]\[\]\\\\]]]^__`__^__^_`_`__a`_`__`a__`bfgfddccababceeeefggikjlnrvyzz{}€~‚ƒ…‡‡ˆˆ‰ˆ„„‚ƒ…ˆŠŠŠŠ‰ˆ‹‹ŒŒŠˆ……†‡‡ƒ„‡�“–˜™ž¤¨©«­®®®°±±®«©¨¤¡š�ˆ…‰Ž’’”—™™——“‘ŽŒ‰„€|zzzzz{{gac`ŒŒ’�•‘’¢–ަ˜šŒŒ˜Ž‰|{ŠŸ™„˜¡œ£Ÿ©©›™˜ˆˆ—˜–]JNH>?87RAKLW‰�”—›š‘‘Ž‘�’’‘�‘‘“”””–šœ››š˜›œœœ›™˜™œ º¦¢¯ÐáÀ¶ÊƲ¦›“�†Ÿ™¡¨ª°­­¬®µ³¯ª¬ª¨ª¬©¥¡¢¤¨¨©£²ÙÕÆÅ×êì·HXVVVWWWVWWVWWVWWVVWVVWWVWWWXXXYYXYXXYYYYYZZZZZZZ[ZZZ[[Z[[Z[[[\[[[[[[[[[[[\\[[\\\\\]]]]^^____^_^^^```__`_``____``aefeeddbbabbbceeeffgijkklpvyz{|}€€€‚„†††„…‡ˆ‡…††‡ŠŠŠ‹Š‰‰Š�ŽŽ‹Š‡†……ƒ…ˆŒ�“—–˜›žž¡¦ª««ª«®±°­¨¤Ÿ›’‹…„…‡‰‹�”•–•””“‘�†�~|zyyzz{}gad_†™“�Š�‰ˆ£’‹�Ÿ§™”ŸŸ¢Ÿ‹Ž¤¥–’—”–‘�©£Ÿ�ˆ“��`GMFA?87QDBFL~�“—™“’��‘‘•““‘�‘““’–”˜œššš™œœœœœ�——ž›¶ÒÏ·±ÇßÔ¹½½°¥Ÿ™ŽŒ›••£³·¸¸ºº¸·³­©§§ª­­©¥¡¥¨©¬¶¶¶¿ÑÛÐåçeQWVUWXWWWWWWWWWWVVVWWVVWWWWXWXWXXXYYXXYYYYZZYZZZ[ZZZZZZZ[Z[[\[[[Z[[[[[[\\\\\\[[[]\\\]]]^]]_^^^^^_```__`_____^^`bcffdeddbbacbcdefgfgiklmnpsux{|}~€€�„……„ƒ…†ˆˆˆ‰ˆˆ‰‰‰ŠŒŠ‰‰ŠŒ�Ž‹‰‡†…††Š��‘“–——˜™˜™Ÿ¥¨¨§§«¯°«¤›–’�‡ƒƒƒ‚€ƒ‰Ž�’”’’”‘Šƒ€}{zyz|}}~haca}‹�—Ž—›‰ƒ�ˆ–š‘—�Ÿ�•‰“Œ�‘š�Š�’‹‡–�¢¨©Š˜žYJNG@B:9O=GJHl‹�–™�Ž�’�”–““’��‘’”””˜›™—šš›�ž›��™—œŸ�¤×íßÜÕà縜 ¢ž˜—™™Ÿ›“š§¶º¹º¹¸¹¸²ªª¦£¦¨©§£§¥ª©¨²¹¸ÔÜáýšGZVVVWWVVVVXWVVVWVVVVVVVWWWWWXXWWXYYXYYZYYYZYZZZZZZZZZZZ[[[ZZZ[[\[[[Z[[[[[[[[[[[\]][]^]]^]]^^^___``_`a___^^^^_acddfedccbbbbcdeffhhhjnnooqtwx{|}}~€‚„„„„…††ˆŠŠŠ‰‰‰‰ˆ‹Œ‹‰ˆ‰ŠŠŠŠŠˆ‡‡†ˆ‹�Ž���““—˜–•—�¡¢¢¤§ª©¥œ”��Іƒ‚�~}~ƒ‡ˆ‹�����‡�~}{{{|~�hac`Š�„���›š‹”†~�•��†~…Žœ˜�Œ’¡†{ˆ“—’��–¦�z’VLLFA@:6M?HKIV…Š�“Ž‘’‘–•””““‘�‘’”“”—š˜“šœ�žžœž�œ›™Ÿ¢£¢´Æàåèéæ¶�Œ”™œ�œŸ¡Ÿ—‘–¥°²¶·¹¹¹¶±°®©ª¬­¨¦¨¾´®©·ÇÊÒçóÙSUVVWVWWWVWWVVVVVVVVVVWWXWWWWWXXXWXYXXYYYYYZYZZZZZYZZZZZZ[[Z[[[[[[[[[[[[\\\[[\\\\[\\\]]\]^^]_`aaa_``aaa````^^`accddddcccbccddfghhjkmqopoprvz||z{€€ƒƒƒ…†‡‡ˆ‰‹ŠŠŠˆˆˆ‰‰‰ˆ‡ˆˆˆˆ‰‰Š‰ˆˆ‹‹Œ��ŒŠ�‘•–”��•˜™™�¡££¡š’‹ˆ‡…‚�€}||~€€†‹Ž��Šƒ�€~|}}}~€€hacbwƒ—’ˆ’�ˆ˜š™€{u…‚‹ŒŒ’›Ž“Š�œž•’‘“—””” žŒHGLF@@68NAIJEEx†‹�Š�Ž‘—•••””“��’“““”˜•”˜�œžž���›�››�£¤¤®±²º¶½í×®£�–��”Ÿ£ �•‘˜ ¤©­°±µ·µ¯©¦ª­¯®­µ½¶­³¾ËÜÕâùŠJYVVVWXVWWVVVVVWVVWVVWWWWXWWWWWXXWXXYXXXYYXYZZYZYZ[ZZZZZZ[Z[Z[[[[[[[[[\\[[[[[[[\\\\\\]]]]]]_a`abaaabbbbbca_^`bbbccccbcbcddeefhijjknnonooquy|{xy€€€€ƒ‡‡†ˆ‡ˆ‰‰ŠŠ‰‡‡‡†‡ˆ‡‰ˆ‰‰‰‰ŠŠŠ‹‹Œ‹‹‹‰ˆ‡‹��ŽŠ‹Ž��‘”šœ�›–�І„…ƒ�~}|||{~ƒˆŒ�ˆ…‚€~}}~�€ƒhac`Œ�„”Š~—›�€��sy�©©� ˜††‘Œ’��…†‚š˜““Š†�ŠlC3IF?B88P_‡‡�‰Œ�“——–•””’‘‘’’’“–•’”’šžŸžœ›œ›�››™œŸ�¢®³³×åÛÏïõðçÍ®•‰�›Ÿœ™“•šœžž¢£›ªÕÔɹ±¬§ª¨¯¹¸²´ÀÉÐÊíÉEYWVVVWVWVVVVVVVVVWWVWVWWVWXXWWWWXWWXXYXXYXXYYYYZZZZYZZZZZZ[[Z[[Z[[[[[[[[[Z[Z[[[\[\\[]\]]]^^`bcdefeeffdbca_``abbbbabbabcdefgghiklmoponmmpuy{yy|€€€€…†‡†…†ˆŠŠŠ‹‡††…„…‡ˆˆ‰ˆˆˆ‰‰Š‹ŠŠŠ‹‰ˆ†………ˆˆ‰ˆ‡‰‰ˆŠ�•˜˜•’�‡……„‚�€}}~~€„ˆŠŠ‡‚~�€����…iac`€oyŸ›‚�‘’‰š¢›•ˆ–œ�¯¢‹‘•�ƒ—ž‹ugŒ™�‡„‚�aH?HE?B58Q?G?CAJ|‰‰ˆŠ�’•–•••””�’”‘�”•’’’�–�žžœ�œœ™›�››––˜”›­»µµØæïôôøöîͪ‘Œ—œ™”–œœ”’™¦ËÖÜéðêæÕÈ·­£§°«¬¶Í÷îzIQWXVVVUVVVVVVWVWVVVVVWWWWXXWWWXXWXXYWWXYYYZZYYYZYYZZZZZZZYZZZ[\[[[[[\Z[[ZZ[\[\[[[\[\\[\]^_`efhjihhhgea```aabaababaaccbeghjhjjklnpqoommrvxyz{~�‚‚‚ƒ…‡†††…‡ˆ‰Š‰ˆ‡……„†‡ˆ‰‡ˆˆˆ‰ˆˆŠŠ‰Š‰ˆ‡…‚‚ƒƒ„…†††………†‹‘“’‘�Šˆˆˆ‡‚‚��€�ƒ‡‰‰„�€€�‚‚�€€‚ƒ…iad`ƒš¥“~™�~†•ž—¦˜“œ‘‰„‡›«ž–ž ƒŽ•¦˜lh„˜”Œ’`KLHF>>69PBHG<8[v‚„І‹�•••–•””’“’�’“Ž�’—‘œ›��›››œ™œ��›•–˜‘”¡©¯®½ÜÏåòîñóùøì—Œ”—™˜•©ÀßðôíééíèâëõóëØ³£©©¤¯æ×ÊŃfLPUUVVVVVVVVVVVVVVWWVWWWXXWWWXXXXXXWXXXXYYYYYYYZZZZZZZZYZYZZZ[ZZ[[[[[[[[Z[[[Z[\\\[[[]]]_`dhiijhghfecba`a`baaaaaaaabccdgijjjkllprspooptwxy{}€€‚‚‚„††††……‡‡‰ˆˆ‡‡†„ƒ„‡ˆŠ‰‰‡ˆ‰‰‰ˆˆ‰‰‡†…„‚€€��‚‚ƒ………„…‡ŠŽ�‹‹‹ˆ‰‰Š‰†‚�‚€€€€‚„†…ƒ����ƒ‚‚���‚„…iac`‰“Ž ™Ž—‘˜™”’‰”‰‚“‘„xt�žž’–ž¥ ‘˜“‡wi‡”ˆPLJHF=<9=49N8Nz~vvrn~ƒŠ‹�’“””•–•””�Š‹‹‹i†— `‡¦ššš››œœšš™š—”’‘Œ‘—›Ÿ›¤®¼ñ÷òñññðïñôôòìåãæÐÒÕàÏâòòñõóñðâÒàܼ»¯­Õß˹¦¬ž†}sTKQWWUVVVVVWWWWVWVVWVWWWXWXXXXWXXXXYXXXYYXYYYZZYYZZZYYYZ[ZZZ[[Z[ZZ[[ZZ[[\\]^_aefhjkjiijhfededccdcddccaabaabacddfhijnqrrqrssuvz{{yy{|‚‚„†‡…ƒ„‡‰‰‰…„‚��‚‚ƒƒ…‡Šˆ‰ˆ…„„„„………‚ƒ…„‚‚‚ƒ„††‡ˆ‡…„ƒ‚��€}|{|~~€‚ƒ‚‚‚�€�‚€�€���€�‚‚€€�‚„…‡ˆiaca€‘‡pn„†Œ’�€’ˆ‡†Ž‡ƒ›”Šˆ�’™›š¢ š˜t…�š‚t\NMIFD:<0:KU~|xxushs~ƒ†‹Ž�‘’“”•”“’�j5b–Ns o€r¡™šš™šš™›™™—––•“�ŽŽ�‘‘Œ�–±Ïëøöôòòñîíñóñëìîîèçé×ßïðîîðòòïëìÒ´ÈÄ×ßı³º·›œÁ¸�_LOUWVVUVVVUVVWXWWXWWWWWXXXYXYXYYYYYYYZYXYZYYXZZZYZYZZ[ZZZ[[Z[[Z[[Z[Z[\]^acdeeghhhgfgfdcccceeffedddcbbabdefhiijllsuwvuvxyzyyyxy{{|~�ƒƒƒ„ƒ…‰‰‰†„ƒ��€€‚ƒ…†‡‡†„‚ƒ„ƒ…†…††‡†…„…‡†ˆˆˆ‡…ƒ‚�€}}}{yy{|~~~~€€€��~€€�‚‚�����‚……†iaca}—› ‘yv}Œ˜�Œ’��”˜Œ“£˜Ÿ“Ž––��Ÿ¢­§€’‹‰^PLHIF<=0,d€{yxxvtkm�€ƒŠŒ�‘’””••’—{K˜i#:Q£v‘œ—š˜˜™ššš˜———––•’ŽŒŠ„‡ˆŠŒŠ›»ÛíóïíòõîîóðîãÜñ÷óõñïðëâØèõóóíëÇ ­¼Í±«Ÿš¨«¥¬¶Ê·‹bRKTXVUWVVVVVWWWWWWXXYYXWYZYYYYXYYYYYYYYYYYYZYYYYYZZZZZZZZZZ[ZZ[[Z\\]`cbddcefgeeeddcccbccegfgffeeeeedfghjlmnprsvyyyy{{{{z{yy{{||}~�‚‚‚ƒ…†‡†…ƒƒ‚‚€€€�‚ƒƒ„‚��‚ƒ„†‡ˆ‰‰‰ˆ‡‡‡ˆˆ†‡†„‚~}|{{zzxxy{||{||}}~~~��€€€€��ƒ��€�‚„„‚‚haca‡‡‰ˆ’”‡{ƒˆˆ˜•ƒ’ ™œŽ€šŸ“¡‹x�¡œ§©•Ž™‘WPMJIG=?&hŒ{yyxwvtpgy~‚‡ŠŒ�‘’“••’›lmâÖØ×Šuzxttvuuqqnt�„‰Œ�Ž�“’’“‘�”Œ]Hq’_jƒ™™˜—–•’••–•••••–•‘‘‘ŒŠ‹Œ�‰ŠŒŠŠˆ‡„†……‡…†„‚€€}{}}}€„…‰�}sw‚{…œ­”¤ž�££¯±²«§Ÿ«±­´°ž¨¨¬·¯—�ƒ{��–‘�š™™”–˜›�¥£˜ƒv~‡’Ÿ¡—†cMTZZZXYYXYZYYYYZZ[Z[\^__````_`aadefghffeefijjjmmmopqrqomjhgiiijkklopoqrtuuuwwwwwvwxwyy|}~}}{yzzzyyzz{zy{z{z|}||{z{~€�‚‚�€€€~~~~~|}}~~~~||}||}~€�ƒ‚ƒƒ‚��‚‚€~~~~}|zzwttqonmpebca}ps~Ž––¦•‹�ƒ…›®œ„�›—‰��‡�ƒŠ““ƒ‹Œ’�„WOPMJKÅÝÍØÖŠtyuuvvussqon|‚…‹ŒŽŽ�‘“•—�•lF‡‹j<ž˜“˜•—–”“”’””””•””���ŽŽ�Ž�ŒŠ‹‹‹‹ŠŠ‡‰†ˆ‡ˆ‹Š†……‚�}zzzz{‚ˆvqu€wŽ ”›ŒŠ ž“ž®©¤¡¬©®¸©¤©™¥°Ÿ…vhamsim€�Ž˜š¡�œ™�‹• ¥”xz€ƒŽ•�¡…XMNSYZYZYYYYYZZY[[\]^__^_``_abbdffggggeefgijijjkjlmpoonkgddeeeghijmmpqststuuutttuvxx{}}}zyzxvwxxyyxyyyz{z{z|}{zzy{��ƒƒ�€~||}}}{|{{||~}}}~|||}ƒ…†‡ˆ‡…†…„‚€~~}~~~}}}{xvtrqnnmmndbd`‰™–ˆ…rv‰ƒ›Œ ¢›€��‡}{yŒŠ}~•‘ŽŠŠ‘‰Œ†ƒ‚\QPQBŽãÑÕÑщtwtvvvtrusqlt€ƒ‡‹Œ�Ž‘“•”‘—ˆ1M?W›�•–•—•’“’‘“�“––”’��Ž����Œ‹ŠŒ‰ŒŠŠŠŠ‹‰‰‡‰‹‰ˆ‰‡†…„ƒ€€~~‚…uosv“ž˜•›™°±®¨¬©¨¨¤ª¿œ²·±´›„f^\^ga\isgbt‚†“¡£ž “��’›š…w€Œ�’•¢™„{bNPYZYYXYZZZ[[[]]^_^^__^`acabdeffffeedefghfggghijlmnlgecbbddfghjlmoppsrrqpqqrsvwy{zyyxvwvuuvwxxxzy{zyyzzz{zzy{}€‚�‚€�~||z{{zyyxyyz|}|}~}}zy{|€„…‡ŠŠ‡‰‡†„‚€~}ƒ�~~}zzxvussqnlmllnebcayˆŸ´§“zŽ•†�wx‚’�¨°¡ž™Œ�ŠŽ�†„…„ŠŠŠŽ‚�]QSKYÎÕÒÓÔ͆tuvvvvtuttqop|�„ˆŠ‹Œ�‘“’”•™m2v�œ’“••–”’‘‘‘‘”•’’����‘‘�Ž�‹��Š‹ŠŠ‰‹ŠŠ‰‡ŠŠŠ‰ˆ‡ˆ…„‚�‚€�‚�…†smsy››˜’¤³¬®ª® ‹š˜›¦¥nd³«|f^]`eha^ekccvsr€€Š— �‰��–”•žŠno{„�“š�¦©›iNWYXXZZZZ[Z[\]]]^^^]^`ababbcecccbcccddeedddfggijijjjgdccdffhjjklmnoommnpqstvuvxvvtstrsuuvwwxxyy{zyyyyxz{y{~€ƒ„‚€}zxyzzyyyxxxxyz{|}|}|{yxz}�ƒ†ˆˆ‡‡†‡…ƒ‚�€~ƒ€{{yxxurqqoomklkloebc`…–‰Š�—™…‰†}�y|Љ€Š•�“¦¤–š�Ž�˜‘…ƒŒ˜ŸŽQOPE’àÑÕÑ×Çsvwuutuuusqqou}€�„‰‰‹���“–•‘—†€Nd–�“••’‘���‘�’‘’’‘’‘�‘ŽŽŒ‹Ž‹Š‰‹ŠˆŠ‰‰ˆˆŠ‹ˆ‹ˆ‡†…„ƒ��€�€‚„„plt{€�™˜“ ´®¯­¡€–­³«©˜Ž”‚c]_bnd`]]fib_omegegkm|“|UKYmtxŽŸ{_dr��”�‘¡­‚RV[XZZZZ[[[]^^\]\]]]^aabcbbbbbbbcbceddcbbdefgghghkkkgdccdcfhiijjjllklnprsssrrrqrqpqruvwvvvwxxvxzzyyxwx{}~�‚ƒƒ�}{yvvwyxwxzxwwxyyy{|}}||{z{|~‚„…†‡ˆ†††„„ƒ����|zxwutsponmmlkjklnebca‹”’tpŠ„Œ„�Œ™ª’‹‘}l|‰†|ާ�Š–’�¤¨£�ˆŒŒSTPVÆØÒÐÐÖ¿xtvvvttuuvstrppy}~�…‡Š‹Ž�‘•””‘�‰)KsVƒ•�•”’‘�Ž����““‘����‘Ž�Š�‹ŠŠŒ‰ˆŠ‹‰ˆˆ‹Š‹ˆ‹ˆ‡…„ƒ�€€�€��„€lluvŠž–—‘�³±¯¯¤…¬³­¯£˜…dV[hjhb``fgc^bli`a`aehkx‚�žmIMXVZn‰‡}x}�”�Œ’ ˆVQ[ZY[[[\]^^^]^]\\]^_`bdcba`abdcbbdcbaccdedefgggiklifedccdeggiiillmlmonomooppoprqpruwuvvvvvvuwy{{xxxy}~€‚�~{yxwtsvxxxyxwwuvxyz{|}}~~~~~€‚‚„‚„…ƒƒ‚‚‚���€€{xurrqonmlkkjkkklldbca��‚¤£’”Œ�zŒ‡x��—Ÿ£—ŽŒŽ‰”¡£œ’’yy–™‘•�PTG|ÜÓÓÔÒØµqtvussuuvttttrmt|}�†ˆŠŒ��“•”’�‘QP€g9‚ŽŽ’��‘�ŽŽŒ������Ž‘Ž��Š‹ŠŠ‹�Ї‹Š‰†ˆ‰‰ˆ‡ˆ…‡ƒƒ„�ƒƒƒ�‚‚„{jnus’š–•�𣢬¯¤£¢©­¤šŒ€~„…{‚Œ‚x~|tomd_`fkh^\j€„“£�ZJYYQUfz�ŒŠ‡‹��“•’ŒfMW][\\\]]]]]]]\]\]]_`bcaaaaccccba`aaccccbddedeghiigeeddccffgiilllllkllmloprrrssstvxwyyvvvwvx{||{yz{~~~|zywwwutuwxxxwvvuvuwyz{}~~€�‚����ƒ‚‚�€~~~~}~}~{yvsqoonnmkjjjjjjkoebc`�”‰�‘£š’–�‰‰�šŽ‰�‘˜™—‘’’‰‰’“‹�…lu“’RTI¥ÞÒÖÓÑÚ´ovvurtuvusvusprqx}~~ƒ†ˆŒ��‘“•“’’–k#W“’•–‰}�‹��‘�‘‘�����Œ‹‰Š‹‰‹ŒŠˆŠ‰‡ˆˆ…‰Šˆ††‡ƒ‚ƒ€ƒ„„�‚ƒ…xjrqu•™—”�–°¢›š“{�–𡙥¢¤¡™™––˜•‘‘‡‚xqlhid^^dle_cu‡Ÿ¤sHNYWTP\w„‰�“”š™”’ƒZQ]]]\\]]]\\]]\\]^^^_aa`abcbba``__acbab`abbcdfhhiihgeedbdefghhiijkjkmnopqssstuwvwyz|{yxwwwy|€~~||}|zxtsssuvwwxxwwvttuwvwyzz|}€��‚‚ƒ‚�‚�€~}}}|||{zyyyvwsqpopnmlkjjjiijknebd`y•’Šƒ�™••†‡‹~�¤Ž�œ‘��™‰…’��Ÿ§¢£ªŽ�žQPUÀÙÕÕØÔØ­pwwsstttsuvtrssrq{|}ƒˆˆ‹��‘’“‘‘”‰"5hkoqnQ%>x‘Ž�‘���Ž��ŠŠŠŠŒˆˆ‰ŒŠ‰‹‰‡‰„…‡ˆ‡†††…���„„‚�ƒƒ„tjsn}˜—•‘Œ‘©¨©•ƒ|y—¦›œŸ�Ÿ¡¡Ÿ�“•›™˜š““‘ˆ†vpstlc\^hpv~ˆ¢˜eIOY[VVcq‰’’‘—™‡Ÿ rQW^][\\\\\]\\]]]^^^__``aaa_`____aba``a``aabcefgjiihffdefefghiiikklmopqrsttvvvvxyz||yxxxwy}�€}zyyxuusqpqtvwxyxwvutttuvz{|zz|€�‚���~}}|{{{zzzxvvvvtsqpomnnllkjihhijjldbccomwy{qv€Žš�‹‹|�¡~‰œ¡›�®”Š�™Ž�ˆ�Ž¢ŽŽrNMhÐÕÔÕÕÓÞ¢pwvssturtuutstrros}}~€…ˆŠ‹Ž�‘“‘‘�’}R<"9b‰Ž��Ž���‘��Œ‰Š‹‹‰ˆ‡‰ŒŠ‰ˆˆˆ‡ƒ„„„……‡‡‚‚�‚‡‡‚ƒƒƒƒopslŠ—–‘�‰“® £¦£—}v£� ¥¦¦«¥ž Ÿ›™™›¡šš–‘�‡ƒ‚|mjvsnhdit~ŽŸ…[HOX[ZZq�Š‘•–—‹™©�^Q\\[[\]\\]^]^]^_^^^__`__^]^^^_`````a`````acdfhhijhffeefefghijklmnppprrtuvuuuvwxwwwwwvwy{|||{yvvussrqqqqrtwwvvwvustuvx}}||~€�~}{|zzz{zyywwuttsrrpopommlmlkiiiiiijldbca„ŠŒ‹}v|}xvŠœ¢¢ˆƒšŠŠ‹ˆ�Š—��Œˆ€�›‹‚��YRJlÒÕÖ×ÙÖÛ™owtsutrrttusussqqqw~}€‚†‰‰Œ��’“���”ƒ)$I~“ŒŠ�Ž‘�ŽŽ��ŒŠ‰‰Š‡ˆˆ‡‹Œˆ‰‰††…‚ƒ…„„‡ˆ…ƒ‚€ƒ‡…�ƒƒ„|nvks”–“�‰ˆ�ª¬¡ŸŸ –™�’“˜ž�ž¢¡¢¥¦¥¢ Ÿž ¡›˜“�‹‚ˆ€~�‘�”—’’�‰‰•�ƒXGRYXUctwu‡——’ˆŒ�¢rNY][[[[[\^]]^^_^^^_^^__^^___``__`__`_^^^_acegffggfffffeeeehjmopqqpoqqrtutrrtttttuuttuxxwvvuttsrpoomnooprttttuutsuxyz~}}}}~}||{yzyxzyxwuuttqqqonnoonnmmlljiiiikjkldbc`…•–¤¬¢�‡Š‘}…‘’‘ƒ~†‹—œ•�Ž™’����“‘�ˆ‹gSJqÒÖÖÖÔÔÕ’ovssttrrtussutrqtrry~}‚†‰ŠŒŒ����ŽŽ�mOQYG!vŠŒ�Ž�ŽŒŒŽŒŠ‰‰Š‡‡‰ˆŠŠ‰†‰††…ƒ�„‚„…†‡…ƒ�‚‚„„ƒ‚ƒ‡trsh„˜”�‰†„‡–«ª¡›ž�¡�‚yrkder|‡Š•�¡£¦¢›˜Ÿ¡›˜”ŒˆŠ‰���” —€{x‰�¡¨ƒNJWUOKf}fx�—��Ž‹¡‡WS]\Z[[\]]^_^^]]^^__]]^```````_^___]^^^^_`bcceedeefffgghiikmpqrppppoqqqqqpqqqqrrqqstutssrrrpnnnlllllmmmprsqtusuwyz|~}~~~}{{{{zyzzxxxwxvutsqpoonnnnmllmmmkjijjijjklebc`‰�‘‘�œ’ymŠ“ƒ‚„ˆ’¡£¤šœž™•”˜�™–Ž~‰‡VRHpÕØÔÙ×ÕÒ…quqrsrqsttqtutqrrrqp{~€„†ˆ‰‹Œ��ŽŽ�Š‘�ŽL!6v€rpŠŒ†ŠŒ‹ŠŠ‰ˆ‡…ˆ‰ˆ‰Šˆˆ†„„„‚€‚ƒ‚��„…‚�€ƒƒ‚ƒ„€nuns”““‹…�€y¬¬«­ª—‘•y`Y]\]]]_alrx€‹–› ¦¡ ¢Ÿ¡œ““�€Ž’”�‰‰‡}iS[d��œfJSTSHercv‰�–—‘” ”hO[]\\\\^]]]]]^]^^^]^__`_`__`^]__^]^]^^^`aabdddcdeefiiikkjnoqoonnmlmmmmnlmnnoppqoqppppqqonmlljjkjkkkjklnpprtuvwyy}}~~~~}{z{{{zxxxxwvwvuvtspnnnnnnlllkmmlkjjjjjiiijdbd^¨¶š”—’¡ª ”””�‹’¡ ‘w~un‹™‡‰�ƒ‚Š�ž¤›�[RNiÍÚרÖÛÉzqtqrsrqssrrstsqtsrprs}~�†…‡ŠŠŒŠŒ��‹Š‰ŒW3>;*K€‰‰�Šˆ‡ˆŠ††‡‰Š‰‰‡ˆ„„ƒ��ƒ‚‚‚€€‚ƒ€€€�‚ƒ„vosi‡—“ކ‚€{mœ­žŽ™¤“uhWZ]^_^^^___baelt~“š–——š•›–˜œ¡˜Ž‹Š”‘„vkab`hw’zMQSSJ^]\w’””šš–™Ÿ~QY][\]]]^\\]]]]]^^___^^^_^^^^^^]]\]]^__`a`bbbbdfgghhijjjmonljjihihhijiijklmnnnnnmmnonoljiijigijihhiijknnprruuvz{}}~~||z{zyyxxwvuutuutusrqnnnnmmmlklmmkjjjjjijiikdbcauy†œœ”˜™‰…‘—„€Š‡…‰|�Šu{‡“š�””ƒŽwŒ�WQP\ÄÛר×ÜÀusrorrpqrsqrttrrtspqrqs~}~�„ƒ†Š‰‰‹Š‹Š����xrA1]zHR‰ˆ†ˆ†ˆˆ†ƒ…‰‰†…ˆ„„ƒ‚�ƒƒ�‚‚€�€€���„~pulˆ›“‘‰ƒ�|sjŽ�žšŸ¦‘a\SW[\\]]]]^_`_^_]`am{}ˆŒ’™˜š—��n]Yb ž–�j[T^d€uITSQPgcZv™�““‰Œ’¡�YW^\[]]^\]]\\\]]]]]^^^^^]^]]]]]\]]\^]^___^_`abceffffhijkjiheeffffefgghijijllkllkkllmmjjjhhgfggggeghijlmnnorstwxz{||{{zywwvuttrqqqrrqrsqqooonnmmlkkkkkkkijiiiijjdbcbe�ƒlm…Œ—ž¡“ŠŽ––�|x…‘Œ–•“—ym‰�’‘�ŽŠ‚QONN°ÝØ×ÕÝÂtsrprrqqrsppsrqtsqqsrrqt}}|‚ƒƒ…†ˆ‰ˆ†‹Œ‹ŒŠŠŒr)9<(#_xmyŒ�“’ {T^]]]]]]]^]]]]_^__`___^```_^]^]]]\]adeddeecddbbaaaabcbcb`aceegfffedcccccedfggghiiiiihihggffeeffghhhhijlnnooonomooqrrqqqppqqpppqppppoonmnmlllkjjjigfffhiijldbc`‡‹�‡Š––…o…¡‚ˆ�‰Ž‘—�†�•‹�‘ Ÿ‹ˆ™•‡›lIONME„âÞÙߪlrqpoqqnoqmoqpoqqpqpqqpoqqswywvz}}��‚…†„„…‡Š‰††ƒ‚ˆ‰~LAwu#806jO9WM,P|…‚‚€‚���ƒ‚€ƒ~msok��‹…ƒxqq{‚¦Ÿ¦©˜§¨¤aOPQSUWXYZZ[[[\\]\][[XYVPPMPQIGJKIKMUYZZXWTRPQPLISo|‡„�Š`?=::d…‰‘Œ„†�“�kU_\]^]]]^^^]^__`_``a``abba``_^^_`bcdededccbaa`aaabccccbcefgghgecccccacccddeeffghiihiiiiggghgfhhiiijllmnnmmnnnnoqrtsrqqqrqqpppopnnnlllmlmmmlkjjiihhfhjkklldbc`…Ž�–˜˜——�xw‹€v‹£�ˆ™Œˆ–˜�„‰‚ƒ„~sަ›dLOOLGWÂáÜÞ¥npqqnppoopooqpprqopqqppoporsvxwvwz|}~€‚ƒƒƒ„„……„……„‚�„Šˆƒt66NQ(;AL] V~}~��„‚��ƒƒumtio‹Ž…‚€zqr{x—¯“}ˆ–§¬�QSNORUVWYYZYZ[\\\\][XXRNRMLMMLIKMONLIQ[YWWVSROORQNW~ˆŽš¤�GA?zÛã•nsqnppmpolnpnnqooponpppooonnoortwwtstuxz}~�‚„ƒ‚„ƒ�„�€€‚ƒ‚‚~}ƒ„ƒ†‰ˆ‚€�‚‚�‚„ƒ~~€}|olpim�}}~wqst{£§§“�¦�š¨œTTUPOPQTUVUXYYXXZZXSMMMJMLKJNQSRNMOMMKJHDMYVUVRPQPONPPLNbyˆfTXB=DMMMORRQQQgaccced][[ZZ\emusgb_\]bghjijkjigdbcbdbbddcabbbeffedeghjjfedcccacbbcddcddcddcdbbbceddeceddceefgijklllllnmnnnopprqppqqqqqqpppnmmnmlmnmlkklnonlkjjiiijjjjijdbcatˆ€djcx™‹”¦œ“Œ�©–“Š��{‡’zt‚•˜–™ˆš€MLNNIGB;D©ê˜msrortnnpmloomnpmopnmpoononnnmnppsxxwutvy|~~}~‚��}~~‚‚��€€‚��~}‚‚ƒƒ�}}|z{{zklnhv~xxuqpqx¤§�•™—››Œ”–VVYSMOQTUUVXXXYXZYRLLNJLJMLMQRPMMONLLKKJIFLYVTUROOPPOPQOQltmyyK>BGOMMOQQPN]fceg`b~Š’—˜¦¯¹ÄÅ¿ª¥ž‡e`ikkjkjhedccdddeffcbbcegffeceghiifdbcabbbbbccdcdbddcdccdefgddeddfffffhikkkklmmmnnnpoopqqqpqqpqqpqqomnmmmmmnnmnnopponmljjjjjkjjjjjdbccd}ˆz�•osš‘’Š‹‹qz|“–”ƒ‹’› �…š“ŠŠ�ONPNIFCA:]Ê£jsqqorqnnonopnnppmnpmmnmmnnmmmmnomorwywvvv{|{z|~{y{~}|}~}}~~~}�~~€}€�}}zyyxywwvzuhkhi|xsnnopt˜ž¡¡›——œž–—€KY[[LNORSTXVTVWXVOMNMNIILLLOQPNMOPMLLKKMIFDKXUUSPPQPPOJLNOYvprC<7*B€oqqpppnqnmoolnnmlnnjmonjlnmllllllljkkigmuuppoqsvtsutuwwxwxxwwyxvxvuvtsutstqpqrppqpgehiplefhhŸ´”¬­�Ž¥¥œ�›�•€GKH[aIMMNNOOPLHKJJLHKNORSQQQPQQOPNMLLKLMKLLHFBGTUQPPQOIUe€xpowvn†�YEEV[JLMNMKJMKJJJNPRPQNPRQQPNOPMLKLLKLKKKJJKGECAQTQOU[VOROr�z|niluƒxbTdQUx|v`gilmllmt‰±¾¡¢ ™”¤½³¨«Š^ep˜Ò¯pqqponmmknqtwxxuromjhgfeefedeeeeeffgghiijjhhihijkjjklmnnpponpqponmllkkjjjjjknmmoppqqpnonnmlllllnnqttrrqpmlllkkjjihiikjjkdbccev�‹‡…‰Žž‹ŽŸ“��‘–ƒ€–”™–…Š‘¨�ysœ“^ILIIHE@;<716/_{nqqqrpmpnlmpnmlolknmkkkmjijllljkjjjhhhhgfhmuxrpqqppoonprstvursrppqqoopommmmlkid`adccd^sº©£¨®¬››¤™Š¨£’‚–«b:@IE`KJKIJJLJIHKMPPPPMOQPPPOOPMLJKKLJKKJMLMLKHDCBPTPOOQRQOZ{‡„mfixtpeKUOPjeefhlollniccgcc{©ÂǸ§Ÿ¥µ‹Zebz± rqspoqsttvwzzurnljihgggfefgggfghhijijkklkjjjjklmmlmnppqrqppqqqmmkiijjjijjkmmmnoopqrqpnooonmmllmoqrsronllkkkjjihffgijjjkdbca„…�—‹”œ�~}~�œ••‡ˆ�†ƒ{ƒˆ€t~�—ukˆƒZGFGHGC@@:4.41#]zmrqpqompoknonlmnljmnljjmlikkkkjjjjihhhhhhghjoqrsrpoonmpopqoonnnnopnnlijjiigfd`a\^^aie‚³«§§¥¢¬¡Œ¥’Ч¤›u¢„>CDBDIBLIJHGGIJKJKNMMNOONONMLLLJJHFKJIHKLLLLJIGDBBPTOPQPNPW[k|�zhdjvek]@OQTfbcejknnnnpnklkn‚›±²«ŸŸ§¦…\eco¢ rpstwy{{zwwvsqooljjijkihhhhhhiiklllmnlmlkkjjkmnonoqrrtttrqqoomkihiiiiijjlmlmnnopqqponqrqpnmllmpopponlijjijihggfffgiiiidcca‰�†ƒ†�••”’Šw~•œ˜ˆœ�¡¡vg“£’›—ž‘�_GIMKHEE==73/52 Yznpqpqokoqlnopllnmjlmmhjllihjklkjijlhhhhfhhgghjmnppppqolkhfihggfghffededccba_^[Xafine�°¤©£¦ž™ªŸ—¡‘˜¤ ’€™ID>??K=GHEEGGJJKKJJJLNOMNNOMJIHIFEDFKIIKLKLKJJIGDBBNROOT\YROPelqa\lx^nICRW```agknppppoollhfuŒ–¥¤ œ–©�Yignª·‡tx}~€€~xxvutuutssqnmkjikkkkklmnnnnonmmlmmlmoqrrsttsttropolkkihhhhjjjklmlkmnnooqqqpqrsrqommmmoonllkiihhggggfefffghjhfccc`~„€ˆ—š›››š�Š�‰Š�‡€‘ˆ‘¨‘u‡•™ƒ�«œuVNMLEEEB>>98243" Sznoqrppnmpnlnonkmokjlmlhjllhjkkljjkhiiigggggfffghhloooqpjjiigfeeedddbcaa`]\Z[_eijkni « ¢¦ ¤¡˜¥¦”¥˜•£˜wž`<>=AJ@:FFEGIJLKLLKLKLMMNKJJIGHGFECDEKKJJKKKKKIHFECBMQPQYb[[^TLXus\gumZi9JX][^_diknpqpoonmlkjp†�•›¡¡¡¦pWiit›£’{}„ƒ‚‚{zz|~}||{xsonllmooonmoprqooqoonnnnprssssrrqqqonmkkihhhhhijjjkmmmlmnonoqqrsssssqonmmmmnlkiiigfgfggffffffggffecccaŒ�Š�|{‰•˜“Œ’’„|‚~ƒŽ‰‘™‹s€�š‰p‡hMPLIFGE@@<:7.61#Hzpooopqmloolmpnjlmmiilljhjlkgijkjijjjiihhfgggfgggfhhknnnljhhfedb_]\]\[]\\]cefijjllr§¤¤¡¢£¢Ÿšš™¢�žš� Ž�z@E6W\Y\]^dgkooopoookiiopy‘™˜œ§¼¯aYfkpˆ¿µ”„…††ƒ�€€ƒ„‚€~~{wsqqqssrsrqrsstrrsqppppqqrqqppommlmmlllkiiijjijlllmmoommmmooqssttrqppooommmlkjhijgghgggffffgffefedccd]¥±•‘…€…†€…ŽŒ~�˜¡ž‰Š‰„…ŒŸ§‡…zsl€_HJEHIJHBA>:6.31('"!>vtnppppmlpomlmolknnkjjlkjiklighikjjjjjiihhhhhhhgghhhihhgeeedbbb`]````decfhhglllogƒ³¡¤¥�¢ž©£š�™™  ˜’ž–‚CI<7M@A:?FFGIJKLLLMMNNNLLFFJGDE4134?GIKJKJKJIJKHHIDCBIPOPNNOFENNSgbVdsNoXK^XZZ\`ejmnoopnmmkjix……™Ÿœ£±´¤aZhnz§¥£©‹†Šˆ………†„�~~}|ywvuwwxwvwuuvuuvtsqpqrqqppmlllkjkjlmlmlkkkllkklnnooopnnnopqstusqqpooppomkkjiihhihfhgggggfggfgffeedcd_Œª¡œ”„~‹‘‚‚š�‚ˆ€“¥ž�’‹—І‰wux‘MIOLJJFB??>94)2.&'&&$5pumpppqokmpmkmnnklmmiijkjjhjkkghjkjiiijjihjhhhhiiihhkhhegfedffddefdegfdhigkllmnh”¤¥¤› Ÿ ›Ÿ¡™Ÿ—•™�–ˆžŸL?D;K@A@:@EFHIKKKLLLLMKJLIGACI23FA:31BNKKJIHJJIHHIGEBCGMONNNDINONV[LRg]SaH\UYYZ_bhklnonlmnlilsz…���‘—¯Å¥]Vdlt‡¨Á¿”…‡‡……„�~~~~|zyzz}{{{zxwwxwutqqqrrqqnnlkllmlllmnmoonnmmmmmnnooopooooppruuusqqponommkjihhgggffffffggfffhhgfeedcccbn†–Ž–ž‘{w{|ƒ—ŠŠ‹z~}€�œwd_|ˆ‚†–jGLJFHGEDBA@93*4.##""!",ewnoppqpmlnplkonljkmliilmjhikkjhhjkjjijjjiiijhjiiiiiighhheegfeffffhhhiiihmnmmloª¦  £˜›¡ž•˜ŸœŸš——›œ�œ`;?:KB@@>:AEFHHKKLLKKLKKJM7G=,@FF:;.:MJKHIHHIIGIIGFDCEKMLKEJNOOPQQMVYOTKWSWWZ]`gllnmlmnljkkltyŠ�‹ª°¬ ¬©XP\cs‹¡«º«•ˆ„ƒ�}|{||||||}}}{{|{{zz{zwuqrsrrrqnlmmooopooooqqrpoppqppppppqqoooqrqsuuusppqoonlkiggffgffefffgffffggghgfeeccccbglyˆ•”“…ƒ�‚qt„„‘”‘ޕІ�˜—Š‹�§‰WKIIIIFACB@>63(6." #Tuoopppqnknpnklnlkjlljgjlkihijkigiijkjjjjjjjiijjjhjhgkjhhihhfhhfghhgjkilonnog…ª¡¤ šŸ¡›Ÿ¡™’œ ž—–’™œ q:B7KB@?@=;BDEGHJIHJJJLKJP8,FDH;+.17JL4>NHJGGIJIJIHHGECEEHJICFMNNOQPMOWPRSURWXZ]_bglnnnmnmlllkhlz€‰‹��£»¾¢pYW]bnƒ–§‡Žˆƒ‚€~|{yy{|}~}~}{z{|}}}|zxutsttturpppprsrrrrsstuuuuuutsssrsrqqqqrsssrstsrqoonlkjihgfffgfgffefffggfghfffeecbcccbzƒŠ…€ƒ��‘”‘�Šz€‚‡|{ˆ†“ž›�–Š‘pHIHKKFGEDD?<51'20%# ?otmpppqpmmpnklnokjjlmhhjkkhhiikkgigikjkjjjjjijijihlkjhijifiiihiiiilljnnnnohž¨�¨ž£š�¤™™Ÿ–’œœ™�—“‘�Ž>A8JC@@?><=BDFHHHJJIJJJKKN/;KKKE:3/"(1DMFFGHHIIHGGHGFFEDFF@DMONNPOMNNONJUSXZ[]^adfjlnmmnljjijihrz…�®­¦•�…{VTUJMhLKr�…‚€€€~}|||}||||{zz|}~~|ywvvvxwwwvuuuuwxvvuwwxyyzz|{zyyvuuttrrrstssrqrrqoonnmiiihggffggggfdeeeeffffffdddcb`bccb}rw…yq“ƒ„‘š“€{„‡�‡‚{€�‡„��|SLLKJEBEFE@@>83$30(&!-`wqppppqnkmpnklnnjikmljhjjljiiikkiigijkjjkjjkkjikkljikkhhkkhijjhllkkoooolu¬§£Ÿž›¥ž™ �•š™™˜™™•—•‘‘KC6GE@@@??<>BCDGGHIIHGJJGIK,%%%=<@BCCFGGHHHGHKHIM>2/*8K>.;?+0FHIIIJHFFFFFFFFEEBACFGHIIIIHFGGHLRRVWZ_^`dfgghghihiiifkrq‚‚}cjz�—�gKAB?=XS*?}ˆƒƒ‚‚‚�€�~‚€�€‚€}{xwx{|}}{||{{|||||||~€‚����€~}zyyxyvwwvvvtrssqpnmlkkjiiiggfeeecbcdcdeeeeedcdcaa_^^]accax‹ˆ~z†�||z}ŠˆŠœš‹‡„Ž�€s}‚ŽœrJMJGFIGHGB<=<8+"42##!$$%$%$&$6etpopoopljnonkikmkjiklkihiklkihgjlkjihhhijlmnmlkmnnmmmkkmmmjmmllppnpom�—®¤Ÿ¤œ œœ™�š’™�’—œ›’˜”™o99AI?A@@>>=;;J?A@???>==AABDDDEFFFHHHIHL-&+ 9PJLIFGHHFEFFGEEGGEDDCCDDEDCDDCEFDFDHMLUVX[^_bcfjjjiihhheiihhaSMO\N59:\�‡_@IO€¤lE€‹‡ˆ†…ƒ„„��€€�ƒ†‡†„ƒ�€}|~�‚‚‚�€€€€�€�€�€���€~||zz{||{yzxvuttsqpponlkjjhggfedccbbaaa_aacccb``^^__^^\\\acca}~||††€r~‰�‰z‚�Š�Œ„�‡–¡�uaLMPLEEIGDFB@@65/(72&%"$%'())*'$9aspooponnkjnnmiilmliikkmkghillljhggijjjikiknmnmjlmlkllmkmnomppopqk�©¨˜�£™˜ –™›–• œ��ž—‘‘š��ŽF>7K@@@@???=:=ABBCDCBDEEFGHHIK3&('57FGFJKGEGFGFDEFEEDCCCCDEDFEFEDFEEEGNGNSVY\]`ddfhjkijgddgfgh]MLROJA?FNKzË£WXs�Œ‚Kw•ˆ‡‡‡‡…�†…„ˆˆ†…„„…„…‚��‚ƒ„†„„„‚��‚‚�€��€‚���€~|||{|~}|{yywvvttrqppnmkjihfeedcdbbcaa`_`_aabb``^^^^]][[[Zacdau�„�„ŒŠŒ�y………tzzu‚š•ŒŠvy��qGOOFDIJIEE@9<61/'81 $  #$$'('(((*%+Kktponnonnjjnolkimmmjijkmkjhhkkkkkkijkkkmnnmklnnnlmnmlknomoqqpqpk ¢›£œ–ŸŸ•™™™›–œ˜’š�šž�Š””•Q:5IB??@??>><;?A@CCCCDBCDFGFGGLK=,20HHFFFGFEDDFFFDCDDCCDDDEEEEEDECEEMFGMRWX\^`bbegjljfdeffheUHLPLB<>LW\Yc¡¤”•Ÿ�ƒ�yƒ•�‡„‰„„Ž�€v{}�‡‰‰‡„�ƒ„…„…………„„ƒ‚ƒ‚‚‚€€�‚‚‚ƒ‚�‚€‚€}|}}{{yyxwuvrpponljihhffedddccccbaa``_``a``_]][[Z[ZZZZaccb|‚†‰‚�€Ž‰p}vƒ‚{ƒ|jr„v†�wmiNHNJDDEGGBA?=;:60'92&$$"$%&'()*)**(%6YpsnnoooomjknnlijlonkikkmmjigijkmmlmmmlllklonnlmomnlnpnnrrqpsiŠ¢” ˜¡¢˜�ž•¢›™™—�’–›�ˆ¡•Œ‘ h84FD?@@@?>>=<;>@@BABBBCCCEDFGFG@118&+EBCFHGEEDDCAABCBCDCDEEEEDEEEDELKDHKQVY\\^abehigeeeffi`NHKKG=?HV``[Z[n�°¨˜“”Œ™‰“”¢˜…†�…|{}{yzz{|}„†ƒ€ƒ…„ƒ„„„‚‚‚‚€��€�€�‚‚�€�����~|||{zzyyxvvurpnmlkjhfgffeddcaba```^______^^]\ZZZYYYYYZbcc`ŽŽ€wŠŠ‡�€‰�‚‚{ŒŽŠš‰koƒ‚ŠŒ…vLMIEGFFHDB?B><<61*70#%'" !#&&&()))***()?arqoonooonjknmljiklnlhjiklmlkiijhjjikllnnonkmnnplmppnqqqqqrj˜­¢�›Ÿ ¤�–Ÿ�šš�——ŸŽ”—Š‰šš„ˆ‡:5AI?@@???>><:?AABBBACCDEFFHK&06DIGC>=BDBCCCCCBBCCCEEEFDEFEDDHURDHKPUWX[]`cegeeihffeYJHHD>@??@??==<:==<;9;>?>?@@@BBBDDEDDEFD'$#7MMGDEDDDCCCCDDCEEEEEFBDLNST^JDIMQVXYZ[`cdghgj_MEGD=9?CJPMHJJR[`Zf…•§µ±¸´£ ˆ{ˆx—�’‹vwsiiigbbemswts~„†€vqrsvuutsrtttvuvvz{||{ywvvxwvtssqomkjiiigffdca`_^]]]]]]]]^]]^^^\[Z[ZZZYWVWWWWYZaccbwˆ“•‘�ˆ†…‚{}zxzu†–’~xy‚‚yVGFFIIIIGFBA:<<961'36,+'$')+,-..-*(&&'())(*+,-+(6Tlqpnnnooonjjkmmnkjimnnnnlkkkjjjlklnooomlnppomqqrrrrraœ Ÿ�™Ÿ§Ž�©¡•‘Ÿ£•”�––•—–“™…‹™Ÿ`44EE?@???>>=<;;::>>>?@AAADCDCCDCDDEG-!8<8GDBCCDCCCDCCEFDCEF@To]HTVZQBGLPRVWZ[_bdghgWGBD>;:?GKNLILIFEIW^Xsžº»¶ªº½ª¢qqi—€‡�jcaceabedbbdhjgku€†�zqmmpqqpqoqpoqtwxwvuutrttrrrpolhgfffffededb_^]]]]^_^_^^^^^]^^^\\[ZZZYXWVWVWYZbcca}‰–‰qw�—™„z„Ž•�ˆ}ouy��‡uŠŠSGHKIIHFHF?A@><833*54-+'$&'*))*,-,.---)***)*)*,,*);VmqonnnnnnnkikmnnllkljlnonpnmonooppmkmoqqpmprqrrrsqI{£šžš–›š�𤣛ޔ¢˜•Ÿ˜““••“—Œ‘œ|10:K?A@??>?==<;;9:==>>>ABBCCCDBCDEEC)'##-+)GHGEBBCCCCDEDDGEC]•’lEPTYUBEJMOTVV[_abibOEEA;9=EJMMKILKJKHABPXk«¶³­«¬¦œ¨„lvdnŸsrc\ZUTTV]]ZUURXdfefmx€†�ukefilkkjjnqsssqrrppopppomkhfeefffdcdeda___``bbba``abbabba`^][ZZYXXWVVWYYYaccbo{‚„‚z~ƒ�†‡—†zŽ‘’…‚„uw‡~nyLIIHJKEFGCBC@>:=4/%351/%##&+.,+,+,+*+-+,-.+,,+**))&):Ujrponnnnoomjjknonnlkjlkmmmmllllllopppomqrrrrrqr[Ae¦››™—˜™�˜–›Ÿ¢–“™›”•�•”˜“”“‘�‰@3)JA@@???>>=<;;;:9<===?AAACCABCCCACGD!%&%)(:AGFEEEEECFHDD]�”�…PGOT\E>EKMPRVWZ_bZIDC<:;BHLMMKJLJJJFIGA@IVz¥¤˜¡®¦“�¦vunT}�ue]_\UW]]ZYYXUVYagkf\^iv}‚~o_ahfgilmnmnooomlmnpomjggfeeefedbcecbaacefffdcddfegffecb`_][ZZYYYXXYYXYbcca‚�vv�•›—�•™zy~‰ŠŒŠ�Ž‚€xcLLEEGCFHFCAA==:=2*%,83.&%(&').//--+*++)''*-.+*,.,-,-**8QgqqnnnnnoonklkmmnnpoonmllknooopqpomnqqqqqrqrbHDO—˜›�–—™œ™˜•—˜™›•’›”�˜•–•”’Ž‘�J:,?G?@???>>=<<;<;:9;=>=?AAA@ABA?@@AC@C:).$* ,2D?CB;EIBH„”�˜““`@EL\M9BHKNPQTZXNDA?:9=DLMLLJKMJIKHHIJIC?FNj�– ¡�~ˆ�‚x~YVƒl_a`^_ZUT\c`]YVU\cggc^]]dp~~e\dfgijjikllkkjkmomjfefgffeddbbdcabccefhhgfffhiggffdcba`_\[ZZ[[ZYZYZ]ccd_�ž…~ˆ„ƒ‘…’™•š‹‡€wvŽ‘}ƒ‰tJKLIHHJFDB@@@><:2+%+50/'%**,,*+/00/-+,--+'(*-././../0/,+5J`mrpnnnmnopomlkjlmnppoppqqpommmnprsrqrqqshJHFOœš•™�›˜——˜œ–—™™š”‰˜˜“™–��–‘�—]232K???@?>>=<;;;;:98:==>?@A@@>?@@???@ACE=<502 %0&#+GJ?Q‘–Ž“�“–sACDUY8><;;;<;:979<==>>?>>>@@>>??A@@CB@C<9)&#"-DJ@a”›——’�Š�{@>@CXD3DJLKIIJKKIKJHJIIJIHGFFAAFScqytmXy�joW]dcmXTURMPTQQX]agf^WZ\[ZX`jjg_hw]cddeefggfgkmmihhffhhgedb`_`__aadddeefggggfecddeedca```^]^^[Z[]_cgdcca{†–’“Ÿž�ˆ—�Œ„ƒ�‹po‚su��’–jAIKEDGFIFAAB@=9740)*2,,'&*,+-./010.***+,,,*++)'&*,,-..-,,01/09K]kpqpnmnnooopnoonmmnnopqqrqqpopopoaIEGFHDŽŸ–™™–“š–“’•“˜˜™“�””’‘�–—“‘�”„::./K?????>=<<<;<;::979;;<=>>>?>>>>?>??@@ABBDGHCBBIIEw¥šŽ��‘”���U6=>DO6:@CA@@=649?EJIIJJJKJJLJHHIHHHGHGHGGB@@HXbXUa~xljbZ[YnhfefZRPRUTW]^^\XSZaafiggcYZipl`ccbabeggjllkiiiihgfdc``^]^^__`aadddefgfedcccbbbbba___^\\\[]^abehdbca|gsys„…nq|ˆŠ�|w|ˆœ ˜•…mrhIMHFHIIE>BD@9::83,')//,%&#%*/1110111/,*+,-.,-.,,,+**))*,+,,.0004?NblqrppnnponppoppqrpqpqrqrqprslXGFFGII@„Ÿ––—™“–—”–“‘•˜˜™“”“•—‘�•“•���H56'?>=>?<=;;:::989::;;=>>>=>>?>>>>?@@BBBAABEC@a€„’““—�ˆ‹Š�n7875?84>>A>836;>CIHFHKJJLLLJIJIIIGGHHIHGGFB?>CQX^y‡qarl\Mnyllg``][ZTPPPR\abb__ciinkdNFLYuo^bbcdgijmmjjjjiigfec`_]\\]]^_``abddeeedcabba`_^____^\\\]^_bcdfefdccaƒ}nsr{mj|xcYfrx‰ŸœŽ••’Œ�‰oJGFEDHIBCEA=;;=84/&(120+%%$$&+0233210110/.---..-------//000.,)-1226AR`ioqqponooonpopqppqqqqrsn`L=>CIHGH@zŸ˜–’–˜””“•š˜—•••˜š–‘Œ™˜�‘‘™ŒšZ58/)FB@??>>>=<<<;;::9989::9::;>==?>?>>>>>?@AAA@@@>;\‡Š“�‡„ŽŒˆ‰ˆ|A89518-598448BJV^WGSvbVX€tspkjif\WQMNNRTZagc`acgkecSC>FJQ_adgjkmmnkjkjigfedcb^]\[\[\]_`abcdccbbba``a`^]]]]]]][Z]_`bedcbcddcd`„›¡–ˆ‡upyz�‰x{‡•“ކzŠš””Ÿ�KEFGFJHDDD@;=?:860)(42/.)'$$$&,.0144422210/...--------///.//0,)),14436>IVainpqqsrqqqpqrstrpiXJ@AFA9=CJL@g¤––™“‘–“’Ž’”–•“–”™˜“˜“˜’Œ“�’“s5:3*0I?A@?>>=<<;;;:::997899899:;<=>>>=?>>>??@@??:7:D’Ÿ•–—”‘‘�‹†�R484,82*0169<>BBBDDHLLLMOLHFGJKIIIGGHGGIGIHDB@=?GPUHG[YRdnheekmf_\UPROPQMMR]efehhgd^aL@B59fphiinmljhiigeddcb`^[ZZ[[[]\]_abcc`_`__^_a`__^^\\Z[\^^`abbba^^`bcccax‰Œ…›š¡£˜�zrqu‚vqz…ˆ|{‡€€}NCGKBAAB?BB>;;=94-'%/0-+'$##%#%*-,..2654211010./-,--.-.0-*-..0/,+)+3774226>IPZ`fhjlkkkjfaWLD==?ABGHC<=GIP™›“�ž™’“–’Ž�•••—”‘’˜–˜—˜““Œˆ—‚::41&;G?@??>>=<<;;;::99887899989::<==>>>?>>>=<:526;;_ –—‘ˆ†|{‹Š‹c686+19,,778<<>==<<:;:::99997789999:::;==<=<;98522568@@‡•ІŒ’��•„‰{=76..:3+.57:;=?>?BDILMJIFBBB@=31238DHGGGEEEEEEB??BDBJLPLKJMNNNSW\cfc^XTQOMNMTZ`bdgbLNilaW€Š�—‘‰ƒxd_^\[^addb_\ZZZ[]^_`]]]]^^]]^__ab```_^\[Z]aefeba`][YZ\^`ccc`‚‹{xk[i~Ž�Œ‰€}‰ˆ|€~ux|…‚qHCFGDEHFGDA?<=<92-$+4-10-'#$&(&&*..//.,-56553122000/..-./0.---.,.11/-.37898::9;967;==<:;<<=FHH=d¨Ÿœ˜’””™Š†�˜•��’’””�’’‘–““Žˆ•]7<40*+FA??>>>==<;;::::9898765778::98:9988754456778@=a›�“™˜‹Œ‹|��R7:5*962)0579<>?@AACGIIHFD80>+(85.10>IHGEFEDECCCA@A@FGGIJLMMNNNLLOQOPRPLMQRNFCGGKK@?Dlusht��’�’›š€|zug]]^`a_\[ZZ[^_aa_^_^^^^__abba_^]\ZZ[]`bcb`]\[ZYZZ\^`cccaz‚ww‚{…„„ŠˆŠ��–‹„Š€y†‹ƒzƒ{E@KHADCABD@??:782-#*3-+.2/($%(+,,.0/-0/.-36675321100/0..--.00111000121/0257799:;;989=@?=<>>@>>=?CEGFA=?EDS™‘˜œœ—’”˜”‡„�—”‘�’‘”“�‘’‘���”l6<61.'.F@??>>===<;<:::9:98887654578776555545667788=BAˆ�…Œˆ‰ƒ’ˆƒyT654+694/*157;@@ABBBAABCEFFDDB‰�“�˜�™•�Ž•”��’•“�”‘�Ž��ŒŠ‹’•ƒ:<83.-%2F???>>==<<;;;::9:9988876555555655566777789>>?@?BGHJF-/86-!",6'#AEEEEDEHGGHECKC=BFHIJLMMMNNPOONMLLJA<>@?:=GLLKJJknkrƒ‰Œ�Ž�‹‰ƒ†Š�‰Ž‰€~xtma\[[[^_____``caa_][ZZZ[^`bb_^\[[ZYYYXXXZ[^accda}˜¢œ�…‡ƒ~{}}�‰€x|�‹–‹…tjwcAGFDEFCD<@??C>982*#-1+-'$(,.23/-.04554445106754443332111101000////.1222244320-/017;=>=:6658:99=ACDEDDCDAD>sŸ�‘�”˜™•”’�“’Ž���’’�ŽŽ’�ŽŽ‹Ž’H;;61-+$4E@?>?>=>=<;;:::::::988776766677667777889:<@@B†’��ŒŠ‰‹Ž’�Q9<6/;742+*257;<<=>>??CFFB4(!$9,&(&9BBDDEFGFGGFBPWD=@DGIJKMMNNNNMMMKHC<=?=99>CHMNJHQnfbeuˆŠ‰ŠŠ‰ˆ…ˆˆ‡‡…ˆ‚…Œ¡–„qkh][[]^`bb`_^]\ZZ[]^`bb`^\ZYYYXYYZYZ[]^bcccbrqr‚Š�‰‰‡‰Œˆ�|€yr€xyzm�ƒncHGFFGDADBEECA<875- &-/.$ #$'+04642367987552135664455451/012210010110112233466534/368;>=<;;:;=>===;84/-)#4D@@>??=<<;;<;::9::99988787777777777889:;;@D=c•��Ž�ŽŒŠ‰’e9:/&6:641++2669<====>@GJJJI4#,,!2?BCDCBDEFFGJHERUSN>@CGHIJLMNNMLNNHC?=??;9<<882+!(4/.)!" "#).561/.279887630024676.,*(()*+/0003212211201234552456679:;<=>??ABBBBBCAABCCBH�’‹“™“ŒŒ�“”–””’‘�����Š�ŽŒ‹‘�˜n6@=82-,)#2C@??>><=;<<<;;;;::999888778788887888:;;;>DDGˆ‘ŽŒŽ‹ˆŒ‹ˆj5.0).;7530++2469:;<==>?CFDD?+%-0?FFHCBGIHJIERTOPSD=BEGHIKLMMNNJB>>?>;;;60.*)#/BA??>>>==<<;;;;;::99998888888899:9::;;:=BG>`�“”‘����ŠƒN9;7,987520++1347::<====?BCDFH3 *;944BIHKEBpjLPNSK=@CFGHJMONIC?>>=<<=ADDCCBCBB=>=<>>>>?@ADFJBq¥’’Œ‘’’•“‘��‘“’�‘•—“�‹Œ�Œ�Š�ŽF=@>851,))#,@B??>>>=<<<<;;;;:::9999899999:99:;;;;;=ACBI’•Ž���Œ‰‹Šb9:7.3;8652.+,024699<==>=?ABACE8! 1=IKKDO�”wNPOPM>?BCEHJJHB>>?=:<@BEEDDDCDCBAB?:AMITaR^bOCU\^cdfimt„†ŒŽŠƒƒ…€~‚„‡‰…}~ƒ‚~„�Šœ‡wslf_[XVVVV[^^]^_agjjdbcce_htyqn|‚�“„~†}l||pklvnklkVFHGADFDBAA@>>=70-"27*,$ "!#$%).11234783579964689997765676654544442000/.--.0123566557758;<<=<>:W‡”‹~NIQQRC>ACFFC@>>==;=@CEEEDDDDCCCCB@A?8@JTQGNTVDMZ\]]^^][^cis‡‰…ƒ‚ƒ€~�ƒ‚‚ƒ…�€‚�|„ˆ{x|€�‚~vuokjfca^]^afildbc`�–•‘Œ–§£ Ÿ«¤™ž¦¬ª›œŸ†�ztmbLADE>AHCCFBA@=<740,2+-$##"$$&(,1132232/3654656677998964677722476667666544465563342368879:974;==??ACDEFFFFCD‡Žˆ‰���”‘ŽŽ�““’‘��Ž�‹Š�’�‹‹Š�f9A?=;82.,)'$%6AA??=<=<<<<;;:;;;;::;;99::9:;;;;<<;<@@@=]š“’Ž‘�ŽŠŒ‚H:=:+5:866420)).12379:;<<<<>@ACCB7'E�ogƒˆ[ENNTI=@A@><<<<;=ADEDDCDDECCCCCCBABB@:?JIJJKWY_ic^\]WWWVXWZ`jv…‹Šˆ†ƒ€‚„�€ƒˆƒ�‚~{vx}~}~ƒ†�‡„�||ytolljimdbc`‰˜”‰�“Šwp`ck•‰|��„ˆ‹•Ÿ�œŠMBFD?CGBAC=>@;884. +5--+(&%$$&*/3444455679:;9666665533/.,0332/.064434676776368989<;<<>>>>>??AAAABAAA?=>ACCHC„£•’ˆ†Š�•–•’Ž�’“—–“���‰‹�‘Žˆ”~:???<;60/+)'$"/?A?>>==<<<<<;<;;<;:;;:;;9;:;<;;<<<<@ACAG•�Œ�ŠŠŒˆ‹‡W;=<0+:8766420+(.00359::::;==@@A@BC:947^‡…�yu‡rCIKPM<<<::;:;>BDEDCCCCDDDDCCCBABBC@@@:?HJFT[[SSVVWXZZYZ[[afa]ky‡�ˆ…ƒ€~�€‚€€�‚ƒ„ƒ€~{|~~ƒ†„~}~}~~‚„�†�j`c_�ž’�…}qrlp\lrbgjk}‰ˆ’‰’�Ÿ‰JCIDDG@??@<<:83251',5-/+((&#&&%'*05677676567:;<;:9876667777777666766543432412565688:7697899:<=;>=?ABDDCA@@C=h�•’’––�‹‹Ž•˜”“�Ž’”””“”�ŠŠ‰���F?A@?<:61/+('&");B?>>=<==;<<<<;;;;;;;;;;;;<<<:;<<;?ABG>y‘‹Š…‰‹‹��r=>=8&6:8864421+),013469::<<<=>?ABCEGX†�ƒŠ€ssHBKMPE56979<@BBDDDEECCCBCDCCCBBCAABAA?;?EFGRSLJUX_bd`\__UWZSTZ]ZtŒ‰‡�„ƒ{|~…‡†ƒ€€„†�}{{{}|~�}|zyyyzxwŠk`ccft�|ptvtsy�Žuxu‰”„Š’ŒŠ•—Š_DEDDEGB@D@>>887663$+5140)()($%%&$')+/3698898766888:::87754568889787665767778999:9:8678;:=?@@?>?@@ABAAABDEEGBS•�‰‰‹Ž””�‡‡Š��‘‘�����“•’‰ˆŒ�•W;A>?>=:60-*((&##3@A?>=>=<<<<=<<;<;;;;;;<<<<<<<<=<>CBD9l£—•“ˆ††‡�„G:>;,+;88765310-(*001357:;;;<=>>ACE:ZŠ}‚€~�ƒ€‚U9EMNN<169:>@@ABEEDDDBBBBBCDDDCBAABB@@>=@C@OJGGB5@QW\`_Z[WRVPKRGDo�Ž��ŠŠˆˆˆ†ˆ…„‚ƒ‚€~~|{}}~}z{|{z{vrwxzgacbvwƒzmr‰Š„””‰Š…Š�‰‰~‚‡’‰ƒ|[IECHEDAED:89;>7$+4/2-()*++,*****+,.1567889886532477789767534554445466565566534789;=;;<<=;58>>?;>CCE•™˜—‘���Ž“–•�ˆ†‰‹Š‹Œ‹‹���ˆˆˆ–j;C@>?=<;61-*(&&$!+;@?>><===<<<<;<;<<;<;;<<<<<=<=<>?@FAcœyŠƒw‹Œ‡ŠŠY9<;4#6:99754320-').0023679:;<=?A><6?|�{‚�€‚…f9??@@@A@B@BD:v˜�•–•””’Ћޑ—”�Œ††ˆ‰Œ�Œ�Œ‰ˆ�>==;62.,*'&%!$4?A???==<=<<<<<<<<<<<<<<<<<<===ACE@L““–˜–’”‹wˆk>>;:')<8:88653100*'+/1213579:=<856:6d‚{ƒ†ƒ€ƒx@8>DMJ<5899;>?AACDDDCBA>?15615>DAA@@?@A?AIOYXQOQE2.5@IPPVZYRJA775;`ˆ“”�‹ŠŒŽ…�‚‚‚‚���}|}zyx{{yvvvuw}}}…jacbovpv�¦Ÿ’‹|xŠ…ŠŒral€}uqhIED@CFGF@B>@>;;;8AB3#'4/-&!&)'&(*-/13456666655665677686669:97877433145765342498:8779;<<<==>?@@@AA@ABCDEDEEEFGG@kŸŠˆˆ‹�‹ŒŽ�މ‹‹Ž•–“Ž‹‡‡Œ�އ��ŠF?>@B@><<:74/,*'&&# )9A@??==<<==<<=<;=<=<<==<<==<=@@CBK”“‚€‘…|}sŠG>@<3 3<:997653100-((,133346742146:7J†�|~ƒ„„�‚P59=DMB86998<>?@ACCCCD0-=41.14,9BA@@@A?B>*,38=A:)!%5@?:BS[ZUKED?637X|�ŒˆŠŠ‹Š‡ƒ‚…‚���€~zxz{zxxzwwxz}€…iac`‚‡}vhe{“ž˜•ƒi`x‹…v€~�‰ƒmLIEDDGECAB@@>9<;7@B- 28.-*%""%'*,--/2443232334544576667866549;9:989:::89:9889:98977577778:<;:9::;>>=????@@>?AA=Wœ•’“�‘ŽŠ‡„Œ•”‘�‡ˆŽ�––�ˆˆŒ‘‹†’S=C@@@?@><9830-+'&&%"#/======<;<=<<<=>======>ADEBA~‰�‹Š‰ˆŒ…„�Z<><:'"<::998654210/,(*-0243/-1447:;@@ACCCD613-)+,2*3BAAB@>@;$"&&%%$##(8A?88AGIRXNA:2,*'-Eh‹�ŽŒ‡†‡ˆ†…„ƒ‚ƒƒ‚‚€}|{{}}z{{|~€€‡jacby{‚Œ‚~pv�Œ��~q†“†�‹XCCCDDEFCAA?>>===ACDDEAF‹Ž…€‡Ž’•—–Œ‡‰Š�’��‰…Š�”Š…†��’e:CA?@A>A@<:843/+)'&&$ %2>A?=>>===<>=<====<>=====>A@?A>x™Ž†�•‰„…‡‚h@?<91,>::99665433210/-+,../14467:<7[…}‚}w�u?644;D?;88;78<=>?@AACC;/#2238;DCA?>?K_R<*##$""#*64,5@JJGKPK4&"!#%$#:G€‘‹‹�Œ‰‰†„‡……‡†………�~{{yxzzyz€�‹k`cbn„’ދޒ”ˆƒ�~‹‘umo�˜ˆw{cADFHFDDC=BB>C@>>87A;).6+)(&'$ !"#"%+0677799;:;:::9876369887:852122689;<;94676887888899:;9:;;<<=>@A@?>@BBBCBDEFG@‚ ––‘�Ї‡Š�“–‹€‰’�‘’‘|w“’І‡’{;BAAA@>>?A?:874/,)('&%#!'5>@?====<=====><<<===>?>@AAAC?2@H@=?FMU\\adYB0*..)++*,+:@:GJ?6($" #$'.u”�Ž��Œ…ƒ…†…††„…‡ˆƒ~~yxyz{~ƒ€ƒ‹j`ca}€�‘ƒx†‘~wxyvzs�ƒw~}[HMFCHDBBBFA?C<:;7:;2(49-+'&)(()(((&')-330++/123669;==;:98969844898:;>:298779;;<;;::;;<=;:;;;;;<;9:67:;<;<76/.+((&&$"!)4=@?>>==>===>=<>====@><5:<;::986665443333334556789;<8i„}~x…„ƒc861/29=<97:<98<=>>?@A@BD<+%-5KWXMD1(/;Qa`WSJB@C>301+:E94/**% 'q’�Œ‰†„‡‡†„‚��ƒƒƒ„‚}|~}}}}€€�ˆjaca„zj€‡‰ˆ„†Ž‰‚‚„�Œƒ…y…‰mKIF?EFADDDB@A?;:<<743*66+1-),*+//13465420/((/33344345558;;;;996387347744;=8188:::9889;<<=>>>=;;;;;<?>>??@ADD?T“Œ��Ž‘��‹�Ž€‚Ž•’‹ŠŒ‰‹�‘ˆƒŒ‘†‹N:D@A@A@?@>?@=<86/0,))'&&%!!&2<@@>=>>>>>=>=>?>=>A=@BEAL��Œ��‹‹‰„…Œg>@=<9-'=<;;:9976665545556678788::=9M†||}ƒ|yI53..17=;:7:;98<===?AA@AD=0 IfaUE;84&!(4DTYWXYUND4/@IA92(%,) 'Z�‡ˆŠˆˆ†††ƒƒ€€€‚ƒƒ�‚…€€ƒ‚|}~€€‰k`c`‡Žvqs|ympyz‚ŒŠ{lv€„`EDCFDBCHED?BC>@<@=168)02+($&&%')+,-/131.-1224678887776420.1589877:7468798:917997653/0677::;;:9;;<;<=;<>?@BCCABBB?D‡‹†ˆ†‡��“Š„––‡~€Ž”�‰‚†Œ��ƒ‡Š“a8@DB?AA??@>>A=;;733-+))'&%"!!$.8>@???>=====>>?@>?CCDDC…’�ŽŽ‰Šˆ‰‹ŠzH@@><4#->;;<<887777666677778789;;==;97:;88;=>>?AABA?BMYTa^ZVLGC9% #0CQTVNFJOTQH?2*# #$  "!#'6yއ‰‰Š‰ˆ††††…„†ˆ…€€‚‚ƒ�~€€‚�ƒŒl`cavŒŽsqwicjdm�‡‚{Š‘zjjvOAAHF@EGE?>ADB:=>97574(,4&$!#"$&),./00134687887878999:9:91-**.02458:;:7794335:<<==>=<;;89:::;:9;<<==;:>>?=AC?@??@>=>@?<;:653/+*)(%%%$!#(/8=?A@@>>>?@@;:>?@BF?p‘Œ�Šˆ‹ŒŠ…‹‰U=A@A<02><=<:9:899877888888889;;=:97:=:7;=>>>@@BMZnpHSWJ>4,*)%###!$/?JGPYYKBB/#!"$!"#$$'(ZŽ‹‰ˆ‰‹ˆ††‚�ƒ‡‡ƒƒ…ƒ€‚ƒ€‚€€‚ƒ…�k`caw|yty‹‡x~�€}lpz…‡ƒ€YAEGHFFED?AHHA:;@>8:534)+3)**(&#$%)../2679:;:;:;<::9999:::;<:731.,-0/26766877;:8457579:;:=>==>=;89999:;;?D@??@@>>>?><:;9762/-))'&&&%$#$',26:==>=:58>>?BDE@b•‰ŠŠ‹‰‰ˆ‡„�k?A@@<4(3>=<;;;::99989::9:::9:;;<>;G…ƒ€|z~ˆe66,**)6?<:988<<:9;==>=OipttL=C8:1"%&$$$"!)>LLA>A?/!!&%%$$$'%;��‡ˆ‹Œ‰ˆˆ…†…„…‡‡‡ƒƒƒ‚…ƒ€‚†ƒ‡�j`ca{~|„‰ˆŽ…w|{yxlnx‚�‹[FJFEGDBBCMI@=:>B@98255(/6,+('%%&(*,-./1232468768;;985468:<<6;>;::;;98:;<=<::;;88;;:<;:98999799=>?@?@><<;=<:<:;?ACEAP“ˆzx‚Œš˜‘ˆƒ†�‹Š�‡p�”’�‘x”‹‰�R:BD@?AAA?@@A?>??<<<:99520.+*(('''&%$#%()--028;>?@AAD@U’Œ‹‹ŠŠ‰ˆˆ‡‰yFACA@?7)4>?<;;::::9:9:;::;;:;;;==>;:8869;:::9<;Aevuy^/'"0<7( "####%')+,//-)!!'&'$!$&$(a�Œ��ŠŒŽ‰ˆ‰‡„ƒ�‚‚ƒ‚‚�‚ƒƒ‚ƒ…„†Žk`cbvr~€rsy�ƒ~xyvn�™“„„sMEDBDFDBCGF>:<>AB=98:70'37)+%$'(*,/02466432233341220,**./026568642471/4897899984456899:;?@A@?A@??>>;<:9876521/-****)**++++.39;<=?=?ACCIˆŒ‹‹‡ˆŠ‰ˆ‰ŒˆT>CAB@;0"3?>=<;;;;:;;;;;;<<::<<=>@9Z�„�€}€�|uY85.)&&0?=;:997899:;:<:Svxyi3$14) ""#$##""'(#  "%&(%"#&%#B�”Œˆ‹�‰ˆ‹‹‡‡‡†�~~~‚€~ƒ‚�„‡†Žl`cay�—œŠxr‡ˆ‡€‡š“�{po\@BCFGGGDBCCDB@CA@>97875&04)'$#$)))-.012342234715::9864420.+153334/.685359;:;:9884119;;:857889;=>>=:8557835<>@?ABCDDC9Z‡ƒ�““†ƒ��‘•�…„ˆ††Š‰†ƒƒ†‹Œ‡ƒ�v:A@@@A@==?@@@A@@>>>=<;;:9878533200/-../1237:==<=>@ABC@‘†‰�Œˆ‰ˆ……‹i@CBA@@:/ 1>?=<<<<<;;<<<<<;<<<<>=>=:766;7(+3*'##$#$'+.121./10/2500666786689:889;;;=;<;;<;7789:;;<<;:;<;=>>=<<<<<;:;;<>??=863:=;:767=??>?@??@?><=?=;;::::78766644456798<=<=><>?BC?lŒ„ˆŠŠˆ‡‡‡††yGCDBC@=:, ,=@===<=;<<=<<<<=<<;==>?=v†|~ƒ��€|}c86,&'$)=:8:886++4*(&)&%(*,010133454369887765512359;;=<9::996247547998875559>?>?>??@?@@<79<;89=@@>>@A?>?@?????@>><=?><<;<<;;;9:;:79:;;;;<=??=;?@BD=[�‰‡†…††‡‡‰‡�T?DDCB?>8*&:@>>>><==>=>===<=>==>?:d†}€€„ƒ�…‚|G72((%"0@=;;::::;;:;<;;_rp`6)&+$"""#""! "&&$$%%&(#?‡�‰Š‰ˆ‡‡‡„‚„„„…€€�„„�~‚ˆˆ†�k`ca„€zsp„—’|ƒŽ€{‡‚t„WEGCFIFADDHDAAAAA?=;;@;53&05()&#&&#%(+.0234236446579;<<<<9875677500566547::;;:;:;:99669:;;9::;<99;9329@;89:<99<;:>ACB>>:w¡‘�“‘�|hhv|†‹ƒ}{{{}‚‡Ž‘‹„…‰•f9A@AA@==>?@AA???>>@?<>>?>=<<<<;;;<<:9;<<><=?==?BA@R��„‡‚ƒ†‚ƒ…‚c@CCCCB@>9,  3?@>>==>==>>=====>>=@:[‰„„„…�‚€~„d98.'$$#5@=;;;<;;;;:;<8Hpul>-%&""$# ! !&&$%%&&($/}“‰‰…‚ƒ††„‚„„…„‚‚�„„…ƒ€€†Š•l`cbrv|‚ur’˜•‰qm}‘›•uHEFEGFGDCEF???BC@><;;>842(/6(-+$'""$%'+.1233455676569:<<====99899:9:<;;;<<;;:;<===>=<;;;:97687541574117>==;98:<=<::<>AF;W€�”‘“”•�ƒ}{tz‹‘�����Ї†Ž�‹…‡q;B@@@B@??@?>A@@@?=@???==??=<><=<=><>97?===?:=>@CAE‡‰ŒŽ†‡ˆ‡„|€‰vFBDDCBA@>8.#*:@@????=>>>>>??>??@9YŽƒƒ†„�ƒ„‚�xF:5*&$"&:?<;<<<<;;;;;:9`wsO-$ #"!!%%#%&&&''&m’‡‡‡ˆˆ†„„‡‡�{x~ƒ��||€€€ƒ‰”l`cav„ƒ“–ƒvwz}Š�‡ur~ˆcEGEFFEHG@GF=>@BB@>;>?:643++5++&$&"%&(+**./1013456687554699789:;:;;::<=>=::;;;;<<=>=<>>=<;<=;>?>=>==;;;8977:<;===?>@@>=@@>@>>>>>=<===<>;8:A?@>>=><@==BBCCxކ„ƒ‰‡ˆ‰†ƒ‚~Q?EDCCCA@=90% 0=B@?@?>?>>=>=>???:\�‚€€€‚‚€�_;;2(&$!*=>;<<<<;;;;;;7Hrwd1%  %$$$&&&&(%e“Œ‹‰ˆ††ƒ…„„€{z|‚ƒ}€�€„††Žl`d_•°¦—‰„€€†qmxv~€…�SGIIJJFC?>EEA@CC@<;:@:7543-.7,(% !$&*+,.//00213445567853465433358:::;;56435776678:=?;89:>?=;::=?>;89:;=<<<=<>==9:<<<=?@C@??@?==@><=?>=><<>>>>=<>>AAF;e’„‰‰ˆ†ˆŠŠ…†Šc?DCDDCBBB>:2(!#3>A@>>??>>>????@9i‘„„�~�…ˆ†�‚zG:6.'%#!-??<;<=<<;;;;;9aytE"##%&%&&((j“Œ‰‡‡‡††ƒ|€ƒ‚‚‚�~�‚~�ƒ‰�k`cbwˆ‰~ƒ‰Š‹�‘~t„…‹ŒoHKIIIHCAACDEB?=@B?>==8:775)+4+,)%!!%(()+/123332223345665678::986676564278796544458:;<:747;<>?=>>>>=;::<;;<<<;?@>=?@@@>=@;g›‡~�…�‹‰�ˆ�–‘‘�‹Ž‘‘‘‘’���Љ€†`A@=>>AA>@?>@B<=A?>?@>?>=>@?@>=@????>=>=?C?BD>9b}„ˆˆ‰†ƒ„„~}†sECDCDEBCA??;4+$ $4>@A??>>?>>>?@:qŒ�wx{~�‚€‚‡b<=5+&$" /?>===<<<<;;<7Jrvb,"$&&#%'&.y“‹‡‡†††…‚‚}|‚…„}|}~}|€„ˆŽk`ccg]]hbPczzŒƒy}|ySCFDDB?>CFCCEC==AB@<<:::665**2(*+*(()+,+...1334454434556788789;;::99:::977999::98779;:99::;:;;<<>=:<=;979=<<<;<<;:<<9;?AA:b‡‰‘�ˆ�…‡ˆŽn�coxqrwwr{„‹���Ž’z;@AAB><@B>>A=B@=?@@??@A?A@=>?@@A@=?@><==>?@@@@B?H��‘‡ˆ‚ƒ……‚‚|N@EFDECDDC?><6/*%!&1;@@@???>??>;^‰„zz}{~ƒ„„zH><2)%$""1?@====<<:<<99avuK$&%#%)%H��ЉЉˆ‡ˆ‡ƒ€„†‚�~}|~~€€…ˆ‡�k`c_’�rtƒƒl`v~u”ŽvoSFHD@ABGGEBDEC>ACA>=>;884622")5*-0-**),/00034465656554444448888678999:;:89766899:;:::;:;<<<<=>=;87537:::;9;==>=>?@=;=<>?AC7:EB?=B@>A>A>>A@;?>>;?>ACAA@@??@>@A@?>>>>?>=>@@ABAC…Š€ˆ�‰ƒƒ……„‚�_BCEFEDCBDBA?=:4-*%##,5:=>??><=?N�„…„„€}€~�€�^=?90)%#"!/??=<=<<<<;;7Mprd*$&$&'-v”Š‹‹�ˆ‡ˆ‰†‚…ˆ‚�ƒ���||�…†‡Žk`cbxo}�š¡š�~�˜‡x„�bEFGDFIGJHDCDDB@AB>>?<;67763- (5-12+(*)*)*+,.158888777676666889:7688898899:;966;<;<;<=<<<=<<=<<==>=;;88;==>=??A@>;=7.16:<>BC>6:CB9AE>?@==>@?@?=A>>@?@C?>@?>AD?<@=@B=??>>>?;94.)&$! !&*0348;@CDx‚y�…‚‚‡…€€€€vE>=8/(%$"!,<@>><=<<<<:AlvrJ#$'$R’Ž�Љ†…†††„…„‚ƒ„�‚‚~|}}€‚„‡�k`ca~…vmkr€„�z„•‡yz[FGDCGGGFD@@B?ADBBBB>=<79;81, )5+-+('&&())++++,/57:;8679:98:::;;=>=<<<=====>=:5422459;<=>>???>?>=>>===;<<===<@;2520220/01141`Ž’�Š…ƒ‡††‡ƒ…‰…Š„ƒƒ…‹Š‹‹Š����tn_?ECB<@@?>>>BBB@f�Œ�Œ“’‹ˆŠ‰††}OBGDCBCDDDCA@@>=;750-*(&'()+/37<=<<<<;=>=9878.- )5&%'''*,+-///...--.148989;<==>=<:6577652121123100.,+,-0242/0158;?@@@??@?@>;;<>??4.8>>??<<>=::\clŽ”‘�‰…„Šˆ„€€ˆ‰‰„�€}z„ЉЉŒ†m8>CDCA9C>A@?@?=?B?A@?>A?A?ABAB@AA?C>>B>>BCF@UŽy‚ƒy„†„‰ŽŽ‰…^@BECDDCBCEBA@A@><:97420/013379>BCBU†…€~z|{vw|}�qD??>91*'%#!%3>?=<<<;<:^unpJ+-  a�Љ…ŠŽ‹‰‡………„„ƒ�~�~}�ƒ~{‚‚ƒŠjacbp|…Š’“……|svyy‚qIGIHDDDDDFECDFDBBA@=???::87.-!(2)*-)$)-,-/21442332/--,,,,/2332340**.10.-0111-/2420/-,,--365679889;;>@@BA@:547794+6=<=>?@@BAMŒ�}tmlmu���‡…‡‹Šˆ…ƒ�‰‘�€o~Ž’�„…ƒ:2ADAB;=C>D=@?<@D=C@>DC@;@??@A>>@?BBAA@???@ABEC>>@E@8Bso„‚xsnv�‡‘vFDEDCFDABBDCB??@?===:8978999;>=82+(&%"!,:?>=;<;;c{rof*"#366+!:�އ…ƒ‰Š†„…‰‰†„‚�€�~}~€€{ƒ…€…Œj`cblw‰’�†……Œ„gZ^eZHHHECEGFFHDDDBACBAB?@>;:764.,)3-+*'(('(,02134457666420/./2330232128;;;:;<;;;9:;:99976878<=><<=<<:77779730121//38=?>=>>?@C>Y������ncbz—–‘Œ‰ˆŠ‰�Šwv…’�{y…Œ‹�V2;ADAB;@=AB>A>>E=>D;CBB:AA>??A>@@?B@?AA@@>9A@=DC7@�‘Ž�ƒw………rfqxPDGEBCDDBBBBCB??@A?==<=<<===>@@ABCAk„�ƒ‚�‚€�~~~{|vH??>=92-)'&$"&1:>>>=??=?;6754/,(3,*,(('%(*012233356889997687789:::9;:;;:;9:<;<<;;<;;<=====>==<====>@>=<9543389433117>@A@@@B>n™ŠŠŒŒŽ��„jh~Œ�ŒŠŠˆ„†‹†rz�“ކ{~„�p66AC@A:B;B?>==?EB>CE;:r…€�yq†‰‰Š‹†{rM>GHHCBECBCACBBAA@A?=;:==?>???BBCDAS~‚ƒ‚„‚‚�}ƒ‚‚`?B@>=950-+('%$*18:<8Ozyuqh*+.59:*" ! E„ˆ‰���‰„…‡‡………„‚€~~€z~�€~}€ƒ„…‹j`c`Š�~{…†‚|ut‡�‘PHHBDKJEDGCDDBC@@A?D?<>:78852. (4*(*)&%%#'+0357656789:::99::967889;;;<<<<<<<;;::<<<=<<<<>>:>==>?>>??????>>??>=<?@??;6^uory�‹Šˆˆ‚c[x��Œ‰ˆ‰Š}‹��r{‰ŒŽŠ‚„pB>C=@??@>><@??><<>@@@A@@BDEDHxƒ}~{|ƒ‚‚€€€€xI?BB@=;940-,*++,/269?o~toqR$'!(<783& %DlŽŽ†Š‹ˆ…‡†††�}€‚ƒƒ€~€}yw}~}}�‚ƒ‹k`cawx}ocq‚|jl‚ˆwaHE@@IHDCBDBDDEFBBDAD<:>977772/")3*''%## !%*/368976569:;;;=<=<;<;<::<=>?>>===;;;;:<==><>><:<>???@??@??>=?>>>=<>=>?@?>>>?@ADtxx‚ˆˆŠŒ�ŒŠƒef‡‘Œ‰ˆŒ†„‹††ok…‡‡ˆ†‹vBAA;8B=?@CCEB;AUwŒŽ��ЇˆŠ‰‰‡~yM9AHFED>BBBCA@A?A??@@??@>@@?@BCACDAg…~|{y~ƒ‚��€€…b?CA@?==:8620/0347:=:[|upmj/,"-4?DGBBO\v�‘ˆ…ˆ†…„……‚„‚{}„†ƒ€�€}|z|}}}~€€‚‡Œk`ca�‚utxxvs}‡|ZFECHLGFCAFEDEC@@DC>@==>:7356-/")3'$#""!  !#%)-/1.++-.-033333431.-145445788::8:<<;:;<<<<>@>=?????@@??@?=???>>>=???????>?@=J‡�‹‰Ž��ŒŽ�‹�Žj_„’‰‡‰„‹‡�q€‰‡ŒŠ‹ˆ‡�R;C@8=D?8B?B@B:;A>><=>=@@@@ACBBCE=A>=DCDEE=6BG„‹����Š‹ŽŽŒŒ†€Y@=@FGE@AFABDB@AA@@@@@@A@>AA@ABBCEAU�~|||{|~}�„€}zuJBA@A@>>=;866678:<>=>?>>???>>@?>?>==?>?>?>?=>>>@??>@=S‹‰‰ˆŠŠŠŠ‹Œ‹ŠŠˆoaˆ–Žˆˆ‰ˆ„q…‘‰…‡ˆˆ�{o?BB?5>B?;@@C;?B;=D=5>C<:=?@>@><;=>?@@@?A@;A@>?@AACCDDCGw�~{}€||}y}‚~‚_@DB@A@?<::9989;;=?==e}vsoh+ (*!@pŠŽ‡‡�‡‡Š‡„†…„„„„ƒ„€~€‚‡„~~~�ƒ‚|z|z{€ƒ‰k`caz€{rmv~|`J[`OHEBECAEFCBCDB?@FC>>?=;;86:8414$&4,((&%#$$%'*,--/0101033433546678:<>=<=<=>?>=;:8632232135878:>>???>>?@A@>>?>@@?@>>><=???>?@<_�‰ˆˆ‹ŒŠ‹‰‰ˆ‹Š‡Œ€fz�‘Šƒ„…x}‰‹‹‰‡‡pp‰E><58AAC@<<>@<@?<=BA>>?@=;<>@?<>;??C?7:<=9A>?DEB7D@?Arƒwc|~whk`qq`„ƒK>EB?BEFACEB@@BA@ABAA??@AA?@@@AADDAh„|�€{||�}x}�„zGBD>?B@?;;;;889<>??;MyxvuqO-$!:w‘�„„ˆ‡ƒŠ‡ƒ‚„ˆ†„„�‚„€}}€€�ƒ€}�}yy{z~}†k`cbs�…‚|yltŠ”lLLHDCCDGHFCCDDA@AFD>>@AA?;::;2104(%4+'&)'&(*,-//001112334456556789:95432232369<<<=<<:6336666530/36:==<<=?@@??<88=??>>>>????@A6?=??9A@<5;<==;??<;@@;>AB@?@>ABD@?F==;::<<=?;=:772423'&2)**'%#"#&)/4556688777898::99<873-+06777753345468::;:<<<<;;;996466665689:;;8324:=??>?@@ABB?r�‰‰Œ‹ŒˆŠŒ‹Š‹Œ����Ž‹‚jl‡Œ‡‡�|‹�tn•j59CA@@>?9A@8B==@9=C;2;<:=:B>;>==><=>>:W{xposN &!"!OŒ‹‡‡…„…ƒƒ„‚‚„‚…„‡„�‚ƒ‚ƒ‚‚‚~}|}zz{xwz{}‚ˆjaccjeez}}‘‹l^lwZHHFFEEACFED@?CBDDCAA?<;;;:66815(&4,*))'#$$&'+,-//.//-/14666456314667689;:<>=;;97444578:;<8/5898:<=>??>>=:887551.04689;;:=ACD�–�ŒŽ�����‹‡‡€~~}‚‹��Œ}v|„…„€ƒ…�‰w~�A9=A?AA8:BA;>=:>>:>C87>BC@=?B>5>@?>>>??CA?=;=;=?>?A?;Es|vorj- ! !#!,q‹ˆƒ†‰�„ƒ„†‚††„††‚‚‚€‚�ƒ†�}~{yy|xx{xz}~‡kacbp‡„~}|~�”‚‚QHJEDEDBFDA?@CBCHC??<<=<;;7446-1((5*(%%%"$#!#(+01000111355454555888;;>=:7446668;==<;998876638<<<:8:;;<;;77:<<>>=<==;976334469@CA@=:>B>7B<;<>7>C?<:=@A@@A;=D9@A=@?>AEDDD<7D>E?=P‰{Œ‰w€…„„ƒ��|xR?DDEDCCBBAA@>?@AABA@ABB@@@>?AABBB>Q||z|~yxz}}||~~rEACABAAAA?=;<;>@ABA=`}utpqP!"#"% OŒŠ‰‰‡‚�€~��…†‡ˆ…‚~€ƒ‚�‚‚�€{zy|yy}zx|{|†j`ca~}{yz„†~��‰hHFGDEFEFD?ACDCCED=:Et}{uoife`]owsw€{~}rp{„‹Œ…wu{ŠŠ„‚‚€ŠV9D:>CB@@;>A9?>6@<@:;BA?<9A@?@DBq‘}y…‰†zz„€||…gCCEGFFDA@AACABAAAA@ABBBA>>A>?BBBBCDq}y}||w{~}}€Z?BACAAAA@>>=<=?>@B<>96655.3+&2-,,'## "#%+-/121/./21112224567446349;<<>><<;:77655467777899989889:9:78;;<<==;:::::<===@=TŽ‹‹Ž‘�‰†‚ƒ†‰Šˆ‡‰‰‰‰‰‡�xq}ŠŽ‹xi}�Š…‚ˆn9?@?<=@AA89A9?;<=:@85;@DB<;;:ADD@??@@>@?===?C@>G??F:{†n�“vn}yx€xuxznGBCDEDB@BAACA@CCCCAAA@ACA@CCDCBB@C>`ƒ{x{~z{z}}|}~~tEABCA@@AA@@>>>??@A@Aj~uqnmO" !!""$##%!K‰…„†‚ƒ„…„„‚€~~}ƒ‚€�~ƒ€~{yz~�}z}yz}„‰j`da|“”’‘’‘„{ˆ“qHJIGEBCEDCBCCB?@CA::?@?<::96342/+%3..,&$$#####&&(+-/035767875666777:;<<<8556544887645798899888:::;:;<;:::<===<;;:989<==?=;=8Q{{}zƒˆ‰ˆ‰ŠŠ�ŒŠ‹‹Š‡…†‰Š…zr|„�Œqo€ŠŠ‡{@=>?A<4>B<5@>8C<<=;>95:?ADD?;?>ADCA???>??@ABABE@9DB@a…Їmq…�ˆ†�††„…}U@EB?ACCDCACB@BBABABAAA@C@?BB@@A@CBM~zxzyz~{{wvz}Z=ABBABAA@@@????@@A>Xwwvqtj4!#"#""#$%%"-rŒŠ„„„…~}€}€€�‚€€‚ƒ‚€‚�}}w{|}|y{zu{€‚ˆj`cbx~€€ƒ€„……|rVBGGECDEFEEEDCABE@?=@BA?:::456410)&5/0.*&$%&%)*+-/./00/1222222235666686444689;<==<<:999:9;;989;;;<<:;;<<=<;;:99::::;:988<>?C?h�‡††‚ƒ��~�~‚ƒ�„‰Œ��Ž�Žˆ€ƒ�‹€zuz‘†yy€ƒŠN:@?=@>:=D@7A>9A?:9;>=;;;>ABCCBA@@@ABB@?A??ABB=>EFD>^‰|xv†€ˆyyk~Š…ƒƒdCDCABDBACCBCECBBBA@@A@@AAA?A@>?AADCfvutvz{z{}{wxz}|rE@B@@ABAA@?>??@@AA?Di}|vrtT !$$##$$%%%!K�‡ƒ„ƒ„€�|}ƒƒ„ƒ���€��{ƒ‹‚zzx||wyzy{|ˆjacb{|z}qis{yrkM@EDBACEDFDA?BAC?@C@?AC?<;87892-0'$4.+,*)&&()*-/0012334424435667888:9979;;<=><9:<<:9;;;;9868899;<;<=<<====>>?>>>=::;<=>==;<<:dxpy……‚…†ƒ‚‡†…ƒ€}|ytuunfbgwˆ�Špn‡�‰„rq[=>=@;;A@9>>9=@=:8<@@A@@@>>?@AA?>@@A@@BBAACFFFCD@Ov…€�‡{x}‰‹‰{„‡uKBEFD@BBBCCBAAAAA@AAABA@@AAAB@>>>A?V~w|€€~vxzyz{y}z|[>BAA@@AA@?>>=??@AA@eƒxxvrk=!%$%$%&%&#-t�Ї‡„‚�‚…�„€|}~|}††}}zuz|~~}xyz„iacayyy~{qlgi~xJCHDCHIEEHE@ADBABBA>@C??<78686501*"4-,-+,&#&"#&)+.002356676777446787545899<=:89<=::;;<<=99;::88:===<<=<=>=>>=>=>=<<<<<>?@x�ŒŽŒ‹ŠŒ�†ƒ||~}‚ƒ†ˆ‹‹‰‚}xqgenz�„tx~…‰b:AAA?==>>9=?9:=<7<@?;;=<;>AA@@A@@@@@A@A@@@A@BAABCCBG††‚x€‰†o€€rƒ…‚|UAEDC@CECDECBBAAAAA?@@ABB@??>?>@@?=Gnutx€€{xw|y{}{}sF@CA@AAA@@@>==?@@@>Nz{xwtr]-!&%%%%&%&!Nމ‚���€€‚€€‚��{~}€|z{xx{z{|zx}yt{€�†k`c`}„uo~‡wy‡uIEFCCFCBHIED@@@DB@BA@=?=:86:85601,#3*)++(&&#""#%*.2322234423443467888889:<;;:;>>;:;;<;:;;;==:78::<;==><;=>>????>>><;><<<;=?=Cy„}~zx|zvv|�‰Š�Œˆ†zx~�ˆŽ�’��†}s…�‡tq‘†A:;?B?>>===;>>8;=::;@@?>AB@<>?@@@@@@A@?A@@@A@?@BBE>D~Š{…Œƒu~„{{sjx‚`BBDFFABDBDDAA@AABBBABA@@A@AA@A??@A=b~xov~�{wzzww{z€\>CAABA@A@@>=>?>@A@@e{wxwrpK)  &&&%'''#2{Š„ƒ……€„ƒ€€ƒ||||~wz{{{}zvvwuvz}}ˆk`ca~ƒ}{ut~‹�‰mEDGECFCBIFB?>@FGBB>>?>?;;86854320+$2*+-)%""$#""$'*,-/1111454445779878889;<<<<;<:8<<>>===<=><56<>=<>>?@??==>=>?@>>>??==>>;;<;K‰�Œ�Ž�‘�Ž‘�‹†€x†ˆŒŒŠ„�~zz{„‡‹‰ƒy‚Š„pvŠX<=6=B@?@>=?<;<====;;==>>;;<=?>??@AA?@?@@A?@?@BBA>DAq„z�~n†}ak„…†�yJA@BAABCC?BBABB@@?>BABAAAA@B@@@?>B?R�wu}~€xt{xu{y~tD@BB@BBBA@@????AAA>S{zxvuui<)!&'%&(&&$Z‰…††~ˆ†‚}~‚}{{{|€}{zyyywuzx{{xz}†j`cbw|~€‰p€†qRCEEBDFAAFD@>@CGDA?>@@A>>>:986570//!3++-))&$%%&()*+,-010/1234424554456788::::<<;====<:;==<;;:8<@>::<>?@@@@@>>???>?>>@?>=>@@@;M}�€€~ƒ‡ˆƒ��†ˆ‰‡‡‰ƒ‚��‚ŠŽŠ†ƒ~|z{ˆ�u€�|oZ=C@;6@>=<:<==;<<==@>:;=>>=>@?A@?@@>@B?A@@B@E>n�vŒ‚m‹}fƒˆ„~|uhlRBFEDDCBDBBDBBABCA;?AAAB@@@@AA@@@A@Es~zzuwz}hjwxxw|z}[>BB@@BC@@A>=>??@A@Bn}zwtrtU2-#%(('&(#?€ˆ‡„~~‚�„ƒ~}‚yx~€}~€}~|z{y{{twvy|�‡jaca…‰‚|szwmkSCDBA@@BFGGCBDEC@=>@@@@??>;:7466,.."3(-0+(&%%')*+-/121345543553344455778899;<<==><<==>>>====>>=;:<<<=?>>>=@BABBCA@AAA@??@?>?;\Žˆˆˆ‹��ŒŒ‡…„�ƒ�„†‡‡Š�Ї�{}‚‰��‰eu‰Šzs‡Œc6ACB>99?A@?>><==;;<<=<>=;;<=;<=@@?>?A@AB?=ACBBCB@C>d�oŠ…nƒˆm€…†jZ{rr\AA@ADD==EDCCEDA?AB?@B@?@@@A@@??BAA>euy{tov|y}xz|vx~tF?BAA@A?<=>=<>??@B?XzwxwtvnA20'#(('(%1{‰„…€‚�~€�‚€}~}‚€~{z|z{vtzyz}~ƒiaca‚ƒ…ruˆŒ’•fEGC@BFGCEEABCC@@CC@;>@=>;963365-.-"3-..,*('),,+.133224545557687888878778:;97<===?>==<;======>>>?@A<9<=<=>=>>?A@@@@@A@@A@AAB=eŒ…†…€ƒ„……‡‹‹ŒŠ‰ŠŠ‰†�€ƒˆŒŒˆ†}x}„‡Œ„xuˆ{rˆ�F6@BCB><;>;====<;;;<>=<:;=<<<>>===?ABA@A?@AABD@P€‚�„k…Šot†‡va…†‡tIEFCBBABEEB?AABA??B@A@A@@@@@???@AB?Q~xuqxzyyvxz{x{{€|X@BBAABA@>=<<>@@ACBJu}wwuuuV660+$%((&+o‹‡‚€�‚‚�‚€~~~|yz~||zyxxyyyvvyz|„iacbiuxƒƒ~‘•Œˆ[ADDCGHABH@BECA@CE@<@BB=97766:74/0.!4/-/-))')**+/0122331345667988876789:;;;::??>==>>=>?===>??>>==<;49@AAA@>==<:;<=>??@@>?@AA?p‘‰‹‰‡…‡‡‡‰Š‰‰……ˆ‰‰‡ˆˆ‡‹‰††„†‰‰†‚�…ˆvu†„xx[<:>>=;;<;<<<;<@>;>>====>?=><<@?=@ADDEBLŒ‡xs|„‡‡d€‡b‚„SAFEDEFCADECCB@A?;?ABA@?@?>@@@A@AA@Br�xoxtv{zymr~~zuk`A?C@=ABB?@>:<>>ACCAc}zxtvvjA662-(# "&)(8|�…‚„„…ƒ�~ƒƒ€|~|||z{}}|xuwwuut{~x{‚jaca|‰vtˆŒŠ‰xhNBCDDBBAIJCGFA@CCA?AC?@=8;:8::50.2-"3/-.-+*)((*,.14344224432345556789:899::;<9998;=<=>===>>>><:::;;<@@?@BA<;;=?>>?@@??>=>>@@Bu‘Œ‹ŠŒŒ‹Œ�Ї‹ŒŒ…ˆŠŠ‰ˆ†ˆ‰‹‹Œ‚zyxy|‚ƒ††‚‚�„€Z=B;4;CBBBCA=4:>=>;::;=??===;<=;=>==>>????@?==>@ABAAy~}ŽŒ‹‡vg{‚‰sd‡€�d??<;AEBA@AAABACDC?;=@@@@@A??@A?@BB>^}xwqrxuq{{ps||vxV;BB><@B@@><=<=>BB@LuyuuzyuU79752-(''),3;EoŒ…†„€��„…€{}‚€|{}|zz|zzxsvywyzzz€€iaca}}z��Œƒw{rOCCD@?@GJEADDBDB?>@@>@@;=;8:8431002!3//10.+++-.0//01123123434576557865689;<<;;===>?>>===>>>=<>???=<<<;<:<<;:8:<>?@ABB?@A@>>DCBCB@;<>>?><;9:<=??>>@??>===>>>>;<=@AA><>@>r‹‚yspiƒ†‚†}aw‰…qIB>9@EEEEDDA><;<>>85>?><==>?B?=??B@Mzxostw{vsx~zurwz~rE>ACBABC?@@;<>@ABCA`ssssqunC899751.-/3:BEQ}‡‚~€€„�ƒ€ƒ€~~|x{}y{|zxuvzytwz{}z‚k`ca„Šˆ‹�†odytL@EC@CFKHBBDDB@;=::96686//02/-/.,,+,-///0452233312222566767755889;;;<=<;:79;=>>>?@@???AABBBA=<>??@=J|ƒ„‡…‰‹‰‰ˆ��Ž�Œ�‘�Ž��ŒŒ‰„€�ƒ�†‹ŠŠ„~‡‹�‚†vxV<@?C?89;<=?@AA===>AA@>?@@?CB>@A@?>>>=<>?><=?ADD@<6Qjcbu€ˆŒ……†…†~^sƒ~RAF@=FHDE?=<=>?>>>?m~xusqqx{wuwz{vvxyW?A@AAAC@?>;=>@?BEASuuzo]buW;:9:;84469=?@>>>;978<=====<=>>?><;<===;=???>@ABCBBBCCB@@??CE@`Ž„ˆ‹Š†‡†…„ƒ‚}bTe~bBDF@?JFC??@:=@A@@@?@=;?A@@@;@A=Ry{|xttsvvuuy{||xylD@BAAABA@@A>>A??ABGq{uwtpm[>=<<=<989;=<:56<60/0.3-'-+&()+../1211445643322444465578779::9::9:98:96:=;=>=<;;=====<<<;:9;:<=<;:;;<==??@DFFBc•�ˆ†…†‰‰‡†|ƒ‹‹‰‡††‚~Œ“�‰��……‹‹Š}}Œ’€‰‹y…Š~v@>?>78?A=<<=>><4>A@@A?><;<=>=>>>?@??>??@@>@?>A>Oyz{vw|€|xzywyzzywxX?B@?AA@@B?>89>A@B?Y€~zuwqrQ9@>???<:;>BEGEf‡ˆ„�…ƒ€~�‚�‚€~|}|zx{}{yxyxvywxƒjaca{�“�˜¥—އjFDGEEDDECABA?A@BBA@A<>??>=:68;41/.,3-%*)&&$&*+,--11222200/.0001123456536766677677:;>??>?>=<>>@??@AA?;:;:9:9>>?A>;:7:;;:b‰Œ�‘‡ƒ„Š�‹‹�z}‚‚y~‰Šƒ~ƒ‹�ŠŽ�ŽŒŒŠ‹Šƒ‚Š…ŠŒo‡”ŠM:@A?@@?@A@??@??939@AAA@?A=9?><==????=;:=?>?@=;@B?I}~|ykeenoopg_`TTarP@C?8;HCDE?9;???;<=?CDBGpsv|uorh>>AA@A>;;==??<98787230*,2.#()'&'&$$')*+-../013565577777756567:;<<=A??@@?@@83479;98:;<;9:937<;::99;<<;<<>@CCDDA?>f}vtx‚…ŒŒŒ‹Œ�Ž�††Œ‡ˆ‡‹ˆ„~„‹ŠˆŠ‡Ž�ˆŠ‰Š€ƒ‹}{’l::>C??@??@?@@@?A@=::<<;;;78;=<=<:;=?>=<7=EFADD?98=CA?=;;@@?@@AAB@==><@=Zzwwzn`_qzrywwvyyluS:@@@>ABA@@==@=ABC@b{jqyxqoN;?@ABB>;<>CDGD\‚€|€‡‚~}zzxz|zx{vw~|xx{vv{yytx�hacaqtxx\a~pqkJBGICAA@BBCEAADAA@=>>===;9:9651/-/0/,*,-../.****/1012221120/013223333136789999::<==<768<<;<<>>>=;;<;;<=>@@?>??>=;988:;;>BBE}‘‹‡‡ƒ{y~�…ŠŒŒˆ‡…‡‹ˆƒŠ“‡ƒŽ‡~„‡Œ‡†�‘ˆ��~�‰‚‰}x�E>:?C@;:?A>>=<=?@?@?>==<>?A??=9;<>>>;27<;;==>AA@A>s‚}}z{€‚€z{‚…„‚�h=;;ACHNADA<<:>C@<;>A@@?@BA?>>A<>?>=FquzwwvqlpywytzwstzjA???>>A@>@A;==?A@>>>>=:63110.120-++----,+))+,+,.--..//0/.--,033555556789;:98987:@?>?===<<=>==>?@?>>?>?????==:9:;Bx�ŒŽŒ��‹ˆ…wqt‚Ž‰ŠŠˆ„†€„�‰‹’‰wƒ“ˆ„ƒ�ˆ‡ŠކvŒ‡{NAB:=DB;;@BABA@@?>==><<==@=9:<::8:?@><87;>??>==@D=k�„€|~z{|x{xrqvywqbIBE<=?G@C@>BCDB>?A@BAAA?;;825:@BA?=>o|xoiqutztvuyuyxuuwW;>??>=??B=:<>;@CDBW]YVk{xmK>A@AACA??=@DGEU}„…�~‚~{|}~}z}zxy{|xwxpu{urux{x}hacay~zx„�ˆhECEDDCBA@ACCCA??;<>>>@?<>;963442-/21/'())*)**)+..-+,./,+0573,,,0413667777779;<<;<;;<>==>==>@A@?>>@??????????@???@?<==????;Hvx†ŠŠˆ‰ŽŽŽ�‹�m„€‡ŠŠŒ�‡�‡ŠxŒ’Šu…“Š}‹ˆŽ†‰�†ˆ�€�d5AC;=BA><>>>@AAAA@@?<><8639?@BDD@9:===:8::>??<:=7Kinx†…~}~€{}|yzz|\>=;8;>AA=?B<6:?A@=@>Wvvpegrvb?ABAABC@>@?BCFEj†�{~�~€}}€}xxxx|{|}|vtyxvy|zyx€iacas{yz†Ž…wkYECCED@@A@BA@A<>><>>>A?;:::8565340/40/).011/,+,.00/01144//12242)-02324344456689:;9:;;==??=758;;;=>>>=>>>>>=>?>>>??@>?>===;3Fnku‹�‹Œ�ŽŒŒŒŠtz‘�‹Š‰„‡‡‡}ŒŒ}„�‡n‰Ž„�ˆ†Œ~Š„~ƒ}}sB;CB@@>=>>>=<<<<==<<=??><<=>:45;=;<99<<>??<=AABCCCBB=78:=<:?>?@??>98>@>=@@=65=@>>=BlxvulmokK>CBBA@?>?>@?CAR{}|€~~}z~}w|{xy~|vzzzuwtrvtrux‚iacbpy�‰|iYau_GDDGDABB@B?=AAA>?=;@A;=<9<7862582/3//+0/.,*+)+,*))*+*,.,+,.+-0)+..12..0//133578;;;;;;<==9876554;@??>>>>><:<>=>@@??>=>@>>?8P{xou‚‰ˆ‡†‡Ž‘‹‹wp~‰Š‰Š�Ž�……‹‚‰ŒŠyŒ�†…Š…�„u�Šƒ|„‰P>@;EA>@AAAA@@@>?@>>:5787::;<;:=>??@@@><;;;<@?@A>Fmkmpstw{}|ytpoy{wwtN=@AA?PI@BB@;<><<@BA@>?=:;<;9;>>;:;8Vliu~xrx}moƒxVm€yuwd?A>><>??=>A?=?;<>9554361.3 ..())*++*+,+++)(**())(+--/11,,0////1/01368668977899934:<<=?>>><=>>>?><<=?=>=>>>>>@@?>?9Tunquq���Š…Šˆ‡‡ƒrijy~„‰‹‰‡€��ŠŠz†�„‡‡‡Œ}rŒ�Œ~t“k9E;;EDA>>?@BBB@??>>><>?>?@@AAAAAA>?;6>=::;:;==<:A}‡w}}ywqv{zxuqmxunU>@@?=GM;;:;::===>?=>?==;<;;8Rsknpwyvzslt~revwvwvK<@>?<>?>?=<<>=>?=>>ABKw†�z|€{{|~€zwxy|{vspurrwxxxz{‚iaca{yu€„…‡ƒ|bD@A@???C@<@CABCBA=??><;;>;5265/73.1+,*-.--,*+*+,-,--,**+,,),015225322--.2458<=<<<<;<<<<:;<=<<=<==<=<=<:76889:>?@A=cvky…‰‚„ˆ��Œ‹ŠŠ„…‚pkos‚�‘’Ž�†‚{�‰yŒ‡†‰ŠŒ‹p}�†�y�ƒB9E?;DEB??;8:?CCAAB?@@@>>>>@?B?8=<966;<55;?<;=@>>ABBBWDB?=@==<<>==><;==<=?>><<8Huustnrvqpwqo|snqtyg<>;;::;?@?>anmskqnn_=@C@?A@ADA>?>CA`�|{z{}}{{z{yv{wrxwtxuwvwruvz€haccleo‚‰‰Ž‹‚bCBBBBABCA@CCABEB==@=??<:><7473083/3+/-0000/0/-.--,--../1010,/223333343133/02479<=>==<;<;:96556678788652112467688=?@?=<;857`€w{€†‰ŒŠ‰�‘’Ž��‰ˆ…|wtro}��ˆ‰„‡Œ{‹ˆƒŒ…Љ„n�Œˆ|t”Z;AB@>@DDB@<99<<:<@AAAB@@@A@?97@AAA7i�rw{€„ƒƒzpxx|wxzy|qLA=MN?=><=A?<>>=?>>>?@?@@?>>>>ctlrrrsvtwsotlx|ulsxM:?>=>>>?=:98=ABAA>?BA?@C@?A?@Iu|uy{zz{{{yzztvusxvutvtsuu}€iacbowtnr{~ƒv[EBBCBCDCA@CB@BA?@@>:>>:=<94542451/2.0)+,++**+++**()+,-.,*,-,.//0.01-06465111///135;<=<;994/468:;:9:;741/0369:<;4178955:87>;8@DA@CA:9:9;B??@A;557:99;=;>C>c‡znjonjn~y|€�|�uQDDCCAET<>?:>>=@?<<<>>===??@??>@>===:79=???JqtssikomZ?A@@@@@@??>AA=<]~x}|y||y{uvzxryvtyzsqrqtvyy�iac`„‹vhkkpkSEAAB@A@??BCB?@?A?=;:=;<=87774205222-/&()('('()''&&'''**)*-00//121131/27764001422411568:;:519<<<<;<<<=<:::<<=>??>;88958AA>Cp|kiijs€~~|~~vvxtsx|€……Œ’Š„yƒŽˆ„‹‡‚Œ…†Œ‹‡r�Ž‹…gvNBE@<@CC><@BBB@@?>57CA@ABB=6;?@@@?:45<=79;=?9389T€‡‡ƒ|snnv}z{wcrxy^?==>@>aR>A=>?:;=>?><=<=<=>>>@>?=9:;=<;9=f|vbeosuoI>A@@???AAAACA9Ev€~}|{vwxtuyxyvtzrrwxqwzxx{~haca…‡}phqztufEABA?@?@A@?A=;>><<>@@><<=9795017212,,%(+,*))*+*))(('),-.0124431465331/67785578877764118<;935<;999::;=?>??>???<===>?><<>>:Eede\j~~�ˆŽ���‹‹ŒˆŠ‹ˆ‡ƒ�€y{‡�ˆx�ŽŒ‡…†…‰Ž„ˆŒˆ�‡Š‹…}[?EDC@>?BC@<:=@AB@?:;9?r~‚„pmyqrwstyuz{z}rK=?AA>=>>:>>@?>?=<>>>>?mxuytuutsstsrtrqmlqvd;=>>==>>>;9;<>@<3MoggtqtkgU>A@@????@@@@@B>^€�wtvxy{xuyzwwxomuvtuyzz}€hacay~njt‚Œ†}fC@BB@BBB?@A><>@?@>@@:;:=<46843450.1,.&)-.-+++,,,,))+,,+11026324324651035778767878880/5:<9937:72277769>><=>?>>=;;:F`ftvz{€�wr||€}{z{�…‹Šy}…Œ‰‚Ї‚‚|…Š‚…Ї…‡„€†�z??EDBB?>@@@@AB<5@?A@<>?<8:?ABB><<;56<:<@AA87>A@I‡‰‚…„€||ƒƒ�uv�‚|hu€}W@BABADfG=:ZvotvqnppnsstsssspnqsK9>?====<<::9;>@ACB@???;8<::658644420-0 +.'*../-+*,+*,++--./10000-,154566442104876677422369;;8729:56::::::65<>??@??>>??>@?>><;Qvky�…‡~ygqw|‚†……„…‚�~yqkz„ƒ~xsx‚‚‚‡Š…„‚�Šƒ‚‡†ˆˆ††ƒ„Q=?@ABBCBA@??@>:B@<>@@@AACDDA:;>A><9<<898>>3:A@A~�……ƒƒ…yqoyz||~�€~`:=??@>dX==Mvmuxrktroorontuttppsa;<==>>=><9889<=@@e|qx}eivnY=?AA@@A@@AABCB>\„€{|{yvzuuxwxrqqqsvsquv~hacbgjwˆ‹yim{iGABACBA@?CB?A?>>>?=9;=<:888566530-0!+.'(*+-,,--*,-+,-+++()('*.-.0344466544564345663368::9965:78<;:89:<=429<>>>=;<<;;<><:>9BamyƒŒof�‰€nqw€‡„~~ƒƒ…€vyy†Šˆ‡��„…‡…†…‚†ƒ‡††‡„…†�k>B@@?@BCACBA?<@>?@>>??>??>=9=AC?69<>???;29?:7>?v‹…ˆ|lutgho^aux|vwepoG<>@B?Rc<<>>7:A?9<>;=A@?>ACABA><=>?CpyvuxrptrlooffoottsqpH8=;<>=?=;:87;<=:Qxyqfatnll@;@@?@??@@?ACB@Fp{}yyzxy}{stvpqrqrtvuqtu|~gacbgkq~‚‡‚uulL@@BCDC?>A@@??A?<;;<>?>;89878630-+1!+.&(((&&&''%&''()()*(*,-/1/0120333234776455555567666984697878;86:;<=57;==<<<:::;;<>=82Iu†‡€xk…‹zvx~‡‰�~~€|xw}‚€{qvuot€‹ˆ„„„ƒ…‚†‡†‚‚€„†€…‰~C@AA@>@?>??AB;??=>=>?@@<><=@@?>;@BCB?=><@BDB@?BBAC@A>d„xyuuppssmqojkijmmrub:<;<=<=<<976:<=A??A@>???@AAC?X|||{vzvvwx~zqsurromlotxx{hacbr||k\^hptfE>ABCB?=?@BA@@A=;;678:640/0+0!*-%'')*(''''%%(&'),../0/04632445775441236778876447938;7489752558=;::96<>>>=?>>=>;;;:26a~ywx~„}z}‡~}€zt|„„~}wquy€€||yx{}��€�‚~„†…‡…~€ƒ…ƒƒV>@BB@AAA@>?8;B>>@@@>?=?@>?A@??@A@?@=867=CA?9<@:9>===@CCBCABBB@?=B@>czuuokgmtcH?;<=>?>===?AC@Et}xw}wu|{vwurrurtpiklpxsvhacbp{}wroqswhF?AACCBA@AA?>@>;:??>=:?;78:844011/0!(.%&&()**))+*)**)*+)(+...00//00/246654555333577866767:55:<8879999:;:88;<==;8668;?=58;=gpx~z€{„ƒzxy†‡ˆ„}„�€‚„…‡„€~~‚�~„ƒz}�€€„‚}}~‚…‡…ƒ}|‚k=A?AA?A@@??<->>9?==A?==>?>>>=>?A?=>>@@??>?BC@=f†�ƒ€‚€…ujv{z{}~|wswxeA9C>;;RyI>A?@@>89;?==>BB@BB@AA>=?@=E|~tzutrssqrtolnolspgf\;;;;;<;;9997:<>=RvoptvwuunXA=889<<<>@@ACB@[}|w{u{|qowvstwqqstmkvtu~hacbnnlo|ƒxq]F@BCCCA@A@??>?==>?=?=;=9::8535332,/"%-$"#"$#%'&''(((***,,-//00/13446444554333332335776679633557879:499;:9::89:98246:<:8=99h‚€v…}|z~‚}}xy{~€‚|yxvy~��|}�‚ƒ€�}ƒ……‚ƒƒ€�†ˆˆ‚…€G9??AABB@@=>;=@<@<;<<>@AB@@?<:==<=@@ABA?E=;BC<_ƒ}‚‚€�|v‚…†‡ƒvsy‚„€{U=>?@=En^9B??>;;;=?;>=???>B@d{{}zwsvrrqvqkinqnromnJ5<<<<<<=;889<==Enqorllswt\@>=>?>>=<<;=@ABJk~|yyrptx{urqtomqtoptrs|hacboonr|unqi`H@@ABA???=>>>=?B?>=@>;:::5854434/+0#%+!"$%$ !##&&(*''--,,-,./-/001233343133334444565666677743365878898987<<:7;;:8::7:<:<;Dwv‚uu†~xzwv|~„ƒƒ†‚€��‚‚yzy|~|{}‚ƒ„„�}~‚€‚„…�z€�~‚ˆ‡_;?A@A?@@A@?A?@AA@?BBAA?@ABAABB@@B?<>8_Š„„�‚‚…�|{zuojnttrtswdC@>>>=g{C;=<=>=@?;>>=@@>>A>?=AA??@;Rxttvvswxumnrolfkosqlo`;:;<;=;;<;749>?>dxtrjdgkkaI>@@@?>?A@AC\{zutvvrxztrutomprupovw‚jacaozxvqfguxiI=>BB@><>A@???B@>>=><:;;56;52373,/1#%+"#%""$&&)+**+*+-.//-0320/.110110357766556656766676766865666589:9:;;:79977<<;;7155:9Nly†r~ƒxz‚}…�€|{}z}|{||}�‚€}|{}zw~…„ƒx~‚y}~}x{xwƒuG@CCB@@A@:@?>=@A@AB?@?A>?AAA@????@?@AAAC?AAB=Y}~‚„€y}|zxz�€zuoopqfC=?>>;V}X9A>=>>@==>>@>>@@@A@A?AB>@;GvzrtuvusnkkppoklkqpnnqM7<<:;;:<;969<@=UtkipppnprnI<9=>>AB@?AACB>Koyz~|wppsstttyqusssssx|gbcaztksqkknqaGAEE?=>@BB@????==@><;==85;942470../!$-&$'&#%(())(''**)*,,,..,-+.43331/.1333433567887798787787844654578:97765644:<9:<74792P{}s}~s{‚ƒ‡ƒ�}|~||�ƒƒ€€„~~|€€�€z‡„}{z~„{{}‚||in‚€|{ƒ[;A@???@?@?@@@@?@A@AA@AD;X‡�}€€„‚€}zzttsvzxsqlNDmq?>=>>>><=@@>?=>??@>@@>@@@@?jxrrtwxtuvojqutqomxslp\8:;:9;::<99:<;=IopmmnmfidgU5A@:9;>ABA?>>>>@??><<<;98<<725551/-.!$+#%&&%)***))(((**)'&'*,,-+/2444331./0../....2578999978979889367799;87757:7;>75:=9942W{vw€l€€‚~~z„~„‚€€€~}|zvvww{{{||~{xt|‰„}xw|~€|‚yvqlx€vyq?=>??==6>:>;?@@A@?>?@?CB@?@?@@?@?@>=@A@?>?B======>??@@>??>A>_tphpxqorwsjkkprnoonkmjF8:::9:9::88:;<@fpilmllmib`C<>>A@96A@Oiywqqwywrsrotvtrtrqtqxhac`~�ˆ�{xzrkhN>?>@CA???>?@ACB@<>==;:;98226620/-/"&,##&()***)'((&&'))),,,./0102423330-2420100./110244667:99789878988799668755:=<7<87777Y{xyuw€u€�‚€�~{�€ƒƒ{ttwzz{{xx}}�€yy�„‚€€€{x{rq{xw}}{{T;@>?<=><=86==<=@AC=QrrD<>>?>===<>=???>??>>??>>@=Tvvttttusssrmpnkrrmnpnma;9;;88::897:<=:WplmkknmmjjY;@?>?;::@:9=A@A`qtwxvy{vpppoknxusvuy}gaca�~}xwtvˆ‚W@?@CA>>??A@=BA>99>=;:8::7688541///!%0'#&''''&$%%&$$%%%'***+-.-,./0110.02444434326533544555668888999989879889789;<6<:7;:@iox|ux{y}z}{xy||�‚‚swzzyxuz|z||~€~�€}ƒƒ€}|}}}||~~l>>@?@>?=><=48939:<;==:8;<>@?@A@A@?@>>?A>@C?N��|{€~{|xyyywvsswxyzqP>???>Cj|]9==>?==>>>=>>=>??>>?>?>@=FvxtmlrssstsrrpknkpqkpmmK6:98889;:98;=<>@@>?::A@>=Qku}zsqtpspnustztolqvygacbspsv{…„ƒƒ|]@?DB?=?A@A>>CB<9;>=::9;:7894321/-/!#/%#%$#%&&&''&##%###&'*+)*+,.*.00/-/01100112256566667656568787668888798888989:8:;:<9Adspy{{s{{}{~€�‚€zx|€wv‚ƒ„�xrvzzy}~|~{{�~{��‚xz{uvupxyP<@?>@?=>><:;<2797;;;8:==;<=>?@??@A?><=M�‚�}{€ƒ‚zzzxvx|yy|yy^@??>>?`zvG:=??@?=<;;<====?=<>>><=>>gzqoupqssvqpqqngjlnommmb;6777788889:=;ChkkmlikifbfU9>=<<>?=9<>6=ADbsvuyvtxrpprtooosyy}hacbmqqz„‚}€zmU?AC??=?B>=AAA@<=?;8;<:989941341/-/"","#'(&'(('())'')*((&',-,+.2440+,03225554543334236545566755666767777877:978899;99:<9Bhywv„zww{}yzv|�‚ƒ‚€}�|~}~ƒƒƒ„‚zx{€�~z{}z||~wywjno{vas�j@>?A@>=<==<8;88619:7<;9>6:??<:>===<<<;<<>>O}~||{||}{{ywzz{wvvvx{|wdF>?@?>Onv`9=>>>=;<::===<;<><=?=<=?;Z{tvsrqprllutnqopjlnmnkkO477766788:::<=`plomkjkjfbaB:><<<<;<<6;A=6Lcsvvytststruuptqps|‚iacatwr}ƒ|vysXCBA=>;>>;?A;:<;=;8=?>@@?=<4;=756<>>>><:;A==;?>=?<=>=<==?Y}{zxwvuxxyuuwuvzxppvqpkL9==@=EdszJ7;<<<<==<;<>><<>>=<=<<=8Jqqssnrrllpqpqmmqoonoonrk>887876889;:<:Wrlnnmhjig^dT9;=<:;;;78@<;=?^lwzuutttqtnkimqrqx~hacbir€„~�„xke[JA?>>?@AA@>><;<=;>?>97885780-.20-/""+" %%%'((('&''&'''%%&&(()%&+++,+.//0000000//022222344544445342332233566577756698656Nsyxrt{qfus|…pdx�ƒ‚ƒ…ŠŒ‡y€||zwy€yxt|�ƒ�~zz|†�{routy}{}i_spH=?>=>==9=;976::;:BAA>>?===>?<=A@>><<:9=>==>?>>>;Eh._phgejusloplnokkqrppnqX8;:788678::;:JnlkfhgjdffbdF9:;;:;:;=8;=?>Retyxwtsqlvvoqvpo€}|hacatzxusx{qig[J===??@@@?@><=;;87656841036/+0"!,#!#''%%&''&((&''&&%''*)(./0/,,0/1322255344455554322344334355542235555221355534634Rwvxur|tvv~€rp€€|{}~|jdw|€uv~}rw}…ƒxu|††…x{zy‚‡‡„webus{os}`<;=>>=:;<8<98;87:??@>;==?A?=>>=?@>>=Po}vovvvrwzvqsqruwttxsnpyzfB<>;=;NnprN7?=;<;>==>==>?>>=>>>=>;BT6~ywtrrtpqmosmkleciqqljkE9::9887777:;@gskeinjkiifgU8<;;:98899<9;;Bbguwtuwuwrmos{U/g{ƒjac`~}nfgh_g~‰sK;=>=>@B?;;=BA;::97278544124.+1$!-%"#&(##&'(&&'('%&'&$&((#'---,.,//-./1112223356666764454553456432136678867789943636\skxz{wwvy~|{s{zwzuqwxtw~|yy|xvxxzzhu‰„wwzz€{ysv~~w‚unsslonrnM99:?=>952=:6>B@=B@B=>@??>=?;;??<:=Y{|{|xxxvyuvuxvnspppvwoooztO;==>>>===<;;:;<=9D7Kquruqomqoopjikggkmnrjra98:;:;;987:<<_qln^^hcgffbfF5<>=:98:<::=>:Ufpwstoqttss}Z/Sar€haa`mqojbait‚„rN<<<;=?>89=:49?@<777420110/../.*)+*! "%## #!!#!#$%%%''(+++-+,--/01/0/00/0///..//0010021011222.+11112010,.27Vkzyrgoyvkepwwuxsv{zzyne_ajq{{yuy�rk}…�‚s_x‡~pj{xnkvqyzy{€~oI=>=<:863887782267;529:==956;:::856:9>austrttwwsvqwuuusntwrpstqmsY;9998:YnjlbHNC688768987:;;8886886;'[tmoiojrupmpqlifghkggnjhjG148875765265SrkoH>lfibbdcZ7348:986789:88D[buwptyspzxH.c{wzf_kjtxsqopyƒ|sn\LIHJMMJGIJHGMMKJHFDDBA@BB=>@>>:9:0'0;0.114440-010011/-+*,/34443488::9;<<<;;==>>@@@ABA@ABCAAAA?@>===>>@CCC@@?AAA??DECA>Eh€„|v{||{vwhmx~zy}{{{xxzvrr|€�†€‚†t€‹Š‹€hz‹ˆ†k{ƒ|nho€……‚€‡�dLHJIKKLIFFGDHF@IDIJEJLLHECFBHIECHIITbry||y~{||sw{�€xz}yxz|~zwyxzjLFIHHI`vuvyhfcMEGFDGFGGFGJHFDBEEFC*%,.+('')*))&%#+Kn…†……„ƒ‚€€�‚�‚‚ƒƒƒƒƒƒ„„„„„„„„„ƒ„……„………„…„„…„„…„………………………………………„……………………ƒƒ„„„‚‚„„„„„„„„„„ƒƒ‚‚�‚ƒ„„„ƒ�€�ƒƒ„ƒ‚‚‚~yutsstsrpoppppqqppqqsttuuuuuuv}rmmnmnnmmmmmnmmmmllkkjipkedS9-('))+**(((((&)($!$$0DXekrx|�„ƒ����‚‚ƒƒ‚‚ƒƒ„„„„„„„„„„„„„ƒ„„……………„…„………………………………………„………………………………„„„„„……„„„„„„„ƒ‚�€�‚„„ƒ�€�ƒƒƒ„�‚€{vtttstsqpooqqqqqppqrsttutuuutv~~ronnnmmmmmmmmnnnnoonmlmsl`C+,3300//54/,))&%%%  &$)&$%'.3;Jcz„ƒ‚‚‚‚‚‚‚‚‚ƒ„„„„„…„……„„ƒ„ƒ„…„…………………………………………………………………………………………………„…………………ƒƒ„„ƒ‚�€�ƒ„„‚‚ƒ„ƒ„„ƒ�~yutuuuusqppqrrrqppqqrsstttuuutu~~qnonmnmlmmllmnmnnnoonkptiD-2423640499;70,*)'$!!&%#$9510)%09;:7211.((-! "$ "$"4j†ƒƒ„„…„„„„„…………………………†………………………„………………………††……†…†………………………………………………………ƒ„„„„„„ƒ‚�‚ƒƒ„„„…„„„ƒƒ|{{{zxwvtrrsttttsrqppqrsstttuuutu~rmmmmlmmmmlmmmmnoqppppttP@=872-##.9:7::412,)+%#"" !$$$ .e„„ƒ„„„„…„……………………………………………………………………………†………………†……………………†…………………†……†…„„„…„…„ƒ‚�����ƒ„ƒ„„„ƒ‚�€}{{zyyxurqrssttuutrqqqrrsstuuvvuv~sonmmmmmmmlmmmnnnppppossP<<863*%'/7758:;200+)$""!""$##$#"*R|…ƒ„„„„…………………„………………………………………………†……………………†……†……†…………††……………††………„ƒ„……„„ƒƒƒƒ‚€€����‚ƒ‚‚�€€~}|zyyxvssssttuwwusqqrrssstuwwwxx~~qnpnnmmmllmmllnmnnoopostS=;861+,.674468;901,&## "##&%&&$&'%!9t†ƒ„„„„…„……………………………………………………………†††………†……†…†††……………†…††…†……†…†……„„„„……„„ƒƒƒ��€€€€�����€€}|||{zxurssssvwvtqqrstssttvyyy{{rmnonmmllmmmmmmmnoooqpstZ<;863228:843577;5//%! "'"''#&%"%%'?}…ƒ„ƒ„„…………………………………………………………………………………†………††…†††……†…††††………††…ƒ„„„………„„„ƒ‚��€€€€�€€€€€€~~~}|ywtstsrtwusrsttuuutuxz{||}~rnnnnnnmlllmmmmmnooptutsd@997559:;:635769:1/'!  %!""!%'))*)'%M‚„ƒƒ„„………………………………………………………………………†††…………………††††…………†††……†…………„„…………„„„„„ƒ�€€€~~~~}~~}{zxutrssttttuvuvvvvvx{}}}~~qmnmmmnmlmllllmmmonouwushI9:769;;<:85666695.+# "$(,+)((((((]†ƒ„„……………………………………………………†………†………†††…………†…†††………†…………††…†………„„……………„„„ƒ‚�€€}}}}~~}}}}}~~}{{yvtstsstutvwwwwwwxy{~~~~€qmnmlllllllllllmnnnqvvuskU:99:;<=;:975665572-)"+ !%(()*(')(*'4w…ƒ„………………………………………………………………………††††††††††…††……………………………………„„„…………„„„ƒ‚‚€€}}||}}}|{|{{|}|||{yxvuttttttvyzyxwxxyz|}~}~€~rnnmmmllllllmmllmnnqvvurk^@:;;;<;;::86654455/)# +4/*"!%((*,+*(()&Y‡ƒƒ…………………………………………………………………†…………††…†††††††††………………………………„„…………„„„ƒ‚�€~~}}}||||{{{{{{{|{{zyyxwvuuttvy{{{zyxxy{}~}}}€qmommmmmmlllklmllmnrwvvrjdJ79;;:::;;978523240)$# ),-.+,' !&'(**())&=~„„„……………………………………………………………………††……†††††††…†††††…………………†……„………„„ƒ„ƒ‚‚�€~~}}}}||{|||{|{{{|{{zzzzyxwwuvx{{|}}{zyy{}~|||€~rnnnmmmmmlmllkmlmnnsvvvrjgZ:9;:9::;;99:633211.)# ),-.,./+'%$!"$%%''()*fˆƒ„………………………………………………………………………††…††……†…†………†…………„„„……………………„ƒ„„ƒ‚‚‚‚€€~~~}}}|||||||}|{|{{{|||{{{{yxyz{||}}}{z{||}|||~rnnnmmllllkklllmnootvvurji`C;<889::::;>>44320121*" %'./0/.+(! !$&(,)G}ƒ„„„……………………………………………………………††…†……†……†††††††…„„ƒƒ„„„………………„„„„„ƒ‚���€€~~}||||||||||||{{{||}~}{|||{zz{{||}||{{{||||{{~qmnmnmmmllmkkklmnopuwwurl]HC@=8899:;;=IVA23211244+%"&$',*!! #))0`r{ƒ………………………………………†††………†…………†……††……†††…†……„ƒƒƒƒ„„……„……………„„ƒƒ‚���€€}}}}|||}}}||||||||}|}}}||||||}||{||}||||||{|{|rnomnnmmlklklllmmnrvvwus\CBGD>:8689=RLRJI44310224610+'%&##$$!"#!!!&"  '*Rjiqx€……„„………„…………………………………††…†………††……††……„„ƒƒ„ƒ„„„„„„„……„…„ƒ‚����€}}}}||}~~~}|||}|}}|||||||||}~~}~}}}}|}||||||{|€rmnoonnmmllkklkkmnrvvvuZBBCGG@<8666FhIQXV@23100124689742.,*$%"#&$$$%%! &-Mliiimv„…„„†††‡„†††……………………………†……††…††……„„„„„„„„„„ƒƒ„„„ƒ‚‚��€~}}}}}~~~~~}~}|}}|}||||~~~~~}~}||||||||||{|€qmnnnnnmmkllklmlmmrvuyS0CDDFHA=:765@ZHQdXF34210122567<=?@BA<92*%(+-.2<5..Lljjkjimv€……€|yvnqw~€ƒ…††…„……………………††…………„…„„„„„ƒ„‚‚‚‚‚ƒ���€€€€€€€~}~~~~~~~|||||||}}~€~~||||||||}||}~€~roonnnnmmlllkkllmnsuxd%.EDEEGD?;8655MglWZN043201234468990Ijkkjklljn{r_\[ZYY[^acis{�……„…………†……………„„…„ƒƒ„„ƒ‚‚�€€�‚‚‚‚��€€€€€€€€~~~~~~~}|}}}~}~~~~~~~}||||}||}}}~€ronnnmmlmmklklkmnnsvs92DDEDGF@<87553E[NS;2234213334567778999;=>?@@<:CD<1DbeijjjklkcYXYZZ[[ZZYZXY\bp€„…„„…………………………„ƒƒƒƒƒ‚‚�‚‚�‚‚ƒƒ‚‚‚�€€€€€€€~~~~~~}~~~~~~~~~~~~}|||||||}}}|}~€€�€rnnnnnmmlmmllkmmnprwU0FDDEFGB>98643;_lO4434443333345667778779:=?@?>GG:0Bacccfije]XYZ[[ZYZZ[\\\[ZYZbjwƒ………………„…„…„„„„ƒ„„ƒƒƒƒƒƒ‚‚„„ƒƒ‚‚‚�����€€€€€€~}~~~~~~~~}{{{{{|}~~~~€€�€rnnnnnnnlmlkkkllmoto4 4GEFEEGE@<98543;\gI643344333356677788778:<===>IF51Cbdb_`^]ZXXYZZ[Z[\[[\]\\\\[ZYZl‚†„„………………„„„„„„„„„„ƒƒƒ‚‚ƒ„„„ƒ‚‚‚‚‚�‚��€�€€€€€~~}~€~~~~||||{|||~~€€€�€€€~rnnmnnmmmllkkllmmnv\# 8GFFEEEGC?<97433B^fC3=C84334567768899789;===;86452Mhd`dY:455567787899;::9<=:<;BKB35>]dc`WXYXYXXYYYYZZ[]]\[\\\YZ[[[Y^n�…„„……………„ƒ„…„……„„„„„„ƒƒƒƒ„ƒƒ‚‚‚‚���€€€€€€€€€€€€~~~}}~~~~~~€€€‚�‚‚��~rnnonnmmmmllklmmmotB !>GFFFFFFFD?>976452Mkpf<555678888889;;;::<<;<<976655:ap^XH9468:989:;<<<=;=>=;?HC38@F\db[YXVWWXYYYZZZZZZY[[\^^]\]^][[[Z^qƒ„„„„…………„ƒ………„………………„„ƒ„ƒƒ‚�‚‚‚ƒƒ‚‚‚‚������‚�‚‚‚ƒ‚€€€€~~~€€��€��€���‚€ronmmmmmnmmmlmmmmnuM'EIHHGGFFFFEB><:97765=>?>=EF33>DL]ca^\ZXWWWWXZZZ[ZZ[]^]]\]][\__`\]^[[j�…ƒ„…………†…………†……………………„„ƒƒƒ‚ƒ„„…„ƒƒƒ‚‚‚‚‚‚‚‚‚ƒƒƒƒ‚‚‚��€€€€€€€€€€€€���‚���‚�€~rooonnmmmlllllmmmot\"(GIHHHHGFGFEFB?>;997767A[blnkeWKBFCBC?=>?>>>CJ?1;BHK_cb_][YXWWWWXXZZ[]_`aab_]\\^__``de_[Yd}…„……………………„„…†……………„…„„„„„…………„„„„ƒƒƒƒƒƒ‚‚‚ƒƒ„„„ƒ‚����€€€€�€€€�€€€€€‚��‚‚�‚‚‚�~qnonnonmommmlklmmorl2*HJIIIIHGHGFFEA@?<;988768>JRaetldj_\T==>><;?HI98@FFPcbaa^\[YXWWXXYXZ^^_ab_^^^___]Z[`fh`\\Zb…………„„„„„ƒ………„………„…„„…„„……„„„ƒƒƒ„„„„„„‚‚‚‚ƒ‚‚ƒ‚‚ƒ������€€�€€€€€€€���‚‚�‚�‚���~rnnnnnnnmmnmmmnmmpptQ+HJJJJIHHHHGGGDAAA?=;::9988<;JVbgnhnO<=====BJG9>DFG^dbbd^\[ZYXXYYY[]__`___^\]__``]ZZcfc^_a^m…„„„„„„………„„„„„ƒƒ„„…„……„„„„ƒ„„„„„„„ƒ„„ƒƒ„ƒƒ„ƒ„‚‚‚�‚‚�‚€€€€€€�����€��‚‚‚���€rnnnnnmmnmnmmmmmnqqrm1*IJKKKJJIHHHHHHEBBCA><;:::;:;:9=DFNK?=<<>>@HKF?CHGZedcbe`]\[ZYYYY\^_`^]]_`a_\^_```_\^cgb]^`c}„„…„ƒy|�ƒ„„‚‚‚ƒ„„„„„…„„„ƒ‚ƒ„„„„„„„„„ƒ„„„„„„„ƒ�‚‚�‚�€€€€€€€€�������€€�‚�€�‚€sppoonommmnmmmmmnqqqvX0IJJJKKKJIJJIIHHGECBA@>=<<>=><=<;:9;=>?@ABDLLEFIJXfedddfb^][[ZYZ]___^^^^_`ab`\^```a`^\cgb^``r‡}g^^XRSX_p}‚‚‚ƒ„„ƒ„„„„ƒ„ƒ‚‚„„„„ƒƒ„„ƒƒƒƒƒƒƒƒ‚‚‚‚�‚��€€€€€€€€�€�‚�€€€€€€����€~rnonononnmmnlmnnoqqrtsQGJJKLLKKJJKKKJIIIHHFCDB?@AA@????@ABBCEEEFHNJGMLXfeeedehd_^]\Z\^___]]^^^_``aca]_`a_`a\\bhdaaksYPNKLMJIJLWg{ƒ�‚‚ƒƒƒƒƒ‚�‚‚ƒ„„„ƒ„„ƒ‚ƒƒ‚‚ƒƒ‚‚��ƒ���€€��€€€€€�����€€€€€����€~rnonnnoononmmmnnorrrtvpQHJJLKKLKKKKKJJIIJJJHECDEEDBBBABCDEEDGHHHLONOQYdeedeceih`^^]]_`_^]]]^^^````acb____^]Z\\`a__\UZbaWLKMOPORRWu‚€�‚‚‚��€�‚ƒ„„„„ƒƒƒ‚‚ƒ‚‚‚‚‚‚�‚��€€€����€€€€€‚��‚€€€€�����€snnoonoonoonooonorrsuuvkOIJKLKLLKLKLLLKKKJKKJFEFFEEEECCDEEFFHHHKPRQPYdddeeedejid`_`__`^]^^^^_`````aadc^_`a_Z[][[__^`^Z[^ZYYSPRUZVXv‚€€€€€�‚‚ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚�����€€�‚�‚����€€€�€��€€€�€€�‚���€sonnnpnnnnnponmnqrrstuuviPIKKLLLLLLLLLLLKKKKKLKIGFFFFFGIJIJKLMNPSSOL\edddddfchjhcabb`__^^^_``bbaa``abdc____^[\_]_ca`\YXZ\]^YTSSU[X[s�€~~€€€€��‚‚‚‚‚�‚�����€€€€€€�‚‚���‚‚€€€€€€€€€€€‚‚��‚��‚�€rppomopoponoonnprsrsuuvttlSIKLLLLLLLMMMLLLKKKKLMLLJHGGIJLNNPQRRRQNKM_ededdeedflidecba`____aabcecaaaaabdc`___a`__]bb_`]YXYYZ]ZWUST\VTgz}}~}}~~€€�€€�€€€€�€€€€€€€�‚‚‚‚���€��€€€�‚‚��‚�����€~pmppooooonoooppqssssuvwurtoVIKLKLLLLLMMMLMLLLKKLLLLLKJKLMNOPPPONLKJScddeeefeefkjdfdcaa`_^_adeihhfaaaabbdda`abaab``bab_[YZZZ[[YWVRU\UPZp|||}~~~~~€€€€€€�‚€€��€��€€€€€€€€�‚���������‚€sonopppponooonosssstuvwutsuq\KJKLLLLLLMMMMMMLLLKLLKKKKLLLMMMNMNLKKKYddeeeeefffkkeefdbaa`__`mifhijhaababcddbbdabcbcdba`\ZYYYYZZYWTRW^YSWgy~~~~~~~~~~~€€€€€€€€€€€€€�����������‚‚€tqqonopqpppnnoqsssstvvwvttuuudOJKKLLLLMMMMMMMMLLLLKKKKKKLLLMMLLLKKM_ddeeeffffejmeeffdbbaa`_ejkpollhaaabcccddfcbccddaa`]\ZZYZ\\[XVWV^eeehv~~~~~~~~~~~~~~~~}~~~€€��������‚���‚ƒƒ�tqqpppooppooppsutttuvvwvuuutsulVKJLLLLMMLMMMMMMMMMMLLKKKJKKLLLKJJJTcedeeefffffimfefgfdcbbb``dmnjkkfaabccccdefffffgea`^]\[[Z[\\[\_`^`gnggy~}}~~}~}|}~~~}}|}~}}|||||}~~~~~€€€��‚�‚‚��‚‚‚‚ƒ„ƒ€tpqqqpqqpqpooqtuuttvvwwvuuutrqrp`OIJLLMMMMMMMMMMMNMLLLLJKKKKKKKJIK[eeeeeeffgffgnhefggfdccbbb`dmqkdabbccccdeefgggggeb`^[[ZZZ\\[_cfii`Zf]Zm{}|||||{|||}|{||{||||||||}|}}}~~€€€��‚‚ƒƒƒ‚‚ƒƒƒ„„„€tqqpqqqqqqpppsuuuuuvwwwvuvvutrqqrjXLJKLLMMMMMMMMLMLMLLKKKKKKLJJIIPbdefdeeffggggmieggggfeddcbcbbkpjbbcccccdeeffffffeb`^[ZZ[\[\aeghc``ZVWYZgx~ƒˆˆ†‚~|{{{{{{{|||{{||{||}|~~~€€����‚‚‚ƒƒƒƒƒƒ„„……�rpqpppppppppptuuuuuvvwwvuuvuusrqqqodSKJLLLMMMMMMMMLLLKKKKKKKJIIIJYeeeeefefgfghgkleggggggfedcccbcmrmjgdddddeffffffefc`_]Z[[Z\chjic^\a_UTVWY^o‰Œ‰ˆ…„…€|{{||}}}}}||{|}}|}~~~€€��‚‚ƒƒƒƒ„ƒƒ„„„„……„�sopppppppopqquvvvvvvvwxvuuttsssrqppqm`QJJLLLMMLMLMLLLLKLKJKJJJIIPbdeeeffffffgffjnggggghhgfeddccbcluqgdcddeeeeffhifedb_][ZZ^eijhedec`^VRSTY][mƒ€~€ƒ„‚€~~}~~}}~~~~€���‚ƒƒƒ„„„„„„„„„„„……„�tpqppqppqqqqrvvvvvvwwxxvuvuttsrrqqqppql_QKJKLLMMLLLLLLKKKJJKJIIJ`gefeefffggggggipifgggghhggedccdcdjqrnieddeeefijmhgfc`_[\agkhfeeefgfaWTTUX^`^s~|}~}|~‚ƒ�€~€��€€€��‚��‚ƒƒƒ‚‚‚‚‚‚‚ƒƒ„„………„€spqppopppqqqsvvvvvvwxxxvtvutstssrqqppoppl`TMJJKLLLLLLLKLKKKJIIIYmiefffffgggghgggnmfggghhhiggfeeeeedgknprmljfhijjnlhjfcaaejjgeeeeefehhc\XZ[\bbj}}{z}}�€€�‚‚����€���‚‚‚ƒƒƒƒ��������ƒƒƒ„„„„ƒ€soppqpoqrrqprvvvvvwwxwxvtuutttssrqrqqpooopmdYPLJJKLLLLLKKJJJIKXlnifffgfffggghhgglphggghhhiihgfffefeddefjmlghjijilpmliefjkiedeeeeefffgiga_`]adk~~|z{}€~€‚�}}€‚ƒƒ‚�€���‚ƒƒ„„ƒƒ‚‚���‚‚‚‚ƒƒ„„„ƒ‚€srrqsrqqpooprvvvvvwwxxwwuvvutttssssqqrqppoopoiaWPLJJJJJIIIIJP_mnnjffffgfgggggghfjqmgghhhiiiihhhgggfeeefdegiijjijkqrnljklifeeedeeeffffgiifaacdu‡„‚~{xz~€€�‚€xvz‚ƒ‚�€€��‚ƒ„„„„„ƒƒƒ‚‚ƒƒƒƒ„ƒ„„ƒ‚‚ƒ�sopqqrrrqqqprvvwvwwwxwxwuvvvuttssssrqrqqpoooopomic\VRONNOQV_jpooolffgfghggggggggippkghhhiiiiihiihhgffgghjknljjjjkorpnnljhgfddefggggffggijggfiz~~€�|zx{��~{xw{}~€‚ƒƒƒ‚„„„„„„ƒ‚ƒ„ƒƒƒ„„„ƒƒ‚‚ƒ„ƒ€sqrqqqqrrrrrsvwvwwwwxwwvtuvvvutsrrssrqqrqpppoooonnnmkigghknppooooohfghgghhhghghhhoqpjghhiiiiiiiiiiihhijklklpjjijjmrrmnmjihhedeikmnnjfgggijiiottvx{}}zxwwzzyz�~vtux}�ƒƒ……„„ƒ„„„„ƒƒƒƒ„„„ƒ‚ƒƒ„„ƒ€tqrqqppqqrrrswwvwwwxxxwwutuvvutttrrsrrrrrrqpooooonnnnooooopoooopppjghghghhhhhhhhhnqqpighiiiiijjjkkjjjklkjklpljjkjkqrnmomkhhhfemoorrqlgggiijnqrsuvvwwwwusrsuw�ƒysttuuvy}�ƒ„„„„„ƒƒ„„„ƒƒƒ„„„„„„ƒ€tqqpqpprrrrrtwwwwwxxxxxwvvvuttssssrrssrqrqqqqqppooooooooopqqqpqqpqmghhhghhhhhhhhhlqqqpighiiiiihijjjkjjjjkkjppjjjjjpsomopljiiigfkqsqnjghhhiosqrsuuwvutsrsssuv|}vstsstttuvy{~€�‚ƒ„„„„ƒƒ„„„„„„„ƒ€urrqpqqqqrrqswwwwwwxxxxvvvwvutsrrssssssrrrrrrrqpppopppqqqqqqqqrrqqphgghhhhghhhhhhkrrrrpjgiiihhhjjiikkkkkkkjnsljkkjnsqmmpolkjiigfjotpjjhhinttqqstuusrqrstuttuwy~|‚€|xutttttuwy{~€��ƒ„„„„„ƒƒƒƒ�vrqqqrqqrqrsuwwwxxxyyxxwvwwvvuussssrrrsssrsrqrrqqqpqpqqqrrrrrrrrrqqkgghhhhhhghhhhiprrrrqkhiiihiijjjjjjjjjiilsojkkkmrsolnpomljiiighmuvqlklnstrqrrrqqqssttuuttuy{}Œ—™˜–�ˆ€yuuuuuutuvvwz|}���‚‚‚�roopqppoppqqswwwwwwxywxwvvvvvuttsssssrrrrrrrrqrrrrqrrqqrqrrrrrrrrqrlhihhhhhhhhihhhnsrrrrrmihiihiiiijjjjjiiikrqkjjklqsqmmnppnlkjjjigjprsommqtrqqppqrstttttttttuvwˆ——™˜™™˜’…xuvvvuuuuuvuuuvwxz{|tpqrsrssrqporxxwwwwwxxxwvvvvvvutsssssrrsrssrssrrrrrrrqrrrrrrrrrrrrrnhhhhhhghhhhhhhmrrrrrrspjiihihiiijjjiijijqsljkkjossommoppomlkkjjiilmmmlpttrqqrrtttttttstttttvŒ•“–™˜——˜—Œztuvuuuuuvvvvuuuuvv~tqqqqpqqprrrvwwwwxxxxwxwvuuuuuutttsssrrsrssssssrsrrrrrrsrsrrsrrrrrrqihhiihhhhhhhihkrrrrrrssrmiiihjjijiiijijjptnjkkjmstrmmmnpppnmllklnommllmrttqqrsstttsssttsuuq}“”’‘’––••”“Ž€vttuvuuuvvvvvvwvw~trqopqqqqrrtwwwwwwyyxwxvuuvvuttssttsssrsssrsrssssrssrrrrssssrsrrrrrqkhhhhhihhiiihhiqrrrrrsssspkiijjjjijjjjjjptokkkklrstommmoppqonnopponllllqstsqprrsttsttttsrsy†�ŽŽŒ�““–—’��އvuuuvuuvvuvvwvvv~tpqppprrqqqtwwxxxxxxyxxvvvvwvvutttstsssssssrrsrssssssssssrrsssrrrrrrlghhhhihhihihhhosrrrrrssstrojiijijjjjjjjqtpjjjkkosttmmnnnoppqpqpponllmlosssrpqqrrsstttsty‚�’�‹‹�Ž�“”“‹‡††Šztuuuuuuuuvvvvuv}tqppqrqrrqrvxxxxxxxxxxxvvvvuuuutsttssssrsssssssssssssssssssrssrsrrrsohhhihhhhhhhhhimrrrsrrrsststroljijjjjjiksuskjjjkmtturmmmnnopppppponnlmmmssstrpqqqrsstu~Œ�‘ŽŽ“••“‘�’“ŽŠ†„‚‚|uuuuuvuuuuuuvuv~trrrsrqqrrtxxxxxxyxyxxxvvvvuuutstttttsssstsssssssssssstssssssssrrrrrqihhhhghhghhhihlrsrsrrrsssstttspmljijikptttmkkkklrttvqmmnnooopppononllllpusstsqprrrsts�–“ŽŠˆ‰�’–•”’�ˆ……„„…ƒvuuvvvuuuvuuuuu~urrqrrrrqrvxxxxxxxxxxxxvvvwvvuttttssssssssssssstsssssssssssssssrrrrrskggghihihgiihgjrsrrrssssssstttutsqpoosutttnkkkkkputuvpmmnnnooonnnnommlmmsutttsqqqsvvqwˆ‹Œ‡ˆˆˆŠ���Œ†ƒƒ‡ˆ‡†ˆ|uvvvuuuvuuuuuu~uqqrqqrqqtwwxxxxxxxxxxyvvvvvuttstttssssssrsrstsstsrssttsssstsrrsrrrrsnhighiihihhhhhipssssssssssstttutuuuvuuttttpkkkkkntttuvpmmmnnnnnoonnnmmmlqutuuuustwyxrs~ƒˆŒ‰‡ˆ‡‡‰‡„ƒƒ†ˆˆ‡†ˆ€uuuuuuvvuvvvuv}trqrrpprsvxxxxxxxxxxyxxwvvvvutttttutttsssstssssstssssstsssssssssssrrrqiiihhihghiihihnssssssssssssssttttutttttttrlkllkmttttvvrmmmnnnnnnnnnmmmmotttvwvvwxxyvqy�ƒˆ‹‰ˆ‡†…‚‚…‡‡‡ˆˆ‡‡ƒxuvuuvuuvvuvuu~urrqpqrqrwxyxxxxyxxxxxxvvvvvvuuttttsttstssttstttttttsssrsssrrrsssssssrjhiiihhiiiiiiiksssssssssssssttsstttttttuutmklkllquuuuuwtommnnnnnnnonmmmmqtttvwwxxxxxrs}ƒ„†ˆ‡…ƒ‚ƒ„……‡‡ˆˆ‡‡…zuuuuuuvuuuuuu}soqqqrrqswxxxyxyxxxxxxxvvwwvvvuuttttsssssstttsssstssstssttsssssssssssrjgiiihjiiiiijijrssssssssssststttttttttttutnllllkouuuuuuwwsnmnnnnnnommmnmotuttvxxxxxxvqx�„„ƒ‚‚‚ƒ…………„…ˆˆ‡‡†{tuuvuvvuvvvuu}trsrqrqrvxxxxxxyxxyyxxxvvvwvvvvttttttttttttsttttttsssssssssssssssrrrsrlhiiiiiiihhijijpssstssssstssssttttttttttutollllkmsuuuuuuwxvronnnnnpnnnnmnrvuttwxyyxxxrs~�‚‚ƒ„…………………„…‡‡‡„xuuuuuvuvvvuuv~~trqrrqqtwxxxxxxxxxyxxxxvvvvutttttttttttttttttttttttttttstsrstssssrrrrskhhiiiiijjjjjigntsssssssstssstttttututuuuvqklkmlmruuuuuuuuwwvtrqqsupnnnnnotuvuuwyyxxxtpy€€‚ƒ………………………„…‡‡~uuuuuuuuuuuvuv~sqsqrqquxwxxxyyxxxxxxxxvvvuuutttsstttttsrttttttsssssststtttstssssstsrrjhhhhiiiiiiiijiksssssssssttsttstttuttuuuuusllllklpuuuuuvvuvvvwwwvvwrnnmnnnruuvvvwyyxxvps�€ƒ…………ƒ„…………„„ƒxuuuuuuuuuuuvuv}tppqrtsvyxxxxxxxxxyxxxyvvvvvuuuttttssttssttttttttttttttttsssrrsrsssssqjiihghjiiiiiiiijqsstssssttstttttttttttuuuutmlklllmtvuuuvvvvvvvvvvvwsmnnnnmouuuvvvvwxxvqpz„€€ƒ„…„ƒ…………„|uuuuuuuuuuuuuuu~tppqrrswxxxxxxxxyyyxxxxvvvvvvuttttttttttttttttttttttsstttttttttssstssoghjjjghjjjiihijiosstssssttttttttttttttuuuuunlmlllmsvuuuuuvvvvvvvvvwuonnnnnnsvuuvwvwwwvqor‚„~€‚„…ƒ~~‚„…ƒ~xvuuuuuuuvvvvuuv~ursssqswxxxxxxyxxxxyyxywvvvwwvutsttstttstttttttsttttssstttttttttttsssnghiijjghjiijhijiltsssstsststtttttttutttuutuplmllllpuuvvvvvvvvvvvvvvvqnonnnnpvwwwwvvvwwsopx†‚€‚ƒ„ƒ||{xvuuvuvvuuuvvvvvuv~ursrrsuxxxxxxxxxxxxyyxxwwvwxwvvutuutttuttttttttsttttttttsttttttssstssmiiiiijjiiijihjjjjststssssttttsttttttttuuuuvrllllllntuuvvvvvvvvvvvvvvtnnnnnnnswwwwvvvvvuppqˆ‚��‚„ƒ{vuuuvuuvvvuuuuuuuvvv~vsrsrsvwxyyxyxxxxxyyxxxwvvvwuvuttttttttttttttttsttttttssssssssrssstsrkiiiiiiiijjijjiiihqsttttttsttrtttttttuuuuuuvsmmmmnnnsvuvvvvvvvvvvvvvvupnoononovwvvvvvvvvropvƒ…�€€‚„‚wuuvvvuvvvuuuvvuvuvvv~vrrqrrvxxxxxyxxyxyyyyxxwvvwwvvttttutttttuttttttttttttttttttstsssssssqjihghhhggijijjiijiotststtttttststttttttuuuuutmlmmlmmquuvvvvvvvvvvvvvvvrnooonnnswvvvvvwvvtoosz‚ƒ‚‚‚„…{uvvuvuuvvuuuvwwwwvvv~tqrqprwxwxxxxxxyxyxyyxxvvvwwwwvuvuuttttttsttttttttttttttttsttttsstttqiiiijjjjjjjjjjiijiltstttstttttttttttuuutuuuuunlmlmmnouvuvvvvvvvvvwwwwwtoooononpvvvvvvwvvvqopuz‚…ƒ„„…�wvvuvuuuuuuuvvvvwvuv~tprqqswxxxxxxxxxxxyyyxxwvvwwwvvvuuuttuttttttttttttttttttttttttstssstqhijiiijjiiiiiijjijkrttttsttttttttuutuuuuuuuuuplmmmnmmsuvvvvvvvvvvvvvwvupnonnnoosvvvvvvvvvsoorx{ƒ„„„„„{uvvvvuuvuuvuuuvvwvv~urssrtxxxxxxxxyxyyyyyxxwvvvwvvvuuttttutttttttttttttttttttttttttsttttoiiiiiiijjiiiiiijjjiquttttttttsttutuutuuuuuuuvqlmmmnmmquuuvvuvvvvvvvvvvvrnonnnoopvvvvvvvvwuoooty{‚„„……�vvvvvvvvvvvvvvvvvvv~urrrquxxxxxyyxxyyyyyxxxwvvwwwwvuttttttttttttttttttttsttstttsttsttsttnijjiiiijjjjjjjjjijiotttttttttttttttuttuuuuuuvqlmmlmmmouvvvwuvvvvvvvvvvvuonnonnoosvvvvvvwwvroopvx{�…††…zuvuuvvvvvuvvvvvvvv~tqsrrvxxxxxxxxyyyyyyyxxwvvvwwvvvuuuttttttttttttttttttttsstssttttttttmiiihhiiijjjjjjkkijjlststtttttttttuttuuuuuuuuusmllmmlmntwvvvvvvvvvvvvvvvvpnnonnnnqvvvvvvwwwuoooswxz€„†‡uvwuuvvvvuuvvvvvvv~urrpqvxxxyxxxxxxxyyyywxwvvvvvvuuuutttttttttttttttttttsssttssttstsstsliiiiiiiiiiijjijkkkjkrtttttttttttttuuuuuuuuuuvtmlmlmlmnqvvvuvvvvvvvvvvvvvrnnooooonsvvvvwwvxwqooquvwy|�…~uvwwuuvvvvvvvvvvuv~uqqqrvxxxyxxxxyxxyyyxxxwvvvvvuuuuuuttttutttttttttttsssssstsrstttsssrjiiiihihiijjiiiijjjjjotttttutttttttuuuuuuuuuvutnlmmnllmptuvvvvvvvvvvvvvvvuooooooonpvvwwvvvvwtooosvvwxyyxuuvuuuvvvvvvvvuvvv~tqrsswxxxxxxxxxxyyyxyxxwvvvvvuuuuuttttttttttttttttttstsssssssttssssqhghihhhhhhiiiijkjijjimttttsttttttuuttuuuuuuuuvuommnmlklnuvvvuvvvvvvvvvvvvvqnoooooootwvvvvvvvvqooqvvvwwwwwuvuvvwvvuvvvuvvvv~uqppswxxxxyxxxxxyyxxxwxwvvvvvvuuuuttuuutttstsstttttssttsssssstsssssphhiijihiiihiiiijiiijjkstttttuuttttutuuuuuuuuuuvqmlmllllnrvuvvvuuvvvwvvwvvwsnnonnooopvvvvvvvvwsooptwwxwwwwvvvuvvvvvvvvvvvuv~tqsrsxxxxxyxxxyyyxyyxwxwvvvvvvuuuuuuuuuuttttttttsssstsssssttttssrstojjjjiijjjiiiiiiiiiiijiqutttttuutuuuuuuuuuuuuvvvrllmmmmnnouvvvvuvvvwwvvvvvvuonnnoonnosvvvvwwvwvpnorvwxwwwxwvuuvvvvvvvvvvvvv~ursrrxxxxxxxxyyyxyyyxwxwvvvvvvuuuvuuvvuuttttttttttsstttttttttttttttngjijihgijjihhjiiiiijjimtttututttttttuutttuuvuvvsllmmmlmmmtwvuvvvvvwwvwvvvwvqnonoonnoqvvvvwvvvwroootxwwwwwwvvvvvvvwvvuvuvvw~urrstwxxxxxxyxyyyyxyxwwwvuvvuuuutuuuuutsssttttttttsssstttttttttttttmfgijiihghijhghjhjijjjjksttuttuuuuttuuuttuuuuuuutmlmmmmmmnrvvvvvvvvvvwwvvwvvsonnnnooootvvvvvvuwtooorwxwwxwwwvvvvvvvvvvvvwvv~ussrswxxyxyxxxxyyxyxyxwwvuvvuvvvtttututtssssstttttuttttttttsttttttskgghiiijiggiihhiiiiiiijiquttuttttuuuuuuuuuuuuuvvumlmmmmmmnouvvuvvvvvvvvvvvvvuonooonooopvvvvvvvwvpooouwvwxwwwvvvvvvvvvvwvvuu~vsrqtxxxxxxxxxxxyyxxyxxxvuuuuuuuttuuututttutsstttttsttttssrrssttstrjfggggggijijiiiiiiiijhjiltttuutttttuuutuvuuuuuvvvolllmlllmntvvtvvvvvwvvvvvwvvqooonnnoootvvvwwwwwrnporvvwwwwwvvvvvvvvvvvvvvu~trtstwxxxxxyxyxxxyyxyxxxvvvvvvututuuutuutttuttttsststttttsssttttstrjghiihhhhhiihhiiiiiiihijirttttttuuttuttvuuuvuuvuvpmmllllmmnsvvutvwvvwvvvvvwvwsnnnnnooooqvvvvvwwwtopppuwvwwwwwvvvvvvvvvvvwvv~urrqswxxxxxxxyxxxyxxyxxxvvvvvvvvvuuuuututttttttsrttttttttttttttttuqijjiiiiiiiihhiiiiijjiijijottuutttuutuuuuuuuuuvvuvrnmmmmlmmmpvvvtvwvvvvvwvvwwwuooooooooootvvvvvvwwqooorvwwwwwwvuvvvwvvvwwvvw~vrrrtwxxxxxyyyxyxxyyyxxxvwvvvvvvvuuuuutttttttttsstttttttttttttttttpiihghihhhhhiihhhiiiijiiiilstttuutuuuuuuuuuuuuuvuvsmlllmmlmmmtvvttvwwvvwwwvvxvvpnooooooooqvvvvvvvwsopopuwvvwwwwuvvvvvvvvwvvv~urssswxxxxxxxyyxyyyxyxxxwwvvvvvvvvvuttututttttttttttttttttttttttstpihhhhiihhhhhhhhiihiiijjjjkrttttutuuuuuuutuuuuuuvvslmmmmmlmmlqvutswwwvvvvwvwwvvsnoonooooootvvvvvvwuooppsvvvvwwwuuvvvvvvvvvvv~ursstwxxxyyyxyxyyyyxxxwxwxwwwvvvuuuuttttutttttttttttttttttttttttstohihhiihhhhhiiihhiiiiiiiiiinttttttttttuuuttuuuuuuvsmlllllllmmpvvurvvvvvvvvwvvvvtnnnoonooooqvvvvvvvvpooopuwvwxvwvtuvvvvvvvvvv~urtstwwxxyxyyxxxxyyxyxxxwwwwvvvvvuuuuuuuutttttttttttttttttssttttttmiiiiihiiiihiihhhhhiiiiijihjrttttttuttttuuuuuuuuuusllkllllmmmouvvrswvvvvvvvvvvvuonoonnnooootwvvvvvvroppprwwwxwwxuuvvvvvuuvvv~tqrrsvxxxyxyxxxxyxyyyxxxwwvvvvvvvvvuuuutuuttttttttttttttttttttstttliiiiiiiiiihhiihihhiiiiikkiioutttuttttttuuttutuuuusmlkllmllllmrvvtpuvvvvvvvvvvvvqmnnnnoonooqvvvvvwwtpopopuwwwwxwvtvuuvvvuuvv~uqrqqvxxxwxxxyxxyyxxxxxxvwvvvvvvvvvuuuuuuuttttttttttttttttttttsttrkiiiihiiihhhihiihhihiiiijjihjsttttuuuttttttttttuuutnkklkllllllpvvvprvvvvvvvvvvvvrnnnnnnoooootwvvvwvupppoprwwwwxxwtuvuvuuvvvu~urrqrvxxxxxxxyxxyyxxxxxxwvvvvvvvvvvvvuuuuuttttttttttttttttttttsstqjiiiihhiihihhiihiiiiiiijjjihgottttttuuttttttttttttsllkkklllkllntuvrouvvvvvvvvvvvuonnnnnnnoooqvvvvvvvqoooppuwwwwxxvtuuuuuvvuu}ursssvxwxxyxxxyyxyyxxxxywwwvvvvvvvvvvuuuuuuuuttuttttttuutttttttttqijjjjiiiiiihiiiiihiiiiiiiijjhkrutttuuuuutttttttttuqmlllllmlkkmmrvvtorwvvvvvwvvvvusonnnnnnooooswvvwwwsoppppswwwwxxwttuuuuuwvu~urtsqtwxxxxxxxyxxxxxxxwywwwwwvwwwwwvvuuuuuuttttttttutttttttttttstpihhiiiihhihihgghhggihghhhihhjimstttsttutttstttttutmjkkkkjkkkkllovvuonruvvvvvvvvvvsnmmmmmnnnnnotvvvvwtnppooptvwwwwwvrttttvwtt~|{{{{|}}}}}}}}}}}}}}}}}}}}}}}}}}}}}|||||||||{{{{{{|||||{{{{{{{{{|zwwwwwxxwwwwxwwwwwwwwxwwwwwwwwwwz|{{{{{||{{{{||{|||yxxxxxxxxxxxxy|||zyz{|||||}||||{yyyxyyyyyzyy{|}}|}|yz{zzz{|}}}}}}z{{{{}{{{€�€€€€~~~~~~~}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}���‚��}~}~~~~~}}}}~~~~}~}~~~~~}~~~}}~~~~~}~~~~~~~~~~~~~€€€€€����}|||||||||||||||||{{{{{{{zzzzzzzzyzzzzyzyyyzyzzzyyyzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy|„ƒ�…†„€yxxxxxyyyyyyxyyyyyyyyyyyxxyyyyyyyyzz{{{{{zyyzzzzzzzz{{|{|}||||}}|}}}}}}}}}}}}}}€€‚����€}||||||||||||||||||{{{{{zzzzzzzzzyzzyzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyz…†††xxxyxyyyyyyyyyyyyyyyyyyyyyxyyyyyyyyzz{{{zyyzzzzzzzzzz{|{{||}||||}}}}}}}}}}}}}}}~€€�‚‚�‚‚�~|||||||||||||||||||{{{zzzzzzzzzzzzyyzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy}ƒ„~xxxyyyyyyyyyyyxxyyyyyyyyyyxyyyyyyyyyyzz{zyyyzzyyyyzzyzz|{{|}|||||}}}}}}}}}}}}}}}}€�‚�‚‚‚‚�€}||||||||||||||||||z{{zzzzzzzzzzzyyzzzyyyyzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy{{yyyyyyyxyyyyyyyyyyyyyyyyyyxxyyyyyyyyyyyyzzyyyyzyyyyyyy{z{{||||||}}}}}}}}}}}}}}}}}}€�‚‚���‚‚��|||||||||||{|||||{z{z{{zzzzzzzzzzzyyyzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxyyyyyyyyzzyyyyyyyyyyyyyyyyyyyyzyyyyyyyyyyyyyz{{{||{|||}}}}}}}}}}}}}}}}}}}€��������‚‚‚€}|||||||||{{||||||{{{{{zzzzzzzzzzyyzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyzzyyyyyxz{zyyyyyyyyyyzzyyyyyyyyyyyyyzz{{|||||||}|}}}}}}}}}}|}}}}}€€�����€�‚‚‚‚�~|{|||||||||||||||{{|zzzzz{zzzzzzzyyzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxyzzyyyyyyxyyyyyyyyyyyyy{{zyyyyyyyyzyyxyzz{||{{||||||}}}}}}}}}}}}}}}€€������������‚‚}{|||{{|||{||||{{|{z{{{{{zzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxyyyzzyyyxyxyyyyyyyyyyyyyyz{zyyyyyyyyyyyyyzz{||z|||||||}}}}}}}}}}}}}}}€��€����‚‚����‚‚‚}}}}||||||{{||||{{z{{{z{{zzzzzz{zzzyzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxyyxyyyzz{zyyyxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxz{{{|{|{||||}}}}}}}}}}}}}}}~€€€������������‚‚‚‚‚}}|{|||||||{{||{|{{zzzzzzzzzzzzz{{yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxyyyyyyyyxyyyyyyyxyz{y{{{{zzyyyyyyyyxyyyyyyyyyyyyyyyyyyyyyyxxz{{z{{{z{||}}}}}}}}}}}}}}}}~€€€����������‚����‚‚‚�}{||||{||||||||{zzzzzzzzzzzzzzzyyzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxyyyyyyyyyyxxyyzz{{|{{yyyyxyyyyyyyyyyyyxyyxyyyyyyyyyyyy{{{z{{{{||||||}}}}}}}}}}}}|}€€�€���‚‚����‚‚���‚‚‚‚‚�}||||{|||||||zz{zzzzzzzzzzzzzzzzyzzyyyyyyyzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxyyyyyyyzz{{{{{yyyyyyyyyyyyyyyyyxxyyyyzyyyyyyyyzzzzzz{{|||||||}|}}}}}}}}}}}|€€€���������‚��€���‚‚‚���{{|||{|||||{{{{{{zzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxyyyyyyyyyyyyyxxxyyyxxxyzzz{zzzzzzzyyyyyyyyyyyxxyyyyyyyzyyzyyyzyyzzyzz{{{{||||||||}}}}}}}}}}|€€€�‚€���������‚���€�‚‚����€~}||||{||||{|{{{z{zzzzzzzzzzz{zzzzzyyyyyyyyyzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxyyxxxxyyyyxyxyyyyzzzzyzzzyyyyyyyyyyyyyyyyyyyzyyzzyyyzyyyyyzzzz||}||}}||}}}}}}}}}}}}€€€€‚‚€�������‚������€������‚�}|{||||{{|||||{zzzzzzzyyzyzzzzzyzzzzyzyyyyyyyyyzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxyyyyxyyyyyyyyyyyyyzz{zyyyyyyyxyyyyyyyyzyz{yyyyyyyyyyz{{z{|}|||}|}}}}}}}}|}}~}€��€‚�€���€€�€€€�€€���‚‚�‚‚‚€~||{|{{z{|{{|z|{zzzzzzzzyzzzzzzzz{zyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxyyyxxyyxxyyyyyyyzz{{{zyyyyyyyyyyyyyzyyzzyyyyyyyyyyyz{|{{|}||}}}|}}}}}}}}}|}}€€������€����€����€€��€�‚‚‚‚€~€|{{|zz{{{{|{{|{zzzzzzzzzzzzyzzzzyzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxyyyyyy{zzzzzyyyyyyyyyyyyyyyyyzyyyyyyyyyyzz{||{|||||}||}}}}}}}}}|}}€€����€�€��€€���€�€€€€€€€��ƒ�~~ƒ�}|{{{|||{{|{{{{z{zzzzzzzzzzzzyyzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyzzyyyyyyyyyyyyyyyyyyzzzzyyyyyyyyyz{{{|{{|{{|}}||}}}}}}}}|}}}€���������€€€��€€€�€€€€€€€‚€€€~�‚�€~~€€ƒ�|{{||zzz{zz{zzzzz{yzzyyyzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyzz{zyyyyyyyyyyyyyyyyyzzzzyyyyyyyyyz{|{|||{{||}}|}}}}}}}}}}}}}€�€€�€���€�€€€€�€€€€€€€€€€€ƒƒ�‚‚‚}|~ƒ‡ƒ€}{{|{zz{{{{{{zzzzzzzzzzzzzzzzyzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxyyyyyyyyyyyyyyyzyzyyyyyyyyyyyyyyyyyyzzzyyyyyyyyyz{||||{||{{|||}}}}}}}}}}|}||€€€�€��€�€���€€€���€€€€€€�€€ƒ~�‚�~|{{||‚…||{{{{{z{{{zz{zzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxyxyyyyyyyyyyyyyyyxxyyyyyyyyyyyyyyzyyyyyyyyzz{||||{||||{|}||}}}}}}}}|||}}€€�‚��������€��€€��€€€��€�‚~~~�€}|}}|{}„…{‚�~||{{{{{{{|{{{z{zzzzzyzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxyyyyyyyyyzyyyyyyyyxyyyyyyyyyyyyyyzyyyyyyyy{{{{|||||||||}}||}}}}}|}}||||}€��‚‚�‚‚�€€€�€��€€�€�€€€�‡††~~‚~z|}}||ƒƒ„|z}€…€~}{{{{{{{{{{{{{zzzzzzzzzzzyyyzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxyyxyyyyyyyyyyyyyxyyyyyyyyyyyyyzzyyyyyyyyzz{{{|||||||||||||}}}}}||}||||}€€�������‚��€‚����€��‚�€€…‹‰ˆƒ}|{z{{{|€�‚�}}}‚ƒ��€~}}{{{{{{{{{{zzzzzzzyzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxyxxyxyyyyxyyyyyxyyyyyyyyyyyyyzzyyyyyzyyz{{|||||{|}}}|||||}}}}}}||||||}€€����€€�����€��‚‚‚‚‚��‚ˆŒˆ€}}}}|||}|||}~~~�}~}ƒ�‚€€€‚ƒ€}{{{{zz{{zzzzzzzyyzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxyxyyxyxyxxxxyxxyyxxyxxyyyyyyyyyyyyyyyyyyyyyyyzyyzz{{{||{|{|}||||||}}}}}}|||}}||€€����������������‚�‚ƒ‚ƒˆŽ�z|~~~~~~€€€|}~}€�ƒ}|z{}€ƒ„€|{{zzzzzzyyzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxyyxyxxxyxxyxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyzzz{||{{{z|||||||||}}}}}}}|}}}}|}€€����‚‚�������‚��‚‚‚‚‚„‰Š{{}~~€€~~~��€€}|~}‚ƒ~~|||{|�†ƒ}{zzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxyyxyyyxxxyxxxxxxxxxyyyyyyyyyyyyyzyyyyyyyyyyyyy{z{{{{|{{{||||||||}}}}}}}}}}}}}}}€€���€����‚�€���‚‚‚‚ƒƒƒ…‰„|~~€€~~€€~}~~~~�ƒƒ…‚‚~|~€�‚„„~zzzzzyzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxyyxyxyyxxxxxyxxxxxxyyyyyyyyyyyyzyyyyyyyyyyyyzzzz{{{{|||}||||||}}}}}}}}}}}}}|}€€�€�€€€€�‚������‚‚„ƒƒƒƒ…‰…€€~~€€~€€€€~~€€�…„‚„€~}€€�€�„€{zzyyzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxyyyxxyyxxxxxyxyxxxxxyyyyyyyyyyyyyzyyyyyyyyyyyyz{{{{{{|||}|}}||||}}}}}}}}}}}|||€€‚��€�����������‚�ƒƒ‚ƒ„…‰†€~~~€��€€�€�~~€€�€†ˆ‡ƒ~€€��€�ƒ�}zzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyzzzyyyyyyzzzz{{{{{{|||}}}}||||}}}}}}}}}}||||€€€‚‚�����€�‚�‚���‚‚‚ƒƒ„…‰†€€~€�€€€€€€�{€�€~€ƒ‡‡‡‚€€€€�}zzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxyxyyxxxxxxxxxyxxyyyyyyyyyyyyyyyzzzzzzzyzzzzz{{{{{{{||}}}}|||}}}}}}}}}}|||{|€€€‚‚‚�€�€�€‚�‚‚�‚ƒ‚‚‚ƒ……Šˆ�€~~€~€€€�€{~‚€€‚…„…~‚}~€‚ƒ………†‚|zzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxyxxxxxxxyyxxxyyyyyyyyyyyyyyyzyzzzzzzzzzzz{zzzzz{{{|||}}}||}}}}}}}}}~|||{|€�‚��ƒ‚����€�‚‚‚‚�‚ƒƒ…†‡‰‹‚€~~€€�€€�~}ƒ‚~ƒ‚„†‚€}~�‚„„„……„„ƒ{zyyyyyyyyyyyyyyyzyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxyxxxxxxxxxyyyyyyyyyyyyyyyzzyzzzzzzzzz{{{zzz{{{{{||}}}}}}}|||}||}}}|{{|€�����‚‚‚‚‚€€�‚‚�‚‚‚‚…†ˆ‰�…~~~€~€��€€€€�‚~ƒ‰ƒ€‚�…„‚€}€�‚ƒƒ„„„„„�€zzzyyzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxyxxxxxxyyyyyyyyyyyyyyzzzzzzzzz{{{{z{{{zz{z{{{|||||}}}}}||||||}|}|{{{€€�������€���€��‚‚‚‚ƒ…†‡‰ŽŠ€~~}~~�����€€€�€�…‡€{{|~�‚��‚ƒ„…………………ƒ|zyzyzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxyyxyyxyyyyyyyyyyyyyyzzzzzzzzzzz{{{{{{{{{{z{{{{||||}}|}|||||||}|}}{{{€€���€��€€�‚�����‚‚‚‚…†‡‰‹Œ‚}~~~~€�€€�€€€€€€�€�~}}}~~€�ƒ‚ƒƒ…………„„„ƒ‚zzyyyyyyyzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxyxyyxyyyyyyyyyyyyyyyyzzyzzzzzzzz{{{{{{{{{{{{{{{{{{|||}|||{{{{||||||{{|€�‚��‚‚������‚‚‚‚‚‚‚ƒ……†‰‹Œ…~~€€���€€€€€€��‚‚€€€��€€�‚‚ƒƒ………………ƒ„ƒ€€{zyyyyyyyzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxyyyxxyyyyyyyyyyyyyyyyyyyyzyzzzzzzzzz{{{z{{{{{{{{{{{{{{{{{||||{{{{{{||||{{|{€�����‚„‚‚‚�‚‚‚‚‚‚‚‚„‡…‡‰Š‹‡�~~€€€���€€��‚ƒƒ‚�€„…�€€€���‚ƒ„„…„ƒ„ƒ�€~yzzyzyyzyyzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxyyyyyyyyyyyyyyyyyyyzyyzzzz{zzzzzz{{{{{{{{{{{{{{{{{{{{||||{{|{{{|||{{|||€€���‚‚‚‚‚‚��‚‚‚�‚‚ƒ‚…‡…‡ˆŠŠˆ�~~€�€�€€€€��‚ƒƒƒ‚�ƒ‡‡…ƒ€€ƒƒƒ„‚„…„ƒƒ�‚€{zzzzzzzyzzzzzyzyyz{yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyzyzzzz{zz{z{z{{z{{{{{{{{{{{{{{{{{{{{{|{{{{{{|{{{|{|€€�������‚‚‚�‚‚�‚ƒƒ‚…†…‡‰‰†‚€~€€€��‚�€��‚‚ƒƒƒ‚‚��…ˆ†…„‚‚�ƒƒƒƒ„��‚ƒ„ƒ�††�|zzzzzz{{{z{{{{zz{zyyyyyyyyyyyyyyyyyyyyyyyyyyzyyyyyyyyyyyyyyyyzzzzzzz{{{{{{{{z{zz{{{{{{{{{{{{{{{{{{{{{{{{{{{{|{{{|€€�‚��‚�����‚‚‚��‚‚ƒ………‡‰‡€€~~€�‚‚‚��€€�‚ƒƒ„„ƒƒ„ƒ‚…‡‡‡…†‚€��ƒ†……„‚ƒ„€„‰‰†�}{{{{{{{{{|{{|{{|{zzyyzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyzzyzzzzzzzzz{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{|{{|{{|{|€����‚‚‚‚‚����‚��‚‚‚………ˆ†€€€€€€�„ƒ‚‚�‚�ƒƒƒƒ„„„„………„‚ƒ‚‚�„ƒƒ†…‚��„‚�„„…ˆ‡‡†…‚~|{||zyyy}zyyyz{{{zzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyzzzzzzz{zzz{zzzzzz{{{{z{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{|€����‚���‚����‚‚‚‚‚ƒ……†‡€€€�€€€€ƒ��ƒƒƒ�ƒƒƒ„„„„„†…†††„„„„‚‚ƒ�‚‚„„ƒƒ�‚†‡‡‡ˆ‰‡†…‚~||…Ž”˜¡�—І‚|yyz{{{zyyyyyyyyyyyyyyyyyyyyyzyyzyzzzzzzzzzzzzzzzzz{{{{{{{{{{{{{{{{{{{{{{{{{{{|{{{{{{{{{{{|{|||€€���‚‚�‚�‚�‚����‚‚‚ƒ……‡€}€€€€��€€�ƒ…„‚„�ƒƒƒ„„„„…††††‡‡‡‡‡‡†…„……………†‡…„Š‹ˆˆˆˆ‡††„œ¸»Ã¾ÂÁ¼À¿°ž�„zy{|{zyyyyyyyyyyzyyyzyyzzzzzzyzzzzzzzzzzzzzzz{zz{zz{{zz{{{{{{{{{{{{{{{{{{{{{{{{|{{{{{{{{{{|€��‚��‚���‚���‚�‚ƒ‚„…†ƒ{}€€€€€‚�€€�€�ƒ�„ƒ�‚ƒ„„„„„……‡‡‡†‡‡†‡‡†‡††††……†‡‡ˆ‘˜”މ‰ˆ†„Š¥ÇÎÎÊÈ¿¾ÁÂÅÐÑĹ¢†}zz{{zyyyyyyyyzzyzzyzzzzzzzzyzyyzzzzzzzzzzz{zz{{{{{{z{{{{{{{{{{{{{{{{{{{|{{{{{{{{||{{{{{|€‚����‚‚���‚‚‚‚‚‚‚ƒ„†…}|}�€€€€‚‚€��€€‚…ƒ�ƒ‚ƒ„„„„††…†‡†††††‡†‡‡†‡‡‡‡†‡‡ˆŒ‘˜™›š“‹Œ›¾ÖØÕÑÐÐÏËÀ¾ÈÄÁÊÐÎǹ«•~z|{zzzzyyyyzzyzyyyzzyyzzzyyyyyyzyyyzz{zzzzzzzzzz{{{{{{{{{{{{|{{{{{{{{{{{{{{{|{||{{{||{€€���‚‚‚�‚‚‚���‚‚‚‚„†�}}~€€€€€‚�€��€€€�ƒ„„ƒƒƒ……†…†††††††††‡‡‡‡†‡ˆˆˆˆˆˆˆ‰Œ�–˜Ÿ¢¢­ÀÕÜÚØÓÏÎÏÏÏÐËÄÐÖÏÌÒÏÉÇë‚xz{{{yyyyyzzzyyzyyyyyyyyzzyyyyyyzyzzzzzzzzzzzzz{{z{{{{{{z{|{{{{{{{{{{{{{{{{|||{{|{{{|€�‚��‚‚���‚����‚‚‚‚……~~}}€€€€�ƒ���€€�€€ƒ……ƒƒ……………††††††††‡‡‡‡††ˆˆ‡ˆ‡‰‰Š�‘—šŸ °ÃÈÈÉÊÈÌÎÎÎÎÍÎÎÊÄËØÛ×ÒÍÇÄÅ·�|z|{{yyyyyyyyzyyyyyyyyyyzyyyyyyzzzzzzzzzzz{zzz{{{{{{{{z{{{{|{{{{{{{{{{{{{{||{{{|{|||€‚‚‚‚‚‚‚�‚���‚‚�‚‚‚†ƒ}~}~€€€€€€�‚ƒ����€��‚……„…‡……†……†††††††‡‡‡‡†‡ˆ‡ˆˆˆŠ‰ŠŽ‘—š�§»»¶¶º½¿¿ÂÆÌÎÎÎËÍÎÇÅÏÜäàÒÉÃŦ„y{|zz{zyyyzyyyyyyyyyyyyyyyyyyyyzzzzzzzzz{z{{{{z{{z{{z{{{{{{{{{{{{{{{{{{{{{{{||||||€�‚‚‚ƒ��‚‚���‚‚‚‚‚ƒ†ƒ}~|�€€€€€��ƒ‚���€�‚‚ƒ……††…†††††††††††‡ˆˆ‡‡ˆˆ‡ˆˆ‰Š‹‹Ž�–™›°ÇÊÈÇÅÁ¼º»½¿ÅÊËÉÄÂÊÌÅÄÒßÛÔÒÈÆÉ¸‘zz{zzzyyyyyyyyyyyyyyyyyyyyyzyyzzzzzzzzzzzzz{{zzzzzzz{{{{{{{{{{{{{{{{{{{{{{||{||{{€€���‚‚‚��‚ƒ‚‚‚‚‚‚ƒ†ƒ|}|��€€€€€€�ƒ‚���‚‚ƒƒ„„……†††…†††††††‡‡ˆˆˆˆˆˆˆˆ‰ŠŠ‹�ŽŽ—›ž¼ÑÔØ×ÕÒÐÉÅÀ¿¾ÀÃÄÄÇÈÍÌÊÈÎÖÓÒÙÉÂÄÁ¢~y{zzzyyyyyyyyyyyyyyyyyyzyzzzzzzzyyzzzzzzzzzzzzzzzzzzz{{{{{{{{{{{{{{{{{||||{{|||€‚ƒ‚���‚‚‚‚‚‚‚ƒ‚‚‚ƒ…„}||€��€€€€€€€‚ƒ‚�‚‚ƒƒƒƒ„…††††…†††††††‡‡‡‡ˆˆˆˆˆ‰Š‹‰‹ŽŒ�˜›ž¹ÉÎÓÕÖÕÓÒÐÎÍËÉÈÆÊËÍÅÌÑÎÏÏÑÎÍÒÉÆÆÇ°„x{zyyyyyyyyyyyyyyyyyyyyyyzzyyyyyyyyzzzzzzzzzzzzzzzzzz{{{|{{{{{{{{{{{{||{{||{{|€‚ƒ‚‚‚‚‚‚‚‚��‚‚‚‚‚„…†}|€�€€€€€€��‚ƒ„‚‚ƒƒƒƒ„„………††‡†††‡†‡‡‡‡‡ˆˆˆˆˆ‰‰ŠŠ‰Œ�Œ�–™�²ÅËÏÑÔÔÔÕÓÐÐÑÐÊÆÃÂÂÂÉÊÊÐÍËÌËËÀ»ÅÇʹŒy{yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyzzzzyzzyzzzzzz{{{{{{{{{{{{{{|{{||{{{|€��‚‚‚‚‚�‚‚��‚‚‚‚‚„…†�||€�€€��€���‚‚„…„„„ƒ„ƒ„…„…†‡‡‡††‡‡†ˆ‡‰ˆˆˆˆˆˆ‰ŠŠ‰ŠŒ‹‹’—šœ®ÅÉÍÏÒÕÖÔÑÓÔÎÇÆÃÀÀÇÍÍÎÍËËÍÑÎŹ²ÆÌÇʼˆy{zyyyyyyyyyyyyyyyzyyyyyyyyyyyyyyyyyyyyzzzzzzzzzzzz{{{{{{{{{{{{{{{|||||{{|{|€€��‚‚‚‚‚‚‚ƒ‚‚ƒ‚ƒƒ„………}|������€€€��‚‚„…„„„……………„…†…††‡‡††‡‡‰ˆˆˆˆˆˆ‰ŠŠŠŒ‹ŠŽ”˜šš¬ÃÈËÎÑÕÔÓÔÓÍÇÅÅÂÇÉÈËÏÏÍËÊÊÍÃÆÃ¸ÂÓÐÉͬzzyyyyzzzyyyyzzzyyyyyyyyyyyyzyyyyyyyyyzyyzzyzzzzzzz{z{{{{{{{{{||||{|{{||||{|€�‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒ„……‡‚|€���������‚‚‚ƒ„†………………………†…†††††‡‡ˆ‡‡‡‡ˆˆˆ‰Š‹Œ‹ŠŒ‘••˜œª¾ÇÊÌÏÑÓÕÓÌÆÆÃÆÊÊÈÄÁÇÏÏÌÊÊÌËÍÌĹɨÔÌÆ�w{{zyvsuxyzzzzzzyyyyyyyyyyzzzyyzzyyzzyzyyyyzzzzz{{z{{{{{{{{{{|||{{{{{{{|{{|€‚ƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚‚„………†€�€€�������‚‚‚ƒ„†††‡…………††…†††††††††‡†‡ˆˆ‰Š‹Œ‹ŠŒ‘’”•—œ§¶ÅÈËÌÐÔÐÊÆÅÅÇÊÉÉÇÆÂ½ÅÏÎÊÊÊËÊÎÒ¿¶ÇÒÍÍ¥yvhdeb``cgqx{zzzzyyzyyzzzzzzzyzzzzyzyzzzzzzzzzz{z{{{{{{{{{{{{|{||{{{||{{{{|€���‚ƒ‚‚‚‚‚�‚‚‚‚ƒƒ…………‡…����€�������‚‚ƒ„„†‡ˆ†…‡†‡‡‡†‡‡‡‡‡‡‡‡‡ˆˆˆ‰‰‰‹‹Š‹�‘’“”–š¢ªÀÇÉÍÐÌÆÆÄÄÈÊÉÈÇÆÅÄÁ¼ÃÎÍÉÉÌÊÊÕÏ¿¶ÀÈȲr^^_\^^\\\^clw{zzzzzzzzzz{zyyyyzzzyyzzyzzzzzz{z{{{{{{{{{{{{{{|||{{{{{||||{|€�‚‚�‚‚‚‚‚‚‚‚ƒ‚‚ƒƒ…………†‡„€�€€�������‚‚‚ƒƒ„…ˆ‰ˆ‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡ˆ‰ˆˆ‰ŠŠŠ‹Ž��’’”—˜  ³ÅÆÉÈÄÄÄÆÈÈÈÇÇÇÅÄÄÃÁ»ÁÎÌÉËÌÌÒÑËÅÄÍϹigqod\\\_`_a_`s{yzzzzzzzzzzzyzzzzzzzzzzzzzzz{zz{{{{|{{{{{{{||||{{{{{|||{{{|€‚‚�‚‚‚‚‚‚‚‚‚ƒƒƒƒƒ…………††‡ƒ�€€€������‚‚‚ƒƒ„„†‡ˆˆˆˆ‡‡‡ˆ‡‡‡‡‡ˆˆˆˆˆ‰‰‰‰‰ŠŽŽŽ�’“”—–Ÿ¡¤ÀÃÁÁÃÄÆÈÈÈÇÇÇÅÃÄÃÃÃÁº¿ÌÌÊÉÌÏÐÌÎÒÌÏÁ~nnongfea``agb_s{zzzzz{{{zzzzzzzzzzzzzz{{{{{{z{||{|{{|{{{{{{{||{{{{{{||||{|€‚‚‚‚‚‚‚�‚‚‚ƒƒ‚ƒƒ„…………††‡ˆ„���������‚‚‚‚ƒ„„„…†ˆˆ‰‰‰‰‰ˆ‡‡‡‡‡‡ˆˆ‡‰ˆˆ‰‰‰Ž���’“””˜œ¡£º¾½¾ÀÅÈÈÈÈÇÅÄÀ¾ÁÃÃÄÃÀ¹¾ÌËÉËÍÑÎÈËÈÁÁ…mnnooonhbb`aieap{zz{z{{{{zzzz{{{{{{zz{{{{{{{{{{{{{{{|{{{{{{{||{{{|{{||{{||€�‚‚‚�‚‚‚ƒ‚‚ƒƒ‚‚ƒ……………†††††„���������‚‚‚‚‚ƒ„………†‡ˆˆ‰ŠŠ‰‰‰‰‰‰‰ˆ‰‰ˆˆˆ‡‰Ž���‘’’“–š�¤¹·º½ÀÃÆÇÈÈÃÁ¾»¸ºÁÃÂÃÂÀº¾ÉËËËÈÆÈÉ̽ˆoqnnnnnnkfb_bjc]ix{{{{{{{{{{{{{{{{{{{{{{{{{|{|{{{z{{||{{{{{{{|||||{{{||{{|€€�‚‚‚‚‚‚‚‚‚‚ƒƒƒƒ……………†††††‡…�€������‚‚‚‚‚ƒƒ„…………††‡ˆˆ‰Šˆ‰‰‰ˆˆˆ‡ˆ‡‡‡‹�����’“’”–œ¡¸¶·¼¾ÁÃÅÇȶ·­­®´ÂÄÂÂÂÀº¾ÇÈÈÄÃÃÃÆÅ¾Žrtononnnmhcb_dkbY`r{{{{{{{{{{{{{{{{{{{|||{{|||{|{{{{{{{{{{{{{||{||{{{{{{{|€ƒ‚�‚‚ƒƒƒƒ‚‚ƒƒƒ‚„……………††‡††…‡…‚������‚‚‚‚‚ƒƒƒ„„………†††‡ˆ‡‡‡‡‡‡††††‡†‡�����‘‘’“””›Ÿ¶¹µ¹½¿ÁÃÆÇÆ¤¬³ªªª±ÂÂÂÂÀ¿¼½ÂÄ¿ÃÂÀÁ¿»’ttpooonnnlgda_elf^akw{z{{{{{{{{{{{|{{{{{{{{{{{{{{{{{{{{{{{{{||{{{{||{{|{{|€‚ƒƒ‚‚‚ƒƒ‚‚ƒ‚‚‚ƒ……†………††††………†‡„�������‚‚‚‚‚ƒƒƒ„…………††…†‡††††††††††ˆ������‘‘’“”˜�³¸µµº¾¿ÀÂÄǺ¬¨œ�§¤°ÂÂÃÁ¿¿½¼¼¸¾ÃÀ¿½¶Œturppononnkebdaiqqppuzz{{|||{{{{{{{{{|{{{{{{||||{{{|{{{{{{{|||||||||||{||{€�ƒƒ„ƒƒ‚‚‚‚ƒ„„ƒ„…………………†††…††‡‡‡†�����‚‚‚‚‚‚‚ƒƒ„„………………………………†…………†‹������’‘’’“–›±·¶´¶»¾¿¿ÁÄÆ½£Ÿª¦¨´ÂÂÂÀ¿¿¿½¹¶¶¶·µ´¬‚vusqqoooomllnmhjqvpsyzz{{xxyz||||{{|||{{{{{{||||||||{{{{|||{||||{{|||||{|{€�‚ƒƒ„ƒƒƒƒƒ„„ƒƒ……………………††††††ˆˆ‡ˆˆ„��‚‚‚‚‚‚‚‚‚‚ƒ„ƒ„……„……„„……………………†ŒŽŽ�����’‘’“•™¬¸µµ³¶º½¾¿ÀÂÆ»¤™©¼ÂÁÀ¿¿¿¾¼»¸µ³²³²²˜xwurqqpooporuuuukfpggox|x|‘›Ž�|z|}}||}|||||||}|||||}|{||{{||||{{{{|{|{||||{€�ƒƒ‚‚ƒƒ„ƒ„„ƒƒ„…………………†††††††‡ˆ‡ˆˆ‰†ƒ‚�‚‚‚‚‚‚‚‚‚ƒƒƒƒƒ„…„„„……………………ˆŽŽŽŽ����‘’’’”–¦·´´³²¶º¼¼¾¿Àÿ¦›©¾Á¿¾¾¾¼»¹¸µµ¶¶¶¥�ywurqqppqqtwxxromc`bebhxвÏÕÏÁ°›„z{}}|}|}||||||||||}}||{||{{|{|{{{|{{{{zzz{~€�ƒ‚ƒƒ‚‚‚‚ƒƒƒƒ„…………†……†††‡††‡‡ˆˆˆ‰‰Š‰†‚��‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒ„„„…„„……ŠŽ��Ž�Ž���‘’’“• ¶³´³²²µ¶¹¼½¾À¿¥•£ª²¼½½½¼¹·¶¶··«ˆ{zwuspqqqrvyyyrllog^_bb`cœ×ÔÓÕÙÛÖÅŸ†}z{}}|}||||}}|}}||{|{|{{{|{{{{{{{{zzz{{{~€‚‚‚ƒ‚‚ƒƒƒ‚‚ƒƒ……………………†…‡ˆ†‡ˆˆˆˆˆ‰ŠŠŠŠ‰…‚‚‚‚‚‚‚‚‚‚‚ƒƒ‚‚ƒƒƒƒƒƒ„ƒƒƒ‡�����Ž�Ž���‘“’”š²µ³³±°°²µ¸»½¾¿Á½§�—³¼¿½½¼¹¶·¸²¡‹€~zwusqqqtyzzxtssqni^]_adef Ù×ÔÓÔÖÚÚ˳š†{z||{{|||{{|}}{{{|{|{z{{zzz{z{zzzzzz{€‚ƒƒ‚ƒƒƒ„„ƒƒƒ„……………………††‡ˆ†‡ˆˆˆ‰‰‰ŠŠŠŠŠŠ‰…‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ‚ƒƒƒƒƒƒ„Œ��Ž�ŽŽ������‘‘“•ª¶²²±±°¯²´·¼¼¼½À¿ª˜—Ÿ®¶»»·¶¸®•Šˆ„�{xvtrqvz{zwttttuun`^_achhg´ÖÌÍÎÎÌÐÚßÙɰ–~y|{|{{{|{}||{{|||{z{{{|{{{||{{zzzz~€�ƒ‚ƒƒ‚‚ƒƒƒƒƒƒ…†………………††‡ˆ‡‡ˆˆ‰‰‰ŠŠŠŠŠŠŠŠ‹‰†ƒ‚‚‚‚‚‚‚‚‚‚‚ƒƒ‚‚‚ƒƒƒ‰����Ž�Ž������‘‘“”Ÿ´²±±±°¯¯±´·ºººº¼¼´¨Ÿ˜–Ÿ¢¬·¨‘‰‹Œˆ†~yxvvx{{yuttttttuupfbeffmi‹ÓÐËÈÍÐÎÏÔØÚÛÔ·‹z|||||||||{|||{{|{|{{||||{||{{{zz€�‚‚ƒƒƒƒƒ„„ƒƒƒ……………………†††ˆˆˆˆˆ‰‰ŠŠŠŠŠŠŠŠŠŠ‹‹Šˆ…ƒ‚�‚‚‚‚‚‚ƒƒ‚‚‚‚ƒˆ����ŽŽŽ�������‘�‘”–¬´°±±°¯¯®¯³´¶···¹¼½»µ«£¥°¢�‹‹‹ŒŠ‹„{z{|{zwtttttttttuvslklikm…ÐÔÊÇÉÌÑÒÎÏÑÕÖÔÅŽ{|||||||{||zzzz{||{{{|{{{{||{{{{€‚„„„„„„„‚‚‚ƒ„…………………†††‡ˆ†‡ˆˆ‰‰ŠŠŠŠŠŠŠŠŠŠŠŠ‹�ŒŠ‡…ƒ‚‚‚‚‚‚‚‚‚ƒ…Š����ŽŽ������������’“œ²±±±°¯¯®¬®°±²´µ¶·¸¹¹¹¸µ£��Œ‹‹ŒŠ‹…|}}}zwutttttttttttvvrmmml¢ÞÜÖÐÈÅÇÌÑÒÓ×Ô¾¼°�z|||{{||{zzzzzz{|{||{{|{|{{{||{€‚‚‚ƒƒ„„„„ƒ„ƒƒ………†…………†††ˆ†††‡ˆŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‹Œ��Œ‹‰‡……„„„…‡Š�ŽŽ���ŽŽ������������’““¤´°°°¯®­­¬¬¬®¯±³µ¶´²¯ª¦��ŒŒŒ‹Œ‹Š„|}|zxwvtttvvuuutttuvwttq~ÂÓÏÒÔÐËÇÅÉÏÔÖÔÆ¹©„}}{|{{{|{zzzzzz{{zz{{{{z{|{||zz€‚‚ƒƒƒ„ƒƒ„„ƒ„ƒ……††…………†…†ˆˆ†††‡ˆŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‹‹�����ŒŒŒ‹Œ��Ž��ŽŽ����Ž�Ž���������‘‘’”©³±°¯®­¬¬«ª«¬¬®¯¯­ª¦¤¥£��Œ‹Œ‹ŒŠ…|}|zywwusuxyz{zwttttvwvv ÂÀÂÅÉÎÌÈÄÃÀÁÆÃ¹ÍÆ�€~|{{{{zzzzzzz{{{{{{{z{|{{{zz€‚ƒƒƒƒƒƒ„ƒ„„„„…†………†…††…‡‰ˆ‡†‡‡‰‰ŠŠ‹ŠŠŠŠŠŠŠŠŠŠŠ‹‹Œ����Œ�������ŽŽŽ�Ž�ŽŽ������������‘’‘–«³°¯¯­¬¬««ª©¨©©§¥¥¥¦¨§’ŒŒ‹‹Œ�Ї}{}|zxwwuty||~~}xtttvwx”²ºÀÃÅÃÃÄ¿¸°­°¶·ÉÙ®€‚���€~}|zzzzz{{|{zz{|||{zz{zz€‚ƒ‚‚ƒ‚ƒ„„ƒ„…„†…††……†††…†ˆ††ˆˆ‰ŠŠŠŠ‹ŠŠŠŠŠ‹Š‹ŠŠŠ‹‹‹‹ŒŒŒ���������ŽŽŽ����ŽŽŽ����������‘‘‘—¬²¯®­­¬¬«ª©©§¦¦§§§§¨©˜ŒŒ‹‹‹Š‹‰€z|}{yxwwutx~}zvtuvvy›¸°·½ÁÄÄÿ·¯«ª¬²¼½ÂÉ‘~‚��‚�‚��~}}|{|{zz{{{{{zzzz{z€‚„ƒƒƒƒ„ƒƒƒ„„„……†…†……†††‡ˆ†…†‡ˆ‰‹‹ŠŠŠŠŠŠŠ‹ŠŒ‹‹‹‹‹‹Œ‹ŒŒ�ŒŒ���������Ž���ŽŽ�Ž�Ž���������‘‘–©±¯®­¬¬«ªª©©¨¨¨¨¨¨©ª�ŒŒ‹ŠŠ‹ŒŠ„zz|}{ywwwutw||wwvvx’¸¹¯´º¿ÃÀº°­¬®±²±®µ¼¼È³‚|{{}�‚������€~||||zzzzz{{||€ƒ„„„„„ƒƒ„„ƒ………………†…††††‡‡†……†ˆˆŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‹‹‹ŒŒŒŒŒŒŒŒŒŒ������Ž��Ž�Ž���ŽŽ���������‘�“¥°¯­­¬¬««ª©©©©©©ª©«¢�‹‹‹ŠŠŒŠˆ}y|}}{zxwwvtuz€�}y|‹ž°¹±°·º¸²­­±´´´³³°¬±¾Ä”ppoqsw{����‚��ƒ‚��€}||||{{{€‚‚‚ƒ„„ƒƒƒƒƒƒƒ…†…††…††††‡‡†…††ˆ‰ŠŠŠŠŠŠŠ‹‹‹Œ‹‹‹‹‹‹‹Œ‹‹ŒŒ�ŒŒŒŒ������ŽŽ�Ž��Ž�Ž�ŽŽŽ����������’ ­°­¬¬¬«««ª©©©ªªª«§�Œ‹‹‹Š‹‹‰‚yz{}}{zxwwwvuw|~ƒ�—˜¤´³¬®¬«®²´µµµ´³²±±¬±¹¾ qqpppoory€��€‚����‚ƒ‚��‚‚�€~}€€‚ƒ„„…„„„ƒ„‚‚ƒ…†…†††††††‡ˆ†††††ˆ‰ŠŠŠŠŠŠ‹ŠŠ‹‹ŠŠŠ‹‹‹ŒŒŒŒŒŒŒŒŒŒ������Ž�ŽŽŽŽŽŽŽŽŽŽ�ŽŽ�����ŽŽ���™©¯­¬¬«««ªªªªª«ª«©’ŒŒ‹‹‹Š‹Š‡|yz{|}{{yxxwwvv|Œ�’”š¨¶®£¦¬±µµ´²³´³²²²°¬¯´�uxsooprqry~€€������‚‚‚‚‚ƒƒƒƒ‚€€ƒ„„„„ƒƒƒ‚ƒ„„………††††††††‡ˆ‡‡‡ˆˆ‰‰ŠŠŠŠŠŠ‹ŠŠŠ‹‹Œ‹Œ‹Œ‹ŒŒŒŒŒŒŒŒŒ������Ž�Ž��Ž��ŽŽ�����������ŽŽŽ��“¡­®¬¬«ª««ªªª«««ª•‹‹‹‹‹‹‹‰‰‚yzz{|}||zyyxz{}‹��‘•œ«´§§«¯²µ´²¯«¦§®°¯®¯¡{vy{xtsrsvxy{€€������‚‚‚ƒƒ‚�‚€€ƒ„ƒ„ƒƒ„„„„„…………………††…†††ˆˆ††ˆ‰ŠŠŠŠŠŠŠŠŠŠŠ‹Œ‹ŒŒŒ‹‹Œ‹‹ŒŒŒŒŒŒ���������Ž�ŽŽŽŽ�ŽŽŽ�Ž������ŽŽŽŽŽ�Ž�˜¦­­«««««««««««–‹ŒŒ‹ŒŒŒŠ‰‡|xzz{{}}||{|}}{„���’—�¬¬¦©ª¯²´²¤�˜š¢°°°§‹~}}|ywsrvz|yy€€������‚‚‚‚�‚�€€ƒƒ„„ƒƒƒ„„„ƒ„……†………††††††‡‡†††‡ˆ‰ŠŠŠŠŠŠŠŠŠŠ‹‹ŒŒ‹ŠŠ‹ŒŒŒŒŒŒŒŒ�����������ŽŽŽŽ�ŽŽŽ������ŽŽŽŽŽŽ��Ž���›§¬­«««««ª««ª•‹Œ‹‹Œ‹ŒŒŠ‰ƒyyzzz{|}}}}}|{~����”–�¨§¨¨ª®±²®Ÿ•�¬°ªœ�w}~~}{xvw}€€{~€€€������‚ƒ‚���€€‚„ƒƒƒƒƒ„„„„…††††……†††…†‡‡‡‡‡‡‡ˆŠŠŠŠŠŠŠŠ‹‹ŠŠŠŠ‹‹‹Š‹Š‹‹Œ‹ŒŒŒŒŒ��Œ�����Ž����Ž�������Ž��ŽŽŽŽŽŽ�����Œ‘›¥¬­¬¬«««¬¦�‹‹‹‹‹Š‹ŒŠ‰ˆ�xyzzzz||}}||{z‡���’”•œ¥¦¨©ª­®²²¥—‘ˆ€|{{wttvz|yx|~€��€~€€€�€�����‚‚‚��€€‚„„„„„ƒƒƒ„„……†††…†††††…†ˆ‡‡‡ˆˆ‰Š‰ŠŠŠŠŠŠ‹ŠŠ‰‹‹‹Š‹‹‹‹Œ‹ŒŒŒŒŒŒŒ��Œ�����Ž�Ž�Ž�ŽŽ�‘ŽŽ�ŽŽ�ŽŽŽ���������ŒŒ�— §ª«¬¬©—‹‹‹‹‹‹‹Š‹‹‰‰‡~xyzzzz{|||{zy€Ž���“’“œ¦¥¨©ª¬®±«›…ru{�€|wtsuw{€€€�€}€€���€€��€����€€ƒ„ƒƒ„„„…ƒƒ………††…†††††…††‡‡‡†ˆ‰‰ŠŠŠŠŠŠ‹‹ŠŠ‹Š‹‹Œ‹ŒŒ‹‹ŒŒŒŒŒŒŒŒŒŒŒ��������‘‘����Ž‘�ŽŽ�ŽŽ���������������Œ��•™›š‘‰‹‹Š‹‹‹‹Š‹‹‰‰‰…}xyzzz{{{{zzy|ŠŽŽ�‘‘�’ §¥§©ª©¨šŒŒ�~~�€€�€{y{}€��€~}€€€€�€��€����€€‚ƒƒ„ƒƒƒƒƒ„†…†††…†††††††‡ˆ‡†‡ˆŠŠŠŠŠŠŠŠ‹‹Š‹ŒŒŒ‹‹‹‹‹Œ‹ŒŒ‹‹ŒŒŒŒŒ�������������ŽŽ��Ž����ŽŽŽ����������������Œ‹‹Š‰‰Š‹ŠŠ‹‹‹‹Š‹ŒŠ‰‰‰…}xyzzzzzzzzzz„ŽŽŽ�’��”¤¥£¥¤££Ÿ�Œˆ‚}€���€����€}€€€€€€��������€€ƒ„ƒƒ„ƒƒƒ„……††††††††††††‡‡††‡ˆŠŠŠŠŠŠŠŠŠŠŠŠŠ‹‹‹‹‹‹ŠŠ‹‹Œ‹‹‹‹‹ŒŒŒ�ŒŒ���Ž�ŽŽ�Ž������ŽŽŽŽ�Ž�������������Œ��ŒŒŒŠŠŠŠŠŠŠ‹‹‹‹‹‹Œ‹‰‰‰ˆ…~yyzzzzzzzzy€������Ž�˜¦¤£¢¢££šŽŒ„�~€€€€����€~~€€€€���������€€ƒ„„ƒƒƒ„„ƒ…††…†††††††††††‡†††‡‰ŠŠŠŠŠ‹‹ŠŠŠŠŠ‹‹‹Š‹ŠŠŠŠŠ‹‹ŒŒ‹Œ���Œ�������Ž���Ž‘’‘����ŽŽŽŽ����������������ŒŒ‹ŠŠŠŠŠŠŠŠ‹‹‹‹‹‹‹Š‰‰‰ˆ…€{yyzzzzzzz}‹�����ŽŽ��¥¢¢¢¢¢¢”Œˆ‚�€€€�‚����€€~~€€����������€€€‚‚‚„ƒ„„„„…††…††††††††…†‡ˆ††††ˆˆ‰ŠŠŠŠ‹Œ‹‹‹ŠŠŠ‹Œ‹‹‹Œ‹‹‹Œ‹‹‹‹ŒŒŒŒŒ���������Ž��’Ž�Ž�Ž�Ž�Ž�������������Œ���Œ‹‹Œ‹ŠŠŠŠŠ‹‹‹‹‹‹‹‹‰‰‰‰ˆ†„zyzzzzyy}Š��Œ�Ž����Ÿ¥£¢¢¢£��Šƒ‚�‚‚��������€~~€€�����������€€ƒ„„„ƒƒ„ƒ„…†††††††††††…†‡ˆ‡††‡ˆˆ‰‰‰ŠŠŠ‹ŠŠŠŠŠŠ‹ŠŠ‹‹‹ŒŒŒŒŒ‹ŒŒŒŒŒŒŒŒŒ��������Ž��������ŽŽŽ���������Œ�����ŒŒŒŒŒ‹‹ŠŠŠ‹ŠŒ‹‹Œ‹Œ�‹‰‰‰ˆ‰ˆ‡…ƒ~{yxxyx‚ŒŒ�Œ��Ž��Œ‘ ¥££¢¢¢’Œ†ƒ‚�������€���€~~€€€��€�������€€‚„ƒ„„ƒƒ„†††††††††††††††‡ˆˆ‡ˆŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‹‹ŠŠ‹‹‹Œ�ŒŒŒŒŒŒŒ���Ž����ŽŽ’‘ŽŽ����‘��Ž��Œ�����Œ���ŒŒŒŒŒ‹‹ŠŠ‹‹Š‹Œ‹ŒŒ‹ŒŒŠŠŠ‰‰‰ˆˆ‡†„�}~‚‰‹ŒŒ‹ŒŒ����Œ‘Ÿ¥£¢¢£–�‰‚ƒ�€����������€~~€€€€����������€€ƒ„„ƒ„„„…†††…†††††††††…†‡ˆˆˆˆ‰‰‰ŠŠ‹‹‹ŠŠŠ‹‹Œ‹‹‹‹‹ŒŒŒŒ‹Œ‹ŒŒ‹‹ŒŒŒŒŒŒ�ŒŒ��Ž’‘������Ž�ŽŽ������������Œ�Œ�ŒŒŒŒ‹Œ‹‹ŠŠŠŠ‹‹‹�ŒŒŒ‹‹‹‹ŠŠ‰‰‰‰‰ˆ‡‡‡‡‡‰Š‹ŠŒ‹‹Œ�Œ�Œ��Œ�›¤¤££š��„ƒƒ�����‚‚������~€€€����‚‚��‚��€€ƒƒ‚ƒ„†„…†††…††††††††††††‡††‡ˆˆ‰‰‰Š‹‹‹Š‹‹‹‹ŠŠŠŠ‹‹‹‹‹Œ‹ŠŠ‹‹ŒŒŒ����ŒŒŒŒ�����““Ž�ŽŽŽ����ŽŽŽ�Œ������ŒŒŒŒŒŒŒŒ‹‹‹Š‹‹‹ŠŠ‹ŒŒ�ŒŒŽ�‹ŠŠ‰‰‰‰‰ˆˆˆˆˆ‰ŠŠ‹Š‹‹‹‹‹‹�ŒŒŒŒŒŒ•Ÿ£¤˜‹Ž‡�„ƒ‚���ƒ„‚����€~€€€������‚����€€€‚ƒƒƒ„„„…†††††††††††††…††‡‡††ˆˆ‰‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‹‹ŠŠŠ‹‹ŒŒ‹ŒŒŒŒŒŒ��‘�ŽŽ‘”��ŽŽ���ŽŽ�Ž�Œ����ŒŒ�Œ‹ŒŒŒŒŒŒŒŠŒŒŒ‹ŠŠ‹Œ‹Œ‹Š‹�ŒŠ‰ŠŠ‰‰‰‰‰‰‰‰‰‰Š‹Š‹‹‹‹‹‹‹Œ‹‹‹‹‹Š�“”ŒŠŒŒ‚�ƒ‚����„…‚��€€�������‚‚���‚�€€‚„„„…ƒ„…††††††††††††††††‡‡††‡ˆ‰ŠŠŠŠŠŠ‹ŠŠŠŠŠŠŠ‹‹‹ŠŠŠŠ‹ŒŠŠ‹ŠŒ‹ŒŒŒŒŒŒŒŒŒ�‘�ŽŽ��”���Ž�‘Ž�Ž��ŒŒ�����ŒŒŒŒŒŒŒŒŒ‹‹‹‹ŠŠŠ‹‹ŒŠŠŠ‹‹‹Œ‹ŠŠŠ‰ŠŠ‰‰‰‰‰‰‰ŠŠ‰Š‹‹‹‹‹‹Œ‹‹‹‹‹Š‰‰ˆˆŠ‹�ˆ€‚ƒƒ‚���„…‚€€€€���‚������‚‚‚�€€‚„„„„………†…†††††††††††††††††††‡ˆ‰‰‰‰‰ŠŠŠŠŠŠŠŠ‹‹‹ŒŒ‹ŒŒŒ‹Š‹ŒŠ‹ŒŒŒŒŒŒŒŒŒŒŽ���ŽŽ��‘ŽŽŽ�ŽŒ��‘ŒŒ�ŒŒŒŒŒŒŒŒŒŒŒŒ‹ŒŒ‹Œ‹ŠŠ‹‹‹ŠŒŒ‹Ž���‹Š‹Š‰Š‰‰‰‰‰‰‰‰Š‰‰Š‹Š‹‹‹‹‹Œ‹‹Š‹Š‰‰‰‰‰‹Œ�„‚ƒƒ���€€€€��€�������‚��‚‚‚‚€€ƒ„„…„„††…†††††††††††††††‡‡†‡‡ˆˆˆ‰ŠŠŠŠŠŠŠŠŠŠŠŠŠ‹‹‹ŠŠ‹Œ‹ŒŒŒŒŒŒŒ��ŒŒŒŒŒŒŽ��Ž���ŽŽŽ���ŽŽŽ��Œ�ŒŒŒŒŒŒŒŒŒ�ŒŒŒŒ‹Œ‹‹‹‹‹Š‹ŠŒŒ‹‹ŒŒŒ�ŒŠŠŠ‰‰‰Š‰Š‰‰‰‰Š‰‰‰ŠŠŠŠŠŠ‹Œ‹Š‰‰‰‰‰‰‰‰Š‹�Š�€‚‚‚��€�������������‚��‚‚�€€ƒ…„ƒ„„………†††††††††††††††‡††…‡ˆ‰ŠŠŠŠŠŠŠŠŠ‰ŠŠŠŠŠ‹‹‹ŠŠ‹‹‹‹ŒŒŒŒŒŒŒŒŒŒŒ��Ž����‘‘’““‘��ŽŽŽŽ��Ž�Œ‹ŒŒŒŒŒŒŒŒŒŒŒ‹‹‹Š‹‹‹‹ŠŠŠŠ‹ŒŒŒ‹Œ�ŒŠ‰‰‰‰ŠŠ‰‰‰‰‰‰Š‰‰‰ŠŠŠ‹ŠŠŠ‹‹ŠŠ‰‰‰‰‰‰‰‰‹ŒŒ‡‚����€€���€���������‚‚�‚‚�€€‚ƒƒƒƒ„†……††††††††††††††††††††‡ˆˆˆ‰ŠŠŠŠŠŠŠŠŠŠŠŠ‹ŠŠŠŠ‹ŠŠŠ‹ŒŒŒŒ‹‹‹‹‹‹ŒŒŽ‘�‘‘“‘�����Ž�Ž��ŽŽŽŒŒŒ‹ŒŒŒŒŒŒŒŒŒŒ‹‹‹ŠŠ‹Š‹‹‹ŠŠŒŒŒ�Œ��Œ‹Š‰ŠŠŠŠ‰‰‰‰‰ˆˆˆˆ‰‰ŠŠ‹Š‹‹ŠŒŠ‰‰‰‰‰‰‰‰‰ŠŒ�Š…���€€€����‚�������‚‚‚‚‚‚‚€€‚ƒƒƒƒ„†………††††††††††††††‡ˆ‡††‡‡ˆˆ‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‹‹‹‹‹‹ŒŒŒŒŒŽ‘���ŽŽŽ���Ž���Ž���Ž�ŒŒŒ‹ŒŒŒŒŒŒŒ‹‹‹Š‹‹‹ŠŠŠ‹‹Š‹Œ��Œ�ŒŠ‹‹Š‰ŠŠŠŠ‰‰‰‰‰‰ˆ‰‰‰ˆ‹‹Š‹‹‹ŠŒŒ‰‰‰‰‰‰ˆ‰ˆ‰Š‹Œ‡…�€€€€€��‚‚��‚��‚‚‚‚ƒƒƒƒ�€€ƒ„„…„„…†††††††††††††††††‡ˆ‡†‡‡ˆ‰‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‹‹‹Š‹ŒŒŒ‹ŒŒŒŽ‘�ŽŽ�������‘‘‘���Ž�ŽŒŒŒŒ‹Œ‹‹ŒŒŒ‹‹‹ŠŠ‹‹ŠŠ‹‹Š‹ŠŒ�Œ��Œ�‹‹Š‰Š‰‰‰‰‰‰‰‰‰‰‰‰‰‰Š‹‹Š‹‹‹‹ŒŠ‰‰‰Šˆˆˆ‰ˆŠŠ�І…�€€��‚‚��‚‚‚ƒ‚ƒ‚‚‚‚ƒ‚€€ƒ„„„ƒ„††††††††††††††††††‡‡††††‡ˆ‰ŠŠŠŠŠŠŠŠŠŠŠŠ‹‹ŠŠŠŠŠŠŠŠ‹‹‹‹‹‹‹Œ‹‹ŒŒŒŽŽŽŽŽ���ŽŽŽ�Ž�ŽŽ�Ž���ŒŒŒŒŒŒŒ‹ŒŒ‹‹Œ‹‹‹‹ŠŠ‹‹ŠŠ‹ŠŒ�Œ�Œ�ŒŒŒŠ‰Š‰ŠŠ‰‰‰‰‰‰‰‰ˆ‰‰Š‹Œ‹‹Œ‹‹‹‹‰‰ˆ‰ˆˆˆˆˆ‰ŠŠŒˆ††‚€€‚‚�‚‚‚‚ƒ‚‚ƒ‚‚‚‚ƒ‚€€‚ƒ…„„†††††††††††††††…††††‡†††‡ˆˆ‰‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‹ŒŒ‹Œ‹Œ‹ŒŠ‹Œ‹ŒŽ���Ž���Ž�ŽŽŽ�����Ž��Œ‹‹Œ‹‹ŒŒ‹‹Š‹‹‹Š‹‹‹ŠŠŠŠ‹‹Š‹�Œ��Œ���ŒŠ‰ŠŠ‰‰‰‰‰‰‰‰‰‰‰‰‰‹ŒŒ‹Œ‹‹Š‹Š‰‰‰‰ˆˆˆˆˆŠŠ‹‹‡†…‚~������‚�‚��‚‚ƒ‚ƒƒ‚€€ƒ„„ƒƒ…††††††††††††††††††ˆˆ‡‡‡ˆˆ‰‰‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‹‹‹ŒŠ‹‹ŒŒŒŒŒŒ‹‹ŒŽŽŽŽŽ�����Ž��ŽŽŽŽŽŽŽ�ŒŒ‹‹Š‹ŒŒŒŒ‹Œ‹ŠŠ‹ŠŠ‹‹ŠŠ‹‹ŠŠŒ�ŒŒ��Ž‹‹ŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆŠŒŒ‹‹‹‹Š�Œ‰‰ˆˆˆˆˆˆˆ‰ŠŠŒ‰ˆ‡…„����‚��‚‚‚‚‚ƒƒƒƒƒƒ‚€€ƒ„ƒ„„…†††††††††††††††‡†‡ˆˆˆˆ‡ˆ‰‰‰‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‹ŠŠŠ‹Œ‹‹‹‹‹ŒŒ‹Š‹ŒŒŒ�Ž�ŽŽŽ��Ž���ŽŽ�Ž�ŽŽ����‹ŒŒ‹‹‹‹‹‹Œ‹‹Œ‹‹ŠŠ‹ŠŠ‹‹ŠŠ‹�Ž�ŒŒ‹�Œ‹Š‹‰ˆ‰‰Š‰‰‰‰‰‰‰ˆˆ‰‰ŠŒŒ‹‹ŠŠ‹ŒŠˆˆˆˆˆˆˆˆ‰‹ŠŒ‹ˆˆ‡††…„���‚‚‚‚‚ƒƒƒƒƒ‚ƒ‚ƒ‚€€ƒ„ƒ…………††††††††††††††‡††ˆˆˆˆˆˆ‰‰‰‰Š‹‰ŠŠŠŠŠŠŠ‹ŠŠŠŠŠŠŠŠŠ‹‹‹ŒŒŒ‹ŠŠ‹ŒŒŒ����Ž���Ž�Ž�ŒŽŽ�Ž����ŽŽ‹Œ‹ŒŒŒ‹ŠŠ‹ŠŠ‹Œ‹ŠŠŠ‹Š‹ŠŠŠŠ��Œ‹‹‹Ž‘�Љ‰‰ŠŠŠ‰‰‰‰‰ˆ‰‰‰‰‰Š‹‹‹‹‹ŠŠ‹ŠˆˆˆˆˆˆˆˆˆŠ‹ŒŒ‰ˆˆ‡†‡‡ƒ�‚‚‚ƒƒ‚‚‚ƒƒƒƒƒ‚ƒ‚€€‚ƒƒƒ……††††††††††††††††††‡ˆ†‡ˆˆˆ‰‰‰ŠŠŠŠŠŠŠŠŠ‹Œ‹‹‹Š‹ŠŠ‹Š‹‹ŒŒŒŒ‹ŒŒŒŒŒŒŽ���ŽŽ����ŽŽ�Ž���Ž��ŽŽ�ŒŒ‹‹ŠŠŠ‹Œ‹‹Š‹‹Š‹‹Š‹‹Š‹‹ŠŠ‹Œ�����’�‹‰Š‰‰‰‹Šˆ‰Šˆˆˆˆˆˆˆ‰‹‹ŒŒ‹‹‹‹Œ‰ˆˆˆˆˆˆˆˆ‰ŠŠŒŠˆˆˆ‡‡‡…‚�‚‚ƒƒ‚‚ƒƒƒƒƒƒ‚ƒ‚€€ƒ„…„„…††††††††††††††††††‡‡‡‡‡ˆˆ‰‰‰‰‰‰Š‹Š‹ŠŠŠŠŠŠ‹Œ‹ŠŠ‹‹ŒŒ‹‹‹‹‹‹Œ‹ŒŒ‹�ŽŽŽ�ŽŽ�Ž�ŽŽŽŽ�Ž�Œ�Ž�ŽŽŒ‹‹‹Œ‹‹‹Š‹‹Š‹‹ŠŠ‹Š‹ŠŠŠ‹‹Š‹Œ�Œ�ŽŽŽ�ŒŠ‰‰‰‰ŠŠ‰Š‰ˆˆ‰‰ˆˆˆ‰‹Œ��‹‹‹‹Œ‹ˆˆˆˆˆˆˆˆˆ�ŽŠ‹ˆˆˆˆˆ‡‡„‚‚ƒƒ‚‚ƒƒƒƒƒƒƒƒƒ‚€€„…„„„…††††††††††††††††††‡ˆˆˆˆˆˆ‰‰ˆ‰‰ˆ‰Š‰ŠŠ‰ŠŠŠŠ‹ŠŠŠ‹ŠŠŠŠŠŠŠŠŠŠ‹ŠŠ‹ŒŽ���ŽŽ‘��Œ�ŽŽŽ�Ž�Ž���ŽŽ�Œ‹‹‹‹ŠŠŠ‹‹‹‹‹‹‹Š‹Š‹ŠŠŠŠŠŒŽ������ŒŽ‹‰‰‰‰‰ˆ‰‰‰‰‰‰‰ˆˆˆˆŠŒ�ŒŒ‹‹‹‹Œ‰ˆˆˆˆˆˆˆˆŒŽŒŒŠˆˆˆˆˆ‡†‚‚ƒƒ‚‚ƒƒƒƒƒƒƒƒƒ‚€€ƒ„„………††††††††††††††††††‡ˆˆˆ‰‰ˆŠŠ‰‰‰ˆ‰Š‹‹‹‹ŠŠŠŠŠŠŠ‹Œ‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‹‘“���Œ�’‘Ž��Ž�Ž�������ŽŽŒŒ‹Š‹ŠŠŠ‹‹Œ‹‹‹Š‹‹‹‹‹Š‰‰ŠŒ���������Œ‰‰Š‰ˆˆˆ‰‰ˆˆˆˆˆˆˆˆŠŒ‹ŒŒŒŒŒ‹Œ‹ˆˆˆˆˆˆˆˆ‰‹�ŒŒ‰ˆˆ‡ˆˆˆ„‚ƒƒƒƒƒƒƒƒƒƒƒƒƒ‚€€ƒ…„„………†††††††††††††††††ˆ‰ˆˆˆˆˆˆŠŠ‰‰‰‰ŠŠ‹‹‹ŠŠŠŠ‹ŠŠŠŠŠŠŠŠŠŠ‹‹‹ŠŠŠŠŠ‹�“‘���ŒŽ‘’’ŽŽŽŽŽ���Œ�Ž�ŽŒŒ‹‹ŠŠ‹‹‹‹‹‹Š‹‹ŠŠ‹‹‹ŠŠ‰ŠŠ��ŒŒŒ�ŽŽ��Š‰ŠŠ‰‰‰‰‰ˆˆˆˆˆˆˆˆ‰Œ��‹ŒŒŒ‹‹Œ‰ˆˆˆˆˆˆˆˆŠŒŒŒŠˆˆˆˆˆˆ†‚‚ƒƒƒ‚ƒƒƒƒƒƒ‚ƒ‚€€ƒ…„„…††††…††††††††††††††‡ˆ‰‰‰ˆˆ‰‰‰‰ŠŠŠŠŠŠ‰ŠŠŠ‹‹ŠŠŠŠ‹ŠŠŠŠ‹Œ��Œ‹Œ‹Œ‹�‘““’���ŽŽ����Ž��Ž��ŒŽ�Œ��‹Š‹‹‹‹‹‹‹‹‹ŠŠ‹‹ŠŠŠ‹ŠŠ‰‰ŠŒŽŽ�ŽŽ��Œ�‹ˆ‰‹Šˆ‰ˆˆˆˆˆˆˆˆˆˆˆŠŒŒŒŒŒ‹Œ‹ŒŠˆˆˆˆˆˆˆˆŠ‹Œ‹‹ˆˆˆˆˆˆˆ…ƒƒƒƒƒƒƒƒƒƒƒ‚ƒ‚€€‚…………††††…††††††††††††††‡ˆˆˆˆˆˆˆˆ‰‰‰‰‰‰‰ŠŠ‰‰ŠŠ‹Š‹‹ŠŒŠŠŠŠŠ‹‹‹ŠŠ‹‹‹ŠŒ’”’�������ŽŽŽŽ����Ž��Ž�Ž�ŒŠ‹Œ‹‹‹Š‹Œ‹Š‹Œ‹ŠŠ‹ŠŠŠ‰‰ŠŒŒ�ŽŽ����Œ‹‰‰ŠŠ‰ˆˆˆˆˆˆˆˆˆˆˆˆŠŒ‹‹ŒŒ‹ŒŒ�Œˆˆˆˆˆˆˆˆ‰��‹ŒŠˆˆˆˆˆˆ‡ƒ‚ƒƒƒƒƒƒƒƒƒ‚ƒ‚€€„…„……†………††††††††††††††††‡ˆˆˆˆˆˆˆˆˆ‰Š‰‰‰ŠŠŠŠŠŠŠ‹ŒŠŠ‹ŠŠŠŠŠŠŠŠŠŠŠŠŠŠ�’�Ž����ŽŽ����ŽŽ�Ž���Ž����ŒŠŠ‹‹‹‹ŠŠ‹‹‹‹ŠŠ‹Š‹Š‰ŠŠ‰ˆ‰Š‹Œ���Œ�ŒŒŠ‰ˆŠ‰‰‰ˆˆˆˆˆˆˆˆˆˆ‰Œ‹‹Œ�ŒŒŒ‹ŒŠˆˆˆˆˆˆˆˆŠ‹ŒŒ‹‰ˆˆˆˆˆ‡†ƒƒƒƒƒƒƒƒ„ƒƒƒ‚€€„„„…………†……†††††††††††††††‡ˆˆˆˆˆˆˆ‰ˆ‰‰ŠŠŠŠŠŠŠŠŠŠ‹ŠŠŠŠŠŠŠŠŠ‹ŠŠŠŠŠŠŠŠŽ‘Ž��������������ŽŽ�������Œ‹ŠŠŠŠ‹ŠŠ‹ŠŠŠ‹‹ŠŠŠŠŠŠŠ‰‰‰Š‹�Ž�ŽŽ��Œ‹ˆˆŠŠ‰‰ˆˆˆˆˆˆˆˆˆˆˆ‰‹‹‹ŒŒ��Œ�Œˆˆˆˆˆˆˆˆ‰ŒŒ‹�Šˆˆˆˆˆˆ‡…‚ƒƒƒƒƒƒƒƒ„ƒ‚�€ƒ……………††…†††††††††††††††‡†‡‡ˆˆ‡‡ˆˆˆ‰‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‹Ž����������������Ž�ŽŽ���Ž�ŽŒŠŠŠŠŠŠŠŠŠŠ‹‹ŠŠ‹‹ŠŠŠ‰‰‰‰‹‹ŒŒŒŒŒŒŒŒ�Љ‰Šˆˆˆˆˆˆˆˆˆˆˆˆˆ‰‹‹‹Œ‹‹ŒŒŒ�Šˆˆˆˆˆˆˆ‰‹‹‹‹Œˆˆˆˆˆˆˆ‡ƒƒƒƒƒƒƒƒƒ„ƒƒ€€„…„……††††††††††††††††††††…††‡‡ˆˆˆˆˆ‰‰ŠŠ‰‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‹Ž����������������Ž���ŽŽŽŽ���ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‰ŠŠŠŠŠ‹‹‹ŒŒŒ�Ž��Œ‰‰ˆŠ‰ˆˆˆˆˆˆˆˆˆˆˆˆ‰‹‹‹‹‹Œ‹‹‹ŒŒˆˆˆˆˆˆˆˆŠ‹Œ‹�Šˆˆ‡ˆˆˆˆ…ƒ„„ƒƒƒ„ƒ„ƒƒ€€ƒ…………†……†††††††††††††††††…††‡‡ˆˆˆˆˆ‰‰‰‰‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‹�����������������������Ž���ŽŒŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‹ŠŠŠŠ‰ŠŒ�ŒŒ‹������Šˆˆ‹Šˆˆˆˆˆˆˆˆˆˆˆˆˆ‹Œ‹‹Œ�Œ‹‹‹ŒŠˆˆˆˆˆˆˆ‰Œ‹‹ŒŒˆˆ‡ˆˆ‡ˆˆ„ƒ„„„ƒ„„„„ƒ€€ƒ„„……†……†††††††††††††††††…†ˆˆˆˆˆˆˆˆ‰‰‰‰‰‰‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‹Š‹‹Š‹��������������������ŽŽŽ��Ž���‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‰Š‹Œ��ŒŒŒ��Œ�Œ‰‰‰‹ˆˆˆˆˆˆˆˆˆˆˆˆˆ‹Œ‹Œ‹�ŒŒ‹‹ŒŒ‰ˆˆˆˆˆˆ‰Œ‹‹ŒŒ‰ˆˆˆ‡‡‡ˆ‡„„„„„„„„„ƒ€€ƒ…„„„†††…†…††††††††††††††††‡‡ˆˆˆ‡ˆˆˆ‰‰ˆ‰‰‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‹‹Œ�����������������������Ž���‘Ž‹ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‹ŠŠ‹ŒŒ�Œ��Œ���ŒŠˆˆ‹Šˆˆˆˆˆˆˆˆˆˆˆˆ‰ŒŒ‹‹Œ‹ŒŒ‹‹ŒŠˆˆˆˆˆˆˆ‹‹‹‹�‹ˆˆˆ‡‡‡ˆ‰…„„„„„„„„ƒ�€„…„……††………††…††††††††††††††‡‡‡ˆ‡‡ˆˆˆˆˆˆ‰‰‰‰ŠŠŠ‹ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ�‘�����������Ž���������ŽŽ��Ž’’Ž‹ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‹�ŽŽ����Ž����‹ˆˆ‹�‰ˆˆˆˆˆˆˆˆˆˆˆ‰Œ�ŒŒ�‹‹‹‹‹‹‹‰ˆˆˆˆˆˆ‹ŒŒŒ��Šˆˆ‡ˆ‡‡ˆˆ„„……………„„��„…………†††††††…††††††††††……††††‡‡ˆˆˆˆˆˆ‰‰‰‰‰‰‰ŠŠŠŠŠŠŠŠŠŠŠŠ‹ŠŠŠŠŠŠŠŠ�������‘Ž���‘������������Ž���’�‹ŠŠŠŠ‹‹ŠŠŠŠ‹ŠŠŠŠŠŠŠŠ‹�ŽŽ��ŽŽŽŽ�Ž�‹ˆˆŠ�‹ˆˆˆˆˆˆˆˆˆˆˆ‰Š‹�Œ‹ŒŒŒŒŒ‹‹ŠˆˆˆˆˆˆŠŒ�‹‹�‹ˆˆˆˆˆˆˆ‰‡„…………†…„��„†††…†‡‡††‡††††††††††‡††††‡‡‡‡‡‡ˆˆˆˆ‰‰‰‰‰‰ŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŽ‘�‘‘�‘��‘��‘“’‘�‘‘�Ž�’����‘�����‹‹ŒŒ‹‹Š‹‹‹�‹‹‹‹‹‹‹��ŽŽŽŽŽŽ�ŽŽŽŽ�ЉŠ��‹Š‰‰‰‰‰‰‰‰‰‰‰Œ��ŒŽ�Ž��ŒŒ�Šˆ‰ˆ‰ˆ‰Œ�ŒŒ�Ž‹ˆˆˆˆˆˆ‰‰†……†‡‡‡†�€‚‚‚‚‚‚‚‚‚‚ƒ‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒ‚‚ƒ‚‚ƒƒƒƒƒƒƒ„„„„„„„„„„„„„„„„„„„„„„„„…†††††††††††††‡‡††††……‡†…††‡†…………„„„„„„ƒ„„„„„„„„„„„……………………………………„ƒƒ……„„ƒƒƒƒƒƒƒƒƒƒƒ………„……„…„„„…„ƒƒƒƒƒƒ„„„…„…„ƒƒ‚‚ƒƒƒ„‚‚‚‚‚‚ƒƒ� \ No newline at end of file diff --git a/tests/gtest/avifchangesettingtest.cc b/tests/gtest/avifchangesettingtest.cc index 485a87be2c..31c37dfb50 100644 --- a/tests/gtest/avifchangesettingtest.cc +++ b/tests/gtest/avifchangesettingtest.cc @@ -241,6 +241,36 @@ TEST(ChangeSettingTest, UnchangeableImageChromaSamplePosition) { AVIF_RESULT_INCOMPATIBLE_IMAGE); } +TEST(ChangeSettingTest, UnchangeableRenderedSizeOverride) { + if (avifCodecName(AVIF_CODEC_CHOICE_AOM, AVIF_CODEC_FLAG_CAN_ENCODE) == + nullptr) { + GTEST_SKIP() << "Codec unavailable, skip test."; + } + + ImagePtr image = testutil::CreateImage(/*width=*/64, /*height=*/64, + /*depth=*/8, AVIF_PIXEL_FORMAT_YUV444, + AVIF_PLANES_YUV, AVIF_RANGE_FULL); + ASSERT_NE(image, nullptr); + testutil::FillImageGradient(image.get()); + + EncoderPtr encoder(avifEncoderCreate()); + ASSERT_NE(encoder, nullptr); + encoder->codecChoice = AVIF_CODEC_CHOICE_AOM; + encoder->speed = AVIF_SPEED_FASTEST; + encoder->extraLayerCount = 1; + encoder->width = 128; + encoder->height = 128; + + ASSERT_EQ(avifEncoderAddImage(encoder.get(), image.get(), 1, + AVIF_ADD_IMAGE_FLAG_NONE), + AVIF_RESULT_OK); + + encoder->width = 256; + ASSERT_EQ(avifEncoderAddImage(encoder.get(), image.get(), 1, + AVIF_ADD_IMAGE_FLAG_NONE), + AVIF_RESULT_CANNOT_CHANGE_SETTING); +} + void EncodeAnimation(const char* key, const char* value_before_first_frame, const char* value_after_first_frame, const char* value_before_second_frame, diff --git a/tests/gtest/avifprogressivetest.cc b/tests/gtest/avifprogressivetest.cc index 3071b5604e..9aec82e376 100644 --- a/tests/gtest/avifprogressivetest.cc +++ b/tests/gtest/avifprogressivetest.cc @@ -187,6 +187,65 @@ TEST_F(ProgressiveTest, DimensionChangeWithAlpha) { TestDecode(kImageSize, kImageSize, /*expect_alpha=*/true); } +TEST_F(ProgressiveTest, DimensionChangeExternal) { + encoder_->extraLayerCount = 1; + encoder_->width = kImageSize; + encoder_->height = kImageSize; + + const auto smallImage = testutil::CreateImage( + kImageSize / 2, kImageSize / 2, 8, AVIF_PIXEL_FORMAT_YUV444, + AVIF_PLANES_YUV, AVIF_RANGE_FULL); + ASSERT_NE(smallImage, nullptr); + + ASSERT_EQ(avifEncoderAddImage(encoder_.get(), smallImage.get(), 1, + AVIF_ADD_IMAGE_FLAG_NONE), + AVIF_RESULT_OK); + + ASSERT_EQ(avifEncoderAddImage(encoder_.get(), image_.get(), 1, + AVIF_ADD_IMAGE_FLAG_NONE), + AVIF_RESULT_OK); + + ASSERT_EQ(avifEncoderFinish(encoder_.get(), &encoded_avif_), AVIF_RESULT_OK); + + TestDecode(256, 256); +} + +TEST_F(ProgressiveTest, DimensionChangeExternalWithAlpha) { + const auto image = + testutil::CreateImage(kImageSize, kImageSize, 8, AVIF_PIXEL_FORMAT_YUV444, + AVIF_PLANES_ALL, AVIF_RANGE_FULL); + ASSERT_NE(image, nullptr); + testutil::FillImageGradient(image.get()); + + encoder_->speed = 3; + encoder_->maxThreads = 1; + encoder_->extraLayerCount = 2; + encoder_->width = kImageSize; + encoder_->height = kImageSize; + + auto smallImage = testutil::CreateImage(kImageSize / 2, kImageSize / 2, 8, + AVIF_PIXEL_FORMAT_YUV444, + AVIF_PLANES_ALL, AVIF_RANGE_FULL); + ASSERT_NE(smallImage, nullptr); + testutil::FillImageGradient(smallImage.get(), /*offset=*/17); + + ASSERT_EQ(avifEncoderAddImage(encoder_.get(), smallImage.get(), 1, + AVIF_ADD_IMAGE_FLAG_NONE), + AVIF_RESULT_OK); + + ASSERT_EQ(avifEncoderAddImage(encoder_.get(), smallImage.get(), 1, + AVIF_ADD_IMAGE_FLAG_NONE), + AVIF_RESULT_OK); + + ASSERT_EQ(avifEncoderAddImage(encoder_.get(), image.get(), 1, + AVIF_ADD_IMAGE_FLAG_NONE), + AVIF_RESULT_OK); + + ASSERT_EQ(avifEncoderFinish(encoder_.get(), &encoded_avif_), AVIF_RESULT_OK); + + TestDecode(kImageSize, kImageSize, /*expect_alpha=*/true); +} + TEST_F(ProgressiveTest, LayeredGrid) { encoder_->extraLayerCount = 1; encoder_->quality = 21; diff --git a/tests/test_cmd_progressive.sh b/tests/test_cmd_progressive.sh index 6492ee0d29..6cdd1c6730 100755 --- a/tests/test_cmd_progressive.sh +++ b/tests/test_cmd_progressive.sh @@ -22,14 +22,16 @@ source $(dirname "$0")/cmd_test_common.sh || exit # Input file paths. INPUT_Y4M="${TESTDATA_DIR}/kodim03_yuv420_8bpc.y4m" +INPUT_SMALL_Y4M="${TESTDATA_DIR}/kodim03_yuv420_8bpc_384x256.y4m" # Output file names. ENCODED_FILE="avif_test_cmd_encoded.avif" DECODED_FILE="avif_test_cmd_decoded.png" +INFO_FILE="avif_test_cmd_info.txt" # Cleanup cleanup() { pushd ${TMP_DIR} - rm -- "${ENCODED_FILE}" "${DECODED_FILE}" + rm -- "${ENCODED_FILE}" "${DECODED_FILE}" "${INFO_FILE}" popd } trap cleanup EXIT @@ -45,6 +47,18 @@ pushd ${TMP_DIR} "${AVIFDEC}" "${ENCODED_FILE}" "${DECODED_FILE}" "${AVIFDEC}" --progressive "${ENCODED_FILE}" "${DECODED_FILE}" + echo "Testing manual layered encoding with rendered-size override and mixed input sizes" + "${AVIFENC}" -s 8 --layered --render-size 768x512 \ + "${INPUT_SMALL_Y4M}" "${INPUT_Y4M}" -o "${ENCODED_FILE}" + "${AVIFDEC}" --info "${ENCODED_FILE}" > "${INFO_FILE}" + grep -F "[768x512]" "${INFO_FILE}" + "${AVIFDEC}" "${ENCODED_FILE}" "${DECODED_FILE}" + "${AVIFDEC}" --progressive "${ENCODED_FILE}" "${DECODED_FILE}" + + echo "Testing rendered-size override smaller than an input layer" + "${AVIFENC}" -s 8 --layered --render-size 384x256 \ + "${INPUT_SMALL_Y4M}" "${INPUT_Y4M}" -o "${ENCODED_FILE}" && exit 1 + # libavif relies on libyuv to do scaling echo "Testing layered encoding with frame scaling" if avifenc -V | grep -o "libyuv : available" --quiet; then From f3e8b2e3e4f0678003a18588957c668d4130e74b Mon Sep 17 00:00:00 2001 From: Yuan Tong Date: Tue, 24 Mar 2026 17:45:22 +0800 Subject: [PATCH 02/17] Add layered image fuzzer --- tests/CMakeLists.txt | 1 + tests/gtest/avif_fuzztest_enc_dec_layered.cc | 224 +++++++++++++++++++ tests/gtest/avif_fuzztest_helpers.cc | 92 ++++++++ tests/gtest/avif_fuzztest_helpers.h | 120 ++++++++++ 4 files changed, 437 insertions(+) create mode 100644 tests/gtest/avif_fuzztest_enc_dec_layered.cc diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 96ca5d74d6..8a3dd797a9 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -220,6 +220,7 @@ if(AVIF_FUZZTEST) add_avif_fuzztest(avif_fuzztest_dec_incr gtest/avifincrtest_helpers.cc) add_avif_fuzztest(avif_fuzztest_enc_dec) add_avif_fuzztest(avif_fuzztest_enc_dec_anim) + add_avif_fuzztest(avif_fuzztest_enc_dec_layered) add_avif_fuzztest(avif_fuzztest_enc_dec_incr gtest/avifincrtest_helpers.cc) add_avif_fuzztest(avif_fuzztest_properties) add_avif_fuzztest(avif_fuzztest_read_image) diff --git a/tests/gtest/avif_fuzztest_enc_dec_layered.cc b/tests/gtest/avif_fuzztest_enc_dec_layered.cc new file mode 100644 index 0000000000..ed2f3fd1c3 --- /dev/null +++ b/tests/gtest/avif_fuzztest_enc_dec_layered.cc @@ -0,0 +1,224 @@ +// Copyright 2026 Google LLC +// SPDX-License-Identifier: BSD-2-Clause + +#include +#include +#include +#include + +#include "avif/avif.h" +#include "avif_fuzztest_helpers.h" +#include "aviftest_helpers.h" +#include "fuzztest/fuzztest.h" +#include "gtest/gtest.h" + +namespace avif { +namespace testutil { +namespace { + +constexpr size_t kLayerCount = kMaxNumLayers; + +struct UniformScale { + int32_t n; + int32_t d; +}; + +constexpr UniformScale kNoScale = {1, 1}; +constexpr size_t kRandomScalingModeCount = kLayerCount - 1; +static_assert(kRandomScalingModeCount == 3); +constexpr std::array kSupportedScalingModes = { + UniformScale{1, 8}, UniformScale{1, 4}, UniformScale{1, 2}, + UniformScale{3, 5}, UniformScale{3, 4}, UniformScale{4, 5}}; +constexpr avifScalingMode kNoScalingMode = {{kNoScale.n, kNoScale.d}, + {kNoScale.n, kNoScale.d}}; +constexpr std::array kNoScalingModes = { + kNoScalingMode, kNoScalingMode, kNoScalingMode, kNoScalingMode}; + +constexpr avifScalingMode MakeScalingMode(UniformScale horizontal, + UniformScale vertical) { + return avifScalingMode{{horizontal.n, horizontal.d}, + {vertical.n, vertical.d}}; +} + +constexpr size_t BinomialCoefficient(size_t n, size_t k) { + if (k > n) { + return 0; + } + if (k > (n - k)) { + k = n - k; + } + size_t coefficient = 1; + for (size_t i = 1; i <= k; ++i) { + coefficient = (coefficient * (n - k + i)) / i; + } + return coefficient; +} + +constexpr size_t CombinationCountWithRepetition(size_t value_count, + size_t pick_count) { + return BinomialCoefficient(value_count + pick_count - 1, pick_count); +} + +constexpr size_t kScalingModeCombinationCount = CombinationCountWithRepetition( + kSupportedScalingModes.size(), kRandomScalingModeCount); + +std::array GetScalingModeCombination( + size_t combination_index) { + std::array combination = {}; + size_t remaining_index = combination_index; + size_t next_candidate = 0; + for (size_t slot = 0; slot < combination.size(); ++slot) { + const size_t remaining_slots = combination.size() - slot - 1; + for (size_t candidate = next_candidate; + candidate < kSupportedScalingModes.size(); ++candidate) { + const size_t combinations_with_candidate = CombinationCountWithRepetition( + kSupportedScalingModes.size() - candidate, remaining_slots); + if (remaining_index < combinations_with_candidate) { + combination[slot] = kSupportedScalingModes[candidate]; + next_candidate = candidate; + break; + } + remaining_index -= combinations_with_candidate; + } + } + return combination; +} + +std::array MakeRandomScalingModes( + int horizontal_combination_index, int vertical_combination_index) { + const auto horizontal_combination = + GetScalingModeCombination(horizontal_combination_index); + const auto vertical_combination = + GetScalingModeCombination(vertical_combination_index); + return std::array{ + MakeScalingMode(horizontal_combination[0], vertical_combination[0]), + MakeScalingMode(horizontal_combination[1], vertical_combination[1]), + MakeScalingMode(horizontal_combination[2], vertical_combination[2]), + kNoScalingMode}; +} + +inline auto ArbitraryScalingModes() { + constexpr int kMaxCombinationIndex = + static_cast(kScalingModeCombinationCount - 1); + return fuzztest::Map(MakeRandomScalingModes, + fuzztest::InRange(0, kMaxCombinationIndex), + fuzztest::InRange(0, kMaxCombinationIndex)); +} + +void EncodeDecodeLayered( + std::vector layers, + const std::array& scaling_modes, + uint32_t expected_width, uint32_t expected_height, + bool use_rendered_size_override, EncoderPtr encoder, DecoderPtr decoder) { + ASSERT_EQ(layers.size(), kLayerCount); + ASSERT_NE(encoder, nullptr); + ASSERT_NE(decoder, nullptr); + + if (avifCodecName(AVIF_CODEC_CHOICE_AOM, AVIF_CODEC_FLAG_CAN_ENCODE) == + nullptr) { + return; + } + if (avifLibYUVVersion() == 0) { + return; + } + + const avifImage* const reference = layers.front().get(); + ASSERT_NE(reference, nullptr); + + encoder->codecChoice = AVIF_CODEC_CHOICE_AOM; + encoder->extraLayerCount = static_cast(layers.size() - 1); + if (use_rendered_size_override) { + encoder->width = expected_width; + encoder->height = expected_height; + } + + for (size_t i = 0; i < layers.size(); ++i) { + ASSERT_NE(layers[i].get(), nullptr); + encoder->scalingMode = scaling_modes[i]; + const avifResult result = avifEncoderAddImage( + encoder.get(), layers[i].get(), + /*durationInTimescales=*/1, AVIF_ADD_IMAGE_FLAG_NONE); + ASSERT_EQ(result, AVIF_RESULT_OK) + << " layer " << i << ": " << avifResultToString(result) << ": " + << encoder->diag.error; + } + + AvifRwData encoded_data; + avifResult result = avifEncoderFinish(encoder.get(), &encoded_data); + ASSERT_EQ(result, AVIF_RESULT_OK) + << avifResultToString(result) << ": " << encoder->diag.error; + + result = avifDecoderSetIOMemory(decoder.get(), encoded_data.data, + encoded_data.size); + ASSERT_EQ(result, AVIF_RESULT_OK) + << avifResultToString(result) << ": " << decoder->diag.error; + + result = avifDecoderParse(decoder.get()); + ASSERT_EQ(result, AVIF_RESULT_OK) + << avifResultToString(result) << ": " << decoder->diag.error; + + const int num_decodes = + decoder->allowProgressive ? static_cast(layers.size()) : 1; + if (decoder->allowProgressive) { + EXPECT_EQ(decoder->progressiveState, AVIF_PROGRESSIVE_STATE_ACTIVE); + ASSERT_EQ(decoder->imageCount, static_cast(layers.size())); + } else { + EXPECT_EQ(decoder->progressiveState, AVIF_PROGRESSIVE_STATE_AVAILABLE); + ASSERT_EQ(decoder->imageCount, 1); + } + + for (int i = 0; i < num_decodes; ++i) { + result = avifDecoderNextImage(decoder.get()); + ASSERT_EQ(result, AVIF_RESULT_OK) + << " layer " << i << ": " << avifResultToString(result) << ": " + << decoder->diag.error; + EXPECT_EQ(decoder->image->width, expected_width); + EXPECT_EQ(decoder->image->height, expected_height); + EXPECT_EQ(decoder->image->depth, reference->depth); + EXPECT_EQ(decoder->image->yuvFormat, reference->yuvFormat); + } + result = avifDecoderNextImage(decoder.get()); + ASSERT_EQ(result, AVIF_RESULT_NO_IMAGES_REMAINING) + << avifResultToString(result) << ": " << decoder->diag.error; +} + +void EncodeDecodeDimensionChange( + std::vector layers, + const std::array& scaling_modes, + EncoderPtr encoder, DecoderPtr decoder) { + ASSERT_EQ(layers.size(), kLayerCount); + ASSERT_NE(layers.back().get(), nullptr); + const uint32_t expected_width = layers.back()->width; + const uint32_t expected_height = layers.back()->height; + EncodeDecodeLayered(std::move(layers), scaling_modes, + /*expected_width=*/expected_width, + /*expected_height=*/expected_height, + /*use_rendered_size_override=*/false, std::move(encoder), + std::move(decoder)); +} + +void EncodeDecodeDimensionChangeExternal(std::vector layers, + EncoderPtr encoder, + DecoderPtr decoder) { + ASSERT_EQ(layers.size(), kLayerCount); + ASSERT_NE(layers.back().get(), nullptr); + const uint32_t expected_width = layers.back()->width; + const uint32_t expected_height = layers.back()->height; + EncodeDecodeLayered(std::move(layers), kNoScalingModes, + /*expected_width=*/expected_width, + /*expected_height=*/expected_height, + /*use_rendered_size_override=*/true, std::move(encoder), + std::move(decoder)); +} + +FUZZ_TEST(LayeredEncodeDecodeAvifFuzzTest, EncodeDecodeDimensionChange) + .WithDomains(ArbitraryAvifLayered(), ArbitraryScalingModes(), + ArbitraryAvifEncoder(), ArbitraryAvifDecoder()); + +FUZZ_TEST(LayeredEncodeDecodeAvifFuzzTest, EncodeDecodeDimensionChangeExternal) + .WithDomains(ArbitraryAvifLayeredRandDim(), ArbitraryAvifEncoder(), + ArbitraryAvifDecoder()); + +} // namespace +} // namespace testutil +} // namespace avif diff --git a/tests/gtest/avif_fuzztest_helpers.cc b/tests/gtest/avif_fuzztest_helpers.cc index cfb0f7b902..0d2728af61 100644 --- a/tests/gtest/avif_fuzztest_helpers.cc +++ b/tests/gtest/avif_fuzztest_helpers.cc @@ -4,6 +4,7 @@ #include "avif_fuzztest_helpers.h" #include +#include #include #include #include @@ -22,6 +23,27 @@ namespace { //------------------------------------------------------------------------------ +constexpr size_t kNumLayeredRandDimSeeds = 2 * (kMaxNumLayers - 1); + +template +std::array, kMaxNumLayers> GetAvifLayeredRandDims( + size_t render_width, size_t render_height, const Sample* seeds) { + assert(render_width > 1); + assert(render_height > 1); + std::array, kMaxNumLayers> sizes = {}; + for (size_t i = 0; i + 1 < kMaxNumLayers; ++i) { + const size_t width = + 1 + (static_cast(seeds[2 * i]) % (render_width - 1)); + const size_t height = + 1 + (static_cast(seeds[2 * i + 1]) % (render_height - 1)); + assert(width < render_width); + assert(height < render_height); + sizes[i] = {width, height}; + } + sizes.back() = {render_width, render_height}; + return sizes; +} + ImagePtr CreateAvifImage(size_t width, size_t height, int depth, avifPixelFormat pixel_format, bool has_alpha, const uint8_t* samples) { @@ -104,6 +126,76 @@ std::vector CreateAvifAnim16b(size_t num_frames, size_t width, return frames; } +std::vector CreateAvifLayered8b(size_t width, size_t height, + avifPixelFormat pixel_format, + bool has_alpha, + const std::vector& samples) { + std::vector layers = CreateAvifAnim8b( + kMaxNumLayers, width, height, pixel_format, has_alpha, samples); + return layers; +} + +std::vector CreateAvifLayered16b( + size_t width, size_t height, int depth, avifPixelFormat pixel_format, + bool has_alpha, const std::vector& samples) { + std::vector layers = CreateAvifAnim16b( + kMaxNumLayers, width, height, depth, pixel_format, has_alpha, samples); + return layers; +} + +size_t GetNumSamplesLayeredRandDim(size_t render_width, size_t render_height, + avifPixelFormat pixel_format, + bool has_alpha) { + return kNumLayeredRandDimSeeds + GetNumSamples(kMaxNumLayers, render_width, + render_height, pixel_format, + has_alpha); +} + +std::vector CreateAvifLayeredRandDim8b( + size_t render_width, size_t render_height, avifPixelFormat pixel_format, + bool has_alpha, const std::vector& samples) { + assert(samples.size() >= kNumLayeredRandDimSeeds); + const auto dims = + GetAvifLayeredRandDims(render_width, render_height, samples.data()); + std::vector layers; + layers.reserve(kMaxNumLayers); + + size_t offset = kNumLayeredRandDimSeeds; + for (const auto& [width, height] : dims) { + const size_t num_samples = GetNumSamples( + /*num_frames=*/1, width, height, pixel_format, has_alpha); + layers.push_back(CreateAvifImage8b( + width, height, pixel_format, has_alpha, + std::vector(samples.begin() + offset, + samples.begin() + offset + num_samples))); + offset += num_samples; + } + return layers; +} + +std::vector CreateAvifLayeredRandDim16b( + size_t render_width, size_t render_height, int depth, + avifPixelFormat pixel_format, bool has_alpha, + const std::vector& samples) { + assert(samples.size() >= kNumLayeredRandDimSeeds); + const auto dims = + GetAvifLayeredRandDims(render_width, render_height, samples.data()); + std::vector layers; + layers.reserve(kMaxNumLayers); + + size_t offset = kNumLayeredRandDimSeeds; + for (const auto& [width, height] : dims) { + const size_t num_samples = GetNumSamples( + /*num_frames=*/1, width, height, pixel_format, has_alpha); + layers.push_back(CreateAvifImage16b( + width, height, depth, pixel_format, has_alpha, + std::vector(samples.begin() + offset, + samples.begin() + offset + num_samples))); + offset += num_samples; + } + return layers; +} + EncoderPtr CreateAvifEncoder(avifCodecChoice codec_choice, int max_threads, int min_quantizer, int max_quantizer, int min_quantizer_alpha, int max_quantizer_alpha, diff --git a/tests/gtest/avif_fuzztest_helpers.h b/tests/gtest/avif_fuzztest_helpers.h index 14dda45825..4ddbe7add9 100644 --- a/tests/gtest/avif_fuzztest_helpers.h +++ b/tests/gtest/avif_fuzztest_helpers.h @@ -58,6 +58,20 @@ std::vector CreateAvifAnim16b(size_t num_frames, size_t width, avifPixelFormat pixel_format, bool has_alpha, const std::vector& samples); +std::vector CreateAvifLayered8b(size_t width, size_t height, + avifPixelFormat pixel_format, + bool has_alpha, + const std::vector& samples); +std::vector CreateAvifLayered16b( + size_t width, size_t height, int depth, avifPixelFormat pixel_format, + bool has_alpha, const std::vector& samples); +std::vector CreateAvifLayeredRandDim8b( + size_t render_width, size_t render_height, avifPixelFormat pixel_format, + bool has_alpha, const std::vector& samples); +std::vector CreateAvifLayeredRandDim16b( + size_t render_width, size_t render_height, int depth, + avifPixelFormat pixel_format, bool has_alpha, + const std::vector& samples); EncoderPtr CreateAvifEncoder(avifCodecChoice codec_choice, int max_threads, int min_quantizer, int max_quantizer, int min_quantizer_alpha, int max_quantizer_alpha, @@ -85,9 +99,14 @@ inline constexpr size_t kMaxNumFramesSquareRoot = 2; // Do not generate animations with more than this number of frames. inline constexpr size_t kMaxNumFrames = kMaxNumFramesSquareRoot * kMaxNumFramesSquareRoot; +// Do not generate layered images with more than this number of layers. +inline constexpr size_t kMaxNumLayers = AVIF_MAX_AV1_LAYER_COUNT; size_t GetNumSamples(size_t num_frames, size_t width, size_t height, avifPixelFormat pixel_format, bool has_alpha); +size_t GetNumSamplesLayeredRandDim(size_t render_width, size_t render_height, + avifPixelFormat pixel_format, + bool has_alpha); // To avoid using fuzztest::internal, the return type of the functions below is // auto. @@ -187,6 +206,107 @@ inline auto ArbitraryAvifAnim() { return fuzztest::OneOf(ArbitraryAvifAnim8b(), ArbitraryAvifAnim16b()); } +// Layered avifImage generator type: fixed number of layers, same width/height, +// pixel format and 8-bit samples. +inline auto ArbitraryAvifLayered8b() { + constexpr uint16_t kMinLayerDimension = 8; + constexpr uint16_t kMaxLayerDimension = + kMaxDimension / kMaxNumFramesSquareRoot; + return fuzztest::FlatMap( + [](size_t width, size_t height, avifPixelFormat pixel_format, + bool has_alpha) { + return fuzztest::Map( + CreateAvifLayered8b, fuzztest::Just(width), fuzztest::Just(height), + fuzztest::Just(pixel_format), fuzztest::Just(has_alpha), + fuzztest::Arbitrary>().WithSize(GetNumSamples( + kMaxNumLayers, width, height, pixel_format, has_alpha))); + }, + fuzztest::InRange(kMinLayerDimension, kMaxLayerDimension), + fuzztest::InRange(kMinLayerDimension, kMaxLayerDimension), + ArbitraryPixelFormat(), fuzztest::Arbitrary()); +} + +// Layered avifImage generator type: fixed number of layers, same width/height, +// depth, pixel format and 16-bit samples. +inline auto ArbitraryAvifLayered16b() { + constexpr uint16_t kMinLayerDimension = 8; + constexpr uint16_t kMaxLayerDimension = + kMaxDimension / kMaxNumFramesSquareRoot; + return fuzztest::FlatMap( + [](size_t width, size_t height, int depth, avifPixelFormat pixel_format, + bool has_alpha) { + return fuzztest::Map( + CreateAvifLayered16b, fuzztest::Just(width), fuzztest::Just(height), + fuzztest::Just(depth), fuzztest::Just(pixel_format), + fuzztest::Just(has_alpha), + fuzztest::ContainerOf>( + fuzztest::InRange(0, (1 << depth) - 1)) + .WithSize(GetNumSamples(kMaxNumLayers, width, height, + pixel_format, has_alpha))); + }, + fuzztest::InRange(kMinLayerDimension, kMaxLayerDimension), + fuzztest::InRange(kMinLayerDimension, kMaxLayerDimension), + fuzztest::ElementOf({10, 12}), ArbitraryPixelFormat(), + fuzztest::Arbitrary()); +} + +// Generator for an arbitrary layered still image with same-sized layers. +inline auto ArbitraryAvifLayered() { + return fuzztest::OneOf(ArbitraryAvifLayered8b(), ArbitraryAvifLayered16b()); +} + +// Layered avifImage generator type: fixed number of layers, rendered size, +// pixel format and 8-bit samples. +inline auto ArbitraryAvifLayeredRandDim8b() { + constexpr uint16_t kMinLayerDimension = 8; + constexpr uint16_t kMaxLayerDimension = + kMaxDimension / kMaxNumFramesSquareRoot; + return fuzztest::FlatMap( + [](size_t render_width, size_t render_height, + avifPixelFormat pixel_format, bool has_alpha) { + return fuzztest::Map( + CreateAvifLayeredRandDim8b, fuzztest::Just(render_width), + fuzztest::Just(render_height), fuzztest::Just(pixel_format), + fuzztest::Just(has_alpha), + fuzztest::Arbitrary>().WithSize( + GetNumSamplesLayeredRandDim(render_width, render_height, + pixel_format, has_alpha))); + }, + fuzztest::InRange(kMinLayerDimension, kMaxLayerDimension), + fuzztest::InRange(kMinLayerDimension, kMaxLayerDimension), + ArbitraryPixelFormat(), fuzztest::Arbitrary()); +} + +// Layered avifImage generator type: fixed number of layers, rendered size, +// depth, pixel format and 16-bit samples. +inline auto ArbitraryAvifLayeredRandDim16b() { + constexpr uint16_t kMinLayerDimension = 8; + constexpr uint16_t kMaxLayerDimension = + kMaxDimension / kMaxNumFramesSquareRoot; + return fuzztest::FlatMap( + [](size_t render_width, size_t render_height, int depth, + avifPixelFormat pixel_format, bool has_alpha) { + return fuzztest::Map( + CreateAvifLayeredRandDim16b, fuzztest::Just(render_width), + fuzztest::Just(render_height), fuzztest::Just(depth), + fuzztest::Just(pixel_format), fuzztest::Just(has_alpha), + fuzztest::ContainerOf>( + fuzztest::InRange(0, (1 << depth) - 1)) + .WithSize(GetNumSamplesLayeredRandDim( + render_width, render_height, pixel_format, has_alpha))); + }, + fuzztest::InRange(kMinLayerDimension, kMaxLayerDimension), + fuzztest::InRange(kMinLayerDimension, kMaxLayerDimension), + fuzztest::ElementOf({10, 12}), ArbitraryPixelFormat(), + fuzztest::Arbitrary()); +} + +// Generator for an arbitrary layered still image with rendered size override. +inline auto ArbitraryAvifLayeredRandDim() { + return fuzztest::OneOf(ArbitraryAvifLayeredRandDim8b(), + ArbitraryAvifLayeredRandDim16b()); +} + // Generates two signed fractions where the first one is smaller than or equal // to the second one. inline auto ArbitraryMinMaxSignedFraction() { From 25eb44bce3248d363bbd1f005acb6378314c3103 Mon Sep 17 00:00:00 2001 From: Yuan Tong Date: Thu, 27 Aug 2026 21:59:55 +0800 Subject: [PATCH 03/17] code review --- src/codec_svt.c | 2 -- src/write.c | 38 ++++++++++++++------------------------ 2 files changed, 14 insertions(+), 26 deletions(-) diff --git a/src/codec_svt.c b/src/codec_svt.c index d5d1b88486..99dcfc6646 100644 --- a/src/codec_svt.c +++ b/src/codec_svt.c @@ -170,8 +170,6 @@ static avifResult svtCodecEncodeImage(avifCodec * codec, #endif svt_config->source_width = image->width; svt_config->source_height = image->height; - svt_config->forced_max_frame_width = encoder->width; - svt_config->forced_max_frame_height = encoder->height; #if SVT_AV1_CHECK_VERSION(3, 0, 0) svt_config->level_of_parallelism = encoder->maxThreads; #else diff --git a/src/write.c b/src/write.c index b8cd40fa77..87be0afd59 100644 --- a/src/write.c +++ b/src/write.c @@ -473,11 +473,8 @@ static avifBool avifEncoderUsesRenderedSizeOverride(const avifEncoder * encoder) static avifBool avifScalingModeIsNoScaling(const avifScalingMode * scalingMode) { - avifFraction horizontal = scalingMode->horizontal; - avifFraction vertical = scalingMode->vertical; - avifFractionSimplify(&horizontal); - avifFractionSimplify(&vertical); - return (horizontal.n == 1) && (horizontal.d == 1) && (vertical.n == 1) && (vertical.d == 1); + return (scalingMode->horizontal.n == scalingMode->horizontal.d) && + (scalingMode->vertical.n == scalingMode->vertical.d); } static avifBool avifImageHasEquivalentTransformProperties(const avifImage * lhs, const avifImage * rhs) @@ -2271,10 +2268,6 @@ avifResult avifEncoderAddImageGrid(avifEncoder * encoder, if ((gridCols == 0) || (gridCols > 256) || (gridRows == 0) || (gridRows > 256)) { return AVIF_RESULT_INVALID_IMAGE_GRID; } - if (avifEncoderUsesRenderedSizeOverride(encoder)) { - avifDiagnosticsPrintf(&encoder->diag, "rendered-size override is not supported with avifEncoderAddImageGrid()"); - return AVIF_RESULT_NOT_IMPLEMENTED; - } if (encoder->extraLayerCount == 0) { addImageFlags |= AVIF_ADD_IMAGE_FLAG_SINGLE; // image grids cannot be image sequences } @@ -3335,9 +3328,6 @@ avifResult avifEncoderFinish(avifEncoder * encoder, avifRWData * output) #endif // AVIF_ENABLE_EXPERIMENTAL_MINI const avifImage * imageMetadata = encoder->data->imageMetadata; - const uint32_t imageWidth = encoder->width ? encoder->width : imageMetadata->width; - const uint32_t imageHeight = encoder->height ? encoder->height : imageMetadata->height; - uint64_t now = (uint64_t)time(NULL); uint64_t modificationTime = (encoder->modificationTime != 0) ? encoder->modificationTime : now; uint64_t creationTime = (encoder->creationTime != 0) ? encoder->creationTime : modificationTime; @@ -3752,8 +3742,8 @@ avifResult avifEncoderFinish(avifEncoder * encoder, avifRWData * output) AVIF_CHECKRES(avifRWStreamWriteU16(&s, 0)); // template int(16) volume = {if track_is_audio 0x0100 else 0}; AVIF_CHECKRES(avifRWStreamWriteU16(&s, 0)); // const unsigned int(16) reserved = 0; AVIF_CHECKRES(avifRWStreamWrite(&s, unityMatrix, sizeof(unityMatrix))); // template int(32)[9] matrix= // { 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 }; - AVIF_CHECKRES(avifRWStreamWriteU32(&s, imageWidth << 16)); // unsigned int(32) width; - AVIF_CHECKRES(avifRWStreamWriteU32(&s, imageHeight << 16)); // unsigned int(32) height; + AVIF_CHECKRES(avifRWStreamWriteU32(&s, imageMetadata->width << 16)); // unsigned int(32) width; + AVIF_CHECKRES(avifRWStreamWriteU32(&s, imageMetadata->height << 16)); // unsigned int(32) height; AVIF_CHECKRES(avifRWStreamFinishBox(&s, tkhd)); if (item->irefToID != 0) { @@ -3829,16 +3819,16 @@ avifResult avifEncoderFinish(avifEncoder * encoder, avifRWData * output) AVIF_CHECKRES(avifRWStreamWriteU32(&s, 1)); // unsigned int(32) entry_count; avifBoxMarker imageItem; AVIF_CHECKRES(avifRWStreamWriteBox(&s, encoder->data->imageItemType, AVIF_BOX_SIZE_TBD, &imageItem)); - AVIF_CHECKRES(avifRWStreamWriteZeros(&s, 6)); // const unsigned int(8)[6] reserved = 0; - AVIF_CHECKRES(avifRWStreamWriteU16(&s, 1)); // unsigned int(16) data_reference_index; - AVIF_CHECKRES(avifRWStreamWriteU16(&s, 0)); // unsigned int(16) pre_defined = 0; - AVIF_CHECKRES(avifRWStreamWriteU16(&s, 0)); // const unsigned int(16) reserved = 0; - AVIF_CHECKRES(avifRWStreamWriteZeros(&s, sizeof(uint32_t) * 3)); // unsigned int(32)[3] pre_defined = 0; - AVIF_CHECKRES(avifRWStreamWriteU16(&s, (uint16_t)imageWidth)); // unsigned int(16) width; - AVIF_CHECKRES(avifRWStreamWriteU16(&s, (uint16_t)imageHeight)); // unsigned int(16) height; - AVIF_CHECKRES(avifRWStreamWriteU32(&s, 0x00480000)); // template unsigned int(32) horizresolution - AVIF_CHECKRES(avifRWStreamWriteU32(&s, 0x00480000)); // template unsigned int(32) vertresolution - AVIF_CHECKRES(avifRWStreamWriteU32(&s, 0)); // const unsigned int(32) reserved = 0; + AVIF_CHECKRES(avifRWStreamWriteZeros(&s, 6)); // const unsigned int(8)[6] reserved = 0; + AVIF_CHECKRES(avifRWStreamWriteU16(&s, 1)); // unsigned int(16) data_reference_index; + AVIF_CHECKRES(avifRWStreamWriteU16(&s, 0)); // unsigned int(16) pre_defined = 0; + AVIF_CHECKRES(avifRWStreamWriteU16(&s, 0)); // const unsigned int(16) reserved = 0; + AVIF_CHECKRES(avifRWStreamWriteZeros(&s, sizeof(uint32_t) * 3)); // unsigned int(32)[3] pre_defined = 0; + AVIF_CHECKRES(avifRWStreamWriteU16(&s, (uint16_t)imageMetadata->width)); // unsigned int(16) width; + AVIF_CHECKRES(avifRWStreamWriteU16(&s, (uint16_t)imageMetadata->height)); // unsigned int(16) height; + AVIF_CHECKRES(avifRWStreamWriteU32(&s, 0x00480000)); // template unsigned int(32) horizresolution + AVIF_CHECKRES(avifRWStreamWriteU32(&s, 0x00480000)); // template unsigned int(32) vertresolution + AVIF_CHECKRES(avifRWStreamWriteU32(&s, 0)); // const unsigned int(32) reserved = 0; AVIF_CHECKRES(avifRWStreamWriteU16(&s, 1)); // template unsigned int(16) frame_count = 1; AVIF_CHECKRES(avifRWStreamWriteChars(&s, "\012AOM Coding", 11)); // string[32] compressorname; AVIF_CHECKRES(avifRWStreamWriteZeros(&s, 32 - 11)); // From ae4d14530c5cde83eb12883611d7813ef8ae1d67 Mon Sep 17 00:00:00 2001 From: Yuan Tong Date: Sun, 30 Aug 2026 14:06:41 +0800 Subject: [PATCH 04/17] render size -> display size rename --- apps/avifenc.c | 50 ++++++++++---------- include/avif/avif.h | 38 +++++++++++++-- src/codec_aom.c | 5 +- src/codec_avm.c | 2 +- src/codec_rav1e.c | 2 +- src/codec_svt.c | 2 +- src/write.c | 29 ++++++------ tests/gtest/avif_fuzztest_enc_dec_layered.cc | 8 ++-- tests/gtest/avif_fuzztest_helpers.cc | 30 ++++++------ tests/gtest/avif_fuzztest_helpers.h | 28 +++++------ tests/gtest/avifchangesettingtest.cc | 2 +- tests/test_cmd_progressive.sh | 8 ++-- 12 files changed, 117 insertions(+), 87 deletions(-) diff --git a/apps/avifenc.c b/apps/avifenc.c index 2b8de51a61..b45094e9f8 100644 --- a/apps/avifenc.c +++ b/apps/avifenc.c @@ -244,7 +244,7 @@ static void syntaxLong(void) printf(" --progressive : Automatically set parameters to encode a simple layered image supporting progressive rendering from a single input frame.\n"); printf(" --layered : Encode a layered AVIF. Each input is encoded as one layer and at most %d layers can be encoded.\n", AVIF_MAX_AV1_LAYER_COUNT); - printf(" --render-size WxH : Set the rendered size of the AVIF image.\n"); + printf(" --display-size WxH : Set the size at which the AVIF image is displayed, independent of the encoded pixel dimensions.\n"); printf(" Supported for still images and layered still images only.\n"); printf(" -g,--grid MxN : Encode a single-image grid AVIF with M cols & N rows. Either supply MxN identical W/H/D images, or a single\n"); printf(" image that can be evenly split into the MxN grid and follow AVIF grid image restrictions. The grid will adopt\n"); @@ -458,7 +458,7 @@ static avifBool convertCropToClap(uint32_t srcW, uint32_t srcH, uint32_t clapVal return AVIF_TRUE; } -static avifBool avifSettingsUsesRenderedSizeOverride(const avifSettings * settings) +static avifBool avifSettingsUsesDisplaySizeOverride(const avifSettings * settings) { return (settings->width != 0) || (settings->height != 0); } @@ -469,14 +469,14 @@ static void avifSettingsGetEffectiveOutputDimensions(const avifSettings * settin *height = settings->height ? settings->height : image->height; } -static avifBool avifSettingsVerifyRenderedSizeBounds(const avifSettings * settings, const avifImage * image, const char * filename) +static avifBool avifSettingsVerifyDisplaySizeBounds(const avifSettings * settings, const avifImage * image, const char * filename) { - if (!avifSettingsUsesRenderedSizeOverride(settings)) { + if (!avifSettingsUsesDisplaySizeOverride(settings)) { return AVIF_TRUE; } if ((image->width > settings->width) || (image->height > settings->height)) { fprintf(stderr, - "ERROR: Input image dimensions [%ux%u] exceed rendered size [%ux%u]: %s\n", + "ERROR: Input image dimensions [%ux%u] exceed display size [%ux%u]: %s\n", image->width, image->height, settings->width, @@ -988,7 +988,7 @@ static avifBool avifEncodeRestOfImageSequence(avifEncoder * encoder, settings->inputFormat)) { goto cleanup; } - if (!avifSettingsVerifyRenderedSizeBounds(settings, nextImage, avifPrettyFilename(nextFile->filename))) { + if (!avifSettingsVerifyDisplaySizeBounds(settings, nextImage, avifPrettyFilename(nextFile->filename))) { goto cleanup; } if (!avifEncoderVerifyImageCompatibility(firstImage, @@ -1102,7 +1102,7 @@ static avifBool avifEncodeRestOfLayeredImage(avifEncoder * encoder, settings->inputFormat)) { goto cleanup; } - if (!avifSettingsVerifyRenderedSizeBounds(settings, nextImage, avifPrettyFilename(nextFile->filename))) { + if (!avifSettingsVerifyDisplaySizeBounds(settings, nextImage, avifPrettyFilename(nextFile->filename))) { goto cleanup; } // frameIter is NULL if y4m reached end, so single frame y4m is still supported. @@ -1116,7 +1116,7 @@ static avifBool avifEncodeRestOfLayeredImage(avifEncoder * encoder, nextImage, "layer", avifPrettyFilename(nextFile->filename), - avifSettingsUsesRenderedSizeOverride(settings))) { + avifSettingsUsesDisplaySizeOverride(settings))) { goto cleanup; } if (!avifEncodeUpdateEncoderSettings(encoder, nextSettings)) { @@ -1824,15 +1824,15 @@ int main(int argc, char * argv[]) goto cleanup; } settings.layered = AVIF_TRUE; - } else if (!strcmp(arg, "--render-size")) { - uint32_t renderSize[2] = { 0 }; + } else if (!strcmp(arg, "--display-size")) { + uint32_t displaySize[2] = { 0 }; NEXTARG(); - if (!parseU32List(renderSize, 2, arg, 'x') || (renderSize[0] == 0) || (renderSize[1] == 0)) { - fprintf(stderr, "ERROR: Invalid render size: %s\n", arg); + if (!parseU32List(displaySize, 2, arg, 'x') || (displaySize[0] == 0) || (displaySize[1] == 0)) { + fprintf(stderr, "ERROR: Invalid display size: %s\n", arg); goto cleanup; } - settings.width = renderSize[0]; - settings.height = renderSize[1]; + settings.width = displaySize[0]; + settings.height = displaySize[1]; } else if (!strcmp(arg, "--scaling-mode") || strpre(arg, "--scaling-mode:")) { avifOptionSuffixType type = parseOptionSuffix(arg, input.filesCount != 0); if (type == AVIF_OPTION_SUFFIX_INVALID) { @@ -2193,8 +2193,8 @@ int main(int argc, char * argv[]) fprintf(stderr, "WARNING: Trailing options with update suffix has no effect. Place them before the input you intend to apply to.\n"); } - if (avifSettingsUsesRenderedSizeOverride(&settings) && ((settings.width == 0) || (settings.height == 0))) { - fprintf(stderr, "ERROR: --render-size must be specified as WxH.\n"); + if (avifSettingsUsesDisplaySizeOverride(&settings) && ((settings.width == 0) || (settings.height == 0))) { + fprintf(stderr, "ERROR: --display-size must be specified as WxH.\n"); goto cleanup; } @@ -2225,12 +2225,12 @@ int main(int argc, char * argv[]) fprintf(stderr, "Layered grid image unimplemented in avifenc.\n"); goto cleanup; } - if (avifSettingsUsesRenderedSizeOverride(&settings) && settings.gridDimsPresent) { - fprintf(stderr, "ERROR: --render-size is not supported with --grid.\n"); + if (avifSettingsUsesDisplaySizeOverride(&settings) && settings.gridDimsPresent) { + fprintf(stderr, "ERROR: --display-size is not supported with --grid.\n"); goto cleanup; } - if (avifSettingsUsesRenderedSizeOverride(&settings) && (settings.layers == 1) && (input.filesCount > 1)) { - fprintf(stderr, "ERROR: --render-size is not supported with image sequences. Use --layered for multiple still inputs.\n"); + if (avifSettingsUsesDisplaySizeOverride(&settings) && (settings.layers == 1) && (input.filesCount > 1)) { + fprintf(stderr, "ERROR: --display-size is not supported with image sequences. Use --layered for multiple still inputs.\n"); goto cleanup; } @@ -2453,12 +2453,12 @@ int main(int argc, char * argv[]) goto cleanup; } - if (!avifSettingsVerifyRenderedSizeBounds(&settings, image, avifPrettyFilename(firstFile->filename))) { + if (!avifSettingsVerifyDisplaySizeBounds(&settings, image, avifPrettyFilename(firstFile->filename))) { goto cleanup; } - if (avifSettingsUsesRenderedSizeOverride(&settings) && (settings.layers == 1) && input.frameIter) { - fprintf(stderr, "ERROR: --render-size is not supported with image sequences.\n"); + if (avifSettingsUsesDisplaySizeOverride(&settings) && (settings.layers == 1) && input.frameIter) { + fprintf(stderr, "ERROR: --display-size is not supported with image sequences.\n"); goto cleanup; } @@ -2724,8 +2724,8 @@ int main(int argc, char * argv[]) settings.gridDims[0], settings.gridDims[1], settings.layers > 1 ? AVIF_PROGRESSIVE_STATE_AVAILABLE : AVIF_PROGRESSIVE_STATE_UNAVAILABLE); - if (avifSettingsUsesRenderedSizeOverride(&settings)) { - printf(" * Rendered Size : %ux%u\n", settings.width, settings.height); + if (avifSettingsUsesDisplaySizeOverride(&settings)) { + printf(" * Display Size : %ux%u\n", settings.width, settings.height); } avifEncodedByteSizes byteSizes = { 0, 0, 0 }; diff --git a/include/avif/avif.h b/include/avif/avif.h index 6c57323d75..231b85501c 100644 --- a/include/avif/avif.h +++ b/include/avif/avif.h @@ -821,6 +821,11 @@ typedef struct avifImage // To encode any of these boxes, set the values in the associated box, then enable the flag in // transformFlags. On decode, only honor the values in boxes with the associated transform flag set. // These also apply to gainMap->image, if any. + // + // When encoding with avifEncoder.width/height set (see its comment), these values are interpreted + // relative to that overridden display size rather than to this avifImage's own width/height. + // No special handling is needed during decode: the decoded avifImage is automatically scaled to + // the display size, so these values are relative to its width/height as usual. avifTransformFlags transformFlags; avifPixelAspectRatioBox pasp; avifCleanApertureBox clap; @@ -1630,10 +1635,35 @@ typedef struct avifEncoder // Version 1.4.0 ends here. Add any new members after this line. // -------------------------------------------------------------------------------------------- - // Override the rendered size of the encoded image. - // Defaults to 0. When set to 0, libavif uses the width and height of the first added image. - // Typical use case is layered image, where these are set to the size of the last layer, - // while encoding smaller images as the previous layers. + // Overrides the image's display size (the width and height AVIF declares this image is meant + // to be shown at) independent of the pixel dimensions actually encoded. Any image passed to + // avifEncoderAddImage()/avifEncoderAddImageGrid() that is encoded smaller than the display size + // is upscaled to it on decode. + // + // Defaults to 0 (disabled). When 0, the display size is the size of the first added image. + // When set, both width and height must be nonzero, and neither can be smaller than the coded + // dimensions of any image passed to avifEncoderAddImage()/avifEncoderAddImageGrid(). + // + // Not supported together with image sequences, image grids, scalingMode, sample + // transforms, or gain maps. Cannot be changed once encoding has started (i.e. after the first + // call to avifEncoderAddImage()/avifEncoderAddImageGrid()). + // + // The main use case is a layered image (see extraLayerCount above) where earlier layers' + // pixel data is already available at a smaller size, so encoding them directly at that size + // avoids the wasted round trip of upscaling to the display size only for the encoder to scale + // it back down, and allows scale ratios that scalingMode cannot express for the encoder in use. + // + // avifImage properties that are relative to image dimensions (clap, irot, imir, pasp; see the + // "Transformations" comment above) are interpreted relative to the display size when set, rather + // than to the coded size of whichever layer they came from. + // + // Implementation note: the display size is stored as the ispe box, the dimensions an AVIF + // decoder is required to honor; a coded image smaller than it is upscaled by the decoder to + // match. Separately, an AV1 encoder session declares a maximum frame size once, up front, and + // every later frame must fit within it; by default that maximum is simply the size of the first + // frame encoded. Setting width/height also declares that AV1-level maximum explicitly, in + // addition to the ispe box, so that later, larger layers stay within it. This is why it must be + // at least as large as every layer's coded size. uint32_t width; uint32_t height; } avifEncoder; diff --git a/src/codec_aom.c b/src/codec_aom.c index 7e305ba77e..9f23c62096 100644 --- a/src/codec_aom.c +++ b/src/codec_aom.c @@ -897,8 +897,9 @@ static avifResult aomCodecEncodeImage(avifCodec * codec, // Set the maximum number of frames to encode to 1. This instructs // libaom to set still_picture and reduced_still_picture_header to // 1 in AV1 sequence headers. - // Still picture header requires image size and render size to match - // or the produced file is not decodable. + // Still picture header requires frame size to match + // max_frame_width and max_frame_height, + // so we can't use it if frame can have a different size. cfg->g_limit = 1; } if (useAllIntra) { diff --git a/src/codec_avm.c b/src/codec_avm.c index 01fe18a842..adf2699021 100644 --- a/src/codec_avm.c +++ b/src/codec_avm.c @@ -454,7 +454,7 @@ static avifResult avmCodecEncodeImage(avifCodec * codec, encoderChanges &= ~AVIF_ENCODER_CHANGE_SCALING_MODE; if (encoder->width || encoder->height) { - avifDiagnosticsPrintf(codec->diag, "AVM does not support rendered-size override"); + avifDiagnosticsPrintf(codec->diag, "AVM does not support display-size override"); return AVIF_RESULT_NOT_IMPLEMENTED; } diff --git a/src/codec_rav1e.c b/src/codec_rav1e.c index 1a24fa5443..4b41bfeb52 100644 --- a/src/codec_rav1e.c +++ b/src/codec_rav1e.c @@ -92,7 +92,7 @@ static avifResult rav1eCodecEncodeImage(avifCodec * codec, // rav1e does not support overriding maximum frame width/height in sequence header if (encoder->width || encoder->height) { - avifDiagnosticsPrintf(codec->diag, "rav1e does not support rendered-size override"); + avifDiagnosticsPrintf(codec->diag, "rav1e does not support display-size override"); return AVIF_RESULT_NOT_IMPLEMENTED; } diff --git a/src/codec_svt.c b/src/codec_svt.c index 99dcfc6646..70be13fa14 100644 --- a/src/codec_svt.c +++ b/src/codec_svt.c @@ -84,7 +84,7 @@ static avifResult svtCodecEncodeImage(avifCodec * codec, (void)disableLaggedOutput; if (encoder->width || encoder->height) { - avifDiagnosticsPrintf(codec->diag, "SVT-AV1 does not support rendered-size override"); + avifDiagnosticsPrintf(codec->diag, "SVT-AV1 does not support display-size override"); return AVIF_RESULT_NOT_IMPLEMENTED; } diff --git a/src/write.c b/src/write.c index 87be0afd59..59095ac5f5 100644 --- a/src/write.c +++ b/src/write.c @@ -466,15 +466,14 @@ static avifResult avifItemPropertyDedupFinish(avifItemPropertyDedup * dedup, static const avifScalingMode noScaling = { { 1, 1 }, { 1, 1 } }; -static avifBool avifEncoderUsesRenderedSizeOverride(const avifEncoder * encoder) +static avifBool avifEncoderUsesDisplaySizeOverride(const avifEncoder * encoder) { return (encoder->width != 0) || (encoder->height != 0); } static avifBool avifScalingModeIsNoScaling(const avifScalingMode * scalingMode) { - return (scalingMode->horizontal.n == scalingMode->horizontal.d) && - (scalingMode->vertical.n == scalingMode->vertical.d); + return (scalingMode->horizontal.n == scalingMode->horizontal.d) && (scalingMode->vertical.n == scalingMode->vertical.d); } static avifBool avifImageHasEquivalentTransformProperties(const avifImage * lhs, const avifImage * rhs) @@ -1599,46 +1598,46 @@ static avifCodecType avifEncoderGetCodecType(const avifEncoder * encoder) return avifCodecTypeFromChoice(encoder->codecChoice, AVIF_CODEC_FLAG_CAN_ENCODE); } -static avifResult avifEncoderValidateRenderedSizeOverride(avifEncoder * encoder, uint32_t gridCols, uint32_t gridRows, const avifImage * firstCell) +static avifResult avifEncoderValidateDisplaySizeOverride(avifEncoder * encoder, uint32_t gridCols, uint32_t gridRows, const avifImage * firstCell) { - if (!avifEncoderUsesRenderedSizeOverride(encoder)) { + if (!avifEncoderUsesDisplaySizeOverride(encoder)) { return AVIF_RESULT_OK; } if ((encoder->width == 0) || (encoder->height == 0)) { avifDiagnosticsPrintf(&encoder->diag, - "rendered-size override requires both avifEncoder.width and avifEncoder.height to be non-zero"); + "display-size override requires both avifEncoder.width and avifEncoder.height to be non-zero"); return AVIF_RESULT_INVALID_ARGUMENT; } if ((gridCols > 1) || (gridRows > 1)) { - avifDiagnosticsPrintf(&encoder->diag, "rendered-size override is not supported with grid images"); + avifDiagnosticsPrintf(&encoder->diag, "display-size override is not supported with grid images"); return AVIF_RESULT_NOT_IMPLEMENTED; } if (!avifScalingModeIsNoScaling(&encoder->scalingMode)) { - avifDiagnosticsPrintf(&encoder->diag, "rendered-size override is not supported with encoder->scalingMode"); + avifDiagnosticsPrintf(&encoder->diag, "display-size override is not supported with encoder->scalingMode"); return AVIF_RESULT_NOT_IMPLEMENTED; } if (encoder->sampleTransformRecipe != AVIF_SAMPLE_TRANSFORM_NONE) { - avifDiagnosticsPrintf(&encoder->diag, "rendered-size override is not supported with sample transforms"); + avifDiagnosticsPrintf(&encoder->diag, "display-size override is not supported with sample transforms"); return AVIF_RESULT_NOT_IMPLEMENTED; } if (firstCell->gainMap && firstCell->gainMap->image) { - avifDiagnosticsPrintf(&encoder->diag, "rendered-size override is not supported with gain maps"); + avifDiagnosticsPrintf(&encoder->diag, "display-size override is not supported with gain maps"); return AVIF_RESULT_NOT_IMPLEMENTED; } if ((encoder->data->items.count > 0) && (encoder->extraLayerCount == 0)) { - avifDiagnosticsPrintf(&encoder->diag, "rendered-size override is not supported for image sequences"); + avifDiagnosticsPrintf(&encoder->diag, "display-size override is not supported for image sequences"); return AVIF_RESULT_NOT_IMPLEMENTED; } if ((encoder->width < firstCell->width) || (encoder->height < firstCell->height)) { avifDiagnosticsPrintf(&encoder->diag, - "rendered-size override %ux%u must be at least the coded image size %ux%u", + "display-size override %ux%u must be at least the coded image size %ux%u", encoder->width, encoder->height, firstCell->width, @@ -1655,7 +1654,7 @@ static avifResult avifEncoderValidateRenderedSizeOverride(avifEncoder * encoder, if ((encoder->data->items.count > 0) && (encoder->extraLayerCount > 0) && !avifImageHasEquivalentTransformProperties(firstCell, encoder->data->imageMetadata)) { - avifDiagnosticsPrintf(&encoder->diag, "rendered-size override requires 'pasp', 'clap', 'irot' and 'imir' to match across layers"); + avifDiagnosticsPrintf(&encoder->diag, "display-size override requires 'pasp', 'clap', 'irot' and 'imir' to match across layers"); return AVIF_RESULT_INCOMPATIBLE_IMAGE; } @@ -1844,7 +1843,7 @@ static avifResult avifEncoderAddImageInternal(avifEncoder * encoder, return AVIF_RESULT_NO_CONTENT; } - AVIF_CHECKRES(avifEncoderValidateRenderedSizeOverride(encoder, gridCols, gridRows, firstCell)); + AVIF_CHECKRES(avifEncoderValidateDisplaySizeOverride(encoder, gridCols, gridRows, firstCell)); AVIF_CHECKRES(avifValidateGrid(gridCols, gridRows, cellImages, /*validateGainMap=*/AVIF_FALSE, &encoder->diag)); @@ -1976,7 +1975,7 @@ static avifResult avifEncoderAddImageInternal(avifEncoder * encoder, if (encoder->data->items.count == 0) { // Make a copy of the first image's metadata (sans pixels) for future writing/validation AVIF_CHECKRES(avifImageCopy(encoder->data->imageMetadata, firstCell, 0)); - if (avifEncoderUsesRenderedSizeOverride(encoder)) { + if (avifEncoderUsesDisplaySizeOverride(encoder)) { encoder->data->imageMetadata->width = encoder->width; encoder->data->imageMetadata->height = encoder->height; } diff --git a/tests/gtest/avif_fuzztest_enc_dec_layered.cc b/tests/gtest/avif_fuzztest_enc_dec_layered.cc index ed2f3fd1c3..e1d108ad71 100644 --- a/tests/gtest/avif_fuzztest_enc_dec_layered.cc +++ b/tests/gtest/avif_fuzztest_enc_dec_layered.cc @@ -109,7 +109,7 @@ void EncodeDecodeLayered( std::vector layers, const std::array& scaling_modes, uint32_t expected_width, uint32_t expected_height, - bool use_rendered_size_override, EncoderPtr encoder, DecoderPtr decoder) { + bool use_display_size_override, EncoderPtr encoder, DecoderPtr decoder) { ASSERT_EQ(layers.size(), kLayerCount); ASSERT_NE(encoder, nullptr); ASSERT_NE(decoder, nullptr); @@ -127,7 +127,7 @@ void EncodeDecodeLayered( encoder->codecChoice = AVIF_CODEC_CHOICE_AOM; encoder->extraLayerCount = static_cast(layers.size() - 1); - if (use_rendered_size_override) { + if (use_display_size_override) { encoder->width = expected_width; encoder->height = expected_height; } @@ -193,7 +193,7 @@ void EncodeDecodeDimensionChange( EncodeDecodeLayered(std::move(layers), scaling_modes, /*expected_width=*/expected_width, /*expected_height=*/expected_height, - /*use_rendered_size_override=*/false, std::move(encoder), + /*use_display_size_override=*/false, std::move(encoder), std::move(decoder)); } @@ -207,7 +207,7 @@ void EncodeDecodeDimensionChangeExternal(std::vector layers, EncodeDecodeLayered(std::move(layers), kNoScalingModes, /*expected_width=*/expected_width, /*expected_height=*/expected_height, - /*use_rendered_size_override=*/true, std::move(encoder), + /*use_display_size_override=*/true, std::move(encoder), std::move(decoder)); } diff --git a/tests/gtest/avif_fuzztest_helpers.cc b/tests/gtest/avif_fuzztest_helpers.cc index 0d2728af61..10fc0dd9e3 100644 --- a/tests/gtest/avif_fuzztest_helpers.cc +++ b/tests/gtest/avif_fuzztest_helpers.cc @@ -27,20 +27,20 @@ constexpr size_t kNumLayeredRandDimSeeds = 2 * (kMaxNumLayers - 1); template std::array, kMaxNumLayers> GetAvifLayeredRandDims( - size_t render_width, size_t render_height, const Sample* seeds) { - assert(render_width > 1); - assert(render_height > 1); + size_t display_width, size_t display_height, const Sample* seeds) { + assert(display_width > 1); + assert(display_height > 1); std::array, kMaxNumLayers> sizes = {}; for (size_t i = 0; i + 1 < kMaxNumLayers; ++i) { const size_t width = - 1 + (static_cast(seeds[2 * i]) % (render_width - 1)); + 1 + (static_cast(seeds[2 * i]) % (display_width - 1)); const size_t height = - 1 + (static_cast(seeds[2 * i + 1]) % (render_height - 1)); - assert(width < render_width); - assert(height < render_height); + 1 + (static_cast(seeds[2 * i + 1]) % (display_height - 1)); + assert(width < display_width); + assert(height < display_height); sizes[i] = {width, height}; } - sizes.back() = {render_width, render_height}; + sizes.back() = {display_width, display_height}; return sizes; } @@ -143,20 +143,20 @@ std::vector CreateAvifLayered16b( return layers; } -size_t GetNumSamplesLayeredRandDim(size_t render_width, size_t render_height, +size_t GetNumSamplesLayeredRandDim(size_t display_width, size_t display_height, avifPixelFormat pixel_format, bool has_alpha) { - return kNumLayeredRandDimSeeds + GetNumSamples(kMaxNumLayers, render_width, - render_height, pixel_format, + return kNumLayeredRandDimSeeds + GetNumSamples(kMaxNumLayers, display_width, + display_height, pixel_format, has_alpha); } std::vector CreateAvifLayeredRandDim8b( - size_t render_width, size_t render_height, avifPixelFormat pixel_format, + size_t display_width, size_t display_height, avifPixelFormat pixel_format, bool has_alpha, const std::vector& samples) { assert(samples.size() >= kNumLayeredRandDimSeeds); const auto dims = - GetAvifLayeredRandDims(render_width, render_height, samples.data()); + GetAvifLayeredRandDims(display_width, display_height, samples.data()); std::vector layers; layers.reserve(kMaxNumLayers); @@ -174,12 +174,12 @@ std::vector CreateAvifLayeredRandDim8b( } std::vector CreateAvifLayeredRandDim16b( - size_t render_width, size_t render_height, int depth, + size_t display_width, size_t display_height, int depth, avifPixelFormat pixel_format, bool has_alpha, const std::vector& samples) { assert(samples.size() >= kNumLayeredRandDimSeeds); const auto dims = - GetAvifLayeredRandDims(render_width, render_height, samples.data()); + GetAvifLayeredRandDims(display_width, display_height, samples.data()); std::vector layers; layers.reserve(kMaxNumLayers); diff --git a/tests/gtest/avif_fuzztest_helpers.h b/tests/gtest/avif_fuzztest_helpers.h index 4ddbe7add9..ab9a9ba15e 100644 --- a/tests/gtest/avif_fuzztest_helpers.h +++ b/tests/gtest/avif_fuzztest_helpers.h @@ -66,10 +66,10 @@ std::vector CreateAvifLayered16b( size_t width, size_t height, int depth, avifPixelFormat pixel_format, bool has_alpha, const std::vector& samples); std::vector CreateAvifLayeredRandDim8b( - size_t render_width, size_t render_height, avifPixelFormat pixel_format, + size_t display_width, size_t display_height, avifPixelFormat pixel_format, bool has_alpha, const std::vector& samples); std::vector CreateAvifLayeredRandDim16b( - size_t render_width, size_t render_height, int depth, + size_t display_width, size_t display_height, int depth, avifPixelFormat pixel_format, bool has_alpha, const std::vector& samples); EncoderPtr CreateAvifEncoder(avifCodecChoice codec_choice, int max_threads, @@ -104,7 +104,7 @@ inline constexpr size_t kMaxNumLayers = AVIF_MAX_AV1_LAYER_COUNT; size_t GetNumSamples(size_t num_frames, size_t width, size_t height, avifPixelFormat pixel_format, bool has_alpha); -size_t GetNumSamplesLayeredRandDim(size_t render_width, size_t render_height, +size_t GetNumSamplesLayeredRandDim(size_t display_width, size_t display_height, avifPixelFormat pixel_format, bool has_alpha); @@ -255,21 +255,21 @@ inline auto ArbitraryAvifLayered() { return fuzztest::OneOf(ArbitraryAvifLayered8b(), ArbitraryAvifLayered16b()); } -// Layered avifImage generator type: fixed number of layers, rendered size, +// Layered avifImage generator type: fixed number of layers, display size, // pixel format and 8-bit samples. inline auto ArbitraryAvifLayeredRandDim8b() { constexpr uint16_t kMinLayerDimension = 8; constexpr uint16_t kMaxLayerDimension = kMaxDimension / kMaxNumFramesSquareRoot; return fuzztest::FlatMap( - [](size_t render_width, size_t render_height, + [](size_t display_width, size_t display_height, avifPixelFormat pixel_format, bool has_alpha) { return fuzztest::Map( - CreateAvifLayeredRandDim8b, fuzztest::Just(render_width), - fuzztest::Just(render_height), fuzztest::Just(pixel_format), + CreateAvifLayeredRandDim8b, fuzztest::Just(display_width), + fuzztest::Just(display_height), fuzztest::Just(pixel_format), fuzztest::Just(has_alpha), fuzztest::Arbitrary>().WithSize( - GetNumSamplesLayeredRandDim(render_width, render_height, + GetNumSamplesLayeredRandDim(display_width, display_height, pixel_format, has_alpha))); }, fuzztest::InRange(kMinLayerDimension, kMaxLayerDimension), @@ -277,23 +277,23 @@ inline auto ArbitraryAvifLayeredRandDim8b() { ArbitraryPixelFormat(), fuzztest::Arbitrary()); } -// Layered avifImage generator type: fixed number of layers, rendered size, +// Layered avifImage generator type: fixed number of layers, display size, // depth, pixel format and 16-bit samples. inline auto ArbitraryAvifLayeredRandDim16b() { constexpr uint16_t kMinLayerDimension = 8; constexpr uint16_t kMaxLayerDimension = kMaxDimension / kMaxNumFramesSquareRoot; return fuzztest::FlatMap( - [](size_t render_width, size_t render_height, int depth, + [](size_t display_width, size_t display_height, int depth, avifPixelFormat pixel_format, bool has_alpha) { return fuzztest::Map( - CreateAvifLayeredRandDim16b, fuzztest::Just(render_width), - fuzztest::Just(render_height), fuzztest::Just(depth), + CreateAvifLayeredRandDim16b, fuzztest::Just(display_width), + fuzztest::Just(display_height), fuzztest::Just(depth), fuzztest::Just(pixel_format), fuzztest::Just(has_alpha), fuzztest::ContainerOf>( fuzztest::InRange(0, (1 << depth) - 1)) .WithSize(GetNumSamplesLayeredRandDim( - render_width, render_height, pixel_format, has_alpha))); + display_width, display_height, pixel_format, has_alpha))); }, fuzztest::InRange(kMinLayerDimension, kMaxLayerDimension), fuzztest::InRange(kMinLayerDimension, kMaxLayerDimension), @@ -301,7 +301,7 @@ inline auto ArbitraryAvifLayeredRandDim16b() { fuzztest::Arbitrary()); } -// Generator for an arbitrary layered still image with rendered size override. +// Generator for an arbitrary layered still image with display size override. inline auto ArbitraryAvifLayeredRandDim() { return fuzztest::OneOf(ArbitraryAvifLayeredRandDim8b(), ArbitraryAvifLayeredRandDim16b()); diff --git a/tests/gtest/avifchangesettingtest.cc b/tests/gtest/avifchangesettingtest.cc index 31c37dfb50..7cbc83b7dc 100644 --- a/tests/gtest/avifchangesettingtest.cc +++ b/tests/gtest/avifchangesettingtest.cc @@ -241,7 +241,7 @@ TEST(ChangeSettingTest, UnchangeableImageChromaSamplePosition) { AVIF_RESULT_INCOMPATIBLE_IMAGE); } -TEST(ChangeSettingTest, UnchangeableRenderedSizeOverride) { +TEST(ChangeSettingTest, UnchangeableDisplaySizeOverride) { if (avifCodecName(AVIF_CODEC_CHOICE_AOM, AVIF_CODEC_FLAG_CAN_ENCODE) == nullptr) { GTEST_SKIP() << "Codec unavailable, skip test."; diff --git a/tests/test_cmd_progressive.sh b/tests/test_cmd_progressive.sh index 6cdd1c6730..fc4af73c4a 100755 --- a/tests/test_cmd_progressive.sh +++ b/tests/test_cmd_progressive.sh @@ -47,16 +47,16 @@ pushd ${TMP_DIR} "${AVIFDEC}" "${ENCODED_FILE}" "${DECODED_FILE}" "${AVIFDEC}" --progressive "${ENCODED_FILE}" "${DECODED_FILE}" - echo "Testing manual layered encoding with rendered-size override and mixed input sizes" - "${AVIFENC}" -s 8 --layered --render-size 768x512 \ + echo "Testing manual layered encoding with display-size override and mixed input sizes" + "${AVIFENC}" -s 8 --layered --display-size 768x512 \ "${INPUT_SMALL_Y4M}" "${INPUT_Y4M}" -o "${ENCODED_FILE}" "${AVIFDEC}" --info "${ENCODED_FILE}" > "${INFO_FILE}" grep -F "[768x512]" "${INFO_FILE}" "${AVIFDEC}" "${ENCODED_FILE}" "${DECODED_FILE}" "${AVIFDEC}" --progressive "${ENCODED_FILE}" "${DECODED_FILE}" - echo "Testing rendered-size override smaller than an input layer" - "${AVIFENC}" -s 8 --layered --render-size 384x256 \ + echo "Testing display-size override smaller than an input layer" + "${AVIFENC}" -s 8 --layered --display-size 384x256 \ "${INPUT_SMALL_Y4M}" "${INPUT_Y4M}" -o "${ENCODED_FILE}" && exit 1 # libavif relies on libyuv to do scaling From d78bc6c6cae0be0f3826b3588cc71ef7ad3e9fe3 Mon Sep 17 00:00:00 2001 From: Yuan Tong Date: Mon, 7 Sep 2026 23:17:01 +0800 Subject: [PATCH 05/17] patch from Wan-Teh Chang --- apps/avifenc.c | 2 +- include/avif/avif.h | 17 +++++++++-------- src/codec_aom.c | 16 +++++++++++----- src/codec_avm.c | 10 +++++----- src/codec_rav1e.c | 12 ++++++------ src/codec_svt.c | 10 +++++----- src/write.c | 10 +++++----- 7 files changed, 42 insertions(+), 35 deletions(-) diff --git a/apps/avifenc.c b/apps/avifenc.c index b45094e9f8..d8dad2cce5 100644 --- a/apps/avifenc.c +++ b/apps/avifenc.c @@ -2230,7 +2230,7 @@ int main(int argc, char * argv[]) goto cleanup; } if (avifSettingsUsesDisplaySizeOverride(&settings) && (settings.layers == 1) && (input.filesCount > 1)) { - fprintf(stderr, "ERROR: --display-size is not supported with image sequences. Use --layered for multiple still inputs.\n"); + fprintf(stderr, "ERROR: --display-size is not supported with image sequences. Use --layered for multiple still image inputs.\n"); goto cleanup; } diff --git a/include/avif/avif.h b/include/avif/avif.h index 231b85501c..556359cb88 100644 --- a/include/avif/avif.h +++ b/include/avif/avif.h @@ -822,10 +822,11 @@ typedef struct avifImage // transformFlags. On decode, only honor the values in boxes with the associated transform flag set. // These also apply to gainMap->image, if any. // - // When encoding with avifEncoder.width/height set (see its comment), these values are interpreted - // relative to that overridden display size rather than to this avifImage's own width/height. - // No special handling is needed during decode: the decoded avifImage is automatically scaled to - // the display size, so these values are relative to its width/height as usual. + // When encoding with avifEncoder.width/height set (see their comment), these transformations + // are interpreted relative to that overridden display size rather than to this avifImage's own + // width/height. No special handling is needed during decode: the decoded avifImage is + // automatically scaled to the display size, so these transformations are relative to the + // decoded avifImage's width/height as usual. avifTransformFlags transformFlags; avifPixelAspectRatioBox pasp; avifCleanApertureBox clap; @@ -1638,7 +1639,7 @@ typedef struct avifEncoder // Overrides the image's display size (the width and height AVIF declares this image is meant // to be shown at) independent of the pixel dimensions actually encoded. Any image passed to // avifEncoderAddImage()/avifEncoderAddImageGrid() that is encoded smaller than the display size - // is upscaled to it on decode. + // is upscaled to the display size on decode. // // Defaults to 0 (disabled). When 0, the display size is the size of the first added image. // When set, both width and height must be nonzero, and neither can be smaller than the coded @@ -1661,9 +1662,9 @@ typedef struct avifEncoder // decoder is required to honor; a coded image smaller than it is upscaled by the decoder to // match. Separately, an AV1 encoder session declares a maximum frame size once, up front, and // every later frame must fit within it; by default that maximum is simply the size of the first - // frame encoded. Setting width/height also declares that AV1-level maximum explicitly, in - // addition to the ispe box, so that later, larger layers stay within it. This is why it must be - // at least as large as every layer's coded size. + // frame encoded. Setting width/height also declares that AV1-level maximum frame size + // explicitly, in addition to the ispe box, so that later, larger layers stay within it. This is + // why it must be at least as large as every layer's coded size. uint32_t width; uint32_t height; } avifEncoder; diff --git a/src/codec_aom.c b/src/codec_aom.c index 9f23c62096..8edd3f8a2a 100644 --- a/src/codec_aom.c +++ b/src/codec_aom.c @@ -893,14 +893,20 @@ static avifResult aomCodecEncodeImage(avifCodec * codec, } } - if ((addImageFlags & AVIF_ADD_IMAGE_FLAG_SINGLE) && (encoder->width == 0) && (encoder->height == 0)) { + if (addImageFlags & AVIF_ADD_IMAGE_FLAG_SINGLE) { // Set the maximum number of frames to encode to 1. This instructs // libaom to set still_picture and reduced_still_picture_header to // 1 in AV1 sequence headers. - // Still picture header requires frame size to match - // max_frame_width and max_frame_height, - // so we can't use it if frame can have a different size. cfg->g_limit = 1; + // Reduced still picture header requires frame size to match max + // frame size, so we can't use reduced still picture header if frame + // size is different from max frame size. + if (cfg->g_forced_max_frame_width > image->width) { + cfg->g_forced_max_frame_width = image->width; + } + if (cfg->g_forced_max_frame_height > image->height) { + cfg->g_forced_max_frame_height = image->height; + } } if (useAllIntra) { #if !defined(AOM_USAGE_ALL_INTRA) @@ -939,7 +945,7 @@ static avifResult aomCodecEncodeImage(avifCodec * codec, cfg->g_lag_in_frames = 0; } if ((encoder->width || encoder->height) && (cfg->g_lag_in_frames > 1)) { - // libaom does not allow changing frame dimension if + // aom_codec_enc_config_set() does not allow changing frame dimensions if // g_lag_in_frames > 1. cfg->g_lag_in_frames = 1; } diff --git a/src/codec_avm.c b/src/codec_avm.c index adf2699021..ad829fc85b 100644 --- a/src/codec_avm.c +++ b/src/codec_avm.c @@ -444,6 +444,11 @@ static avifResult avmCodecEncodeImage(avifCodec * codec, avifAddImageFlags addImageFlags, avifCodecEncodeOutput * output) { + if (encoder->width || encoder->height) { + avifDiagnosticsPrintf(codec->diag, "AVM does not support display-size override"); + return AVIF_RESULT_NOT_IMPLEMENTED; + } + struct avm_codec_enc_cfg * cfg = &codec->internal->cfg; avifBool quantizerUpdated = AVIF_FALSE; const int quantizer = avmQualityToQuantizer(quality, image->depth); @@ -453,11 +458,6 @@ static avifResult avmCodecEncodeImage(avifCodec * codec, // two fields. encoderChanges &= ~AVIF_ENCODER_CHANGE_SCALING_MODE; - if (encoder->width || encoder->height) { - avifDiagnosticsPrintf(codec->diag, "AVM does not support display-size override"); - return AVIF_RESULT_NOT_IMPLEMENTED; - } - if (!codec->internal->encoderInitialized) { int avmCpuUsed = -1; if (encoder->speed != AVIF_SPEED_DEFAULT) { diff --git a/src/codec_rav1e.c b/src/codec_rav1e.c index 4b41bfeb52..d94553d204 100644 --- a/src/codec_rav1e.c +++ b/src/codec_rav1e.c @@ -82,6 +82,12 @@ static avifResult rav1eCodecEncodeImage(avifCodec * codec, return AVIF_RESULT_NOT_IMPLEMENTED; } + // rav1e does not support overriding maximum frame width/height in sequence header + if (encoder->width || encoder->height) { + avifDiagnosticsPrintf(codec->diag, "rav1e does not support display-size override"); + return AVIF_RESULT_NOT_IMPLEMENTED; + } + // rav1e does not support encoding layered image. if (encoder->extraLayerCount > 0) { return AVIF_RESULT_NOT_IMPLEMENTED; @@ -90,12 +96,6 @@ static avifResult rav1eCodecEncodeImage(avifCodec * codec, // rav1e does not support disabling lagged output. See https://github.com/xiph/rav1e/issues/2267. Ignore this setting. (void)disableLaggedOutput; - // rav1e does not support overriding maximum frame width/height in sequence header - if (encoder->width || encoder->height) { - avifDiagnosticsPrintf(codec->diag, "rav1e does not support display-size override"); - return AVIF_RESULT_NOT_IMPLEMENTED; - } - avifResult result = AVIF_RESULT_UNKNOWN_ERROR; RaConfig * rav1eConfig = NULL; diff --git a/src/codec_svt.c b/src/codec_svt.c index 70be13fa14..71bdac06c2 100644 --- a/src/codec_svt.c +++ b/src/codec_svt.c @@ -75,6 +75,11 @@ static avifResult svtCodecEncodeImage(avifCodec * codec, } } + if (encoder->width || encoder->height) { + avifDiagnosticsPrintf(codec->diag, "SVT-AV1 does not support display-size override"); + return AVIF_RESULT_NOT_IMPLEMENTED; + } + // SVT-AV1 does not support encoding layered image. if (encoder->extraLayerCount > 0) { return AVIF_RESULT_NOT_IMPLEMENTED; @@ -83,11 +88,6 @@ static avifResult svtCodecEncodeImage(avifCodec * codec, // SVT-AV1 does not support disabling lagged output. Ignore this setting. (void)disableLaggedOutput; - if (encoder->width || encoder->height) { - avifDiagnosticsPrintf(codec->diag, "SVT-AV1 does not support display-size override"); - return AVIF_RESULT_NOT_IMPLEMENTED; - } - avifResult result = AVIF_RESULT_UNKNOWN_ERROR; EbColorFormat color_format = EB_YUV420; uint8_t * uvPlanes = NULL; // 4:2:0 U and V placeholder for alpha because SVT-AV1 does not support 4:0:0. diff --git a/src/write.c b/src/write.c index 59095ac5f5..3da38e2aeb 100644 --- a/src/write.c +++ b/src/write.c @@ -525,8 +525,6 @@ avifEncoder * avifEncoderCreate(void) encoder->maxQuantizer = AVIF_QUANTIZER_WORST_QUALITY; encoder->minQuantizerAlpha = AVIF_QUANTIZER_BEST_QUALITY; encoder->maxQuantizerAlpha = AVIF_QUANTIZER_WORST_QUALITY; - encoder->width = 0; - encoder->height = 0; encoder->tileRowsLog2 = 0; encoder->tileColsLog2 = 0; encoder->autoTiling = AVIF_FALSE; @@ -541,6 +539,8 @@ avifEncoder * avifEncoderCreate(void) encoder->creationTime = 0; encoder->modificationTime = 0; encoder->sampleTransformRecipe = AVIF_SAMPLE_TRANSFORM_NONE; + encoder->width = 0; + encoder->height = 0; return encoder; } @@ -574,8 +574,6 @@ static void avifEncoderBackupSettings(avifEncoder * encoder) lastEncoder->timescale = encoder->timescale; lastEncoder->repetitionCount = encoder->repetitionCount; lastEncoder->extraLayerCount = encoder->extraLayerCount; - lastEncoder->width = encoder->width; - lastEncoder->height = encoder->height; lastEncoder->minQuantizer = encoder->minQuantizer; lastEncoder->maxQuantizer = encoder->maxQuantizer; lastEncoder->minQuantizerAlpha = encoder->minQuantizerAlpha; @@ -586,6 +584,8 @@ static void avifEncoderBackupSettings(avifEncoder * encoder) encoder->data->lastTileColsLog2 = encoder->data->tileColsLog2; lastEncoder->scalingMode = encoder->scalingMode; lastEncoder->sampleTransformRecipe = encoder->sampleTransformRecipe; + lastEncoder->width = encoder->width; + lastEncoder->height = encoder->height; } // This function detects changes made on avifEncoder. It returns true on success (i.e., if every @@ -1598,7 +1598,7 @@ static avifCodecType avifEncoderGetCodecType(const avifEncoder * encoder) return avifCodecTypeFromChoice(encoder->codecChoice, AVIF_CODEC_FLAG_CAN_ENCODE); } -static avifResult avifEncoderValidateDisplaySizeOverride(avifEncoder * encoder, uint32_t gridCols, uint32_t gridRows, const avifImage * firstCell) +static avifResult avifEncoderValidateDisplaySizeOverride(const avifEncoder * encoder, uint32_t gridCols, uint32_t gridRows, const avifImage * firstCell) { if (!avifEncoderUsesDisplaySizeOverride(encoder)) { return AVIF_RESULT_OK; From 43279ab89ce4bc1fc0661134cc6884d40afa0c58 Mon Sep 17 00:00:00 2001 From: Yuan Tong Date: Mon, 7 Sep 2026 23:30:59 +0800 Subject: [PATCH 06/17] additional changes --- CHANGELOG.md | 2 ++ tests/gtest/avif_fuzztest_enc_dec_layered.cc | 24 ++++++++------------ 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27558f07b2..6152efd886 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,9 @@ The changes are relative to the previous release, unless the baseline is specifi * Add the ignoreICC option to avifDecoder * Support ignoring alpha in avifDecoder::imageContentToDecode +* Support overriding display size in avifEncoder * avifenc: add --ignore-alpha flag to discard alpha channel on encode +* avifenc: add --display-size flag to override display size of encoded image * avifgainmaputil: add --ignore-alpha flag to discard alpha channel * avifgainmaputil: add --ignore-exif and --ignore-xmp flags * avifdec: add --ignore-exif and --ignore-xmp flags diff --git a/tests/gtest/avif_fuzztest_enc_dec_layered.cc b/tests/gtest/avif_fuzztest_enc_dec_layered.cc index e1d108ad71..4a8a750c67 100644 --- a/tests/gtest/avif_fuzztest_enc_dec_layered.cc +++ b/tests/gtest/avif_fuzztest_enc_dec_layered.cc @@ -18,24 +18,18 @@ namespace { constexpr size_t kLayerCount = kMaxNumLayers; -struct UniformScale { - int32_t n; - int32_t d; -}; - -constexpr UniformScale kNoScale = {1, 1}; +constexpr avifFraction kNoScale = {1, 1}; constexpr size_t kRandomScalingModeCount = kLayerCount - 1; static_assert(kRandomScalingModeCount == 3); -constexpr std::array kSupportedScalingModes = { - UniformScale{1, 8}, UniformScale{1, 4}, UniformScale{1, 2}, - UniformScale{3, 5}, UniformScale{3, 4}, UniformScale{4, 5}}; -constexpr avifScalingMode kNoScalingMode = {{kNoScale.n, kNoScale.d}, - {kNoScale.n, kNoScale.d}}; +constexpr std::array kSupportedScalingModes = { + avifFraction{1, 8}, avifFraction{1, 4}, avifFraction{1, 2}, + avifFraction{3, 5}, avifFraction{3, 4}, avifFraction{4, 5}}; +constexpr avifScalingMode kNoScalingMode = {kNoScale, kNoScale}; constexpr std::array kNoScalingModes = { kNoScalingMode, kNoScalingMode, kNoScalingMode, kNoScalingMode}; -constexpr avifScalingMode MakeScalingMode(UniformScale horizontal, - UniformScale vertical) { +constexpr avifScalingMode MakeScalingMode(avifFraction horizontal, + avifFraction vertical) { return avifScalingMode{{horizontal.n, horizontal.d}, {vertical.n, vertical.d}}; } @@ -62,9 +56,9 @@ constexpr size_t CombinationCountWithRepetition(size_t value_count, constexpr size_t kScalingModeCombinationCount = CombinationCountWithRepetition( kSupportedScalingModes.size(), kRandomScalingModeCount); -std::array GetScalingModeCombination( +std::array GetScalingModeCombination( size_t combination_index) { - std::array combination = {}; + std::array combination = {}; size_t remaining_index = combination_index; size_t next_candidate = 0; for (size_t slot = 0; slot < combination.size(); ++slot) { From d313cafb10a5b437d0bc0150c6d4775c455b028e Mon Sep 17 00:00:00 2001 From: Yuan Tong Date: Mon, 7 Sep 2026 23:46:25 +0800 Subject: [PATCH 07/17] extra fix --- src/write.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/write.c b/src/write.c index 3da38e2aeb..33eacf0d2d 100644 --- a/src/write.c +++ b/src/write.c @@ -1598,7 +1598,7 @@ static avifCodecType avifEncoderGetCodecType(const avifEncoder * encoder) return avifCodecTypeFromChoice(encoder->codecChoice, AVIF_CODEC_FLAG_CAN_ENCODE); } -static avifResult avifEncoderValidateDisplaySizeOverride(const avifEncoder * encoder, uint32_t gridCols, uint32_t gridRows, const avifImage * firstCell) +static avifResult avifEncoderValidateDisplaySizeOverride(avifEncoder * encoder, uint32_t gridCols, uint32_t gridRows, const avifImage * firstCell) { if (!avifEncoderUsesDisplaySizeOverride(encoder)) { return AVIF_RESULT_OK; From 35c6be77ce24b82e3d716daad3ca0dc3852ec6fd Mon Sep 17 00:00:00 2001 From: Yuan Tong Date: Tue, 8 Sep 2026 01:17:18 +0800 Subject: [PATCH 08/17] Strict image size == last layer size --- CHANGELOG.md | 3 +- include/avif/avif.h | 39 ++------- src/codec_aom.c | 9 --- src/codec_avm.c | 1 - src/codec_rav1e.c | 5 +- src/codec_svt.c | 4 +- src/write.c | 83 ++++++++++++++++---- tests/gtest/avif_fuzztest_enc_dec_layered.cc | 10 +-- tests/gtest/avifchangesettingtest.cc | 10 ++- tests/gtest/avifprogressivetest.cc | 62 +++++++++++++-- 10 files changed, 145 insertions(+), 81 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6152efd886..6a1fdc6651 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,9 +12,8 @@ The changes are relative to the previous release, unless the baseline is specifi * Add the ignoreICC option to avifDecoder * Support ignoring alpha in avifDecoder::imageContentToDecode -* Support overriding display size in avifEncoder +* Support encoding layered image with pre-scaled inputs * avifenc: add --ignore-alpha flag to discard alpha channel on encode -* avifenc: add --display-size flag to override display size of encoded image * avifgainmaputil: add --ignore-alpha flag to discard alpha channel * avifgainmaputil: add --ignore-exif and --ignore-xmp flags * avifdec: add --ignore-exif and --ignore-xmp flags diff --git a/include/avif/avif.h b/include/avif/avif.h index 556359cb88..808244e65c 100644 --- a/include/avif/avif.h +++ b/include/avif/avif.h @@ -823,9 +823,9 @@ typedef struct avifImage // These also apply to gainMap->image, if any. // // When encoding with avifEncoder.width/height set (see their comment), these transformations - // are interpreted relative to that overridden display size rather than to this avifImage's own - // width/height. No special handling is needed during decode: the decoded avifImage is - // automatically scaled to the display size, so these transformations are relative to the + // are interpreted relative to that size rather than to this intermediate layer's own + // width/height. No special handling is needed during decode: the decoded layer is + // automatically scaled to the configured size, so these transformations are relative to the // decoded avifImage's width/height as usual. avifTransformFlags transformFlags; avifPixelAspectRatioBox pasp; @@ -1636,35 +1636,10 @@ typedef struct avifEncoder // Version 1.4.0 ends here. Add any new members after this line. // -------------------------------------------------------------------------------------------- - // Overrides the image's display size (the width and height AVIF declares this image is meant - // to be shown at) independent of the pixel dimensions actually encoded. Any image passed to - // avifEncoderAddImage()/avifEncoderAddImageGrid() that is encoded smaller than the display size - // is upscaled to the display size on decode. - // - // Defaults to 0 (disabled). When 0, the display size is the size of the first added image. - // When set, both width and height must be nonzero, and neither can be smaller than the coded - // dimensions of any image passed to avifEncoderAddImage()/avifEncoderAddImageGrid(). - // - // Not supported together with image sequences, image grids, scalingMode, sample - // transforms, or gain maps. Cannot be changed once encoding has started (i.e. after the first - // call to avifEncoderAddImage()/avifEncoderAddImageGrid()). - // - // The main use case is a layered image (see extraLayerCount above) where earlier layers' - // pixel data is already available at a smaller size, so encoding them directly at that size - // avoids the wasted round trip of upscaling to the display size only for the encoder to scale - // it back down, and allows scale ratios that scalingMode cannot express for the encoder in use. - // - // avifImage properties that are relative to image dimensions (clap, irot, imir, pasp; see the - // "Transformations" comment above) are interpreted relative to the display size when set, rather - // than to the coded size of whichever layer they came from. - // - // Implementation note: the display size is stored as the ispe box, the dimensions an AVIF - // decoder is required to honor; a coded image smaller than it is upscaled by the decoder to - // match. Separately, an AV1 encoder session declares a maximum frame size once, up front, and - // every later frame must fit within it; by default that maximum is simply the size of the first - // frame encoded. Setting width/height also declares that AV1-level maximum frame size - // explicitly, in addition to the ispe box, so that later, larger layers stay within it. This is - // why it must be at least as large as every layer's coded size. + // Only for layered image (extraLayerCount > 0), otherwise must be the default value 0. + // Declares the size of the encoded image beforehand, which shall be exactly the size of the + // last layer. This allows adding smaller images as earlier layers to avoid a wasted scaling + // round trip, or scale ratios that the encoder does not support via scalingMode. uint32_t width; uint32_t height; } avifEncoder; diff --git a/src/codec_aom.c b/src/codec_aom.c index 8edd3f8a2a..77b8168c6a 100644 --- a/src/codec_aom.c +++ b/src/codec_aom.c @@ -898,15 +898,6 @@ static avifResult aomCodecEncodeImage(avifCodec * codec, // libaom to set still_picture and reduced_still_picture_header to // 1 in AV1 sequence headers. cfg->g_limit = 1; - // Reduced still picture header requires frame size to match max - // frame size, so we can't use reduced still picture header if frame - // size is different from max frame size. - if (cfg->g_forced_max_frame_width > image->width) { - cfg->g_forced_max_frame_width = image->width; - } - if (cfg->g_forced_max_frame_height > image->height) { - cfg->g_forced_max_frame_height = image->height; - } } if (useAllIntra) { #if !defined(AOM_USAGE_ALL_INTRA) diff --git a/src/codec_avm.c b/src/codec_avm.c index ad829fc85b..ee75c9c427 100644 --- a/src/codec_avm.c +++ b/src/codec_avm.c @@ -445,7 +445,6 @@ static avifResult avmCodecEncodeImage(avifCodec * codec, avifCodecEncodeOutput * output) { if (encoder->width || encoder->height) { - avifDiagnosticsPrintf(codec->diag, "AVM does not support display-size override"); return AVIF_RESULT_NOT_IMPLEMENTED; } diff --git a/src/codec_rav1e.c b/src/codec_rav1e.c index d94553d204..a1a4c8314a 100644 --- a/src/codec_rav1e.c +++ b/src/codec_rav1e.c @@ -82,13 +82,10 @@ static avifResult rav1eCodecEncodeImage(avifCodec * codec, return AVIF_RESULT_NOT_IMPLEMENTED; } - // rav1e does not support overriding maximum frame width/height in sequence header + // rav1e does not support encoding layered image. if (encoder->width || encoder->height) { - avifDiagnosticsPrintf(codec->diag, "rav1e does not support display-size override"); return AVIF_RESULT_NOT_IMPLEMENTED; } - - // rav1e does not support encoding layered image. if (encoder->extraLayerCount > 0) { return AVIF_RESULT_NOT_IMPLEMENTED; } diff --git a/src/codec_svt.c b/src/codec_svt.c index 71bdac06c2..a283999ac6 100644 --- a/src/codec_svt.c +++ b/src/codec_svt.c @@ -75,12 +75,10 @@ static avifResult svtCodecEncodeImage(avifCodec * codec, } } + // SVT-AV1 does not support encoding layered image. if (encoder->width || encoder->height) { - avifDiagnosticsPrintf(codec->diag, "SVT-AV1 does not support display-size override"); return AVIF_RESULT_NOT_IMPLEMENTED; } - - // SVT-AV1 does not support encoding layered image. if (encoder->extraLayerCount > 0) { return AVIF_RESULT_NOT_IMPLEMENTED; } diff --git a/src/write.c b/src/write.c index 33eacf0d2d..ba6e939353 100644 --- a/src/write.c +++ b/src/write.c @@ -466,7 +466,7 @@ static avifResult avifItemPropertyDedupFinish(avifItemPropertyDedup * dedup, static const avifScalingMode noScaling = { { 1, 1 }, { 1, 1 } }; -static avifBool avifEncoderUsesDisplaySizeOverride(const avifEncoder * encoder) +static avifBool avifEncoderSizeIsSet(const avifEncoder * encoder) { return (encoder->width != 0) || (encoder->height != 0); } @@ -1598,46 +1598,78 @@ static avifCodecType avifEncoderGetCodecType(const avifEncoder * encoder) return avifCodecTypeFromChoice(encoder->codecChoice, AVIF_CODEC_FLAG_CAN_ENCODE); } -static avifResult avifEncoderValidateDisplaySizeOverride(avifEncoder * encoder, uint32_t gridCols, uint32_t gridRows, const avifImage * firstCell) +static avifResult avifEncoderValidateSize(avifEncoder * encoder, uint32_t gridCols, uint32_t gridRows, const avifImage * firstCell) { - if (!avifEncoderUsesDisplaySizeOverride(encoder)) { + if (!avifEncoderSizeIsSet(encoder)) { return AVIF_RESULT_OK; } if ((encoder->width == 0) || (encoder->height == 0)) { - avifDiagnosticsPrintf(&encoder->diag, - "display-size override requires both avifEncoder.width and avifEncoder.height to be non-zero"); + avifDiagnosticsPrintf(&encoder->diag, "avifEncoder.width and avifEncoder.height must either both be zero or both be nonzero"); return AVIF_RESULT_INVALID_ARGUMENT; } if ((gridCols > 1) || (gridRows > 1)) { - avifDiagnosticsPrintf(&encoder->diag, "display-size override is not supported with grid images"); + avifDiagnosticsPrintf(&encoder->diag, "avifEncoder.width/height cannot be set with grid images"); return AVIF_RESULT_NOT_IMPLEMENTED; } if (!avifScalingModeIsNoScaling(&encoder->scalingMode)) { - avifDiagnosticsPrintf(&encoder->diag, "display-size override is not supported with encoder->scalingMode"); - return AVIF_RESULT_NOT_IMPLEMENTED; + avifDiagnosticsPrintf(&encoder->diag, "avifEncoder.width/height cannot be set together with encoder->scalingMode"); + return AVIF_RESULT_INVALID_ARGUMENT; } if (encoder->sampleTransformRecipe != AVIF_SAMPLE_TRANSFORM_NONE) { - avifDiagnosticsPrintf(&encoder->diag, "display-size override is not supported with sample transforms"); + avifDiagnosticsPrintf(&encoder->diag, "avifEncoder.width/height cannot be set with sample transforms"); return AVIF_RESULT_NOT_IMPLEMENTED; } if (firstCell->gainMap && firstCell->gainMap->image) { - avifDiagnosticsPrintf(&encoder->diag, "display-size override is not supported with gain maps"); + avifDiagnosticsPrintf(&encoder->diag, "avifEncoder.width/height cannot be set with gain maps"); return AVIF_RESULT_NOT_IMPLEMENTED; } - if ((encoder->data->items.count > 0) && (encoder->extraLayerCount == 0)) { - avifDiagnosticsPrintf(&encoder->diag, "display-size override is not supported for image sequences"); - return AVIF_RESULT_NOT_IMPLEMENTED; + // According to section 2.2.2 of AV1 Image File Format specification v1.2.0: + // [...] the values of image_width and image_height shall respectively equal the values of + // UpscaledWidth and FrameHeight as defined in [AV1] but for a specific frame in the item + // payload. [...] + // The semantics of the 'ispe' property [...] the values of image_width and image_height shall + // respectively equal the values of UpscaledWidth and FrameHeight as defined in [AV1] but for + // a specific frame in the item payload. [...] + // In the absence of a 'lsel' property associated with the item, or if it is present and its + // layer_id value is set to 0xFFFF: + // If no OperatingPointSelectorProperty is associated with the item, the 'ispe' property + // shall document the dimensions of the last frame decoded when processing the operating + // point whose index is 0. + // NOTE: The dimensions of possible intermediate output images might not match the ones given + // in the 'ispe' property. If renderers display these intermediate images, they are expected + // to scale the output image to match the 'ispe' property. + // See https://aomediacodec.github.io/av1-avif/v1.2.0.html#image-spatial-extents-property. + + // Therefore only layered image can have frames of different sizes, so reject otherwise. + if (encoder->extraLayerCount == 0) { + avifDiagnosticsPrintf(&encoder->diag, "avifEncoder.width/height can only be set for layered images (extraLayerCount > 0)"); + return AVIF_RESULT_INVALID_ARGUMENT; } + // We tighten the rule to "earlier layers shall be smaller" due to encoder restrictions. + // The exact-match requirement for the last layer is enforced below in + // avifEncoderAddImageInternal() when adding that image. if ((encoder->width < firstCell->width) || (encoder->height < firstCell->height)) { avifDiagnosticsPrintf(&encoder->diag, - "display-size override %ux%u must be at least the coded image size %ux%u", + "avifEncoder.width/height %ux%u must be at least the coded image size %ux%u", + encoder->width, + encoder->height, + firstCell->width, + firstCell->height); + return AVIF_RESULT_INCOMPATIBLE_IMAGE; + } + + // The declared width/height must exactly match the coded size of the last layer. + if ((encoder->data->frames.count == encoder->extraLayerCount) && + ((encoder->width != firstCell->width) || (encoder->height != firstCell->height))) { + avifDiagnosticsPrintf(&encoder->diag, + "avifEncoder.width/height %ux%u must exactly match the coded size %ux%u of the last layer", encoder->width, encoder->height, firstCell->width, @@ -1654,13 +1686,26 @@ static avifResult avifEncoderValidateDisplaySizeOverride(avifEncoder * encoder, if ((encoder->data->items.count > 0) && (encoder->extraLayerCount > 0) && !avifImageHasEquivalentTransformProperties(firstCell, encoder->data->imageMetadata)) { - avifDiagnosticsPrintf(&encoder->diag, "display-size override requires 'pasp', 'clap', 'irot' and 'imir' to match across layers"); + avifDiagnosticsPrintf(&encoder->diag, + "when avifEncoder.width/height is set, 'pasp', 'clap', 'irot' and 'imir' must match across layers"); return AVIF_RESULT_INCOMPATIBLE_IMAGE; } return AVIF_RESULT_OK; } +static avifResult avifEncoderValidateConsistentSize(avifEncoder * encoder, const avifImage * firstCell) +{ + if (avifEncoderSizeIsSet(encoder) || (encoder->data->items.count == 0)) { + return AVIF_RESULT_OK; + } + if ((firstCell->width != encoder->data->imageMetadata->width) || (firstCell->height != encoder->data->imageMetadata->height)) { + avifDiagnosticsPrintf(&encoder->diag, "All images must have the same width/height unless avifEncoder.width/height is set"); + return AVIF_RESULT_INVALID_ARGUMENT; + } + return AVIF_RESULT_OK; +} + // This function is called after every color frame is encoded. It returns AVIF_TRUE if a keyframe needs to be forced for the next // alpha frame to be encoded, AVIF_FALSE otherwise. static avifBool avifEncoderDataShouldForceKeyframeForAlpha(const avifEncoderData * data, @@ -1843,7 +1888,11 @@ static avifResult avifEncoderAddImageInternal(avifEncoder * encoder, return AVIF_RESULT_NO_CONTENT; } - AVIF_CHECKRES(avifEncoderValidateDisplaySizeOverride(encoder, gridCols, gridRows, firstCell)); + AVIF_CHECKRES(avifEncoderValidateSize(encoder, gridCols, gridRows, firstCell)); + // Reject mixing scalingMode and adding input images of different sizes. + // They are different ways the achieve the same result, so mixing them + // creates confusion without providing any benefit. + AVIF_CHECKRES(avifEncoderValidateConsistentSize(encoder, firstCell)); AVIF_CHECKRES(avifValidateGrid(gridCols, gridRows, cellImages, /*validateGainMap=*/AVIF_FALSE, &encoder->diag)); @@ -1975,7 +2024,7 @@ static avifResult avifEncoderAddImageInternal(avifEncoder * encoder, if (encoder->data->items.count == 0) { // Make a copy of the first image's metadata (sans pixels) for future writing/validation AVIF_CHECKRES(avifImageCopy(encoder->data->imageMetadata, firstCell, 0)); - if (avifEncoderUsesDisplaySizeOverride(encoder)) { + if (avifEncoderSizeIsSet(encoder)) { encoder->data->imageMetadata->width = encoder->width; encoder->data->imageMetadata->height = encoder->height; } diff --git a/tests/gtest/avif_fuzztest_enc_dec_layered.cc b/tests/gtest/avif_fuzztest_enc_dec_layered.cc index 4a8a750c67..04a72f1a3a 100644 --- a/tests/gtest/avif_fuzztest_enc_dec_layered.cc +++ b/tests/gtest/avif_fuzztest_enc_dec_layered.cc @@ -102,8 +102,8 @@ inline auto ArbitraryScalingModes() { void EncodeDecodeLayered( std::vector layers, const std::array& scaling_modes, - uint32_t expected_width, uint32_t expected_height, - bool use_display_size_override, EncoderPtr encoder, DecoderPtr decoder) { + uint32_t expected_width, uint32_t expected_height, bool set_last_layer_size, + EncoderPtr encoder, DecoderPtr decoder) { ASSERT_EQ(layers.size(), kLayerCount); ASSERT_NE(encoder, nullptr); ASSERT_NE(decoder, nullptr); @@ -121,7 +121,7 @@ void EncodeDecodeLayered( encoder->codecChoice = AVIF_CODEC_CHOICE_AOM; encoder->extraLayerCount = static_cast(layers.size() - 1); - if (use_display_size_override) { + if (set_last_layer_size) { encoder->width = expected_width; encoder->height = expected_height; } @@ -187,7 +187,7 @@ void EncodeDecodeDimensionChange( EncodeDecodeLayered(std::move(layers), scaling_modes, /*expected_width=*/expected_width, /*expected_height=*/expected_height, - /*use_display_size_override=*/false, std::move(encoder), + /*set_last_layer_size=*/false, std::move(encoder), std::move(decoder)); } @@ -201,7 +201,7 @@ void EncodeDecodeDimensionChangeExternal(std::vector layers, EncodeDecodeLayered(std::move(layers), kNoScalingModes, /*expected_width=*/expected_width, /*expected_height=*/expected_height, - /*use_display_size_override=*/true, std::move(encoder), + /*set_last_layer_size=*/true, std::move(encoder), std::move(decoder)); } diff --git a/tests/gtest/avifchangesettingtest.cc b/tests/gtest/avifchangesettingtest.cc index 7cbc83b7dc..de4ffe41f5 100644 --- a/tests/gtest/avifchangesettingtest.cc +++ b/tests/gtest/avifchangesettingtest.cc @@ -241,7 +241,7 @@ TEST(ChangeSettingTest, UnchangeableImageChromaSamplePosition) { AVIF_RESULT_INCOMPATIBLE_IMAGE); } -TEST(ChangeSettingTest, UnchangeableDisplaySizeOverride) { +TEST(ChangeSettingTest, UnchangeableEncoderSize) { if (avifCodecName(AVIF_CODEC_CHOICE_AOM, AVIF_CODEC_FLAG_CAN_ENCODE) == nullptr) { GTEST_SKIP() << "Codec unavailable, skip test."; @@ -265,8 +265,14 @@ TEST(ChangeSettingTest, UnchangeableDisplaySizeOverride) { AVIF_ADD_IMAGE_FLAG_NONE), AVIF_RESULT_OK); + ImagePtr image2 = testutil::CreateImage(/*width=*/256, /*height=*/128, + /*depth=*/8, AVIF_PIXEL_FORMAT_YUV444, + AVIF_PLANES_YUV, AVIF_RANGE_FULL); + ASSERT_NE(image2, nullptr); + testutil::FillImageGradient(image2.get()); + encoder->width = 256; - ASSERT_EQ(avifEncoderAddImage(encoder.get(), image.get(), 1, + ASSERT_EQ(avifEncoderAddImage(encoder.get(), image2.get(), 1, AVIF_ADD_IMAGE_FLAG_NONE), AVIF_RESULT_CANNOT_CHANGE_SETTING); } diff --git a/tests/gtest/avifprogressivetest.cc b/tests/gtest/avifprogressivetest.cc index 9aec82e376..8cc78de4f5 100644 --- a/tests/gtest/avifprogressivetest.cc +++ b/tests/gtest/avifprogressivetest.cc @@ -129,7 +129,7 @@ TEST_F(ProgressiveTest, TuneIq) { // `ms_params->ms_buffers.ref->stride == ms_params->search_sites->stride' // failed. // See https://aomedia.googlesource.com/aom/+/945edd671. -TEST_F(ProgressiveTest, DimensionChange) { +TEST_F(ProgressiveTest, ResolutionChange) { if (avifLibYUVVersion() == 0) { GTEST_SKIP() << "libyuv not available, skip test."; } @@ -152,7 +152,7 @@ TEST_F(ProgressiveTest, DimensionChange) { TestDecode(kImageSize, kImageSize); } -TEST_F(ProgressiveTest, DimensionChangeWithAlpha) { +TEST_F(ProgressiveTest, ResolutionChangeWithAlpha) { if (avifLibYUVVersion() == 0) { GTEST_SKIP() << "libyuv not available, skip test."; } @@ -187,7 +187,7 @@ TEST_F(ProgressiveTest, DimensionChangeWithAlpha) { TestDecode(kImageSize, kImageSize, /*expect_alpha=*/true); } -TEST_F(ProgressiveTest, DimensionChangeExternal) { +TEST_F(ProgressiveTest, ResolutionChangeExternal) { encoder_->extraLayerCount = 1; encoder_->width = kImageSize; encoder_->height = kImageSize; @@ -210,15 +210,13 @@ TEST_F(ProgressiveTest, DimensionChangeExternal) { TestDecode(256, 256); } -TEST_F(ProgressiveTest, DimensionChangeExternalWithAlpha) { +TEST_F(ProgressiveTest, ResolutionChangeExternalWithAlpha) { const auto image = testutil::CreateImage(kImageSize, kImageSize, 8, AVIF_PIXEL_FORMAT_YUV444, AVIF_PLANES_ALL, AVIF_RANGE_FULL); ASSERT_NE(image, nullptr); testutil::FillImageGradient(image.get()); - encoder_->speed = 3; - encoder_->maxThreads = 1; encoder_->extraLayerCount = 2; encoder_->width = kImageSize; encoder_->height = kImageSize; @@ -246,6 +244,58 @@ TEST_F(ProgressiveTest, DimensionChangeExternalWithAlpha) { TestDecode(kImageSize, kImageSize, /*expect_alpha=*/true); } +TEST_F(ProgressiveTest, ResolutionChangeExternalBadSize) { + encoder_->extraLayerCount = 1; + encoder_->width = kImageSize * 2; + encoder_->height = kImageSize * 2; + + ASSERT_EQ(avifEncoderAddImage(encoder_.get(), image_.get(), 1, + AVIF_ADD_IMAGE_FLAG_NONE), + AVIF_RESULT_OK); + + // Last layer does not match the pre-declared size + ASSERT_EQ(avifEncoderAddImage(encoder_.get(), image_.get(), 1, + AVIF_ADD_IMAGE_FLAG_NONE), + AVIF_RESULT_INCOMPATIBLE_IMAGE); +} + +// Reject mixed usage of internal and external resolution change. +TEST_F(ProgressiveTest, ResolutionChangeMixedRejected) { + encoder_->extraLayerCount = 1; + encoder_->width = kImageSize; + encoder_->height = kImageSize; + encoder_->scalingMode = {{1, 2}, {1, 2}}; + + const auto smallImage = testutil::CreateImage( + kImageSize / 2, kImageSize / 2, 8, AVIF_PIXEL_FORMAT_YUV444, + AVIF_PLANES_YUV, AVIF_RANGE_FULL); + ASSERT_NE(smallImage, nullptr); + + ASSERT_EQ(avifEncoderAddImage(encoder_.get(), smallImage.get(), 1, + AVIF_ADD_IMAGE_FLAG_NONE), + AVIF_RESULT_INVALID_ARGUMENT); +} + +TEST_F(ProgressiveTest, ResolutionChangeMixedDuringEncodingRejected) { + encoder_->extraLayerCount = 1; + encoder_->width = kImageSize; + encoder_->height = kImageSize; + + const auto smallImage = testutil::CreateImage( + kImageSize / 2, kImageSize / 2, 8, AVIF_PIXEL_FORMAT_YUV444, + AVIF_PLANES_YUV, AVIF_RANGE_FULL); + ASSERT_NE(smallImage, nullptr); + + ASSERT_EQ(avifEncoderAddImage(encoder_.get(), smallImage.get(), 1, + AVIF_ADD_IMAGE_FLAG_NONE), + AVIF_RESULT_OK); + + encoder_->scalingMode = {{1, 2}, {1, 2}}; + ASSERT_EQ(avifEncoderAddImage(encoder_.get(), image_.get(), 1, + AVIF_ADD_IMAGE_FLAG_NONE), + AVIF_RESULT_INVALID_ARGUMENT); +} + TEST_F(ProgressiveTest, LayeredGrid) { encoder_->extraLayerCount = 1; encoder_->quality = 21; From c46adb0722a61ceff3ab253ee49231e309e3a5e9 Mon Sep 17 00:00:00 2001 From: Yuan Tong Date: Thu, 10 Sep 2026 19:40:51 +0800 Subject: [PATCH 09/17] avifenc scaled layer inputs --- apps/avifenc.c | 129 ++++++++++++++++++-------------- apps/avifgainmaputil/imageio.cc | 5 +- apps/shared/avifjpeg.c | 45 +++++++++-- apps/shared/avifjpeg.h | 4 + apps/shared/avifpng.c | 38 +++++++++- apps/shared/avifpng.h | 4 + apps/shared/avifutil.c | 46 ++++++++++-- apps/shared/avifutil.h | 10 ++- apps/shared/y4m.c | 42 +++++++++-- apps/shared/y4m.h | 4 + tests/test_cmd_progressive.sh | 28 ++++--- 11 files changed, 264 insertions(+), 91 deletions(-) diff --git a/apps/avifenc.c b/apps/avifenc.c index d8dad2cce5..a533ac5a29 100644 --- a/apps/avifenc.c +++ b/apps/avifenc.c @@ -44,8 +44,6 @@ typedef struct avifHeaderFormatFlags headerFormat; uint64_t creationTime; uint64_t modificationTime; - uint32_t width; - uint32_t height; avifBool paspPresent; uint32_t paspValues[2]; @@ -80,6 +78,10 @@ typedef struct avifMatrixCoefficients matrixCoefficients; avifChromaDownsampling chromaDownsampling; avifAppFileFormat inputFormat; + + // Inferred from the last input, only needed when using --layered + uint32_t width; + uint32_t height; } avifSettings; typedef struct @@ -244,8 +246,6 @@ static void syntaxLong(void) printf(" --progressive : Automatically set parameters to encode a simple layered image supporting progressive rendering from a single input frame.\n"); printf(" --layered : Encode a layered AVIF. Each input is encoded as one layer and at most %d layers can be encoded.\n", AVIF_MAX_AV1_LAYER_COUNT); - printf(" --display-size WxH : Set the size at which the AVIF image is displayed, independent of the encoded pixel dimensions.\n"); - printf(" Supported for still images and layered still images only.\n"); printf(" -g,--grid MxN : Encode a single-image grid AVIF with M cols & N rows. Either supply MxN identical W/H/D images, or a single\n"); printf(" image that can be evenly split into the MxN grid and follow AVIF grid image restrictions. The grid will adopt\n"); printf(" the color profile of the first image supplied.\n"); @@ -458,25 +458,14 @@ static avifBool convertCropToClap(uint32_t srcW, uint32_t srcH, uint32_t clapVal return AVIF_TRUE; } -static avifBool avifSettingsUsesDisplaySizeOverride(const avifSettings * settings) +static avifBool avifVerifyImageFitsLastLayerSize(const avifSettings * settings, const avifImage * image, const char * filename) { - return (settings->width != 0) || (settings->height != 0); -} - -static void avifSettingsGetEffectiveOutputDimensions(const avifSettings * settings, const avifImage * image, uint32_t * width, uint32_t * height) -{ - *width = settings->width ? settings->width : image->width; - *height = settings->height ? settings->height : image->height; -} - -static avifBool avifSettingsVerifyDisplaySizeBounds(const avifSettings * settings, const avifImage * image, const char * filename) -{ - if (!avifSettingsUsesDisplaySizeOverride(settings)) { + if (settings->width == 0) { return AVIF_TRUE; } if ((image->width > settings->width) || (image->height > settings->height)) { fprintf(stderr, - "ERROR: Input image dimensions [%ux%u] exceed display size [%ux%u]: %s\n", + "ERROR: Input image dimensions [%ux%u] exceed the last layer's size [%ux%u]: %s\n", image->width, image->height, settings->width, @@ -487,6 +476,39 @@ static avifBool avifSettingsVerifyDisplaySizeBounds(const avifSettings * setting return AVIF_TRUE; } +// Checks, ahead of time and in CLI terms, for the settings that the library itself would reject +// once combined with --layered inputs of different sizes (which predeclares avifEncoder.width/height, +// a field avifenc's users never set directly). Only checks conditions actually reachable via avifenc's +// CLI; e.g. grids and non-layered images can't reach this point at all, so they're not checked here. +static avifBool avifVerifyLastLayerSizeCompatibility(const avifSettings * settings, const avifInput * input, const avifImage * firstImage) +{ + if (settings->width == 0) { + return AVIF_TRUE; + } + for (int i = 0; i < settings->layers; ++i) { + const avifScalingMode * scalingMode = &input->files[i].settings.scalingMode.value; + const avifBool isNoScaling = (scalingMode->horizontal.n == scalingMode->horizontal.d) && + (scalingMode->vertical.n == scalingMode->vertical.d); + if (input->files[i].settings.scalingMode.set && !isNoScaling) { + fprintf(stderr, "ERROR: --scaling-mode cannot be used with --layered inputs of different sizes\n"); + return AVIF_FALSE; + } + } + if (input->requestedDepthExtension != 0) { + fprintf(stderr, "ERROR: --depth with a bit depth extension cannot be used with --layered inputs of different sizes\n"); + return AVIF_FALSE; + } +#if defined(AVIF_ENABLE_JPEG_GAIN_MAP_CONVERSION) + if (firstImage->gainMap && firstImage->gainMap->image) { + fprintf(stderr, "ERROR: A gain map cannot be used with --layered inputs of different sizes (use --ignore-gain-map)\n"); + return AVIF_FALSE; + } +#else + (void)firstImage; +#endif + return AVIF_TRUE; +} + static avifBool avifInputAddCachedImage(avifInput * input) { avifImage * newImage = avifImageCreateEmpty(); @@ -988,9 +1010,6 @@ static avifBool avifEncodeRestOfImageSequence(avifEncoder * encoder, settings->inputFormat)) { goto cleanup; } - if (!avifSettingsVerifyDisplaySizeBounds(settings, nextImage, avifPrettyFilename(nextFile->filename))) { - goto cleanup; - } if (!avifEncoderVerifyImageCompatibility(firstImage, nextImage, "sequence", @@ -1102,7 +1121,7 @@ static avifBool avifEncodeRestOfLayeredImage(avifEncoder * encoder, settings->inputFormat)) { goto cleanup; } - if (!avifSettingsVerifyDisplaySizeBounds(settings, nextImage, avifPrettyFilename(nextFile->filename))) { + if (!avifVerifyImageFitsLastLayerSize(settings, nextImage, avifPrettyFilename(nextFile->filename))) { goto cleanup; } // frameIter is NULL if y4m reached end, so single frame y4m is still supported. @@ -1116,7 +1135,7 @@ static avifBool avifEncodeRestOfLayeredImage(avifEncoder * encoder, nextImage, "layer", avifPrettyFilename(nextFile->filename), - avifSettingsUsesDisplaySizeOverride(settings))) { + /*allowDimensionChange=*/AVIF_TRUE)) { goto cleanup; } if (!avifEncodeUpdateEncoderSettings(encoder, nextSettings)) { @@ -1824,15 +1843,6 @@ int main(int argc, char * argv[]) goto cleanup; } settings.layered = AVIF_TRUE; - } else if (!strcmp(arg, "--display-size")) { - uint32_t displaySize[2] = { 0 }; - NEXTARG(); - if (!parseU32List(displaySize, 2, arg, 'x') || (displaySize[0] == 0) || (displaySize[1] == 0)) { - fprintf(stderr, "ERROR: Invalid display size: %s\n", arg); - goto cleanup; - } - settings.width = displaySize[0]; - settings.height = displaySize[1]; } else if (!strcmp(arg, "--scaling-mode") || strpre(arg, "--scaling-mode:")) { avifOptionSuffixType type = parseOptionSuffix(arg, input.filesCount != 0); if (type == AVIF_OPTION_SUFFIX_INVALID) { @@ -2193,11 +2203,6 @@ int main(int argc, char * argv[]) fprintf(stderr, "WARNING: Trailing options with update suffix has no effect. Place them before the input you intend to apply to.\n"); } - if (avifSettingsUsesDisplaySizeOverride(&settings) && ((settings.width == 0) || (settings.height == 0))) { - fprintf(stderr, "ERROR: --display-size must be specified as WxH.\n"); - goto cleanup; - } - // Check layer config if (settings.progressive) { assert(!settings.layered); @@ -2225,14 +2230,6 @@ int main(int argc, char * argv[]) fprintf(stderr, "Layered grid image unimplemented in avifenc.\n"); goto cleanup; } - if (avifSettingsUsesDisplaySizeOverride(&settings) && settings.gridDimsPresent) { - fprintf(stderr, "ERROR: --display-size is not supported with --grid.\n"); - goto cleanup; - } - if (avifSettingsUsesDisplaySizeOverride(&settings) && (settings.layers == 1) && (input.filesCount > 1)) { - fprintf(stderr, "ERROR: --display-size is not supported with image sequences. Use --layered for multiple still image inputs.\n"); - goto cleanup; - } for (int i = 0; i < input.filesCount; ++i) { avifInputFile * file = &input.files[i]; @@ -2453,18 +2450,37 @@ int main(int argc, char * argv[]) goto cleanup; } - if (!avifSettingsVerifyDisplaySizeBounds(&settings, image, avifPrettyFilename(firstFile->filename))) { - goto cleanup; + uint32_t outputImageWidth = image->width; + uint32_t outputImageHeight = image->height; + if (settings.layered) { + // Check the resolution of the last layer without decoding it, to fill + // the image size in advance. + // Only fill if the resolution differs from the first layer's, + // to not interfere with --scaling-mode. + const avifInputFile * lastFile = &input.files[input.filesCount - 1]; + avifImage * lastImage = avifImageCreateEmpty(); + if (!lastImage) { + fprintf(stderr, "ERROR: Out of memory\n"); + goto cleanup; + } + const avifBool lastImageOk = avifPeekImage(lastFile->filename, settings.inputFormat, lastImage) != AVIF_APP_FILE_FORMAT_UNKNOWN; + if (lastImageOk && ((lastImage->width != image->width) || (lastImage->height != image->height))) { + outputImageWidth = settings.width = lastImage->width; + outputImageHeight = settings.height = lastImage->height; + } + avifImageDestroy(lastImage); + if (!lastImageOk) { + fprintf(stderr, "ERROR: Failed to read last layer: %s\n", avifPrettyFilename(lastFile->filename)); + goto cleanup; + } } - if (avifSettingsUsesDisplaySizeOverride(&settings) && (settings.layers == 1) && input.frameIter) { - fprintf(stderr, "ERROR: --display-size is not supported with image sequences.\n"); + if (!avifVerifyImageFitsLastLayerSize(&settings, image, avifPrettyFilename(firstFile->filename))) { + goto cleanup; + } + if (!avifVerifyLastLayerSizeCompatibility(&settings, &input, image)) { goto cleanup; } - - uint32_t outputImageWidth; - uint32_t outputImageHeight; - avifSettingsGetEffectiveOutputDimensions(&settings, image, &outputImageWidth, &outputImageHeight); printf("Successfully loaded: %s\n", avifPrettyFilename(firstFile->filename)); @@ -2720,13 +2736,14 @@ int main(int argc, char * argv[]) } printf("AVIF to be written:%s\n", lossyHint); const avifImage * avif = gridCells ? gridCells[0] : image; + const uint32_t cellWidth = gridCells ? avif->width : outputImageWidth; + const uint32_t cellHeight = gridCells ? avif->height : outputImageHeight; avifImageDump(avif, + cellWidth, + cellHeight, settings.gridDims[0], settings.gridDims[1], settings.layers > 1 ? AVIF_PROGRESSIVE_STATE_AVAILABLE : AVIF_PROGRESSIVE_STATE_UNAVAILABLE); - if (avifSettingsUsesDisplaySizeOverride(&settings)) { - printf(" * Display Size : %ux%u\n", settings.width, settings.height); - } avifEncodedByteSizes byteSizes = { 0, 0, 0 }; if (!avifEncodeImages(&settings, &input, firstFile, image, (const avifImage **)gridCells, &raw, &byteSizes)) { diff --git a/apps/avifgainmaputil/imageio.cc b/apps/avifgainmaputil/imageio.cc index 900f30c319..0b10abc68c 100644 --- a/apps/avifgainmaputil/imageio.cc +++ b/apps/avifgainmaputil/imageio.cc @@ -113,7 +113,7 @@ avifResult WriteAvif(const avifImage* image, avifEncoder* encoder, const std::string& output_filename) { avifRWData encoded = AVIF_DATA_EMPTY; std::cout << "AVIF to be written:\n"; - avifImageDump(image, + avifImageDump(image, image->width, image->height, /*gridCols=*/1, /*gridRows=*/1, AVIF_PROGRESSIVE_STATE_UNAVAILABLE); PrintEncodingSettings(encoder, image->gainMap != nullptr); @@ -158,7 +158,8 @@ avifResult WriteAvifGrid(const avifImage* image, int grid_cols, int grid_rows, avifRWData encoded = AVIF_DATA_EMPTY; std::cout << "AVIF to be written:\n"; - avifImageDump(grid_cells_ptrs[0], grid_cols, grid_rows, + avifImageDump(grid_cells_ptrs[0], grid_cells_ptrs[0]->width, + grid_cells_ptrs[0]->height, grid_cols, grid_rows, AVIF_PROGRESSIVE_STATE_UNAVAILABLE); PrintEncodingSettings(encoder, image->gainMap != nullptr); avifResult result = avifEncoderAddImageGrid(encoder, grid_cols, grid_rows, diff --git a/apps/shared/avifjpeg.c b/apps/shared/avifjpeg.c index 426c5d0a2e..7c5b41216d 100644 --- a/apps/shared/avifjpeg.c +++ b/apps/shared/avifjpeg.c @@ -486,7 +486,8 @@ static avifBool avifJPEGReadInternal(FILE * f, avifBool ignoreExif, avifBool ignoreXMP, avifBool ignoreGainMap, - uint32_t sizeLimit); + uint32_t sizeLimit, + avifBool headerOnly); // Arbitrary max number of jpeg segments to parse before giving up. #define MAX_JPEG_SEGMENTS 100 @@ -1024,7 +1025,8 @@ static avifBool avifJPEGExtractGainMapImageFromMpf(FILE * f, /*ignoreExif=*/AVIF_TRUE, /*ignoreXMP=*/AVIF_FALSE, /*ignoreGainMap=*/AVIF_TRUE, - sizeLimit)) { + sizeLimit, + /*headerOnly=*/AVIF_FALSE)) { continue; } if (avifJPEGHasGainMapXMPNode(avif->xmp.data, avif->xmp.size, NULL)) { @@ -1261,7 +1263,8 @@ static avifBool avifJPEGReadInternal(FILE * f, avifBool ignoreExif, avifBool ignoreXMP, avifBool ignoreGainMap, - uint32_t sizeLimit) + uint32_t sizeLimit, + avifBool headerOnly) { volatile avifBool ret = AVIF_FALSE; uint8_t * volatile iccData = NULL; @@ -1305,6 +1308,8 @@ static avifBool avifJPEGReadInternal(FILE * f, fprintf(stderr, "Too big JPEG dimensions (%u x %u > %u px): %s\n", cinfo.output_width, cinfo.output_height, sizeLimit, inputFilename); goto cleanup; } + avif->width = cinfo.output_width; + avif->height = cinfo.output_height; if (!ignoreColorProfile) { uint8_t * iccDataTmp; @@ -1336,6 +1341,12 @@ static avifBool avifJPEGReadInternal(FILE * f, // JPEG doesn't have alpha. Prevent confusion. avif->alphaPremultiplied = AVIF_FALSE; + if (headerOnly) { + // No real decoding needed. Stop here. + ret = AVIF_TRUE; + goto cleanup; + } + if (avifJPEGReadCopy(avif, sizeLimit, &cinfo)) { // JPEG pixels were successfully copied without conversion. Notify the enduser. @@ -1351,8 +1362,6 @@ static avifBool avifJPEGReadInternal(FILE * f, int row_stride = cinfo.output_width * cinfo.output_components; JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1); - avif->width = cinfo.output_width; - avif->height = cinfo.output_height; if (avif->matrixCoefficients == AVIF_MATRIX_COEFFICIENTS_YCGCO_RO) { fprintf(stderr, "AVIF_MATRIX_COEFFICIENTS_YCGCO_RO cannot be used with JPEG because it has an even bit depth.\n"); goto cleanup; @@ -1672,13 +1681,37 @@ avifBool avifJPEGRead(const char * inputFilename, ignoreExif, ignoreXMP, ignoreGainMap, - sizeLimit); + sizeLimit, + /*headerOnly=*/AVIF_FALSE); if (f && f != stdin) { fclose(f); } return res; } +avifBool avifJPEGPeek(const char * inputFilename, avifImage * avif) +{ + FILE * f = fopen(inputFilename, "rb"); + if (!f) { + fprintf(stderr, "Can't open JPEG file for read: %s\n", inputFilename); + return AVIF_FALSE; + } + const avifBool res = avifJPEGReadInternal(f, + inputFilename, + avif, + AVIF_PIXEL_FORMAT_NONE, + /*requestedDepth=*/0, + AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC, + /*ignoreColorProfile=*/AVIF_TRUE, + /*ignoreExif=*/AVIF_TRUE, + /*ignoreXMP=*/AVIF_TRUE, + /*ignoreGainMap=*/AVIF_TRUE, + /*sizeLimit=*/UINT32_MAX, + /*headerOnly=*/AVIF_TRUE); + fclose(f); + return res; +} + avifBool avifJPEGWrite(const char * outputFilename, const avifImage * avif, int jpegQuality, avifChromaUpsampling chromaUpsampling) { avifBool ret = AVIF_FALSE; diff --git a/apps/shared/avifjpeg.h b/apps/shared/avifjpeg.h index 4cfc1e534d..4b0371c676 100644 --- a/apps/shared/avifjpeg.h +++ b/apps/shared/avifjpeg.h @@ -28,6 +28,10 @@ avifBool avifJPEGRead(const char * inputFilename, uint32_t sizeLimit); avifBool avifJPEGWrite(const char * outputFilename, const avifImage * avif, int jpegQuality, avifChromaUpsampling chromaUpsampling); +// Parse the jpeg file at path 'inputFilename' and write its metadata into 'avif', +// without decoding the pixels. +avifBool avifJPEGPeek(const char * inputFilename, avifImage * avif); + #if defined(AVIF_ENABLE_JPEG_GAIN_MAP_CONVERSION) // Parses XMP gain map metadata. Visible for testing. avifBool avifJPEGParseGainMapXMP(const uint8_t * xmpData, size_t xmpSize, avifGainMap * gainMap, avifBool * isAppleGainMap); diff --git a/apps/shared/avifpng.c b/apps/shared/avifpng.c index 9d7fee54eb..2bed26442c 100644 --- a/apps/shared/avifpng.c +++ b/apps/shared/avifpng.c @@ -279,7 +279,8 @@ static avifBool avifPNGReadImpl(FILE * f, avifBool ignoreXMP, avifBool ignoreAlpha, uint32_t imageSizeLimit, - uint32_t * outPNGDepth) + uint32_t * outPNGDepth, + avifBool headerOnly) { volatile avifBool readResult = AVIF_FALSE; png_structp png = NULL; @@ -515,6 +516,13 @@ static avifBool avifPNGReadImpl(FILE * f, goto cleanup; } + if (headerOnly) { + // All the metadata read so far (dimensions, depth, yuvFormat, ICC/color primaries if + // requested) is already set on avif. Stop here instead of decoding any pixel data. + readResult = AVIF_TRUE; + goto cleanup; + } + avifRGBImageSetDefaults(&rgb, avif); rgb.chromaDownsampling = chromaDownsampling; rgb.depth = imgBitDepth; @@ -613,7 +621,8 @@ avifBool avifPNGRead(const char * inputFilename, ignoreXMP, ignoreAlpha, imageSizeLimit, - outPNGDepth); + outPNGDepth, + /*headerOnly=*/AVIF_FALSE); if (f != stdin) { fclose(f); @@ -621,6 +630,31 @@ avifBool avifPNGRead(const char * inputFilename, return res; } +avifBool avifPNGPeek(const char * inputFilename, avifImage * avif) +{ + FILE * f = fopen(inputFilename, "rb"); + if (!f) { + fprintf(stderr, "Can't open PNG file for read: %s\n", inputFilename); + return AVIF_FALSE; + } + + const avifBool res = avifPNGReadImpl(f, + inputFilename, + avif, + /*requestedFormat=*/AVIF_PIXEL_FORMAT_NONE, + /*requestedDepth=*/0, + AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC, + /*ignoreColorProfile=*/AVIF_TRUE, + /*ignoreExif=*/AVIF_TRUE, + /*ignoreXMP=*/AVIF_TRUE, + /*ignoreAlpha=*/AVIF_TRUE, + /*imageSizeLimit=*/UINT32_MAX, + /*outPNGDepth=*/NULL, + /*headerOnly=*/AVIF_TRUE); + fclose(f); + return res; +} + //------------------------------------------------------------------------------ // Writing diff --git a/apps/shared/avifpng.h b/apps/shared/avifpng.h index b50d2b7c2b..7b5ce3557d 100644 --- a/apps/shared/avifpng.h +++ b/apps/shared/avifpng.h @@ -28,6 +28,10 @@ avifBool avifPNGWrite(const char * outputFilename, avifChromaUpsampling chromaUpsampling, int compressionLevel); +// Parse the PNG file at path 'inputFilename' and write its metadata into 'avif', +// without decoding the pixels. +avifBool avifPNGPeek(const char * inputFilename, avifImage * avif); + #ifdef __cplusplus } // extern "C" #endif diff --git a/apps/shared/avifutil.c b/apps/shared/avifutil.c index bd0eaf671c..041e8b7b4d 100644 --- a/apps/shared/avifutil.c +++ b/apps/shared/avifutil.c @@ -61,10 +61,16 @@ static void printClapFraction(const char * name, int32_t n, int32_t d) } } -static void avifImageDumpInternal(const avifImage * avif, uint32_t gridCols, uint32_t gridRows, avifBool alphaPresent, avifProgressiveState progressiveState) +static void avifImageDumpInternal(const avifImage * avif, + uint32_t cellWidth, + uint32_t cellHeight, + uint32_t gridCols, + uint32_t gridRows, + avifBool alphaPresent, + avifProgressiveState progressiveState) { - uint32_t width = avif->width; - uint32_t height = avif->height; + uint32_t width = cellWidth; + uint32_t height = cellHeight; if (gridCols && gridRows) { width *= gridCols; height *= gridRows; @@ -193,15 +199,15 @@ static void avifImageDumpInternal(const avifImage * avif, uint32_t gridCols, uin } } -void avifImageDump(const avifImage * avif, uint32_t gridCols, uint32_t gridRows, avifProgressiveState progressiveState) +void avifImageDump(const avifImage * avif, uint32_t cellWidth, uint32_t cellHeight, uint32_t gridCols, uint32_t gridRows, avifProgressiveState progressiveState) { const avifBool alphaPresent = avif->alphaPlane && (avif->alphaRowBytes > 0); - avifImageDumpInternal(avif, gridCols, gridRows, alphaPresent, progressiveState); + avifImageDumpInternal(avif, cellWidth, cellHeight, gridCols, gridRows, alphaPresent, progressiveState); } void avifContainerDump(const avifDecoder * decoder) { - avifImageDumpInternal(decoder->image, 0, 0, decoder->alphaPresent, decoder->progressiveState); + avifImageDumpInternal(decoder->image, decoder->image->width, decoder->image->height, 0, 0, decoder->alphaPresent, decoder->progressiveState); if (decoder->imageSequenceTrackPresent) { if (decoder->repetitionCount == AVIF_REPETITION_COUNT_INFINITE) { printf(" * Repeat Count : Infinite\n"); @@ -364,6 +370,34 @@ avifAppFileFormat avifReadImage(const char * filename, return inputFormat; } +avifAppFileFormat avifPeekImage(const char * filename, avifAppFileFormat inputFormat, avifImage * image) +{ + if (inputFormat == AVIF_APP_FILE_FORMAT_UNKNOWN) { + inputFormat = avifGuessFileFormat(filename); + } + + if (inputFormat == AVIF_APP_FILE_FORMAT_Y4M) { + if (!y4mPeek(filename, image)) { + return AVIF_APP_FILE_FORMAT_UNKNOWN; + } + } else if (inputFormat == AVIF_APP_FILE_FORMAT_JPEG) { + if (!avifJPEGPeek(filename, image)) { + return AVIF_APP_FILE_FORMAT_UNKNOWN; + } + } else if (inputFormat == AVIF_APP_FILE_FORMAT_PNG) { + if (!avifPNGPeek(filename, image)) { + return AVIF_APP_FILE_FORMAT_UNKNOWN; + } + } else if (inputFormat == AVIF_APP_FILE_FORMAT_UNKNOWN) { + fprintf(stderr, "Unrecognized file format for input file: %s\n", filename); + return AVIF_APP_FILE_FORMAT_UNKNOWN; + } else { + fprintf(stderr, "Unsupported file format %s for input file: %s\n", avifFileFormatToString(inputFormat), filename); + return AVIF_APP_FILE_FORMAT_UNKNOWN; + } + return inputFormat; +} + avifBool avifReadEntireFile(const char * filename, avifRWData * raw) { FILE * f = fopen(filename, "rb"); diff --git a/apps/shared/avifutil.h b/apps/shared/avifutil.h index 5b01d8582e..b984828208 100644 --- a/apps/shared/avifutil.h +++ b/apps/shared/avifutil.h @@ -28,7 +28,7 @@ extern "C" { #define AVIF_FMT_ZU "zu" #endif -void avifImageDump(const avifImage * avif, uint32_t gridCols, uint32_t gridRows, avifProgressiveState progressiveState); +void avifImageDump(const avifImage * avif, uint32_t cellWidth, uint32_t cellHeight, uint32_t gridCols, uint32_t gridRows, avifProgressiveState progressiveState); void avifContainerDump(const avifDecoder * decoder); void avifPrintVersions(void); void avifDumpDiagnostics(const avifDiagnostics * diag); @@ -118,6 +118,14 @@ avifAppFileFormat avifReadImage(const char * filename, avifAppSourceTiming * sourceTiming, struct y4mFrameIterator ** frameIter); +// Determines only the metadata available before pixel decoding starts (currently width, height, +// depth, yuvFormat and, for JPEG/PNG, color profile information) for an image file, without +// decoding any pixel data. +// If 'inputFormat' is AVIF_APP_FILE_FORMAT_UNKNOWN, the image format is guessed +// based on the filename or first few bytes. +// Returns the format of the file, or AVIF_APP_FILE_FORMAT_UNKNOWN in case of error. +avifAppFileFormat avifPeekImage(const char * filename, avifAppFileFormat inputFormat, avifImage * image); + // Copies all the bytes from the file at filename to a newly allocated memory chunk. avifBool avifReadEntireFile(const char * filename, avifRWData * raw); diff --git a/apps/shared/y4m.c b/apps/shared/y4m.c index 9a604ed0bf..7074067351 100644 --- a/apps/shared/y4m.c +++ b/apps/shared/y4m.c @@ -253,12 +253,13 @@ static avifBool y4mClampSamples(avifImage * avif) goto cleanup; \ } while (0) -avifBool y4mRead(const char * inputFilename, - avifBool ignoreAlpha, - uint32_t imageSizeLimit, - avifImage * avif, - avifAppSourceTiming * sourceTiming, - struct y4mFrameIterator ** iter) +static avifBool y4mReadInternal(const char * inputFilename, + avifBool ignoreAlpha, + uint32_t imageSizeLimit, + avifImage * avif, + avifAppSourceTiming * sourceTiming, + struct y4mFrameIterator ** iter, + avifBool headerOnly) { avifBool result = AVIF_FALSE; @@ -412,6 +413,14 @@ avifBool y4mRead(const char * inputFilename, avif->yuvFormat = frame.format; avif->yuvRange = frame.range; avif->yuvChromaSamplePosition = frame.chromaSamplePosition; + + if (headerOnly) { + // All the metadata (dimensions, depth, format, range, chroma sample position) is already + // known. Stop here instead of reading any frame data. + result = AVIF_TRUE; + goto cleanup; + } + avifResult allocationResult = avifImageAllocatePlanes(avif, frame.hasAlpha ? AVIF_PLANES_ALL : AVIF_PLANES_YUV); if (allocationResult != AVIF_RESULT_OK) { fprintf(stderr, "Failed to allocate the planes: %s\n", avifResultToString(allocationResult)); @@ -478,6 +487,27 @@ avifBool y4mRead(const char * inputFilename, return result; } +avifBool y4mRead(const char * inputFilename, + avifBool ignoreAlpha, + uint32_t imageSizeLimit, + avifImage * avif, + avifAppSourceTiming * sourceTiming, + struct y4mFrameIterator ** iter) +{ + return y4mReadInternal(inputFilename, ignoreAlpha, imageSizeLimit, avif, sourceTiming, iter, /*headerOnly=*/AVIF_FALSE); +} + +avifBool y4mPeek(const char * inputFilename, avifImage * avif) +{ + return y4mReadInternal(inputFilename, + /*ignoreAlpha=*/AVIF_TRUE, + /*imageSizeLimit=*/UINT32_MAX, + avif, + /*sourceTiming=*/NULL, + /*iter=*/NULL, + /*headerOnly=*/AVIF_TRUE); +} + avifBool y4mWrite(const char * outputFilename, const avifImage * avif) { avifBool hasAlpha = (avif->alphaPlane != NULL) && (avif->alphaRowBytes > 0); diff --git a/apps/shared/y4m.h b/apps/shared/y4m.h index bf9d645672..5521fb097c 100644 --- a/apps/shared/y4m.h +++ b/apps/shared/y4m.h @@ -26,6 +26,10 @@ avifBool y4mRead(const char * inputFilename, struct y4mFrameIterator ** iter); avifBool y4mWrite(const char * outputFilename, const avifImage * avif); +// Parse the y4m file at path 'inputFilename' and write its metadata into 'avif', +// without decoding the pixels. +avifBool y4mPeek(const char * inputFilename, avifImage * avif); + #ifdef __cplusplus } // extern "C" #endif diff --git a/tests/test_cmd_progressive.sh b/tests/test_cmd_progressive.sh index fc4af73c4a..c2e1583b19 100755 --- a/tests/test_cmd_progressive.sh +++ b/tests/test_cmd_progressive.sh @@ -47,18 +47,6 @@ pushd ${TMP_DIR} "${AVIFDEC}" "${ENCODED_FILE}" "${DECODED_FILE}" "${AVIFDEC}" --progressive "${ENCODED_FILE}" "${DECODED_FILE}" - echo "Testing manual layered encoding with display-size override and mixed input sizes" - "${AVIFENC}" -s 8 --layered --display-size 768x512 \ - "${INPUT_SMALL_Y4M}" "${INPUT_Y4M}" -o "${ENCODED_FILE}" - "${AVIFDEC}" --info "${ENCODED_FILE}" > "${INFO_FILE}" - grep -F "[768x512]" "${INFO_FILE}" - "${AVIFDEC}" "${ENCODED_FILE}" "${DECODED_FILE}" - "${AVIFDEC}" --progressive "${ENCODED_FILE}" "${DECODED_FILE}" - - echo "Testing display-size override smaller than an input layer" - "${AVIFENC}" -s 8 --layered --display-size 384x256 \ - "${INPUT_SMALL_Y4M}" "${INPUT_Y4M}" -o "${ENCODED_FILE}" && exit 1 - # libavif relies on libyuv to do scaling echo "Testing layered encoding with frame scaling" if avifenc -V | grep -o "libyuv : available" --quiet; then @@ -69,6 +57,22 @@ pushd ${TMP_DIR} done fi + echo "Testing manual layered encoding with pre-scaled input" + "${AVIFENC}" -s 8 --layered \ + "${INPUT_SMALL_Y4M}" "${INPUT_Y4M}" -o "${ENCODED_FILE}" + "${AVIFDEC}" --info "${ENCODED_FILE}" > "${INFO_FILE}" + grep -F "[768x512]" "${INFO_FILE}" + "${AVIFDEC}" "${ENCODED_FILE}" "${DECODED_FILE}" + "${AVIFDEC}" --progressive "${ENCODED_FILE}" "${DECODED_FILE}" + + echo "Testing an earlier layer larger than the last layer" + "${AVIFENC}" -s 8 --layered \ + "${INPUT_Y4M}" "${INPUT_SMALL_Y4M}" -o "${ENCODED_FILE}" && exit 1 + + echo "Testing layered encoding with pre-scaled input and frame scaling (rejected)" + "${AVIFENC}" -s 8 --layered --scaling-mode:u 1/2 \ + "${INPUT_SMALL_Y4M}" "${INPUT_Y4M}" -o "${ENCODED_FILE}" && exit 1 + echo "Testing too few layers" "${AVIFENC}" -s 8 --layered -q:u 60 "${INPUT_Y4M}" -o "${ENCODED_FILE}" && exit 1 From 09021a9fa607baf4e61e9737dca65787bceb18a6 Mon Sep 17 00:00:00 2001 From: Yuan Tong Date: Wed, 16 Sep 2026 00:39:17 +0800 Subject: [PATCH 10/17] adjust comments & checks --- src/write.c | 88 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 37 deletions(-) diff --git a/src/write.c b/src/write.c index ba6e939353..e849f406b1 100644 --- a/src/write.c +++ b/src/write.c @@ -1601,6 +1601,50 @@ static avifCodecType avifEncoderGetCodecType(const avifEncoder * encoder) static avifResult avifEncoderValidateSize(avifEncoder * encoder, uint32_t gridCols, uint32_t gridRows, const avifImage * firstCell) { if (!avifEncoderSizeIsSet(encoder)) { + // First image, encoder->data->imageMetadata not initialized yet, nothing to check against. + if (encoder->data->items.count == 0) { + return AVIF_RESULT_OK; + } + + // For animation, the encoder will verify the input size never changes, so this check is redundant for it. + // But for layered image, the encoder would relax the check to allow layers to have different sizes. + // We support 2 ways to produce different sized layers: + // 1. Send full sized inputs and let the encoder scale it via scalingMode + // 2. Declare the full size via width/height and send pre-scaled inputs + // To avoid confusion, we require the user to consistently use only one of the 2 ways, + // and this check blocks the attempt to start with method 1 and tries to switch to method 2. + if ((firstCell->width != encoder->data->imageMetadata->width) || (firstCell->height != encoder->data->imageMetadata->height)) { + avifDiagnosticsPrintf(&encoder->diag, "All images must have the same width/height unless avifEncoder.width/height is set"); + return AVIF_RESULT_INVALID_ARGUMENT; + } + + // According to section 2.2.2 of AV1 Image File Format specification v1.2.0: + // [...] the values of image_width and image_height shall respectively equal the values of + // UpscaledWidth and FrameHeight as defined in [AV1] but for a specific frame in the item + // payload. [...] + // The semantics of the 'ispe' property [...] the values of image_width and image_height shall + // respectively equal the values of UpscaledWidth and FrameHeight as defined in [AV1] but for + // a specific frame in the item payload. [...] + // In the absence of a 'lsel' property associated with the item, or if it is present and its + // layer_id value is set to 0xFFFF: + // If no OperatingPointSelectorProperty is associated with the item, the 'ispe' property + // shall document the dimensions of the last frame decoded when processing the operating + // point whose index is 0. + // NOTE: The dimensions of possible intermediate output images might not match the ones given + // in the 'ispe' property. If renderers display these intermediate images, they are expected + // to scale the output image to match the 'ispe' property. + // See https://aomediacodec.github.io/av1-avif/v1.2.0.html#image-spatial-extents-property. + + // Therefore the last layer must not have any scaling. + if ((encoder->data->frames.count == encoder->extraLayerCount) && !avifScalingModeIsNoScaling(&encoder->scalingMode)) { + avifDiagnosticsPrintf(&encoder->diag, + "The last layer must not be scaled, but got scalingMode=(%d/%d, %d/%d)", + encoder->scalingMode.horizontal.n, + encoder->scalingMode.horizontal.d, + encoder->scalingMode.vertical.n, + encoder->scalingMode.vertical.d); + return AVIF_RESULT_INVALID_ARGUMENT; + } return AVIF_RESULT_OK; } @@ -1614,6 +1658,9 @@ static avifResult avifEncoderValidateSize(avifEncoder * encoder, uint32_t gridCo return AVIF_RESULT_NOT_IMPLEMENTED; } + // This blocks the attempt to use both ways to produce different sized layers together, + // or start with method 2 and tries to switch to method 1, + // so the result is INVALID_ARGUMENT. See the comment above for the detail. if (!avifScalingModeIsNoScaling(&encoder->scalingMode)) { avifDiagnosticsPrintf(&encoder->diag, "avifEncoder.width/height cannot be set together with encoder->scalingMode"); return AVIF_RESULT_INVALID_ARGUMENT; @@ -1629,32 +1676,15 @@ static avifResult avifEncoderValidateSize(avifEncoder * encoder, uint32_t gridCo return AVIF_RESULT_NOT_IMPLEMENTED; } - // According to section 2.2.2 of AV1 Image File Format specification v1.2.0: - // [...] the values of image_width and image_height shall respectively equal the values of - // UpscaledWidth and FrameHeight as defined in [AV1] but for a specific frame in the item - // payload. [...] - // The semantics of the 'ispe' property [...] the values of image_width and image_height shall - // respectively equal the values of UpscaledWidth and FrameHeight as defined in [AV1] but for - // a specific frame in the item payload. [...] - // In the absence of a 'lsel' property associated with the item, or if it is present and its - // layer_id value is set to 0xFFFF: - // If no OperatingPointSelectorProperty is associated with the item, the 'ispe' property - // shall document the dimensions of the last frame decoded when processing the operating - // point whose index is 0. - // NOTE: The dimensions of possible intermediate output images might not match the ones given - // in the 'ispe' property. If renderers display these intermediate images, they are expected - // to scale the output image to match the 'ispe' property. - // See https://aomediacodec.github.io/av1-avif/v1.2.0.html#image-spatial-extents-property. - - // Therefore only layered image can have frames of different sizes, so reject otherwise. + // These 3 checks below are according to section 2.2.2 of AV1 Image File Format specification v1.2.0. + // See the comment above for the detail. + // Only layered image can have frames of different sizes, so reject otherwise. if (encoder->extraLayerCount == 0) { avifDiagnosticsPrintf(&encoder->diag, "avifEncoder.width/height can only be set for layered images (extraLayerCount > 0)"); return AVIF_RESULT_INVALID_ARGUMENT; } - // We tighten the rule to "earlier layers shall be smaller" due to encoder restrictions. - // The exact-match requirement for the last layer is enforced below in - // avifEncoderAddImageInternal() when adding that image. + // The spec allows arbitrary sizes. We tighten the rule to "earlier layers shall be smaller" due to encoder restrictions. if ((encoder->width < firstCell->width) || (encoder->height < firstCell->height)) { avifDiagnosticsPrintf(&encoder->diag, "avifEncoder.width/height %ux%u must be at least the coded image size %ux%u", @@ -1694,18 +1724,6 @@ static avifResult avifEncoderValidateSize(avifEncoder * encoder, uint32_t gridCo return AVIF_RESULT_OK; } -static avifResult avifEncoderValidateConsistentSize(avifEncoder * encoder, const avifImage * firstCell) -{ - if (avifEncoderSizeIsSet(encoder) || (encoder->data->items.count == 0)) { - return AVIF_RESULT_OK; - } - if ((firstCell->width != encoder->data->imageMetadata->width) || (firstCell->height != encoder->data->imageMetadata->height)) { - avifDiagnosticsPrintf(&encoder->diag, "All images must have the same width/height unless avifEncoder.width/height is set"); - return AVIF_RESULT_INVALID_ARGUMENT; - } - return AVIF_RESULT_OK; -} - // This function is called after every color frame is encoded. It returns AVIF_TRUE if a keyframe needs to be forced for the next // alpha frame to be encoded, AVIF_FALSE otherwise. static avifBool avifEncoderDataShouldForceKeyframeForAlpha(const avifEncoderData * data, @@ -1889,10 +1907,6 @@ static avifResult avifEncoderAddImageInternal(avifEncoder * encoder, } AVIF_CHECKRES(avifEncoderValidateSize(encoder, gridCols, gridRows, firstCell)); - // Reject mixing scalingMode and adding input images of different sizes. - // They are different ways the achieve the same result, so mixing them - // creates confusion without providing any benefit. - AVIF_CHECKRES(avifEncoderValidateConsistentSize(encoder, firstCell)); AVIF_CHECKRES(avifValidateGrid(gridCols, gridRows, cellImages, /*validateGainMap=*/AVIF_FALSE, &encoder->diag)); From 328f99980e74ff18236748b77569811d2a38ed43 Mon Sep 17 00:00:00 2001 From: Yuan Tong Date: Mon, 21 Sep 2026 21:42:00 +0800 Subject: [PATCH 11/17] patch from Wan-Teh Chang --- apps/avifenc.c | 23 ++++++++++---------- apps/shared/avifjpeg.h | 5 +++-- apps/shared/avifpng.c | 11 +++++----- apps/shared/avifpng.h | 9 ++++---- apps/shared/y4m.c | 10 ++++----- apps/shared/y4m.h | 5 +++-- include/avif/avif.h | 2 +- src/codec_avm.c | 1 + src/codec_rav1e.c | 7 ++---- src/codec_svt.c | 7 ++---- src/write.c | 23 +++++++++----------- tests/gtest/avif_fuzztest_enc_dec_layered.cc | 3 +-- tests/gtest/avifprogressivetest.cc | 4 ++-- 13 files changed, 53 insertions(+), 57 deletions(-) diff --git a/apps/avifenc.c b/apps/avifenc.c index a533ac5a29..663226aa42 100644 --- a/apps/avifenc.c +++ b/apps/avifenc.c @@ -79,7 +79,7 @@ typedef struct avifChromaDownsampling chromaDownsampling; avifAppFileFormat inputFormat; - // Inferred from the last input, only needed when using --layered + // The last layer's size. Inferred from the last input, only needed when using --layered. uint32_t width; uint32_t height; } avifSettings; @@ -476,10 +476,11 @@ static avifBool avifVerifyImageFitsLastLayerSize(const avifSettings * settings, return AVIF_TRUE; } -// Checks, ahead of time and in CLI terms, for the settings that the library itself would reject -// once combined with --layered inputs of different sizes (which predeclares avifEncoder.width/height, -// a field avifenc's users never set directly). Only checks conditions actually reachable via avifenc's -// CLI; e.g. grids and non-layered images can't reach this point at all, so they're not checked here. +// Checks, before encoding and in terms of CLI, for the settings that the library would reject once +// combined with --layered inputs of different sizes (--layered sets avifEncoder.width/height, two +// fields avifenc's users never set directly). Only checks conditions actually reachable via +// avifenc's CLI. For example, grids and non-layered images can't reach this point at all, so they +// are not checked here. static avifBool avifVerifyLastLayerSizeCompatibility(const avifSettings * settings, const avifInput * input, const avifImage * firstImage) { if (settings->width == 0) { @@ -495,7 +496,7 @@ static avifBool avifVerifyLastLayerSizeCompatibility(const avifSettings * settin } } if (input->requestedDepthExtension != 0) { - fprintf(stderr, "ERROR: --depth with a bit depth extension cannot be used with --layered inputs of different sizes\n"); + fprintf(stderr, "ERROR: --depth with bit depth extension cannot be used with --layered inputs of different sizes\n"); return AVIF_FALSE; } #if defined(AVIF_ENABLE_JPEG_GAIN_MAP_CONVERSION) @@ -2453,10 +2454,10 @@ int main(int argc, char * argv[]) uint32_t outputImageWidth = image->width; uint32_t outputImageHeight = image->height; if (settings.layered) { - // Check the resolution of the last layer without decoding it, to fill - // the image size in advance. - // Only fill if the resolution differs from the first layer's, - // to not interfere with --scaling-mode. + // Get the resolution of the last layer without decoding it, to fill the output image size + // in advance. + // Only fill the output image size if the last layer's resolution differs from the first + // layer's, to not interfere with --scaling-mode. const avifInputFile * lastFile = &input.files[input.filesCount - 1]; avifImage * lastImage = avifImageCreateEmpty(); if (!lastImage) { @@ -2470,7 +2471,7 @@ int main(int argc, char * argv[]) } avifImageDestroy(lastImage); if (!lastImageOk) { - fprintf(stderr, "ERROR: Failed to read last layer: %s\n", avifPrettyFilename(lastFile->filename)); + fprintf(stderr, "ERROR: Failed to peek last layer: %s\n", avifPrettyFilename(lastFile->filename)); goto cleanup; } } diff --git a/apps/shared/avifjpeg.h b/apps/shared/avifjpeg.h index 4b0371c676..ad035d71ac 100644 --- a/apps/shared/avifjpeg.h +++ b/apps/shared/avifjpeg.h @@ -26,12 +26,13 @@ avifBool avifJPEGRead(const char * inputFilename, avifBool ignoreXMP, avifBool ignoreGainMap, uint32_t sizeLimit); -avifBool avifJPEGWrite(const char * outputFilename, const avifImage * avif, int jpegQuality, avifChromaUpsampling chromaUpsampling); -// Parse the jpeg file at path 'inputFilename' and write its metadata into 'avif', +// Parse the jpeg file at path 'inputFilename' and write its metadata into 'avif' // without decoding the pixels. avifBool avifJPEGPeek(const char * inputFilename, avifImage * avif); +avifBool avifJPEGWrite(const char * outputFilename, const avifImage * avif, int jpegQuality, avifChromaUpsampling chromaUpsampling); + #if defined(AVIF_ENABLE_JPEG_GAIN_MAP_CONVERSION) // Parses XMP gain map metadata. Visible for testing. avifBool avifJPEGParseGainMapXMP(const uint8_t * xmpData, size_t xmpSize, avifGainMap * gainMap, avifBool * isAppleGainMap); diff --git a/apps/shared/avifpng.c b/apps/shared/avifpng.c index 2bed26442c..cfb504924a 100644 --- a/apps/shared/avifpng.c +++ b/apps/shared/avifpng.c @@ -506,11 +506,6 @@ static avifBool avifPNGReadImpl(FILE * f, // Note: There is no support for the rare "Raw profile type icc" or "Raw profile type icm" text chunks. } - const int numChannels = png_get_channels(png, info); - if (numChannels < 1 || numChannels > 4) { - fprintf(stderr, "png_get_channels() should return 1, 2, 3 or 4 but returns %d.\n", numChannels); - goto cleanup; - } if (avif->width > imageSizeLimit / avif->height) { fprintf(stderr, "Too big PNG dimensions (%u x %u > %u px): %s\n", avif->width, avif->height, imageSizeLimit, inputFilename); goto cleanup; @@ -523,6 +518,12 @@ static avifBool avifPNGReadImpl(FILE * f, goto cleanup; } + const int numChannels = png_get_channels(png, info); + if (numChannels < 1 || numChannels > 4) { + fprintf(stderr, "png_get_channels() should return 1, 2, 3 or 4 but returns %d.\n", numChannels); + goto cleanup; + } + avifRGBImageSetDefaults(&rgb, avif); rgb.chromaDownsampling = chromaDownsampling; rgb.depth = imgBitDepth; diff --git a/apps/shared/avifpng.h b/apps/shared/avifpng.h index 7b5ce3557d..cbe3774da3 100644 --- a/apps/shared/avifpng.h +++ b/apps/shared/avifpng.h @@ -22,16 +22,17 @@ avifBool avifPNGRead(const char * inputFilename, avifBool ignoreAlpha, uint32_t imageSizeLimit, uint32_t * outPNGDepth); + +// Parse the PNG file at path 'inputFilename' and write its metadata into 'avif' +// without decoding the pixels. +avifBool avifPNGPeek(const char * inputFilename, avifImage * avif); + avifBool avifPNGWrite(const char * outputFilename, const avifImage * avif, uint32_t requestedDepth, avifChromaUpsampling chromaUpsampling, int compressionLevel); -// Parse the PNG file at path 'inputFilename' and write its metadata into 'avif', -// without decoding the pixels. -avifBool avifPNGPeek(const char * inputFilename, avifImage * avif); - #ifdef __cplusplus } // extern "C" #endif diff --git a/apps/shared/y4m.c b/apps/shared/y4m.c index 7074067351..791aa82aa8 100644 --- a/apps/shared/y4m.c +++ b/apps/shared/y4m.c @@ -256,10 +256,10 @@ static avifBool y4mClampSamples(avifImage * avif) static avifBool y4mReadInternal(const char * inputFilename, avifBool ignoreAlpha, uint32_t imageSizeLimit, + avifBool headerOnly, avifImage * avif, avifAppSourceTiming * sourceTiming, - struct y4mFrameIterator ** iter, - avifBool headerOnly) + struct y4mFrameIterator ** iter) { avifBool result = AVIF_FALSE; @@ -494,7 +494,7 @@ avifBool y4mRead(const char * inputFilename, avifAppSourceTiming * sourceTiming, struct y4mFrameIterator ** iter) { - return y4mReadInternal(inputFilename, ignoreAlpha, imageSizeLimit, avif, sourceTiming, iter, /*headerOnly=*/AVIF_FALSE); + return y4mReadInternal(inputFilename, ignoreAlpha, imageSizeLimit, /*headerOnly=*/AVIF_FALSE, avif, sourceTiming, iter); } avifBool y4mPeek(const char * inputFilename, avifImage * avif) @@ -502,10 +502,10 @@ avifBool y4mPeek(const char * inputFilename, avifImage * avif) return y4mReadInternal(inputFilename, /*ignoreAlpha=*/AVIF_TRUE, /*imageSizeLimit=*/UINT32_MAX, + /*headerOnly=*/AVIF_TRUE, avif, /*sourceTiming=*/NULL, - /*iter=*/NULL, - /*headerOnly=*/AVIF_TRUE); + /*iter=*/NULL); } avifBool y4mWrite(const char * outputFilename, const avifImage * avif) diff --git a/apps/shared/y4m.h b/apps/shared/y4m.h index 5521fb097c..4b4630e4ac 100644 --- a/apps/shared/y4m.h +++ b/apps/shared/y4m.h @@ -24,12 +24,13 @@ avifBool y4mRead(const char * inputFilename, avifImage * avif, avifAppSourceTiming * sourceTiming, struct y4mFrameIterator ** iter); -avifBool y4mWrite(const char * outputFilename, const avifImage * avif); -// Parse the y4m file at path 'inputFilename' and write its metadata into 'avif', +// Parse the y4m file at path 'inputFilename' and write its metadata into 'avif' // without decoding the pixels. avifBool y4mPeek(const char * inputFilename, avifImage * avif); +avifBool y4mWrite(const char * outputFilename, const avifImage * avif); + #ifdef __cplusplus } // extern "C" #endif diff --git a/include/avif/avif.h b/include/avif/avif.h index 808244e65c..92ea16132e 100644 --- a/include/avif/avif.h +++ b/include/avif/avif.h @@ -823,7 +823,7 @@ typedef struct avifImage // These also apply to gainMap->image, if any. // // When encoding with avifEncoder.width/height set (see their comment), these transformations - // are interpreted relative to that size rather than to this intermediate layer's own + // are interpreted relative to that size rather than to the current layer's own // width/height. No special handling is needed during decode: the decoded layer is // automatically scaled to the configured size, so these transformations are relative to the // decoded avifImage's width/height as usual. diff --git a/src/codec_avm.c b/src/codec_avm.c index ee75c9c427..77b795a08d 100644 --- a/src/codec_avm.c +++ b/src/codec_avm.c @@ -444,6 +444,7 @@ static avifResult avmCodecEncodeImage(avifCodec * codec, avifAddImageFlags addImageFlags, avifCodecEncodeOutput * output) { + // AVM does not support encoding a layered image. if (encoder->width || encoder->height) { return AVIF_RESULT_NOT_IMPLEMENTED; } diff --git a/src/codec_rav1e.c b/src/codec_rav1e.c index a1a4c8314a..7fc064ef47 100644 --- a/src/codec_rav1e.c +++ b/src/codec_rav1e.c @@ -82,11 +82,8 @@ static avifResult rav1eCodecEncodeImage(avifCodec * codec, return AVIF_RESULT_NOT_IMPLEMENTED; } - // rav1e does not support encoding layered image. - if (encoder->width || encoder->height) { - return AVIF_RESULT_NOT_IMPLEMENTED; - } - if (encoder->extraLayerCount > 0) { + // rav1e does not support encoding a layered image. + if (encoder->width || encoder->height || encoder->extraLayerCount > 0) { return AVIF_RESULT_NOT_IMPLEMENTED; } diff --git a/src/codec_svt.c b/src/codec_svt.c index a283999ac6..395afc8044 100644 --- a/src/codec_svt.c +++ b/src/codec_svt.c @@ -75,11 +75,8 @@ static avifResult svtCodecEncodeImage(avifCodec * codec, } } - // SVT-AV1 does not support encoding layered image. - if (encoder->width || encoder->height) { - return AVIF_RESULT_NOT_IMPLEMENTED; - } - if (encoder->extraLayerCount > 0) { + // SVT-AV1 does not support encoding a layered image. + if (encoder->width || encoder->height || encoder->extraLayerCount > 0) { return AVIF_RESULT_NOT_IMPLEMENTED; } diff --git a/src/write.c b/src/write.c index 1cdb74661f..f6653d17b0 100644 --- a/src/write.c +++ b/src/write.c @@ -1639,13 +1639,13 @@ static avifResult avifEncoderValidateSize(avifEncoder * encoder, uint32_t gridCo return AVIF_RESULT_OK; } - // For animation, the encoder will verify the input size never changes, so this check is redundant for it. - // But for layered image, the encoder would relax the check to allow layers to have different sizes. + // For animation, the encoder verifies the input size never changes, so this check is redundant. + // But for a layered image, the encoder relaxes the check to allow layers to have different sizes. // We support 2 ways to produce different sized layers: - // 1. Send full sized inputs and let the encoder scale it via scalingMode + // 1. Send full sized inputs and let the encoder scale them via scalingMode // 2. Declare the full size via width/height and send pre-scaled inputs // To avoid confusion, we require the user to consistently use only one of the 2 ways, - // and this check blocks the attempt to start with method 1 and tries to switch to method 2. + // and this check blocks the attempt to start with method 1 and try to switch to method 2. if ((firstCell->width != encoder->data->imageMetadata->width) || (firstCell->height != encoder->data->imageMetadata->height)) { avifDiagnosticsPrintf(&encoder->diag, "All images must have the same width/height unless avifEncoder.width/height is set"); return AVIF_RESULT_INVALID_ARGUMENT; @@ -1655,9 +1655,6 @@ static avifResult avifEncoderValidateSize(avifEncoder * encoder, uint32_t gridCo // [...] the values of image_width and image_height shall respectively equal the values of // UpscaledWidth and FrameHeight as defined in [AV1] but for a specific frame in the item // payload. [...] - // The semantics of the 'ispe' property [...] the values of image_width and image_height shall - // respectively equal the values of UpscaledWidth and FrameHeight as defined in [AV1] but for - // a specific frame in the item payload. [...] // In the absence of a 'lsel' property associated with the item, or if it is present and its // layer_id value is set to 0xFFFF: // If no OperatingPointSelectorProperty is associated with the item, the 'ispe' property @@ -1667,7 +1664,7 @@ static avifResult avifEncoderValidateSize(avifEncoder * encoder, uint32_t gridCo // in the 'ispe' property. If renderers display these intermediate images, they are expected // to scale the output image to match the 'ispe' property. // See https://aomediacodec.github.io/av1-avif/v1.2.0.html#image-spatial-extents-property. - + // // Therefore the last layer must not have any scaling. if ((encoder->data->frames.count == encoder->extraLayerCount) && !avifScalingModeIsNoScaling(&encoder->scalingMode)) { avifDiagnosticsPrintf(&encoder->diag, @@ -1692,7 +1689,7 @@ static avifResult avifEncoderValidateSize(avifEncoder * encoder, uint32_t gridCo } // This blocks the attempt to use both ways to produce different sized layers together, - // or start with method 2 and tries to switch to method 1, + // or start with method 2 and try to switch to method 1, // so the result is INVALID_ARGUMENT. See the comment above for the detail. if (!avifScalingModeIsNoScaling(&encoder->scalingMode)) { avifDiagnosticsPrintf(&encoder->diag, "avifEncoder.width/height cannot be set together with encoder->scalingMode"); @@ -1709,9 +1706,9 @@ static avifResult avifEncoderValidateSize(avifEncoder * encoder, uint32_t gridCo return AVIF_RESULT_NOT_IMPLEMENTED; } - // These 3 checks below are according to section 2.2.2 of AV1 Image File Format specification v1.2.0. + // These 3 checks below are based on section 2.2.2 of AV1 Image File Format specification v1.2.0. // See the comment above for the detail. - // Only layered image can have frames of different sizes, so reject otherwise. + // Only a layered image can have frames of different sizes, so reject otherwise. if (encoder->extraLayerCount == 0) { avifDiagnosticsPrintf(&encoder->diag, "avifEncoder.width/height can only be set for layered images (extraLayerCount > 0)"); return AVIF_RESULT_INVALID_ARGUMENT; @@ -1750,7 +1747,7 @@ static avifResult avifEncoderValidateSize(avifEncoder * encoder, uint32_t gridCo if ((encoder->data->items.count > 0) && (encoder->extraLayerCount > 0) && !avifImageHasEquivalentTransformProperties(firstCell, encoder->data->imageMetadata)) { avifDiagnosticsPrintf(&encoder->diag, - "when avifEncoder.width/height is set, 'pasp', 'clap', 'irot' and 'imir' must match across layers"); + "When avifEncoder.width/height is set, 'pasp', 'clap', 'irot' and 'imir' must match across layers"); return AVIF_RESULT_INCOMPATIBLE_IMAGE; } @@ -1994,7 +1991,7 @@ static avifResult avifEncoderAddImageInternal(avifEncoder * encoder, encoder->data->singleImage = AVIF_TRUE; if (encoder->extraLayerCount > 0) { - // AVIF_ADD_IMAGE_FLAG_SINGLE may not be set for layered image. + // AVIF_ADD_IMAGE_FLAG_SINGLE may not be set for a layered image. return AVIF_RESULT_INVALID_ARGUMENT; } diff --git a/tests/gtest/avif_fuzztest_enc_dec_layered.cc b/tests/gtest/avif_fuzztest_enc_dec_layered.cc index 04a72f1a3a..ddc2eb0e65 100644 --- a/tests/gtest/avif_fuzztest_enc_dec_layered.cc +++ b/tests/gtest/avif_fuzztest_enc_dec_layered.cc @@ -30,8 +30,7 @@ constexpr std::array kNoScalingModes = { constexpr avifScalingMode MakeScalingMode(avifFraction horizontal, avifFraction vertical) { - return avifScalingMode{{horizontal.n, horizontal.d}, - {vertical.n, vertical.d}}; + return {horizontal, vertical}; } constexpr size_t BinomialCoefficient(size_t n, size_t k) { diff --git a/tests/gtest/avifprogressivetest.cc b/tests/gtest/avifprogressivetest.cc index 8cc78de4f5..40dd2572cb 100644 --- a/tests/gtest/avifprogressivetest.cc +++ b/tests/gtest/avifprogressivetest.cc @@ -267,7 +267,7 @@ TEST_F(ProgressiveTest, ResolutionChangeMixedRejected) { encoder_->scalingMode = {{1, 2}, {1, 2}}; const auto smallImage = testutil::CreateImage( - kImageSize / 2, kImageSize / 2, 8, AVIF_PIXEL_FORMAT_YUV444, + kImageSize, kImageSize, 8, AVIF_PIXEL_FORMAT_YUV444, AVIF_PLANES_YUV, AVIF_RANGE_FULL); ASSERT_NE(smallImage, nullptr); @@ -277,7 +277,7 @@ TEST_F(ProgressiveTest, ResolutionChangeMixedRejected) { } TEST_F(ProgressiveTest, ResolutionChangeMixedDuringEncodingRejected) { - encoder_->extraLayerCount = 1; + encoder_->extraLayerCount = 2; encoder_->width = kImageSize; encoder_->height = kImageSize; From 862cbd4adef4125cff775cadbf655eb2ad5fa64b Mon Sep 17 00:00:00 2001 From: Yuan Tong Date: Mon, 21 Sep 2026 22:28:14 +0800 Subject: [PATCH 12/17] review changes --- apps/avifenc.c | 2 ++ apps/shared/avifutil.h | 5 +++++ tests/gtest/avifprogressivetest.cc | 7 +------ 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/avifenc.c b/apps/avifenc.c index 663226aa42..858d9517a6 100644 --- a/apps/avifenc.c +++ b/apps/avifenc.c @@ -2736,6 +2736,8 @@ int main(int argc, char * argv[]) lossyHint = " (Lossless)"; } printf("AVIF to be written:%s\n", lossyHint); + // avifImageDump wants the info of one cell, but image/outputImageWidth/outputImageHeight are the before-split image/info + // when avifImageSplitGrid is called. const avifImage * avif = gridCells ? gridCells[0] : image; const uint32_t cellWidth = gridCells ? avif->width : outputImageWidth; const uint32_t cellHeight = gridCells ? avif->height : outputImageHeight; diff --git a/apps/shared/avifutil.h b/apps/shared/avifutil.h index b984828208..60d550b96d 100644 --- a/apps/shared/avifutil.h +++ b/apps/shared/avifutil.h @@ -28,6 +28,9 @@ extern "C" { #define AVIF_FMT_ZU "zu" #endif +// Dump an AVIF file's information, that has gridCols*gridRows cells (1*1 for non-grid image) and +// 'avif' as the first cell that's encoded to have size cellWidth*cellHeight. +// progressiveState indicates if the file is a progressive image. void avifImageDump(const avifImage * avif, uint32_t cellWidth, uint32_t cellHeight, uint32_t gridCols, uint32_t gridRows, avifProgressiveState progressiveState); void avifContainerDump(const avifDecoder * decoder); void avifPrintVersions(void); @@ -124,6 +127,8 @@ avifAppFileFormat avifReadImage(const char * filename, // If 'inputFormat' is AVIF_APP_FILE_FORMAT_UNKNOWN, the image format is guessed // based on the filename or first few bytes. // Returns the format of the file, or AVIF_APP_FILE_FORMAT_UNKNOWN in case of error. +// Note: This function reuses the code that reads image. Current user of this function only uses the +// width and height reported. Double check first when using other info returned. avifAppFileFormat avifPeekImage(const char * filename, avifAppFileFormat inputFormat, avifImage * image); // Copies all the bytes from the file at filename to a newly allocated memory chunk. diff --git a/tests/gtest/avifprogressivetest.cc b/tests/gtest/avifprogressivetest.cc index 40dd2572cb..2690015dff 100644 --- a/tests/gtest/avifprogressivetest.cc +++ b/tests/gtest/avifprogressivetest.cc @@ -266,12 +266,7 @@ TEST_F(ProgressiveTest, ResolutionChangeMixedRejected) { encoder_->height = kImageSize; encoder_->scalingMode = {{1, 2}, {1, 2}}; - const auto smallImage = testutil::CreateImage( - kImageSize, kImageSize, 8, AVIF_PIXEL_FORMAT_YUV444, - AVIF_PLANES_YUV, AVIF_RANGE_FULL); - ASSERT_NE(smallImage, nullptr); - - ASSERT_EQ(avifEncoderAddImage(encoder_.get(), smallImage.get(), 1, + ASSERT_EQ(avifEncoderAddImage(encoder_.get(), image_.get(), 1, AVIF_ADD_IMAGE_FLAG_NONE), AVIF_RESULT_INVALID_ARGUMENT); } From d788bf1f860c27b3842a5f34d99fab86c6863d51 Mon Sep 17 00:00:00 2001 From: Yuan Tong Date: Wed, 23 Sep 2026 08:20:17 +0800 Subject: [PATCH 13/17] patch from Wan-Teh Chang --- apps/avifenc.c | 4 ++-- apps/shared/avifutil.h | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/apps/avifenc.c b/apps/avifenc.c index 858d9517a6..c3b37d0359 100644 --- a/apps/avifenc.c +++ b/apps/avifenc.c @@ -2736,8 +2736,8 @@ int main(int argc, char * argv[]) lossyHint = " (Lossless)"; } printf("AVIF to be written:%s\n", lossyHint); - // avifImageDump wants the info of one cell, but image/outputImageWidth/outputImageHeight are the before-split image/info - // when avifImageSplitGrid is called. + // avifImageDump wants the info of one cell, but image, outputImageWidth, and outputImageHeight + // are the before-split image and its info when avifImageSplitGrid is called. const avifImage * avif = gridCells ? gridCells[0] : image; const uint32_t cellWidth = gridCells ? avif->width : outputImageWidth; const uint32_t cellHeight = gridCells ? avif->height : outputImageHeight; diff --git a/apps/shared/avifutil.h b/apps/shared/avifutil.h index 60d550b96d..bec09ab83e 100644 --- a/apps/shared/avifutil.h +++ b/apps/shared/avifutil.h @@ -28,9 +28,8 @@ extern "C" { #define AVIF_FMT_ZU "zu" #endif -// Dump an AVIF file's information, that has gridCols*gridRows cells (1*1 for non-grid image) and -// 'avif' as the first cell that's encoded to have size cellWidth*cellHeight. -// progressiveState indicates if the file is a progressive image. +// Dumps the information of an AVIF file that has gridCols*gridRows cells (1*1 for non-grid image) +// and 'avif' as the first cell that's encoded to have size cellWidth*cellHeight. void avifImageDump(const avifImage * avif, uint32_t cellWidth, uint32_t cellHeight, uint32_t gridCols, uint32_t gridRows, avifProgressiveState progressiveState); void avifContainerDump(const avifDecoder * decoder); void avifPrintVersions(void); @@ -127,8 +126,8 @@ avifAppFileFormat avifReadImage(const char * filename, // If 'inputFormat' is AVIF_APP_FILE_FORMAT_UNKNOWN, the image format is guessed // based on the filename or first few bytes. // Returns the format of the file, or AVIF_APP_FILE_FORMAT_UNKNOWN in case of error. -// Note: This function reuses the code that reads image. Current user of this function only uses the -// width and height reported. Double check first when using other info returned. +// Note: This function reuses the code that reads an image. The current user of this function only +// uses the width and height reported. Double check first when using the other info returned. avifAppFileFormat avifPeekImage(const char * filename, avifAppFileFormat inputFormat, avifImage * image); // Copies all the bytes from the file at filename to a newly allocated memory chunk. From 9179042bcbee7c6e2b3d50f3718dfcfc31dc3932 Mon Sep 17 00:00:00 2001 From: Yuan Tong Date: Wed, 23 Sep 2026 08:24:36 +0800 Subject: [PATCH 14/17] review changes --- apps/shared/avifutil.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/shared/avifutil.c b/apps/shared/avifutil.c index 041e8b7b4d..6a370fc39d 100644 --- a/apps/shared/avifutil.c +++ b/apps/shared/avifutil.c @@ -126,7 +126,7 @@ static void avifImageDumpInternal(const avifImage * avif, avifCropRect cropRect; avifDiagnostics diag; avifDiagnosticsClearError(&diag); - avifBool validClap = avifCropRectFromCleanApertureBox(&cropRect, &avif->clap, avif->width, avif->height, &diag); + avifBool validClap = avifCropRectFromCleanApertureBox(&cropRect, &avif->clap, cellWidth, cellHeight, &diag); if (validClap) { printf(" * Valid, derived crop rect: X: %d, Y: %d, W: %d, H: %d%s\n", cropRect.x, From 0b5ac4acfdda02a9f50d322829db0feda54878c5 Mon Sep 17 00:00:00 2001 From: Yuan Tong Date: Sat, 26 Sep 2026 12:28:02 +0800 Subject: [PATCH 15/17] reject problematic encoding --- src/codec_aom.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/codec_aom.c b/src/codec_aom.c index 77b8168c6a..3d22bff043 100644 --- a/src/codec_aom.c +++ b/src/codec_aom.c @@ -944,6 +944,20 @@ static avifResult aomCodecEncodeImage(avifCodec * codec, // libaom fails if cfg->g_threads is greater than 64 threads. See MAX_NUM_THREADS in // aom/aom_util/aom_thread.h. cfg->g_threads = AVIF_MIN(encoder->maxThreads, 64); + + // Detect the libaom bug before v3.15.2 described in + // https://issuetracker.google.com/issues/559019046. + // See the changes in + // https://aomedia-review.googlesource.com/c/aom/+/216921. + static const int aomVersion_3_15_2 = (3 << 16) | (15 << 8) | 2; + if (aom_codec_version() < aomVersion_3_15_2) { + // libaom has a bug when creating extra workers during encoding + // that skips allocating some buffers needed by GOOD_QUALITY + // encoding. That can happen when the new frame is larger. + if (aomUsage == AOM_USAGE_GOOD_QUALITY && (encoder->width || encoder->height)) { + cfg->g_threads = 1; + } + } } // Encode alpha as 4:0:0. From d6891fc48b79ef8a060bd7f09e84f789550af051 Mon Sep 17 00:00:00 2001 From: Wan-Teh Chang Date: Sat, 26 Sep 2026 08:14:31 -0700 Subject: [PATCH 16/17] Edit comments in codec_aom.c --- src/codec_aom.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/codec_aom.c b/src/codec_aom.c index 3d22bff043..dd6205afbc 100644 --- a/src/codec_aom.c +++ b/src/codec_aom.c @@ -946,14 +946,15 @@ static avifResult aomCodecEncodeImage(avifCodec * codec, cfg->g_threads = AVIF_MIN(encoder->maxThreads, 64); // Detect the libaom bug before v3.15.2 described in - // https://issuetracker.google.com/issues/559019046. - // See the changes in + // https://issues.oss-fuzz.com/issues/559019046. See the changes in // https://aomedia-review.googlesource.com/c/aom/+/216921. static const int aomVersion_3_15_2 = (3 << 16) | (15 << 8) | 2; if (aom_codec_version() < aomVersion_3_15_2) { - // libaom has a bug when creating extra workers during encoding - // that skips allocating some buffers needed by GOOD_QUALITY - // encoding. That can happen when the new frame is larger. + // When creating extra worker threads during encoding (which can + // happen when the new frame is larger), libaom may skip + // allocating the pixel_gradient_info buffers needed by + // GOOD_QUALITY mode. Work around the bug by disabling + // multithreading. if (aomUsage == AOM_USAGE_GOOD_QUALITY && (encoder->width || encoder->height)) { cfg->g_threads = 1; } From cf16e98d4acce6ff6ec94999eb399fd1f3f2c95c Mon Sep 17 00:00:00 2001 From: Wan-Teh Chang Date: Sat, 26 Sep 2026 09:28:47 -0700 Subject: [PATCH 17/17] avifprogressivetest.cc: Fill smallImage with gradient --- tests/gtest/avifprogressivetest.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/gtest/avifprogressivetest.cc b/tests/gtest/avifprogressivetest.cc index 2690015dff..641a9d97b3 100644 --- a/tests/gtest/avifprogressivetest.cc +++ b/tests/gtest/avifprogressivetest.cc @@ -196,6 +196,7 @@ TEST_F(ProgressiveTest, ResolutionChangeExternal) { kImageSize / 2, kImageSize / 2, 8, AVIF_PIXEL_FORMAT_YUV444, AVIF_PLANES_YUV, AVIF_RANGE_FULL); ASSERT_NE(smallImage, nullptr); + testutil::FillImageGradient(smallImage.get(), /*offset=*/17); ASSERT_EQ(avifEncoderAddImage(encoder_.get(), smallImage.get(), 1, AVIF_ADD_IMAGE_FLAG_NONE), @@ -280,6 +281,7 @@ TEST_F(ProgressiveTest, ResolutionChangeMixedDuringEncodingRejected) { kImageSize / 2, kImageSize / 2, 8, AVIF_PIXEL_FORMAT_YUV444, AVIF_PLANES_YUV, AVIF_RANGE_FULL); ASSERT_NE(smallImage, nullptr); + testutil::FillImageGradient(smallImage.get(), /*offset=*/17); ASSERT_EQ(avifEncoderAddImage(encoder_.get(), smallImage.get(), 1, AVIF_ADD_IMAGE_FLAG_NONE),