diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..79c3e0d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,18 @@ +; This file is for unifying the coding style for different editors and IDEs. +; More information at http://editorconfig.org + +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false + +[*.yml] +indent_size = 2 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..7b50fc8 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,14 @@ +/art export-ignore +/docs export-ignore +/tests export-ignore +/scripts export-ignore +/.github export-ignore +/.php_cs export-ignore +.editorconfig export-ignore +.gitattributes export-ignore +.gitignore export-ignore +phpstan.neon.dist export-ignore +phpunit.xml.dist export-ignore +CHANGELOG.md export-ignore +CONTRIBUTING.md export-ignore +README.md export-ignore diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..791c38c --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: mozex diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml new file mode 100644 index 0000000..00a9ee3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -0,0 +1,58 @@ +name: Bug Report +description: Report an Issue or Bug with the Package +title: "[Bug]: " +labels: ["bug"] +body: + - type: markdown + attributes: + value: | + We're sorry to hear you have a problem. Can you help us solve it by providing the following details. + - type: textarea + id: what-happened + attributes: + label: What happened? + description: What did you expect to happen? + placeholder: I cannot currently do X thing because when I do, it breaks X thing. + validations: + required: true + - type: textarea + id: how-to-reproduce + attributes: + label: How to reproduce the bug + description: How did this occur, please add any config values used and provide a set of reliable steps if possible. + placeholder: When I do X I see Y. + validations: + required: true + - type: input + id: package-version + attributes: + label: Package Version + description: What version of our Package are you running? Please be as specific as possible + placeholder: 1.0.0 + validations: + required: true + - type: input + id: php-version + attributes: + label: PHP Version + description: What version of PHP are you running? Please be as specific as possible + placeholder: 8.3.0 + validations: + required: true + - type: dropdown + id: operating-systems + attributes: + label: Which operating systems does with happen with? + description: You may select more than one. + multiple: true + options: + - macOS + - Windows + - Linux + - type: textarea + id: notes + attributes: + label: Notes + description: Use this field to provide any other notes that you feel might be relevant to the issue. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..4d3bc18 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,11 @@ +blank_issues_enabled: false +contact_links: + - name: Ask a question + url: https://github.com/mozex/commonmark-routes/discussions/new?category=q-a + about: Ask the community for help + - name: Request a feature + url: https://github.com/mozex/commonmark-routes/discussions/new?category=ideas + about: Share ideas for new features + - name: Report a security issue + url: https://github.com/mozex/commonmark-routes/security/policy + about: Learn how to notify us for sensitive bugs diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..fdbf155 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,16 @@ + + +### What: + +- [ ] Bug Fix +- [ ] New Feature + +### Description: + + + +### Related: + + diff --git a/.github/SECURITY.md b/.github/SECURITY.md new file mode 100644 index 0000000..c2db9db --- /dev/null +++ b/.github/SECURITY.md @@ -0,0 +1,11 @@ +# Security Policy + +**PLEASE DON'T DISCLOSE SECURITY-RELATED ISSUES PUBLICLY, [SEE BELOW](#reporting-a-vulnerability).** + +## Supported Versions + +Only the latest major version receives security fixes. + +## Reporting a Vulnerability + +If you discover a security vulnerability within this package, please send an email to Mozex at mozex@alphorld.com. All security vulnerabilities will be promptly addressed. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..1815dd6 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,9 @@ +version: 2 +updates: + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + labels: + - "dependencies" diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml new file mode 100644 index 0000000..bdedd30 --- /dev/null +++ b/.github/workflows/changelog.yml @@ -0,0 +1,33 @@ +name: Changelog + +on: + release: + types: [released] + +permissions: + contents: write + +jobs: + update: + name: Update + runs-on: ubuntu-latest + timeout-minutes: 5 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: main + + - name: Update Changelog + uses: stefanzweifel/changelog-updater-action@v1 + with: + latest-version: ${{ github.event.release.name }} + release-notes: ${{ github.event.release.body }} + + - name: Commit updated CHANGELOG + uses: stefanzweifel/git-auto-commit-action@v5 + with: + branch: main + commit_message: Update CHANGELOG + file_pattern: CHANGELOG.md diff --git a/.github/workflows/formats.yml b/.github/workflows/formats.yml new file mode 100644 index 0000000..907bddb --- /dev/null +++ b/.github/workflows/formats.yml @@ -0,0 +1,44 @@ +name: Formats + +on: ['push', 'pull_request'] + +jobs: + ci: + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: true + matrix: + os: [ubuntu-latest] + php: [8.2] + dependency-version: [prefer-lowest, prefer-stable] + + name: Formats P${{ matrix.php }} - ${{ matrix.os }} - ${{ matrix.dependency-version }} + + steps: + + - name: Checkout + uses: actions/checkout@v4 + + - name: Cache dependencies + uses: actions/cache@v4 + with: + path: ~/.composer/cache/files + key: dependencies-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }} + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: dom, mbstring, zip + tools: prestissimo + coverage: pcov + + - name: Install Composer dependencies + run: composer update --${{ matrix.dependency-version }} --no-interaction --prefer-dist + + - name: Coding Style Checks + run: composer test:lint + + - name: Type Checks + run: composer test:types diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..7fa7d2b --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,48 @@ +name: Tests + +on: ['push', 'pull_request'] + +jobs: + ci: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: true + matrix: + os: [ubuntu-latest, windows-latest] + php: [8.1, 8.2, 8.3] + laravel: [11.*, 10.*, 9.*] + dependency-version: [prefer-lowest, prefer-stable] + exclude: + - php: 8.1 + laravel: 11.* + + name: Tests P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.os }} - ${{ matrix.dependency-version }} + steps: + + - name: Checkout + uses: actions/checkout@v4 + + - name: Cache dependencies + uses: actions/cache@v4 + with: + path: ~/.composer/cache/files + key: dependencies-php-${{ matrix.php }}-L${{ matrix.laravel }}-${{ matrix.dependency-version }}-composer-${{ hashFiles('composer.json') }} + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: dom, mbstring, zip, fileinfo + coverage: none + + - name: Require Laravel Version + run: > + composer require + "laravel/framework:${{ matrix.laravel }}" + --no-interaction --no-update + + - name: Install Composer dependencies + run: composer update --${{ matrix.dependency-version }} --no-interaction --prefer-dist + + - name: Integration Tests + run: php ./vendor/bin/pest diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8e954e3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +/.phpunit.cache +/.php-cs-fixer.cache +/.php-cs-fixer.php +/composer.lock +/phpunit.xml +/vendor/ +*.swp +*.swo diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..23b1a32 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +# Changelog + +All notable changes to `commonmark-routes` will be documented in this file. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..e8a5a8b --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,48 @@ +# CONTRIBUTING + +Contributions are welcome, and are accepted via pull requests. +Please review these guidelines before submitting any pull requests. + +## Process + +1. Fork the project +1. Create a new branch +1. Code, test, commit and push +1. Open a pull request detailing your changes. Make sure to follow the [template](.github/PULL_REQUEST_TEMPLATE.md) + +## Guidelines + +* Please ensure the coding style running `composer lint`. +* Send a coherent commit history, making sure each individual commit in your pull request is meaningful. +* You may need to [rebase](https://git-scm.com/book/en/v2/Git-Branching-Rebasing) to avoid merge conflicts. +* Please remember that we follow [SemVer](http://semver.org/). + +## Setup + +Clone your fork, then install the dev dependencies: +```bash +composer install +``` +## Lint + +Lint your code: +```bash +composer lint +``` + +## Tests + +Run all tests: +```bash +composer test +``` + +Check types: +```bash +composer test:types +``` + +Unit tests: +```bash +composer test:unit +``` diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..b85950c --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) mozex + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..34418a8 --- /dev/null +++ b/README.md @@ -0,0 +1,117 @@ +# Use Laravel Routes inside markdown + +[![Latest Version on Packagist](https://img.shields.io/packagist/v/mozex/commonmark-routes.svg?style=flat-square)](https://packagist.org/packages/mozex/commonmark-routes) +[![GitHub Tests Workflow Status](https://img.shields.io/github/actions/workflow/status/mozex/commonmark-routes/tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/mozex/commonmark-routes/actions/workflows/tests.yml) +[![License](https://img.shields.io/github/license/mozex/commonmark-routes.svg?style=flat-square)](https://packagist.org/packages/mozex/commonmark-routes) + +An extension for [league/commonmark](https://github.com/thephpleague/commonmark) that allows you to use Laravel routes +inside markdown, just as you would in your PHP code. + +> **Warning:** This extension is intended for use in controlled environments where the markdown is trusted. Do not use +this extension for processing user-input markdown due to potential security risks. + +## Table of Contents + +- [Support Us](#support-us) +- [Installation](#installation) +- [Usage](#usage) + - [Basic Usage](#usage) + - [Spatie Laravel Markdown](#spatie-laravel-markdown) +- [Testing](#testing) +- [Changelog](#changelog) +- [Contributing](#contributing) +- [Security Vulnerabilities](#security-vulnerabilities) +- [Credits](#credits) +- [License](#license) + +## Support us + +Creating and maintaining open-source projects requires significant time and effort. Your support will help enhance the project and enable further contributions to the PHP community. + +Sponsorship can be made through the [GitHub Sponsors](https://github.com/sponsors/mozex) program. Just click the "**[Sponsor](https://github.com/sponsors/mozex)**" button at the top of this repository. Any amount is greatly appreciated, even a contribution as small as $1 can make a big difference and will go directly towards developing and improving this package. + +Thank you for considering sponsoring. Your support truly makes a difference! + +## Installation + +> **Requires [PHP 8.1+](https://php.net/releases/)** + +You can install the package via composer: + +```bash +composer require mozex/commonmark-routes +``` + +## Usage + +Register RoutesExtension as a CommonMark extension and use the route function instead of URLs in your markdown, just as +you would in your PHP code. + +```php +use League\CommonMark\Environment\Environment; +use League\CommonMark\CommonMarkConverter; +use Mozex\CommonMarkRoutes\RoutesExtension; + +$converter = new CommonMarkConverter($environment); +$converter->getEnvironment()->addExtension(new RoutesExtension()); + +echo $converter->convert("[Home](route('home'))"); +// Output:

Home

+ +echo $converter->convert("[Home](route('home', absolute: false))"); +// Output:

Home

+ +echo $converter->convert("[Product](route('product', 3))"); +// Output:

Product

+ +echo $converter->convert("[Features](route('home', ['id' => 'features']))"); +// Output:

Features

+ +echo $converter->convert("[Features](route('home', ['id' => 'features'], false))"); +// Output:

Features

+``` + +For more information on CommonMark extensions and environments, refer to the [CommonMark documentation](https://commonmark.thephpleague.com/2.4/basic-usage/). + +### Spatie Laravel Markdown + +When using the [Laravel Markdown](https://github.com/spatie/laravel-markdown/) package, you may register the extension in `config/markdown.php`: + +```php +/* + * These extensions should be added to the markdown environment. A valid + * extension implements League\CommonMark\Extension\ExtensionInterface + * + * More info: https://commonmark.thephpleague.com/2.4/extensions/overview/ + */ +'extensions' => [ + Mozex\CommonMarkRoutes\RoutesExtension::class, +], +``` + +## Testing + +```bash +composer test +``` + +## Changelog + +Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. + +## Contributing + +Please see [CONTRIBUTING](CONTRIBUTING.md) for details. + +## Security Vulnerabilities + +Please review [our security policy](../../security/policy) on how to report security vulnerabilities. + +## Credits + +- [Mozex](https://github.com/mozex) +- [All Contributors](../../contributors) + +## License + +The MIT License (MIT). Please see [License File](LICENSE.md) for more information. diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..336408e --- /dev/null +++ b/composer.json @@ -0,0 +1,96 @@ +{ + "name": "mozex/commonmark-routes", + "description": "Laravel routes in Markdown: A CommonMark extension to seamlessly use Laravel route functions within your Markdown content.", + "keywords": [ + "laravel", + "php", + "commmonmark", + "markdown", + "routes", + "commonmark-routes" + ], + "homepage": "https://github.com/mozex/commonmark-routes", + "license": "MIT", + "authors": [ + { + "name": "Mozex", + "email": "mozex@alphorld.com", + "role": "Developer" + } + ], + "require": { + "php": "^8.1", + "illuminate/contracts": "^10.0|^11.0", + "league/commonmark": "^2.4", + "spatie/laravel-package-tools": "^1.16" + }, + "require-dev": { + "laravel/pint": "^1.13.6", + "larastan/larastan": "^2.0.1", + "nunomaduro/collision": "^7.8|^8.1", + "orchestra/testbench": "^8.21|^9.0", + "pestphp/pest": "^2.34", + "pestphp/pest-plugin-laravel": "^2.0", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-phpunit": "^1.0", + "spatie/laravel-ray": "^1.26" + }, + "autoload": { + "psr-4": { + "Mozex\\CommonMarkRoutes\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Mozex\\CommonMarkRoutes\\Tests\\": "tests/", + "Workbench\\App\\": "workbench/app/" + } + }, + "minimum-stability": "dev", + "prefer-stable": true, + "config": { + "sort-packages": true, + "preferred-install": "dist", + "allow-plugins": { + "pestphp/pest-plugin": true, + "phpstan/extension-installer": true + } + }, + "extra": { + "laravel": { + "providers": [ + "Mozex\\CommonMarkRoutes\\CommonMarkRoutesServiceProvider" + ] + } + }, + "scripts": { + "post-autoload-dump": [ + "@clear", + "@prepare", + "@composer run prepare" + ], + "clear": "@php vendor/bin/testbench package:purge-skeleton --ansi", + "prepare": "@php vendor/bin/testbench package:discover --ansi", + "build": "@php vendor/bin/testbench workbench:build --ansi", + "start": [ + "Composer\\Config::disableProcessTimeout", + "@composer run build", + "@php vendor/bin/testbench serve" + ], + "serve": [ + "Composer\\Config::disableProcessTimeout", + "@build", + "@php vendor/bin/testbench serve" + ], + "lint": "pint", + "test:lint": "pint --test", + "test:types": "phpstan analyse --ansi", + "test:unit": "pest --colors=always", + "test": [ + "@test:lint", + "@test:types", + "@test:unit" + ] + } +} diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 0000000..5fd25fc --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,6 @@ +parameters: + level: max + paths: + - src + + reportUnmatchedIgnoredErrors: true diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..03df8d9 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,34 @@ + + + + + ./tests + + + + + ./src + + + diff --git a/src/CommonMarkRoutesServiceProvider.php b/src/CommonMarkRoutesServiceProvider.php new file mode 100644 index 0000000..b5424a2 --- /dev/null +++ b/src/CommonMarkRoutesServiceProvider.php @@ -0,0 +1,15 @@ +name('laravel-commonmark-routes'); + } +} diff --git a/src/RoutesExtension.php b/src/RoutesExtension.php new file mode 100644 index 0000000..14d63ed --- /dev/null +++ b/src/RoutesExtension.php @@ -0,0 +1,59 @@ +configuration = $configuration; + } + + public function register(EnvironmentBuilderInterface $environment): void + { + $environment->addEventListener( + eventClass: DocumentPreParsedEvent::class, + listener: [$this, 'onPreParsed'] + ); + } + + public function onPreParsed(DocumentPreParsedEvent $event): void + { + $event->replaceMarkdown( + new MarkdownInput( + str($event->getMarkdown()->getContent()) + ->replaceMatches( + $this->pattern, + $this->replaceRouteWithUrl(...) + ) + ) + ); + } + + /** + * @param array $matches + */ + private function replaceRouteWithUrl(array $matches): string + { + $linkText = $matches[1]; + $url = $this->getUrl($matches[2]); + + return "[$linkText]($url)"; + } + + public function getUrl(string $routeString): string + { + return eval("return route($routeString);"); + } +} diff --git a/testbench b/testbench new file mode 100644 index 0000000..fea5314 --- /dev/null +++ b/testbench @@ -0,0 +1,19 @@ +#!/usr/bin/env php + [], + 'dont-discover' => [], + ], +); + +$commander = new Orchestra\Testbench\Console\Commander($config, $workingPath); + +$commander->handle(); diff --git a/testbench.yaml b/testbench.yaml new file mode 100644 index 0000000..f431f89 --- /dev/null +++ b/testbench.yaml @@ -0,0 +1,3 @@ +providers: + - Workbench\App\Providers\WorkbenchServiceProvider + - Mozex\CommonMarkRoutes\CommonMarkRoutesServiceProvider diff --git a/tests/ArchTest.php b/tests/ArchTest.php new file mode 100644 index 0000000..df1a27a --- /dev/null +++ b/tests/ArchTest.php @@ -0,0 +1,5 @@ +expect(['dd', 'ddd', 'dump', 'ray', 'die', 'var_dump', 'print_r']) + ->each->not->toBeUsed(); diff --git a/tests/Feature/RoutesExtensionTest.php b/tests/Feature/RoutesExtensionTest.php new file mode 100644 index 0000000..0363355 --- /dev/null +++ b/tests/Feature/RoutesExtensionTest.php @@ -0,0 +1,60 @@ +getEnvironment()->addExtension(new RoutesExtension()); + + expect(trim($converter->convert('[About](/about)')->getContent())) + ->toBe('

About

'); +}); + +it('will not replace normal absolute link route in links', function () { + $converter = new CommonMarkConverter(); + $converter->getEnvironment()->addExtension(new RoutesExtension()); + + expect(trim($converter->convert('[Google](https://google.com)')->getContent())) + ->toBe('

Google

'); +}); + +it('replaces route in links', function () { + $converter = new CommonMarkConverter(); + $converter->getEnvironment()->addExtension(new RoutesExtension()); + + expect(trim($converter->convert("[About](route('about'))")->getContent())) + ->toBe('

About

'); +}); + +it('replaces route in links with parameter', function () { + $converter = new CommonMarkConverter(); + $converter->getEnvironment()->addExtension(new RoutesExtension()); + + expect(trim($converter->convert("[Product](route('product', 1))")->getContent())) + ->toBe('

Product

'); +}); + +it('replaces route in links with query string', function () { + $converter = new CommonMarkConverter(); + $converter->getEnvironment()->addExtension(new RoutesExtension()); + + expect(trim($converter->convert("[Home](route('home', ['id' => 'features']))")->getContent())) + ->toBe('

Home

'); +}); + +it('replaces route in links as relative url', function () { + $converter = new CommonMarkConverter(); + $converter->getEnvironment()->addExtension(new RoutesExtension()); + + expect(trim($converter->convert("[Home](route('home', ['id' => 'features'], false))")->getContent())) + ->toBe('

Home

'); +}); + +it('replaces route with named arguments', function () { + $converter = new CommonMarkConverter(); + $converter->getEnvironment()->addExtension(new RoutesExtension()); + + expect(trim($converter->convert("[Home](route('home', absolute: false))")->getContent())) + ->toBe('

Home

'); +}); diff --git a/tests/Pest.php b/tests/Pest.php new file mode 100644 index 0000000..a6db057 --- /dev/null +++ b/tests/Pest.php @@ -0,0 +1,5 @@ +in(__DIR__); diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..9db7e79 --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,30 @@ + 'home') + ->name('home'); + + Route::get('about', fn () => 'about') + ->name('about'); + + Route::get('product/{id}', fn (int $id) => "product $id") + ->name('product'); + + } +} diff --git a/workbench/app/Providers/WorkbenchServiceProvider.php b/workbench/app/Providers/WorkbenchServiceProvider.php new file mode 100644 index 0000000..2be93c9 --- /dev/null +++ b/workbench/app/Providers/WorkbenchServiceProvider.php @@ -0,0 +1,7 @@ +