xref: /plugin/combo/ComboStrap/TagAttribute/BackgroundAttribute.php (revision 70bbd7f1f72440223cc13f3495efdcb2b0a11514)
104fd306cSNickeau<?php
204fd306cSNickeau
304fd306cSNickeau
404fd306cSNickeaunamespace ComboStrap\TagAttribute;
504fd306cSNickeau
604fd306cSNickeau
704fd306cSNickeauuse ComboStrap\ColorRgb;
804fd306cSNickeauuse ComboStrap\ExceptionBadArgument;
904fd306cSNickeauuse ComboStrap\ExceptionCompile;
1004fd306cSNickeauuse ComboStrap\ExceptionInternal;
1104fd306cSNickeauuse ComboStrap\ExceptionNotFound;
1204fd306cSNickeauuse ComboStrap\FetcherSvg;
1304fd306cSNickeauuse ComboStrap\LazyLoad;
1404fd306cSNickeauuse ComboStrap\LogUtility;
1504fd306cSNickeauuse ComboStrap\MediaMarkup;
1604fd306cSNickeauuse ComboStrap\Opacity;
1704fd306cSNickeauuse ComboStrap\PluginUtility;
1804fd306cSNickeauuse ComboStrap\StringUtility;
1904fd306cSNickeauuse ComboStrap\TagAttributes;
2004fd306cSNickeau
2104fd306cSNickeau/**
2204fd306cSNickeau * Process background attribute
2304fd306cSNickeau */
2404fd306cSNickeauclass BackgroundAttribute
2504fd306cSNickeau{
2604fd306cSNickeau    /**
2704fd306cSNickeau     * Background Logical attribute / Public
2804fd306cSNickeau     */
2904fd306cSNickeau    const BACKGROUND_COLOR = 'background-color';
3004fd306cSNickeau    const BACKGROUND_FILL = "fill";
3104fd306cSNickeau
3204fd306cSNickeau
3304fd306cSNickeau    /**
3404fd306cSNickeau     * CSS attribute / not public
3504fd306cSNickeau     */
3604fd306cSNickeau    const BACKGROUND_IMAGE = 'background-image';
3704fd306cSNickeau    const BACKGROUND_SIZE = "background-size";
3804fd306cSNickeau    const BACKGROUND_REPEAT = "background-repeat";
3904fd306cSNickeau    const BACKGROUND_POSITION = "background-position";
4004fd306cSNickeau
4104fd306cSNickeau
4204fd306cSNickeau    /**
4304fd306cSNickeau     * The page canonical of the documentation
4404fd306cSNickeau     */
4504fd306cSNickeau    const CANONICAL = "background";
4604fd306cSNickeau    /**
4704fd306cSNickeau     * A component attributes to store backgrounds
4804fd306cSNickeau     */
4904fd306cSNickeau    const BACKGROUNDS = "backgrounds";
5004fd306cSNickeau
5104fd306cSNickeau    /**
5204fd306cSNickeau     * Pattern css
5304fd306cSNickeau     * https://bansal.io/pattern-css
5404fd306cSNickeau     */
5504fd306cSNickeau    const PATTERN_ATTRIBUTE = "pattern";
5604fd306cSNickeau    const PATTERN_CSS_SNIPPET_ID = "pattern.css";
5704fd306cSNickeau    const PATTERN_CSS_SIZE = ["sm", "md", "lg", "xl"];
5804fd306cSNickeau    const PATTERN_NAMES = ['checks', 'grid', 'dots', 'cross-dots', 'diagonal-lines', 'horizontal-lines', 'vertical-lines', 'diagonal-stripes', 'horizontal-stripes', 'vertical-stripes', 'triangles', 'zigzag'];
5904fd306cSNickeau    const PATTERN_CSS_CLASS_PREFIX = "pattern";
6004fd306cSNickeau    const PATTERN_COLOR_ATTRIBUTE = "pattern-color";
6104fd306cSNickeau
6204fd306cSNickeau
6304fd306cSNickeau    public static function processBackgroundAttributes(TagAttributes &$tagAttributes)
6404fd306cSNickeau    {
6504fd306cSNickeau
6604fd306cSNickeau        /**
6704fd306cSNickeau         * Backgrounds set with the {@link \syntax_plugin_combo_background} component
6804fd306cSNickeau         */
6904fd306cSNickeau        if ($tagAttributes->hasComponentAttribute(self::BACKGROUNDS)) {
7004fd306cSNickeau            PluginUtility::getSnippetManager()->attachCssInternalStyleSheet(self::CANONICAL);
7104fd306cSNickeau            $backgrounds = $tagAttributes->getValueAndRemove(self::BACKGROUNDS);
7204fd306cSNickeau            switch (sizeof($backgrounds)) {
7304fd306cSNickeau                case 1:
7404fd306cSNickeau                    // Only one background was specified
7504fd306cSNickeau                    $background = $backgrounds[0];
7604fd306cSNickeau                    if (
7704fd306cSNickeau                        /**
7804fd306cSNickeau                         * We need to create a background node
7904fd306cSNickeau                         * if we transform or
8004fd306cSNickeau                         * use a CSS pattern (because it use the text color as one of painting color)
8104fd306cSNickeau                         */
8204fd306cSNickeau                        !isset($background[TagAttributes::TRANSFORM]) &&
8304fd306cSNickeau                        !isset($background[self::PATTERN_ATTRIBUTE])
8404fd306cSNickeau                    ) {
8504fd306cSNickeau                        /**
8604fd306cSNickeau                         * For readability,
8704fd306cSNickeau                         * we put the background on the parent node
8804fd306cSNickeau                         * because there is only one background
8904fd306cSNickeau                         */
90*70bbd7f1Sgerardnico                        $backgroundImage = $background[self::BACKGROUND_IMAGE] ?? null;
91*70bbd7f1Sgerardnico                        if ($backgroundImage !== null) {
92*70bbd7f1Sgerardnico                            $tagAttributes->addComponentAttributeValueIfNotEmpty(self::BACKGROUND_IMAGE, $backgroundImage);
93*70bbd7f1Sgerardnico                        }
94*70bbd7f1Sgerardnico                        $backgroundColor = $background[self::BACKGROUND_COLOR] ?? null;
95*70bbd7f1Sgerardnico                        if ($backgroundColor !== null) {
96*70bbd7f1Sgerardnico                            $tagAttributes->addComponentAttributeValueIfNotEmpty(self::BACKGROUND_COLOR, $backgroundColor);
97*70bbd7f1Sgerardnico                        }
98*70bbd7f1Sgerardnico                        $opacityAttribute = $background[Opacity::OPACITY_ATTRIBUTE] ?? null;
99*70bbd7f1Sgerardnico                        if ($opacityAttribute !== null) {
100*70bbd7f1Sgerardnico                            $tagAttributes->addComponentAttributeValueIfNotEmpty(Opacity::OPACITY_ATTRIBUTE, $opacityAttribute);
101*70bbd7f1Sgerardnico                        }
102*70bbd7f1Sgerardnico                        $backgroundPosition = $background[self::BACKGROUND_POSITION] ?? null;
103*70bbd7f1Sgerardnico                        if ($backgroundPosition !== null) {
104*70bbd7f1Sgerardnico                            $tagAttributes->addComponentAttributeValueIfNotEmpty(self::BACKGROUND_POSITION, $backgroundPosition);
105*70bbd7f1Sgerardnico                        }
106*70bbd7f1Sgerardnico                        $backgroundFill = $background[self::BACKGROUND_FILL] ?? null;
107*70bbd7f1Sgerardnico                        if ($backgroundFill !== null) {
108*70bbd7f1Sgerardnico                            $tagAttributes->addComponentAttributeValueIfNotEmpty(self::BACKGROUND_FILL, $backgroundFill);
109*70bbd7f1Sgerardnico                        }
11004fd306cSNickeau                    } else {
11104fd306cSNickeau                        $backgroundTagAttribute = TagAttributes::createFromCallStackArray($background);
11204fd306cSNickeau                        $backgroundTagAttribute->addClassName(self::CANONICAL);
11304fd306cSNickeau                        $backgroundHTML = "<div class=\"backgrounds\">" .
11404fd306cSNickeau                            $backgroundTagAttribute->toHtmlEnterTag("div") .
11504fd306cSNickeau                            "</div>" .
11604fd306cSNickeau                            "</div>";
11704fd306cSNickeau                        $tagAttributes->addHtmlAfterEnterTag($backgroundHTML);
11804fd306cSNickeau                    }
11904fd306cSNickeau                    break;
12004fd306cSNickeau                default:
12104fd306cSNickeau                    /**
12204fd306cSNickeau                     * More than one background
12304fd306cSNickeau                     * This backgrounds should have been set on the backgrounds
12404fd306cSNickeau                     */
12504fd306cSNickeau                    $backgroundHTML = "";
12604fd306cSNickeau                    foreach ($backgrounds as $background) {
12704fd306cSNickeau                        $backgroundTagAttribute = TagAttributes::createFromCallStackArray($background);
12804fd306cSNickeau                        $backgroundTagAttribute->addClassName(self::CANONICAL);
12904fd306cSNickeau                        $backgroundHTMLEnter = $backgroundTagAttribute->toHtmlEnterTag("div");
13004fd306cSNickeau                        $backgroundHTML .= $backgroundHTMLEnter . "</div>";
13104fd306cSNickeau                    }
13204fd306cSNickeau                    $tagAttributes->addHtmlAfterEnterTag($backgroundHTML);
13304fd306cSNickeau                    break;
13404fd306cSNickeau            }
13504fd306cSNickeau        }
13604fd306cSNickeau
13704fd306cSNickeau        /**
13804fd306cSNickeau         * Background-image attribute
13904fd306cSNickeau         */
14004fd306cSNickeau        $backgroundImageStyleValue = "";
14104fd306cSNickeau        if ($tagAttributes->hasComponentAttribute(self::BACKGROUND_IMAGE)) {
14204fd306cSNickeau            $backgroundImageValue = $tagAttributes->getValueAndRemove(self::BACKGROUND_IMAGE);
14304fd306cSNickeau            if (is_string($backgroundImageValue)) {
14404fd306cSNickeau                /**
14504fd306cSNickeau                 * Image background is set by the user
14604fd306cSNickeau                 */
14704fd306cSNickeau                $backgroundImageStyleValue = $tagAttributes->getValueAndRemove(self::BACKGROUND_IMAGE);
14804fd306cSNickeau
14904fd306cSNickeau            } else {
15004fd306cSNickeau
15104fd306cSNickeau                if (is_array($backgroundImageValue)) {
15204fd306cSNickeau
15304fd306cSNickeau                    /**
15404fd306cSNickeau                     * Background-fill for background image
15504fd306cSNickeau                     */
15604fd306cSNickeau                    $backgroundFill = $tagAttributes->getValueAndRemove(self::BACKGROUND_FILL, "cover");
15704fd306cSNickeau                    switch ($backgroundFill) {
15804fd306cSNickeau                        case "cover":
15904fd306cSNickeau                            // it makes the background responsive
16004fd306cSNickeau                            $tagAttributes->addStyleDeclarationIfNotSet(self::BACKGROUND_SIZE, $backgroundFill);
16104fd306cSNickeau                            $tagAttributes->addStyleDeclarationIfNotSet(self::BACKGROUND_REPEAT, "no-repeat");
16204fd306cSNickeau                            $tagAttributes->addStyleDeclarationIfNotSet(self::BACKGROUND_POSITION, "center center");
16304fd306cSNickeau
16404fd306cSNickeau                            /**
16504fd306cSNickeau                             * The type of image is important for the processing of SVG
16604fd306cSNickeau                             */
16704fd306cSNickeau                            $backgroundImageValue[TagAttributes::TYPE_KEY] = FetcherSvg::ILLUSTRATION_TYPE;
16804fd306cSNickeau                            break;
16904fd306cSNickeau                        case "tile":
17004fd306cSNickeau                            // background size is then "auto" (ie repeat), the default
17104fd306cSNickeau                            // background position is not needed (the tile start on the left top corner)
17204fd306cSNickeau                            $tagAttributes->addStyleDeclarationIfNotSet(self::BACKGROUND_REPEAT, "repeat");
17304fd306cSNickeau
17404fd306cSNickeau                            /**
17504fd306cSNickeau                             * The type of image is important for the processing of SVG
17604fd306cSNickeau                             * A tile needs to have a width and a height
17704fd306cSNickeau                             */
17804fd306cSNickeau                            $backgroundImageValue[TagAttributes::TYPE_KEY] = FetcherSvg::TILE_TYPE;
17904fd306cSNickeau                            break;
18004fd306cSNickeau                        case "css":
18104fd306cSNickeau                            // custom, set by the user in own css stylesheet, nothing to do
18204fd306cSNickeau                            break;
18304fd306cSNickeau                        default:
18404fd306cSNickeau                            LogUtility::msg("The background `fill` attribute ($backgroundFill) is unknown. If you want to take over the filling via css, set the `fill` value to `css`.", self::CANONICAL);
18504fd306cSNickeau                            break;
18604fd306cSNickeau                    }
18704fd306cSNickeau
18804fd306cSNickeau
18904fd306cSNickeau                    try {
19004fd306cSNickeau                        $mediaMarkup = MediaMarkup::createFromCallStackArray($backgroundImageValue)
19104fd306cSNickeau                            ->setLinking(MediaMarkup::LINKING_NOLINK_VALUE);
19204fd306cSNickeau                    } catch (ExceptionCompile $e) {
19304fd306cSNickeau                        LogUtility::error("We could not create a background image. Error: {$e->getMessage()}");
19404fd306cSNickeau                        return;
19504fd306cSNickeau                    }
19604fd306cSNickeau
19704fd306cSNickeau                    try {
19804fd306cSNickeau                        $imageFetcher = $mediaMarkup->getFetcher();
19904fd306cSNickeau                    } catch (ExceptionBadArgument|ExceptionInternal|ExceptionNotFound $e) {
20004fd306cSNickeau                        LogUtility::internalError("The fetcher for the background image ($mediaMarkup) returns an error", self::CANONICAL, $e);
20104fd306cSNickeau                        return;
20204fd306cSNickeau                    }
20304fd306cSNickeau                    $mime = $imageFetcher->getMime();
20404fd306cSNickeau                    if (!$mime->isImage()) {
20504fd306cSNickeau                        LogUtility::error("The background image ($mediaMarkup) is not an image but a $mime", self::CANONICAL);
20604fd306cSNickeau                        return;
20704fd306cSNickeau                    }
20804fd306cSNickeau                    $backgroundImageStyleValue = "url(" . $imageFetcher->getFetchUrl()->toAbsoluteUrl()->toCssString() . ")";
20904fd306cSNickeau
21004fd306cSNickeau                } else {
21104fd306cSNickeau                    LogUtility::msg("Internal Error: The background image value ($backgroundImageValue) is not a string nor an array", LogUtility::LVL_MSG_ERROR, self::CANONICAL);
21204fd306cSNickeau                }
21304fd306cSNickeau
21404fd306cSNickeau            }
21504fd306cSNickeau        }
21604fd306cSNickeau        if (!empty($backgroundImageStyleValue)) {
21704fd306cSNickeau            if ($tagAttributes->hasComponentAttribute(Opacity::OPACITY_ATTRIBUTE)) {
21804fd306cSNickeau                $opacity = $tagAttributes->getValueAndRemove(Opacity::OPACITY_ATTRIBUTE);
21904fd306cSNickeau                $finalOpacity = 1 - $opacity;
22004fd306cSNickeau                /**
22104fd306cSNickeau                 * In the argument of linear-gradient, we don't use `0 100%` to apply the
22204fd306cSNickeau                 * same image everywhere
22304fd306cSNickeau                 *
22404fd306cSNickeau                 * because the validator https://validator.w3.org/ would complain with
22504fd306cSNickeau                 * `
22604fd306cSNickeau                 * CSS: background-image: too few values for the property linear-gradient.
22704fd306cSNickeau                 * `
22804fd306cSNickeau                 */
22904fd306cSNickeau                $backgroundImageStyleValue = "linear-gradient(to right, rgba(255,255,255, $finalOpacity) 0 50%, rgba(255,255,255, $finalOpacity) 50% 100%)," . $backgroundImageStyleValue;
23004fd306cSNickeau            }
23104fd306cSNickeau            $tagAttributes->addStyleDeclarationIfNotSet(self::BACKGROUND_IMAGE, $backgroundImageStyleValue);
23204fd306cSNickeau        }
23304fd306cSNickeau
23404fd306cSNickeau
23504fd306cSNickeau        /**
23604fd306cSNickeau         * Process the pattern css
23704fd306cSNickeau         * https://bansal.io/pattern-css
23804fd306cSNickeau         * This call should be before the processing of the background color
23904fd306cSNickeau         * because it will set one if it's not available
24004fd306cSNickeau         */
24104fd306cSNickeau        self::processPatternAttribute($tagAttributes);
24204fd306cSNickeau
24304fd306cSNickeau        /**
24404fd306cSNickeau         * Background color
24504fd306cSNickeau         */
24604fd306cSNickeau        if ($tagAttributes->hasComponentAttribute(self::BACKGROUND_COLOR)) {
24704fd306cSNickeau
24804fd306cSNickeau            $colorValue = $tagAttributes->getValueAndRemove(self::BACKGROUND_COLOR);
24904fd306cSNickeau
25004fd306cSNickeau            $gradientPrefix = 'gradient-';
25104fd306cSNickeau            if (strpos($colorValue, $gradientPrefix) === 0) {
25204fd306cSNickeau                /**
25304fd306cSNickeau                 * A gradient is an image
25404fd306cSNickeau                 * Check that there is no image
25504fd306cSNickeau                 */
25604fd306cSNickeau                if (!empty($backgroundImageStyleValue)) {
25704fd306cSNickeau                    LogUtility::msg("An image and a linear gradient color are exclusive because a linear gradient color creates an image. You can't use the linear color (" . $colorValue . ") and the image (" . $backgroundImageStyleValue . ")", LogUtility::LVL_MSG_WARNING, self::CANONICAL);
25804fd306cSNickeau                } else {
25904fd306cSNickeau                    $mainColorValue = substr($colorValue, strlen($gradientPrefix));
26004fd306cSNickeau                    $tagAttributes->addStyleDeclarationIfNotSet(self::BACKGROUND_IMAGE, 'linear-gradient(to top,#fff 0,' . ColorRgb::createFromString($mainColorValue)->toCssValue() . ' 100%)');
26104fd306cSNickeau                    $tagAttributes->addStyleDeclarationIfNotSet(self::BACKGROUND_COLOR, 'unset!important');
26204fd306cSNickeau                }
26304fd306cSNickeau            } else {
26404fd306cSNickeau
26504fd306cSNickeau                $colorValue = ColorRgb::createFromString($colorValue)->toCssValue();
26604fd306cSNickeau                $tagAttributes->addStyleDeclarationIfNotSet(self::BACKGROUND_COLOR, $colorValue);
26704fd306cSNickeau
26804fd306cSNickeau            }
26904fd306cSNickeau        }
27004fd306cSNickeau
27104fd306cSNickeau
27204fd306cSNickeau    }
27304fd306cSNickeau
27404fd306cSNickeau    /**
27504fd306cSNickeau     * Return a background array with background properties
27604fd306cSNickeau     * from a media {@link MediaLink::toCallStackArray()}
27704fd306cSNickeau     * @param array $mediaCallStackArray
27804fd306cSNickeau     * @return array
27904fd306cSNickeau     */
28004fd306cSNickeau    public static function fromMediaToBackgroundImageStackArray(array $mediaCallStackArray): array
28104fd306cSNickeau    {
28204fd306cSNickeau        /**
28304fd306cSNickeau         * This attributes should no be taken
28404fd306cSNickeau         */
28504fd306cSNickeau        $mediaCallStackArray[MediaMarkup::LINKING_KEY] = LazyLoad::LAZY_LOAD_METHOD_NONE_VALUE;
28604fd306cSNickeau        $mediaCallStackArray[Align::ALIGN_ATTRIBUTE] = null;
28704fd306cSNickeau        $mediaCallStackArray[TagAttributes::TITLE_KEY] = null; // not sure why
28804fd306cSNickeau        return $mediaCallStackArray;
28904fd306cSNickeau
29004fd306cSNickeau    }
29104fd306cSNickeau
29204fd306cSNickeau    /**
29304fd306cSNickeau     * @param TagAttributes $tagAttributes
29404fd306cSNickeau     * Process the `pattern` attribute
29504fd306cSNickeau     * that implements
29604fd306cSNickeau     * https://bansal.io/pattern-css
29704fd306cSNickeau     */
29804fd306cSNickeau    private static function processPatternAttribute(TagAttributes &$tagAttributes)
29904fd306cSNickeau    {
30004fd306cSNickeau        /**
30104fd306cSNickeau         * Css Pattern
30204fd306cSNickeau         */
30304fd306cSNickeau        if ($tagAttributes->hasComponentAttribute(self::PATTERN_ATTRIBUTE)) {
30404fd306cSNickeau
30504fd306cSNickeau            /**
30604fd306cSNickeau             * Attach the stylesheet
30704fd306cSNickeau             */
30804fd306cSNickeau            PluginUtility::getSnippetManager()->attachRemoteCssStyleSheet(
30904fd306cSNickeau                self::PATTERN_CSS_SNIPPET_ID,
31004fd306cSNickeau                "https://cdn.jsdelivr.net/npm/pattern.css@1.0.0/dist/pattern.min.css",
31104fd306cSNickeau                "sha256-Vwich3JPJa27TO9g6q+TxJGE7DNEigBaHNPm+KkMR6o=")
31204fd306cSNickeau                ->setCritical(false); // not blocking for rendering
31304fd306cSNickeau
31404fd306cSNickeau
31504fd306cSNickeau            $patternValue = strtolower($tagAttributes->getValueAndRemove(self::PATTERN_ATTRIBUTE));
31604fd306cSNickeau
31704fd306cSNickeau            $lastIndexOfMinus = StringUtility::lastIndexOf($patternValue, "-");
31804fd306cSNickeau            $lastMinusPart = substr($patternValue, $lastIndexOfMinus);
31904fd306cSNickeau            /**
32004fd306cSNickeau             * Do we have the size as last part
32104fd306cSNickeau             */
32204fd306cSNickeau            if (!in_array($lastMinusPart, self::PATTERN_CSS_SIZE)) {
32304fd306cSNickeau                /**
32404fd306cSNickeau                 * We don't have a size
32504fd306cSNickeau                 */
32604fd306cSNickeau                $pattern = $patternValue;
32704fd306cSNickeau                $size = "md";
32804fd306cSNickeau            } else {
32904fd306cSNickeau                $pattern = substr($patternValue, 0, $lastIndexOfMinus);
33004fd306cSNickeau                $size = $lastMinusPart;
33104fd306cSNickeau            }
33204fd306cSNickeau            /**
33304fd306cSNickeau             * Does this pattern is a known pattern
33404fd306cSNickeau             */
33504fd306cSNickeau            if (!in_array($pattern, self::PATTERN_NAMES)) {
33604fd306cSNickeau                LogUtility::msg("The pattern (" . $pattern . ") is not a known CSS pattern and was ignored.", LogUtility::LVL_MSG_WARNING, self::CANONICAL);
33704fd306cSNickeau                return;
33804fd306cSNickeau            } else {
33904fd306cSNickeau                $tagAttributes->addClassName(self::PATTERN_CSS_CLASS_PREFIX . "-" . $pattern . "-" . $size);
34004fd306cSNickeau            }
34104fd306cSNickeau
34204fd306cSNickeau            if (!$tagAttributes->hasComponentAttribute(self::BACKGROUND_COLOR)) {
34304fd306cSNickeau                LogUtility::msg("The background color was not set for the background with the (" . $pattern . "). It was set to the default color.", LogUtility::LVL_MSG_INFO, self::CANONICAL);
34404fd306cSNickeau                $tagAttributes->addComponentAttributeValue(self::BACKGROUND_COLOR, "steelblue");
34504fd306cSNickeau            }
34604fd306cSNickeau            /**
34704fd306cSNickeau             * Color
34804fd306cSNickeau             */
34904fd306cSNickeau            if ($tagAttributes->hasComponentAttribute(self::PATTERN_COLOR_ATTRIBUTE)) {
35004fd306cSNickeau                $patternColor = $tagAttributes->getValueAndRemove(self::PATTERN_COLOR_ATTRIBUTE);
35104fd306cSNickeau            } else {
35204fd306cSNickeau                LogUtility::msg("The pattern color was not set for the background with the (" . $pattern . "). It was set to the default color.", LogUtility::LVL_MSG_INFO, self::CANONICAL);
35304fd306cSNickeau                $patternColor = "#FDE482";
35404fd306cSNickeau            }
35504fd306cSNickeau            $tagAttributes->addStyleDeclarationIfNotSet(ColorRgb::COLOR, $patternColor);
35604fd306cSNickeau
35704fd306cSNickeau        }
35804fd306cSNickeau    }
35904fd306cSNickeau
36004fd306cSNickeau
36104fd306cSNickeau}
362